From 0ec07e442b35fbf55e4e174f44d6d188b40b945c Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 25 Jan 2023 13:43:13 +0000 Subject: [PATCH 01/35] Add functions to hide some internals of long object. --- Include/cpython/longintrepr.h | 4 +++ Include/internal/pycore_long.h | 50 ++++++++++++++++++++++++++++++++-- Modules/_decimal/_decimal.c | 43 ++++++----------------------- Modules/mathmodule.c | 15 +++++----- Objects/listobject.c | 16 ++++------- Objects/longobject.c | 32 ++++++++++++++-------- Python/bltinmodule.c | 12 ++++---- Python/bytecodes.c | 13 ++++----- Python/generated_cases.c.h | 11 ++++---- Python/marshal.c | 7 +++-- Python/specialize.c | 8 +++--- 11 files changed, 120 insertions(+), 91 deletions(-) diff --git a/Include/cpython/longintrepr.h b/Include/cpython/longintrepr.h index 810daa83165e71..55fa50cc7eeddb 100644 --- a/Include/cpython/longintrepr.h +++ b/Include/cpython/longintrepr.h @@ -94,6 +94,10 @@ PyAPI_FUNC(PyLongObject *) _PyLong_New(Py_ssize_t); /* Return a copy of src. */ PyAPI_FUNC(PyObject *) _PyLong_Copy(PyLongObject *src); +PyAPI_FUNC(PyLongObject *) +_PyLong_FromDigits(int sign, Py_ssize_t digit_count, digit *digits); + + #ifdef __cplusplus } #endif diff --git a/Include/internal/pycore_long.h b/Include/internal/pycore_long.h index 8c1d017bb95e4e..d18559f464d0e5 100644 --- a/Include/internal/pycore_long.h +++ b/Include/internal/pycore_long.h @@ -112,7 +112,7 @@ PyAPI_FUNC(char*) _PyLong_FormatBytesWriter( /* Return 1 if the argument is positive single digit int */ static inline int -_PyLong_IsPositiveSingleDigit(PyObject* sub) { +_PyLong_IsPositiveSingleDigit(const PyObject* op) { /* For a positive single digit int, the value of Py_SIZE(sub) is 0 or 1. We perform a fast check using a single comparison by casting from int @@ -124,11 +124,55 @@ _PyLong_IsPositiveSingleDigit(PyObject* sub) { The function is not affected by -fwrapv, -fno-wrapv and -ftrapv compiler options of GCC and clang */ - assert(PyLong_CheckExact(sub)); - Py_ssize_t signed_size = Py_SIZE(sub); + assert(PyLong_Check(op)); + Py_ssize_t signed_size = Py_SIZE(op); return ((size_t)signed_size) <= 1; } + +static inline int +_PyLong_IsSingleDigit(const PyObject* op) { + assert(PyLong_Check(op)); + Py_ssize_t signed_size = Py_SIZE(op); + return ((size_t)(signed_size+1)) <= 2; +} + +static inline Py_ssize_t +_PyLong_SingleDigitValue(const PyLongObject *op) +{ + assert(PyLong_Check(op)); + assert(Py_SIZE(op) >= -1 && Py_SIZE(op) <= 1); + return Py_SIZE(op) * op->long_value.ob_digit[0]; +} + +static inline Py_ssize_t +_PyLong_DigitCount(const PyLongObject *op) +{ + assert(PyLong_Check(op)); + return Py_ABS(Py_SIZE(op)); +} + + +static inline bool +_PyLong_IsNegative(const PyLongObject *op) +{ + return Py_SIZE(op) < 0; +} + + +static inline bool +_PyLong_IsZero(const PyLongObject *op) +{ + return Py_SIZE(op) == 0; +} + +static inline bool +_PyLong_IsPositive(const PyLongObject *op) +{ + return Py_SIZE(op) > 0; +} + + #ifdef __cplusplus } #endif diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 5936fbaaf35eb0..4abd92e326402f 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -30,6 +30,7 @@ #endif #include +#include "pycore_long.h" // _PyLong_IsZero() #include "pycore_pystate.h" // _PyThreadState_GET() #include "complexobject.h" #include "mpdecimal.h" @@ -2146,35 +2147,25 @@ dec_from_long(PyTypeObject *type, PyObject *v, { PyObject *dec; PyLongObject *l = (PyLongObject *)v; - Py_ssize_t ob_size; - size_t len; - uint8_t sign; dec = PyDecType_New(type); if (dec == NULL) { return NULL; } - ob_size = Py_SIZE(l); - if (ob_size == 0) { + if (_PyLong_IsZero(l)) { _dec_settriple(dec, MPD_POS, 0, 0); return dec; } - if (ob_size < 0) { - len = -ob_size; - sign = MPD_NEG; - } - else { - len = ob_size; - sign = MPD_POS; - } + uint8_t sign = _PyLong_IsNegative(l) ? MPD_NEG : MPD_POS; - if (len == 1) { - _dec_settriple(dec, sign, *l->long_value.ob_digit, 0); + if (_PyLong_IsSingleDigit((PyObject *)l)) { + _dec_settriple(dec, sign, l->long_value.ob_digit[0], 0); mpd_qfinalize(MPD(dec), ctx, status); return dec; } + size_t len = _PyLong_DigitCount(l); #if PYLONG_BITS_IN_DIGIT == 30 mpd_qimport_u32(MPD(dec), l->long_value.ob_digit, len, sign, PyLong_BASE, @@ -3482,7 +3473,6 @@ dec_as_long(PyObject *dec, PyObject *context, int round) PyLongObject *pylong; digit *ob_digit; size_t n; - Py_ssize_t i; mpd_t *x; mpd_context_t workctx; uint32_t status = 0; @@ -3536,26 +3526,9 @@ dec_as_long(PyObject *dec, PyObject *context, int round) } assert(n > 0); - pylong = _PyLong_New(n); - if (pylong == NULL) { - mpd_free(ob_digit); - mpd_del(x); - return NULL; - } - - memcpy(pylong->long_value.ob_digit, ob_digit, n * sizeof(digit)); + assert(!mpd_iszero(x)); + pylong = _PyLong_FromDigits(mpd_isnegative(x) ? -1 : 1, n, ob_digit); mpd_free(ob_digit); - - i = n; - while ((i > 0) && (pylong->long_value.ob_digit[i-1] == 0)) { - i--; - } - - Py_SET_SIZE(pylong, i); - if (mpd_isnegative(x) && !mpd_iszero(x)) { - Py_SET_SIZE(pylong, -i); - } - mpd_del(x); return (PyObject *) pylong; } diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index 544560e8322c72..5ce91af6aa8eaf 100644 --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -729,7 +729,7 @@ long_lcm(PyObject *a, PyObject *b) { PyObject *g, *m, *f, *ab; - if (Py_SIZE(a) == 0 || Py_SIZE(b) == 0) { + if (_PyLong_IsZero((PyLongObject *)a) || _PyLong_IsZero((PyLongObject *)b)) { return PyLong_FromLong(0); } g = _PyLong_GCD(a, b); @@ -2147,7 +2147,7 @@ loghelper(PyObject* arg, double (*func)(double)) Py_ssize_t e; /* Negative or zero inputs give a ValueError. */ - if (Py_SIZE(arg) <= 0) { + if (!_PyLong_IsPositive((PyLongObject *)arg)) { PyErr_SetString(PyExc_ValueError, "math domain error"); return NULL; @@ -3751,12 +3751,12 @@ math_perm_impl(PyObject *module, PyObject *n, PyObject *k) } assert(PyLong_CheckExact(n) && PyLong_CheckExact(k)); - if (Py_SIZE(n) < 0) { + if (_PyLong_IsNegative((PyLongObject *)n)) { PyErr_SetString(PyExc_ValueError, "n must be a non-negative integer"); goto error; } - if (Py_SIZE(k) < 0) { + if (_PyLong_IsNegative((PyLongObject *)k)) { PyErr_SetString(PyExc_ValueError, "k must be a non-negative integer"); goto error; @@ -3843,12 +3843,12 @@ math_comb_impl(PyObject *module, PyObject *n, PyObject *k) } assert(PyLong_CheckExact(n) && PyLong_CheckExact(k)); - if (Py_SIZE(n) < 0) { + if (_PyLong_IsNegative((PyLongObject *)n)) { PyErr_SetString(PyExc_ValueError, "n must be a non-negative integer"); goto error; } - if (Py_SIZE(k) < 0) { + if (_PyLong_IsNegative((PyLongObject *)k)) { PyErr_SetString(PyExc_ValueError, "k must be a non-negative integer"); goto error; @@ -3880,7 +3880,8 @@ math_comb_impl(PyObject *module, PyObject *n, PyObject *k) if (temp == NULL) { goto error; } - if (Py_SIZE(temp) < 0) { + assert(PyLong_Check(temp)); + if (_PyLong_IsNegative((PyLongObject *)temp)) { Py_DECREF(temp); result = PyLong_FromLong(0); goto done; diff --git a/Objects/listobject.c b/Objects/listobject.c index 1a210e77d55c29..6d24172c7dc129 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -4,6 +4,7 @@ #include "pycore_abstract.h" // _PyIndex_Check() #include "pycore_interp.h" // PyInterpreterState.list #include "pycore_list.h" // struct _Py_list_state, _PyListIterObject +#include "pycore_long.h" // _PyLong_DigitCount #include "pycore_object.h" // _PyObject_GC_TRACK() #include "pycore_tuple.h" // _PyTuple_FromArray() #include @@ -2149,19 +2150,14 @@ unsafe_long_compare(PyObject *v, PyObject *w, MergeState *ms) /* Modified from Objects/longobject.c:long_compare, assuming: */ assert(Py_IS_TYPE(v, &PyLong_Type)); assert(Py_IS_TYPE(w, &PyLong_Type)); - assert(Py_ABS(Py_SIZE(v)) <= 1); - assert(Py_ABS(Py_SIZE(w)) <= 1); + assert(_PyLong_IsSingleDigit(v)); + assert(_PyLong_IsSingleDigit(w)); vl = (PyLongObject*)v; wl = (PyLongObject*)w; - v0 = Py_SIZE(vl) == 0 ? 0 : (sdigit)vl->long_value.ob_digit[0]; - w0 = Py_SIZE(wl) == 0 ? 0 : (sdigit)wl->long_value.ob_digit[0]; - - if (Py_SIZE(vl) < 0) - v0 = -v0; - if (Py_SIZE(wl) < 0) - w0 = -w0; + v0 = _PyLong_SingleDigitValue(vl); + w0 = _PyLong_SingleDigitValue(wl); res = v0 < w0; assert(res == PyObject_RichCompareBool(v, w, Py_LT)); @@ -2359,7 +2355,7 @@ list_sort_impl(PyListObject *self, PyObject *keyfunc, int reverse) if (keys_are_all_same_type) { if (key_type == &PyLong_Type && ints_are_bounded && - Py_ABS(Py_SIZE(key)) > 1) { + !_PyLong_IsSingleDigit(key)) { ints_are_bounded = 0; } diff --git a/Objects/longobject.c b/Objects/longobject.c index 51655cd0bad9ec..3433fdcbd17108 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -170,30 +170,40 @@ _PyLong_New(Py_ssize_t size) return result; } +PyLongObject * +_PyLong_FromDigits(int sign, Py_ssize_t digit_count, digit *digits) +{ + assert(digit_count >= 0); + PyLongObject *result = _PyLong_New(digit_count); + if (result == NULL) { + PyErr_NoMemory(); + return NULL; + } + assert(sign >= -1 && sign <= 1); + result->long_value.ob_size = sign * digit_count; + memcpy(result->long_value.ob_digit, digits, digit_count * sizeof(digit)); + return result; +} + PyObject * _PyLong_Copy(PyLongObject *src) { - PyLongObject *result; Py_ssize_t i; assert(src != NULL); i = Py_SIZE(src); - if (i < 0) - i = -(i); + int sign = 1; + if (i < 0) { + i = -i; + sign = -1; + } if (i < 2) { stwodigits ival = medium_value(src); if (IS_SMALL_INT(ival)) { return get_small_int((sdigit)ival); } } - result = _PyLong_New(i); - if (result != NULL) { - Py_SET_SIZE(result, Py_SIZE(src)); - while (--i >= 0) { - result->long_value.ob_digit[i] = src->long_value.ob_digit[i]; - } - } - return (PyObject *)result; + return (PyObject *)_PyLong_FromDigits(sign, i, src->long_value.ob_digit); } static PyObject * diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 53439ab16040c4..c9ae65855a19e1 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -5,6 +5,7 @@ #include "pycore_ast.h" // _PyAST_Validate() #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_compile.h" // _PyAST_Compile() +#include "pycore_long.h" // _PyLong_SingleDigitValue #include "pycore_object.h" // _Py_AddToAllObjects() #include "pycore_pyerrors.h" // _PyErr_NoMemory() #include "pycore_pystate.h" // _PyThreadState_GET() @@ -2506,12 +2507,11 @@ builtin_sum_impl(PyObject *module, PyObject *iterable, PyObject *start) long b; overflow = 0; /* Single digits are common, fast, and cannot overflow on unpacking. */ - switch (Py_SIZE(item)) { - case -1: b = -(sdigit) ((PyLongObject*)item)->long_value.ob_digit[0]; break; - // Note: the continue goes to the top of the "while" loop that iterates over the elements - case 0: Py_DECREF(item); continue; - case 1: b = ((PyLongObject*)item)->long_value.ob_digit[0]; break; - default: b = PyLong_AsLongAndOverflow(item, &overflow); break; + if (_PyLong_IsSingleDigit(item)) { + b = _PyLong_SingleDigitValue((PyLongObject *)item); + } + else { + b = PyLong_AsLongAndOverflow(item, &overflow); } if (overflow == 0 && (i_result >= 0 ? (b <= LONG_MAX - i_result) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 63dbecad3b45fc..b85128d6fdea19 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -357,7 +357,6 @@ dummy_func( // Deopt unless 0 <= sub < PyList_Size(list) DEOPT_IF(!_PyLong_IsPositiveSingleDigit(sub), BINARY_SUBSCR); - assert(((PyLongObject *)_PyLong_GetZero())->long_value.ob_digit[0] == 0); Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; DEOPT_IF(index >= PyList_GET_SIZE(list), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); @@ -375,7 +374,6 @@ dummy_func( // Deopt unless 0 <= sub < PyTuple_Size(list) DEOPT_IF(!_PyLong_IsPositiveSingleDigit(sub), BINARY_SUBSCR); - assert(((PyLongObject *)_PyLong_GetZero())->long_value.ob_digit[0] == 0); Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; DEOPT_IF(index >= PyTuple_GET_SIZE(tuple), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); @@ -1782,12 +1780,13 @@ dummy_func( assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), COMPARE_AND_BRANCH); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_AND_BRANCH); - DEOPT_IF((size_t)(Py_SIZE(left) + 1) > 2, COMPARE_AND_BRANCH); - DEOPT_IF((size_t)(Py_SIZE(right) + 1) > 2, COMPARE_AND_BRANCH); + DEOPT_IF(!_PyLong_IsSingleDigit(left), COMPARE_AND_BRANCH); + DEOPT_IF(!_PyLong_IsSingleDigit(right), COMPARE_AND_BRANCH); STAT_INC(COMPARE_AND_BRANCH, hit); - assert(Py_ABS(Py_SIZE(left)) <= 1 && Py_ABS(Py_SIZE(right)) <= 1); - Py_ssize_t ileft = Py_SIZE(left) * ((PyLongObject *)left)->long_value.ob_digit[0]; - Py_ssize_t iright = Py_SIZE(right) * ((PyLongObject *)right)->long_value.ob_digit[0]; + assert(_PyLong_DigitCount((PyLongObject *)left) <= 1 && + _PyLong_DigitCount((PyLongObject *)right) <= 1); + Py_ssize_t ileft = _PyLong_SingleDigitValue((PyLongObject *)left); + Py_ssize_t iright = _PyLong_SingleDigitValue((PyLongObject *)right); // 2 if <, 4 if >, 8 if ==; this matches the low 4 bits of the oparg int sign_ish = COMPARISON_BIT(ileft, iright); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 271ba26f489521..72f04eb5870d0a 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2242,12 +2242,13 @@ assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), COMPARE_AND_BRANCH); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_AND_BRANCH); - DEOPT_IF((size_t)(Py_SIZE(left) + 1) > 2, COMPARE_AND_BRANCH); - DEOPT_IF((size_t)(Py_SIZE(right) + 1) > 2, COMPARE_AND_BRANCH); + DEOPT_IF(!_PyLong_IsSingleDigit(left), COMPARE_AND_BRANCH); + DEOPT_IF(!_PyLong_IsSingleDigit(right), COMPARE_AND_BRANCH); STAT_INC(COMPARE_AND_BRANCH, hit); - assert(Py_ABS(Py_SIZE(left)) <= 1 && Py_ABS(Py_SIZE(right)) <= 1); - Py_ssize_t ileft = Py_SIZE(left) * ((PyLongObject *)left)->long_value.ob_digit[0]; - Py_ssize_t iright = Py_SIZE(right) * ((PyLongObject *)right)->long_value.ob_digit[0]; + assert(_PyLong_DigitCount((PyLongObject *)left) <= 1 && + _PyLong_DigitCount((PyLongObject *)right) <= 1); + Py_ssize_t ileft = _PyLong_SingleDigitValue((PyLongObject *)left); + Py_ssize_t iright = _PyLong_SingleDigitValue((PyLongObject *)right); // 2 if <, 4 if >, 8 if ==; this matches the low 4 bits of the oparg int sign_ish = COMPARISON_BIT(ileft, iright); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); diff --git a/Python/marshal.c b/Python/marshal.c index 94e79d4392ae6d..1ccf1c06d20b3c 100644 --- a/Python/marshal.c +++ b/Python/marshal.c @@ -11,6 +11,7 @@ #include "Python.h" #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_code.h" // _PyCode_New() +#include "pycore_long.h" // _PyLong_DigitCount #include "pycore_hashtable.h" // _Py_hashtable_t #include "marshal.h" // Py_MARSHAL_VERSION @@ -232,13 +233,13 @@ w_PyLong(const PyLongObject *ob, char flag, WFILE *p) digit d; W_TYPE(TYPE_LONG, p); - if (Py_SIZE(ob) == 0) { + if (_PyLong_IsZero(ob)) { w_long((long)0, p); return; } /* set l to number of base PyLong_MARSHAL_BASE digits */ - n = Py_ABS(Py_SIZE(ob)); + n = _PyLong_DigitCount(ob); l = (n-1) * PyLong_MARSHAL_RATIO; d = ob->long_value.ob_digit[n-1]; assert(d != 0); /* a PyLong is always normalized */ @@ -251,7 +252,7 @@ w_PyLong(const PyLongObject *ob, char flag, WFILE *p) p->error = WFERR_UNMARSHALLABLE; return; } - w_long((long)(Py_SIZE(ob) > 0 ? l : -l), p); + w_long((long)(_PyLong_IsNegative(ob) ? -l : l), p); for (i=0; i < n-1; i++) { d = ob->long_value.ob_digit[i]; diff --git a/Python/specialize.c b/Python/specialize.c index 3405d2b0ab0680..1779735550d62d 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -1294,7 +1294,7 @@ _Py_Specialize_BinarySubscr( PyTypeObject *container_type = Py_TYPE(container); if (container_type == &PyList_Type) { if (PyLong_CheckExact(sub)) { - if (Py_SIZE(sub) == 0 || Py_SIZE(sub) == 1) { + if (_PyLong_IsPositiveSingleDigit(sub)) { instr->op.code = BINARY_SUBSCR_LIST_INT; goto success; } @@ -1307,7 +1307,7 @@ _Py_Specialize_BinarySubscr( } if (container_type == &PyTuple_Type) { if (PyLong_CheckExact(sub)) { - if (Py_SIZE(sub) == 0 || Py_SIZE(sub) == 1) { + if (_PyLong_IsPositiveSingleDigit(sub)) { instr->op.code = BINARY_SUBSCR_TUPLE_INT; goto success; } @@ -1375,7 +1375,7 @@ _Py_Specialize_StoreSubscr(PyObject *container, PyObject *sub, _Py_CODEUNIT *ins PyTypeObject *container_type = Py_TYPE(container); if (container_type == &PyList_Type) { if (PyLong_CheckExact(sub)) { - if ((Py_SIZE(sub) == 0 || Py_SIZE(sub) == 1) + if (_PyLong_IsPositiveSingleDigit(sub) && ((PyLongObject *)sub)->long_value.ob_digit[0] < (size_t)PyList_GET_SIZE(container)) { instr->op.code = STORE_SUBSCR_LIST_INT; @@ -1993,7 +1993,7 @@ _Py_Specialize_CompareAndBranch(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *inst goto success; } if (PyLong_CheckExact(lhs)) { - if (Py_ABS(Py_SIZE(lhs)) <= 1 && Py_ABS(Py_SIZE(rhs)) <= 1) { + if (_PyLong_IsSingleDigit(lhs) && _PyLong_IsSingleDigit(rhs)) { instr->op.code = COMPARE_AND_BRANCH_INT; goto success; } From 292b9d0ed867dc3c9c22d37d961f14bfe78ab9e8 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 25 Jan 2023 16:42:11 +0000 Subject: [PATCH 02/35] Add internal functions to longobject.c for setting sign and digit count. --- Objects/longobject.c | 70 ++++++++++++++++++++++++++++---------------- 1 file changed, 44 insertions(+), 26 deletions(-) diff --git a/Objects/longobject.c b/Objects/longobject.c index 3433fdcbd17108..4b8043befa05a6 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -42,6 +42,19 @@ medium_value(PyLongObject *x) /* If defined, use algorithms from the _pylong.py module */ #define WITH_PYLONG_MODULE 1 +static inline void +_PyLong_SetSignAndSize(PyLongObject *op, bool negative, Py_ssize_t size) +{ + int sign = 1-negative*2; + assert(sign == -1 || sign == 1); + op->long_value.ob_size = sign * size; +} + +static inline void +_PyLong_FlipSign(PyLongObject *op) { + op->long_value.ob_size = -op->long_value.ob_size; +} + static inline void _Py_DECREF_INT(PyLongObject *op) { @@ -132,7 +145,7 @@ long_normalize(PyLongObject *v) while (i > 0 && v->long_value.ob_digit[i-1] == 0) --i; if (i != j) { - Py_SET_SIZE(v, (Py_SIZE(v) < 0) ? -(i) : i); + _PyLong_SetSignAndSize(v, _PyLong_IsNegative(v), i); } return v; } @@ -228,18 +241,18 @@ static PyObject * _PyLong_FromLarge(stwodigits ival) { twodigits abs_ival; - int sign; + bool negative; assert(!is_medium_int(ival)); if (ival < 0) { /* negate: can't write this as abs_ival = -ival since that invokes undefined behaviour when ival is LONG_MIN */ abs_ival = 0U-(twodigits)ival; - sign = -1; + negative = true; } else { abs_ival = (twodigits)ival; - sign = 1; + negative = false; } /* Must be at least two digits */ assert(abs_ival >> PyLong_SHIFT != 0); @@ -252,7 +265,7 @@ _PyLong_FromLarge(stwodigits ival) PyLongObject *v = _PyLong_New(ndigits); if (v != NULL) { digit *p = v->long_value.ob_digit; - Py_SET_SIZE(v, ndigits * sign); + _PyLong_SetSignAndSize(v, negative, ndigits); t = abs_ival; while (t) { *p++ = Py_SAFE_DOWNCAST( @@ -318,7 +331,7 @@ _PyLong_Negate(PyLongObject **x_p) x = (PyLongObject *)*x_p; if (Py_REFCNT(x) == 1) { - Py_SET_SIZE(x, -Py_SIZE(x)); + _PyLong_FlipSign(x); return; } @@ -357,7 +370,7 @@ PyLong_FromLong(long ival) v = _PyLong_New(ndigits); if (v != NULL) { digit *p = v->long_value.ob_digit; - Py_SET_SIZE(v, ival < 0 ? -ndigits : ndigits); + _PyLong_SetSignAndSize(v, ival < 0, ndigits); t = abs_ival; while (t) { *p++ = (digit)(t & PyLong_MASK); @@ -467,7 +480,7 @@ PyLong_FromDouble(double dval) frac = ldexp(frac, PyLong_SHIFT); } if (neg) { - Py_SET_SIZE(v, -(Py_SIZE(v))); + _PyLong_FlipSign(v); } return (PyObject *)v; } @@ -962,7 +975,7 @@ _PyLong_FromByteArray(const unsigned char* bytes, size_t n, } } - Py_SET_SIZE(v, is_signed ? -idigit : idigit); + _PyLong_SetSignAndSize(v, is_signed, idigit); return (PyObject *)maybe_small_long(long_normalize(v)); } @@ -1184,7 +1197,7 @@ PyLong_FromLongLong(long long ival) v = _PyLong_New(ndigits); if (v != NULL) { digit *p = v->long_value.ob_digit; - Py_SET_SIZE(v, ival < 0 ? -ndigits : ndigits); + _PyLong_SetSignAndSize(v, ival < 0, ndigits); t = abs_ival; while (t) { *p++ = (digit)(t & PyLong_MASK); @@ -1227,7 +1240,7 @@ PyLong_FromSsize_t(Py_ssize_t ival) v = _PyLong_New(ndigits); if (v != NULL) { digit *p = v->long_value.ob_digit; - Py_SET_SIZE(v, negative ? -ndigits : ndigits); + _PyLong_SetSignAndSize(v, negative, ndigits); t = abs_ival; while (t) { *p++ = (digit)(t & PyLong_MASK); @@ -2542,7 +2555,7 @@ long_from_non_binary_base(const char *start, const char *end, Py_ssize_t digits, *res = NULL; return 0; } - Py_SET_SIZE(z, 0); + _PyLong_SetSignAndSize(z, false, 0); /* `convwidth` consecutive input digits are treated as a single * digit in base `convmultmax`. @@ -2593,7 +2606,8 @@ long_from_non_binary_base(const char *start, const char *end, Py_ssize_t digits, assert(c < PyLong_BASE); if (Py_SIZE(z) < size_z) { *pz = (digit)c; - Py_SET_SIZE(z, Py_SIZE(z) + 1); + assert(!_PyLong_IsNegative(z)); + _PyLong_SetSignAndSize(z, false, Py_SIZE(z) + 1); } else { PyLongObject *tmp; @@ -2809,7 +2823,7 @@ PyLong_FromString(const char *str, char **pend, int base) /* Set sign and normalize */ if (sign < 0) { - Py_SET_SIZE(z, -(Py_SIZE(z))); + _PyLong_FlipSign(z); } long_normalize(z); z = maybe_small_long(z); @@ -3472,7 +3486,7 @@ x_sub(PyLongObject *a, PyLongObject *b) } assert(borrow == 0); if (sign < 0) { - Py_SET_SIZE(z, -Py_SIZE(z)); + _PyLong_FlipSign(z); } return maybe_small_long(long_normalize(z)); } @@ -3494,7 +3508,7 @@ _PyLong_Add(PyLongObject *a, PyLongObject *b) That also means z is not an element of small_ints, so negating it in-place is safe. */ assert(Py_REFCNT(z) == 1); - Py_SET_SIZE(z, -(Py_SIZE(z))); + _PyLong_FlipSign(z); } } else @@ -3532,7 +3546,7 @@ _PyLong_Subtract(PyLongObject *a, PyLongObject *b) z = x_add(a, b); if (z != NULL) { assert(Py_SIZE(z) == 0 || Py_REFCNT(z) == 1); - Py_SET_SIZE(z, -(Py_SIZE(z))); + _PyLong_FlipSign(z); } } } @@ -3943,7 +3957,8 @@ k_lopsided_mul(PyLongObject *a, PyLongObject *b) /* Multiply the next slice of b by a. */ memcpy(bslice->long_value.ob_digit, b->long_value.ob_digit + nbdone, nbtouse * sizeof(digit)); - Py_SET_SIZE(bslice, nbtouse); + assert(nbtouse >= 0); + _PyLong_SetSignAndSize(bslice, false, nbtouse); product = k_mul(a, bslice); if (product == NULL) goto fail; @@ -4914,7 +4929,7 @@ long_neg(PyLongObject *v) return _PyLong_FromSTwoDigits(-medium_value(v)); z = (PyLongObject *)_PyLong_Copy(v); if (z != NULL) - Py_SET_SIZE(z, -(Py_SIZE(v))); + _PyLong_FlipSign(z); return (PyObject *)z; } @@ -5034,7 +5049,7 @@ long_rshift1(PyLongObject *a, Py_ssize_t wordshift, digit remshift) significant `wordshift` digits of `a` is nonzero. Digit `wordshift` of `2**shift - 1` has value `PyLong_MASK >> hishift`. */ - Py_SET_SIZE(z, -newsize); + _PyLong_SetSignAndSize(z, true, newsize); digit sticky = 0; for (Py_ssize_t j = 0; j < wordshift; j++) { @@ -5115,7 +5130,7 @@ long_lshift1(PyLongObject *a, Py_ssize_t wordshift, digit remshift) return NULL; if (Py_SIZE(a) < 0) { assert(Py_REFCNT(z) == 1); - Py_SET_SIZE(z, -Py_SIZE(z)); + _PyLong_FlipSign(z); } for (i = 0; i < wordshift; i++) z->long_value.ob_digit[i] = 0; @@ -5299,7 +5314,7 @@ long_bitwise(PyLongObject *a, /* Complement result if negative. */ if (negz) { - Py_SET_SIZE(z, -(Py_SIZE(z))); + _PyLong_FlipSign(z); z->long_value.ob_digit[size_z] = PyLong_MASK; v_complement(z->long_value.ob_digit, z->long_value.ob_digit, size_z+1); } @@ -5456,7 +5471,8 @@ _PyLong_GCD(PyObject *aarg, PyObject *barg) T = -C; C = -D; D = T; } if (c != NULL) { - Py_SET_SIZE(c, size_a); + assert(size_a >= 0); + _PyLong_SetSignAndSize(c, false, size_a); } else if (Py_REFCNT(a) == 1) { c = (PyLongObject*)Py_NewRef(a); @@ -5469,11 +5485,13 @@ _PyLong_GCD(PyObject *aarg, PyObject *barg) } if (d != NULL) { - Py_SET_SIZE(d, size_a); + assert(size_a >= 0); + _PyLong_SetSignAndSize(d, false, size_a); } else if (Py_REFCNT(b) == 1 && size_a <= alloc_b) { d = (PyLongObject*)Py_NewRef(b); - Py_SET_SIZE(d, size_a); + assert(size_a >= 0); + _PyLong_SetSignAndSize(d, false, size_a); } else { alloc_b = size_a; @@ -5659,7 +5677,7 @@ long_subtype_new(PyTypeObject *type, PyObject *x, PyObject *obase) return NULL; } assert(PyLong_Check(newobj)); - Py_SET_SIZE(newobj, Py_SIZE(tmp)); + newobj->long_value.ob_size = tmp->long_value.ob_size; for (i = 0; i < n; i++) { newobj->long_value.ob_digit[i] = tmp->long_value.ob_digit[i]; } From 5c54894ef94d80835bbbdd785b11a4a65d39cbb5 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Tue, 28 Feb 2023 13:56:35 +0000 Subject: [PATCH 03/35] Replace Py_SIZE(x) < 0 with _PyLong_IsNegative(x) in longobject.c --- Objects/longobject.c | 71 ++++++++++++++++++++++---------------------- 1 file changed, 35 insertions(+), 36 deletions(-) diff --git a/Objects/longobject.c b/Objects/longobject.c index 4b8043befa05a6..5110eabc8617d7 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -300,7 +300,7 @@ _PyLong_AssignValue(PyObject **target, Py_ssize_t value) return 0; } else if (old != NULL && PyLong_CheckExact(old) && - Py_REFCNT(old) == 1 && Py_SIZE(old) == 1 && + Py_REFCNT(old) == 1 && _PyLong_IsPositiveSingleDigit(old) && (size_t)value <= PyLong_MASK) { // Mutate in place if there are no other references the old @@ -824,8 +824,7 @@ _PyLong_Sign(PyObject *vv) assert(v != NULL); assert(PyLong_Check(v)); - - return Py_SIZE(v) == 0 ? 0 : (Py_SIZE(v) < 0 ? -1 : 1); + return _PyLong_IsPositive(v) - _PyLong_IsNegative(v); } static int @@ -996,7 +995,7 @@ _PyLong_AsByteArray(PyLongObject* v, assert(v != NULL && PyLong_Check(v)); - if (Py_SIZE(v) < 0) { + if (_PyLong_IsNegative(v)) { ndigits = -(Py_SIZE(v)); if (!is_signed) { PyErr_SetString(PyExc_OverflowError, @@ -1848,7 +1847,7 @@ long_to_decimal_string_internal(PyObject *aa, return -1; } size_a = Py_ABS(Py_SIZE(a)); - negative = Py_SIZE(a) < 0; + negative = _PyLong_IsNegative(a); /* quick and dirty pre-check for overflowing the decimal digit limit, based on the inequality 10/3 >= log2(10) @@ -2079,7 +2078,7 @@ long_format_binary(PyObject *aa, int base, int alternate, return -1; } size_a = Py_ABS(Py_SIZE(a)); - negative = Py_SIZE(a) < 0; + negative = _PyLong_IsNegative(a); /* Compute a rough upper bound for the length of the string */ switch (base) { @@ -2956,14 +2955,14 @@ long_divrem(PyLongObject *a, PyLongObject *b, The quotient z has the sign of a*b; the remainder r has the sign of a, so a = b*z + r. */ - if ((Py_SIZE(a) < 0) != (Py_SIZE(b) < 0)) { + if ((_PyLong_IsNegative(a)) != (_PyLong_IsNegative(b))) { _PyLong_Negate(&z); if (z == NULL) { Py_CLEAR(*prem); return -1; } } - if (Py_SIZE(a) < 0 && Py_SIZE(*prem) != 0) { + if (_PyLong_IsNegative(a) && Py_SIZE(*prem) != 0) { _PyLong_Negate(prem); if (*prem == NULL) { Py_DECREF(z); @@ -3007,7 +3006,7 @@ long_rem(PyLongObject *a, PyLongObject *b, PyLongObject **prem) return -1; } /* Set the sign. */ - if (Py_SIZE(a) < 0 && Py_SIZE(*prem) != 0) { + if (_PyLong_IsNegative(a) && Py_SIZE(*prem) != 0) { _PyLong_Negate(prem); if (*prem == NULL) { Py_CLEAR(*prem); @@ -3264,7 +3263,7 @@ _PyLong_Frexp(PyLongObject *a, Py_ssize_t *e) } *e = a_bits; - return Py_SIZE(a) < 0 ? -dx : dx; + return _PyLong_IsNegative(a) ? -dx : dx; overflow: /* exponent > PY_SSIZE_T_MAX */ @@ -3326,7 +3325,7 @@ long_compare(PyLongObject *a, PyLongObject *b) break; } } - sign = Py_SIZE(a) < 0 ? -diff : diff; + sign = _PyLong_IsNegative(a) ? -diff : diff; } return sign; } @@ -3499,8 +3498,8 @@ _PyLong_Add(PyLongObject *a, PyLongObject *b) } PyLongObject *z; - if (Py_SIZE(a) < 0) { - if (Py_SIZE(b) < 0) { + if (_PyLong_IsNegative(a)) { + if (_PyLong_IsNegative(b)) { z = x_add(a, b); if (z != NULL) { /* x_add received at least one multiple-digit int, @@ -3515,7 +3514,7 @@ _PyLong_Add(PyLongObject *a, PyLongObject *b) z = x_sub(b, a); } else { - if (Py_SIZE(b) < 0) + if (_PyLong_IsNegative(b)) z = x_sub(a, b); else z = x_add(a, b); @@ -3538,8 +3537,8 @@ _PyLong_Subtract(PyLongObject *a, PyLongObject *b) if (IS_MEDIUM_VALUE(a) && IS_MEDIUM_VALUE(b)) { return _PyLong_FromSTwoDigits(medium_value(a) - medium_value(b)); } - if (Py_SIZE(a) < 0) { - if (Py_SIZE(b) < 0) { + if (_PyLong_IsNegative(a)) { + if (_PyLong_IsNegative(b)) { z = x_sub(b, a); } else { @@ -3551,7 +3550,7 @@ _PyLong_Subtract(PyLongObject *a, PyLongObject *b) } } else { - if (Py_SIZE(b) < 0) + if (_PyLong_IsNegative(b)) z = x_add(a, b); else z = x_sub(a, b); @@ -4160,8 +4159,8 @@ l_divmod(PyLongObject *v, PyLongObject *w, #endif if (long_divrem(v, w, &div, &mod) < 0) return -1; - if ((Py_SIZE(mod) < 0 && Py_SIZE(w) > 0) || - (Py_SIZE(mod) > 0 && Py_SIZE(w) < 0)) { + if ((_PyLong_IsNegative(mod) && Py_SIZE(w) > 0) || + (Py_SIZE(mod) > 0 && _PyLong_IsNegative(w))) { PyLongObject *temp; temp = (PyLongObject *) long_add(mod, w); Py_SETREF(mod, temp); @@ -4207,8 +4206,8 @@ l_mod(PyLongObject *v, PyLongObject *w, PyLongObject **pmod) } if (long_rem(v, w, &mod) < 0) return -1; - if ((Py_SIZE(mod) < 0 && Py_SIZE(w) > 0) || - (Py_SIZE(mod) > 0 && Py_SIZE(w) < 0)) { + if ((_PyLong_IsNegative(mod) && Py_SIZE(w) > 0) || + (Py_SIZE(mod) > 0 && _PyLong_IsNegative(w))) { PyLongObject *temp; temp = (PyLongObject *) long_add(mod, w); Py_SETREF(mod, temp); @@ -4344,7 +4343,7 @@ long_true_divide(PyObject *v, PyObject *w) /* Reduce to case where a and b are both positive. */ a_size = Py_ABS(Py_SIZE(a)); b_size = Py_ABS(Py_SIZE(b)); - negate = (Py_SIZE(a) < 0) ^ (Py_SIZE(b) < 0); + negate = (_PyLong_IsNegative(a)) ^ (_PyLong_IsNegative(b)); if (b_size == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "division by zero"); @@ -4661,7 +4660,7 @@ long_pow(PyObject *v, PyObject *w, PyObject *x) Py_RETURN_NOTIMPLEMENTED; } - if (Py_SIZE(b) < 0 && c == NULL) { + if (_PyLong_IsNegative(b) && c == NULL) { /* if exponent is negative and there's no modulus: return a float. This works because we know that this calls float_pow() which converts its @@ -4683,7 +4682,7 @@ long_pow(PyObject *v, PyObject *w, PyObject *x) /* if modulus < 0: negativeOutput = True modulus = -modulus */ - if (Py_SIZE(c) < 0) { + if (_PyLong_IsNegative(c)) { negativeOutput = 1; temp = (PyLongObject *)_PyLong_Copy(c); if (temp == NULL) @@ -4697,14 +4696,14 @@ long_pow(PyObject *v, PyObject *w, PyObject *x) /* if modulus == 1: return 0 */ - if ((Py_SIZE(c) == 1) && (c->long_value.ob_digit[0] == 1)) { + if ((_PyLong_IsPositiveSingleDigit(c) && (c->long_value.ob_digit[0] == 1)) { z = (PyLongObject *)PyLong_FromLong(0L); goto Done; } /* if exponent is negative, negate the exponent and replace the base with a modular inverse */ - if (Py_SIZE(b) < 0) { + if (_PyLong_IsNegative(b)) { temp = (PyLongObject *)_PyLong_Copy(b); if (temp == NULL) goto Error; @@ -4730,7 +4729,7 @@ long_pow(PyObject *v, PyObject *w, PyObject *x) base % modulus instead. We could _always_ do this reduction, but l_mod() isn't cheap, so we only do it when it buys something. */ - if (Py_SIZE(a) < 0 || Py_SIZE(a) > Py_SIZE(c)) { + if (_PyLong_IsNegative(a) || Py_SIZE(a) > Py_SIZE(c)) { if (l_mod(a, c, &temp) < 0) goto Error; Py_SETREF(a, temp); @@ -4936,7 +4935,7 @@ long_neg(PyLongObject *v) static PyObject * long_abs(PyLongObject *v) { - if (Py_SIZE(v) < 0) + if (_PyLong_IsNegative(v)) return long_neg(v); else return long_long((PyObject *)v); @@ -5007,7 +5006,7 @@ long_rshift1(PyLongObject *a, Py_ssize_t wordshift, digit remshift) return _PyLong_FromSTwoDigits(x); } - a_negative = Py_SIZE(a) < 0; + a_negative = _PyLong_IsNegative(a); size_a = Py_ABS(Py_SIZE(a)); if (a_negative) { @@ -5079,7 +5078,7 @@ long_rshift(PyObject *a, PyObject *b) CHECK_BINOP(a, b); - if (Py_SIZE(b) < 0) { + if (_PyLong_IsNegative(b)) { PyErr_SetString(PyExc_ValueError, "negative shift count"); return NULL; } @@ -5128,7 +5127,7 @@ long_lshift1(PyLongObject *a, Py_ssize_t wordshift, digit remshift) z = _PyLong_New(newsize); if (z == NULL) return NULL; - if (Py_SIZE(a) < 0) { + if (_PyLong_IsNegative(a)) { assert(Py_REFCNT(z) == 1); _PyLong_FlipSign(z); } @@ -5156,7 +5155,7 @@ long_lshift(PyObject *a, PyObject *b) CHECK_BINOP(a, b); - if (Py_SIZE(b) < 0) { + if (_PyLong_IsNegative(b)) { PyErr_SetString(PyExc_ValueError, "negative shift count"); return NULL; } @@ -5219,7 +5218,7 @@ long_bitwise(PyLongObject *a, /* If a is negative, replace it by its two's complement. */ size_a = Py_ABS(Py_SIZE(a)); - nega = Py_SIZE(a) < 0; + nega = _PyLong_IsNegative(a); if (nega) { z = _PyLong_New(size_a); if (z == NULL) @@ -5233,7 +5232,7 @@ long_bitwise(PyLongObject *a, /* Same for b. */ size_b = Py_ABS(Py_SIZE(b)); - negb = Py_SIZE(b) < 0; + negb = _PyLong_IsNegative(b); if (negb) { z = _PyLong_New(size_b); if (z == NULL) { @@ -5771,7 +5770,7 @@ _PyLong_DivmodNear(PyObject *a, PyObject *b) } /* Do a and b have different signs? If so, quotient is negative. */ - quo_is_neg = (Py_SIZE(a) < 0) != (Py_SIZE(b) < 0); + quo_is_neg = (_PyLong_IsNegative(a)) != (_PyLong_IsNegative(b)); if (long_divrem((PyLongObject*)a, (PyLongObject*)b, &quo, &rem) < 0) goto error; @@ -5792,7 +5791,7 @@ _PyLong_DivmodNear(PyObject *a, PyObject *b) Py_DECREF(twice_rem); quo_is_odd = Py_SIZE(quo) != 0 && ((quo->long_value.ob_digit[0] & 1) != 0); - if ((Py_SIZE(b) < 0 ? cmp < 0 : cmp > 0) || (cmp == 0 && quo_is_odd)) { + if ((_PyLong_IsNegative(b) ? cmp < 0 : cmp > 0) || (cmp == 0 && quo_is_odd)) { /* fix up quotient */ if (quo_is_neg) temp = long_sub(quo, (PyLongObject *)one); From 029aaa4eb7a0e1c83287b7cdf60a82cc4b010a0d Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Tue, 28 Feb 2023 14:07:33 +0000 Subject: [PATCH 04/35] Replace Py_ABS(Py_SIZE(a)) with _PyLong_DigitCount(a) in longobject.c --- Objects/longobject.c | 92 ++++++++++++++++++++++---------------------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/Objects/longobject.c b/Objects/longobject.c index 5110eabc8617d7..da2c3cbe1ac51d 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -139,7 +139,7 @@ maybe_small_long(PyLongObject *v) static PyLongObject * long_normalize(PyLongObject *v) { - Py_ssize_t j = Py_ABS(Py_SIZE(v)); + Py_ssize_t j = _PyLong_DigitCount(v); Py_ssize_t i = j; while (i > 0 && v->long_value.ob_digit[i-1] == 0) @@ -847,7 +847,7 @@ _PyLong_NumBits(PyObject *vv) assert(v != NULL); assert(PyLong_Check(v)); - ndigits = Py_ABS(Py_SIZE(v)); + ndigits = _PyLong_DigitCount(v); assert(ndigits == 0 || v->long_value.ob_digit[ndigits - 1] != 0); if (ndigits > 0) { digit msd = v->long_value.ob_digit[ndigits - 1]; @@ -1716,7 +1716,7 @@ inplace_divrem1(digit *pout, digit *pin, Py_ssize_t size, digit n) static PyLongObject * divrem1(PyLongObject *a, digit n, digit *prem) { - const Py_ssize_t size = Py_ABS(Py_SIZE(a)); + const Py_ssize_t size = _PyLong_DigitCount(a); PyLongObject *z; assert(n > 0 && n <= PyLong_MASK); @@ -1748,7 +1748,7 @@ inplace_rem1(digit *pin, Py_ssize_t size, digit n) static PyLongObject * rem1(PyLongObject *a, digit n) { - const Py_ssize_t size = Py_ABS(Py_SIZE(a)); + const Py_ssize_t size = _PyLong_DigitCount(a); assert(n > 0 && n <= PyLong_MASK); return (PyLongObject *)PyLong_FromLong( @@ -1846,7 +1846,7 @@ long_to_decimal_string_internal(PyObject *aa, PyErr_BadInternalCall(); return -1; } - size_a = Py_ABS(Py_SIZE(a)); + size_a = _PyLong_DigitCount(a); negative = _PyLong_IsNegative(a); /* quick and dirty pre-check for overflowing the decimal digit limit, @@ -2077,7 +2077,7 @@ long_format_binary(PyObject *aa, int base, int alternate, PyErr_BadInternalCall(); return -1; } - size_a = Py_ABS(Py_SIZE(a)); + size_a = _PyLong_DigitCount(a); negative = _PyLong_IsNegative(a); /* Compute a rough upper bound for the length of the string */ @@ -2914,7 +2914,7 @@ static int long_divrem(PyLongObject *a, PyLongObject *b, PyLongObject **pdiv, PyLongObject **prem) { - Py_ssize_t size_a = Py_ABS(Py_SIZE(a)), size_b = Py_ABS(Py_SIZE(b)); + Py_ssize_t size_a = _PyLong_DigitCount(a), size_b = _PyLong_DigitCount(b); PyLongObject *z; if (size_b == 0) { @@ -2979,7 +2979,7 @@ long_divrem(PyLongObject *a, PyLongObject *b, static int long_rem(PyLongObject *a, PyLongObject *b, PyLongObject **prem) { - Py_ssize_t size_a = Py_ABS(Py_SIZE(a)), size_b = Py_ABS(Py_SIZE(b)); + Py_ssize_t size_a = _PyLong_DigitCount(a), size_b = _PyLong_DigitCount(b); if (size_b == 0) { PyErr_SetString(PyExc_ZeroDivisionError, @@ -3017,7 +3017,7 @@ long_rem(PyLongObject *a, PyLongObject *b, PyLongObject **prem) } /* Unsigned int division with remainder -- the algorithm. The arguments v1 - and w1 should satisfy 2 <= Py_ABS(Py_SIZE(w1)) <= Py_ABS(Py_SIZE(v1)). */ + and w1 should satisfy 2 <= _PyLong_DigitCount(w1) <= _PyLong_DigitCount(v1). */ static PyLongObject * x_divrem(PyLongObject *v1, PyLongObject *w1, PyLongObject **prem) @@ -3037,8 +3037,8 @@ x_divrem(PyLongObject *v1, PyLongObject *w1, PyLongObject **prem) that won't overflow a digit. */ /* allocate space; w will also be used to hold the final remainder */ - size_v = Py_ABS(Py_SIZE(v1)); - size_w = Py_ABS(Py_SIZE(w1)); + size_v = _PyLong_DigitCount(v1); + size_w = _PyLong_DigitCount(w1); assert(size_v >= size_w && size_w >= 2); /* Assert checks by div() */ v = _PyLong_New(size_v+1); if (v == NULL) { @@ -3177,7 +3177,7 @@ _PyLong_Frexp(PyLongObject *a, Py_ssize_t *e) multiple of 4, rounding ties to a multiple of 8. */ static const int half_even_correction[8] = {0, -1, -2, 1, 0, -1, 2, 1}; - a_size = Py_ABS(Py_SIZE(a)); + a_size = _PyLong_DigitCount(a); if (a_size == 0) { /* Special case for 0: significand 0.0, exponent 0. */ *e = 0; @@ -3317,7 +3317,7 @@ long_compare(PyLongObject *a, PyLongObject *b) { Py_ssize_t sign = Py_SIZE(a) - Py_SIZE(b); if (sign == 0) { - Py_ssize_t i = Py_ABS(Py_SIZE(a)); + Py_ssize_t i = _PyLong_DigitCount(a); sdigit diff = 0; while (--i >= 0) { diff = (sdigit) a->long_value.ob_digit[i] - (sdigit) b->long_value.ob_digit[i]; @@ -3405,7 +3405,7 @@ long_hash(PyLongObject *v) static PyLongObject * x_add(PyLongObject *a, PyLongObject *b) { - Py_ssize_t size_a = Py_ABS(Py_SIZE(a)), size_b = Py_ABS(Py_SIZE(b)); + Py_ssize_t size_a = _PyLong_DigitCount(a), size_b = _PyLong_DigitCount(b); PyLongObject *z; Py_ssize_t i; digit carry = 0; @@ -3439,7 +3439,7 @@ x_add(PyLongObject *a, PyLongObject *b) static PyLongObject * x_sub(PyLongObject *a, PyLongObject *b) { - Py_ssize_t size_a = Py_ABS(Py_SIZE(a)), size_b = Py_ABS(Py_SIZE(b)); + Py_ssize_t size_a = _PyLong_DigitCount(a), size_b = _PyLong_DigitCount(b); PyLongObject *z; Py_ssize_t i; int sign = 1; @@ -3572,8 +3572,8 @@ static PyLongObject * x_mul(PyLongObject *a, PyLongObject *b) { PyLongObject *z; - Py_ssize_t size_a = Py_ABS(Py_SIZE(a)); - Py_ssize_t size_b = Py_ABS(Py_SIZE(b)); + Py_ssize_t size_a = _PyLong_DigitCount(a); + Py_ssize_t size_b = _PyLong_DigitCount(b); Py_ssize_t i; z = _PyLong_New(size_a + size_b); @@ -3681,7 +3681,7 @@ kmul_split(PyLongObject *n, { PyLongObject *hi, *lo; Py_ssize_t size_lo, size_hi; - const Py_ssize_t size_n = Py_ABS(Py_SIZE(n)); + const Py_ssize_t size_n = _PyLong_DigitCount(n); size_lo = Py_MIN(size_n, size); size_hi = size_n - size_lo; @@ -3710,8 +3710,8 @@ static PyLongObject *k_lopsided_mul(PyLongObject *a, PyLongObject *b); static PyLongObject * k_mul(PyLongObject *a, PyLongObject *b) { - Py_ssize_t asize = Py_ABS(Py_SIZE(a)); - Py_ssize_t bsize = Py_ABS(Py_SIZE(b)); + Py_ssize_t asize = _PyLong_DigitCount(a); + Py_ssize_t bsize = _PyLong_DigitCount(b); PyLongObject *ah = NULL; PyLongObject *al = NULL; PyLongObject *bh = NULL; @@ -3928,8 +3928,8 @@ ah*bh and al*bl too. static PyLongObject * k_lopsided_mul(PyLongObject *a, PyLongObject *b) { - const Py_ssize_t asize = Py_ABS(Py_SIZE(a)); - Py_ssize_t bsize = Py_ABS(Py_SIZE(b)); + const Py_ssize_t asize = _PyLong_DigitCount(a); + Py_ssize_t bsize = _PyLong_DigitCount(b); Py_ssize_t nbdone; /* # of b digits already multiplied */ PyLongObject *ret; PyLongObject *bslice = NULL; @@ -4016,8 +4016,8 @@ fast_mod(PyLongObject *a, PyLongObject *b) sdigit right = b->long_value.ob_digit[0]; sdigit mod; - assert(Py_ABS(Py_SIZE(a)) == 1); - assert(Py_ABS(Py_SIZE(b)) == 1); + assert(_PyLong_DigitCount(a) == 1); + assert(_PyLong_DigitCount(b) == 1); if (Py_SIZE(a) == Py_SIZE(b)) { /* 'a' and 'b' have the same sign. */ @@ -4039,8 +4039,8 @@ fast_floor_div(PyLongObject *a, PyLongObject *b) sdigit right = b->long_value.ob_digit[0]; sdigit div; - assert(Py_ABS(Py_SIZE(a)) == 1); - assert(Py_ABS(Py_SIZE(b)) == 1); + assert(_PyLong_DigitCount(a) == 1); + assert(_PyLong_DigitCount(b) == 1); if (Py_SIZE(a) == Py_SIZE(b)) { /* 'a' and 'b' have the same sign. */ @@ -4121,7 +4121,7 @@ l_divmod(PyLongObject *v, PyLongObject *w, { PyLongObject *div, *mod; - if (Py_ABS(Py_SIZE(v)) == 1 && Py_ABS(Py_SIZE(w)) == 1) { + if (_PyLong_DigitCount(v) == 1 && _PyLong_DigitCount(w) == 1) { /* Fast path for single-digit longs */ div = NULL; if (pdiv != NULL) { @@ -4146,8 +4146,8 @@ l_divmod(PyLongObject *v, PyLongObject *w, return 0; } #if WITH_PYLONG_MODULE - Py_ssize_t size_v = Py_ABS(Py_SIZE(v)); /* digits in numerator */ - Py_ssize_t size_w = Py_ABS(Py_SIZE(w)); /* digits in denominator */ + Py_ssize_t size_v = _PyLong_DigitCount(v); /* digits in numerator */ + Py_ssize_t size_w = _PyLong_DigitCount(w); /* digits in denominator */ if (size_w > 300 && (size_v - size_w) > 150) { /* Switch to _pylong.int_divmod(). If the quotient is small then "schoolbook" division is linear-time so don't use in that case. @@ -4199,7 +4199,7 @@ l_mod(PyLongObject *v, PyLongObject *w, PyLongObject **pmod) PyLongObject *mod; assert(pmod); - if (Py_ABS(Py_SIZE(v)) == 1 && Py_ABS(Py_SIZE(w)) == 1) { + if (_PyLong_DigitCount(v) == 1 && _PyLong_DigitCount(w) == 1) { /* Fast path for single-digit longs */ *pmod = (PyLongObject *)fast_mod(v, w); return -(*pmod == NULL); @@ -4226,7 +4226,7 @@ long_div(PyObject *a, PyObject *b) CHECK_BINOP(a, b); - if (Py_ABS(Py_SIZE(a)) == 1 && Py_ABS(Py_SIZE(b)) == 1) { + if (_PyLong_DigitCount((PyLongObject*)a) == 1 && _PyLong_DigitCount((PyLongObject*)b) == 1) { return fast_floor_div((PyLongObject*)a, (PyLongObject*)b); } @@ -4341,8 +4341,8 @@ long_true_divide(PyObject *v, PyObject *w) */ /* Reduce to case where a and b are both positive. */ - a_size = Py_ABS(Py_SIZE(a)); - b_size = Py_ABS(Py_SIZE(b)); + a_size = _PyLong_DigitCount(a); + b_size = _PyLong_DigitCount(b); negate = (_PyLong_IsNegative(a)) ^ (_PyLong_IsNegative(b)); if (b_size == 0) { PyErr_SetString(PyExc_ZeroDivisionError, @@ -4457,7 +4457,7 @@ long_true_divide(PyObject *v, PyObject *w) inexact = 1; Py_DECREF(rem); } - x_size = Py_ABS(Py_SIZE(x)); + x_size = _PyLong_DigitCount(x); assert(x_size > 0); /* result of division is never zero */ x_bits = (x_size-1)*PyLong_SHIFT+bit_length_digit(x->long_value.ob_digit[x_size-1]); @@ -4696,7 +4696,7 @@ long_pow(PyObject *v, PyObject *w, PyObject *x) /* if modulus == 1: return 0 */ - if ((_PyLong_IsPositiveSingleDigit(c) && (c->long_value.ob_digit[0] == 1)) { + if (_PyLong_IsPositiveSingleDigit((PyObject *)c) && (c->long_value.ob_digit[0] == 1)) { z = (PyLongObject *)PyLong_FromLong(0L); goto Done; } @@ -5007,7 +5007,7 @@ long_rshift1(PyLongObject *a, Py_ssize_t wordshift, digit remshift) } a_negative = _PyLong_IsNegative(a); - size_a = Py_ABS(Py_SIZE(a)); + size_a = _PyLong_DigitCount(a); if (a_negative) { /* For negative 'a', adjust so that 0 < remshift <= PyLong_SHIFT, @@ -5078,7 +5078,7 @@ long_rshift(PyObject *a, PyObject *b) CHECK_BINOP(a, b); - if (_PyLong_IsNegative(b)) { + if (_PyLong_IsNegative((PyLongObject *)b)) { PyErr_SetString(PyExc_ValueError, "negative shift count"); return NULL; } @@ -5120,7 +5120,7 @@ long_lshift1(PyLongObject *a, Py_ssize_t wordshift, digit remshift) return _PyLong_FromSTwoDigits(x); } - oldsize = Py_ABS(Py_SIZE(a)); + oldsize = _PyLong_DigitCount(a); newsize = oldsize + wordshift; if (remshift) ++newsize; @@ -5155,7 +5155,7 @@ long_lshift(PyObject *a, PyObject *b) CHECK_BINOP(a, b); - if (_PyLong_IsNegative(b)) { + if (_PyLong_IsNegative((PyLongObject *)b)) { PyErr_SetString(PyExc_ValueError, "negative shift count"); return NULL; } @@ -5217,7 +5217,7 @@ long_bitwise(PyLongObject *a, result back to sign-magnitude at the end. */ /* If a is negative, replace it by its two's complement. */ - size_a = Py_ABS(Py_SIZE(a)); + size_a = _PyLong_DigitCount(a); nega = _PyLong_IsNegative(a); if (nega) { z = _PyLong_New(size_a); @@ -5231,7 +5231,7 @@ long_bitwise(PyLongObject *a, Py_INCREF(a); /* Same for b. */ - size_b = Py_ABS(Py_SIZE(b)); + size_b = _PyLong_DigitCount(b); negb = _PyLong_IsNegative(b); if (negb) { z = _PyLong_New(size_b); @@ -5770,7 +5770,7 @@ _PyLong_DivmodNear(PyObject *a, PyObject *b) } /* Do a and b have different signs? If so, quotient is negative. */ - quo_is_neg = (_PyLong_IsNegative(a)) != (_PyLong_IsNegative(b)); + quo_is_neg = (_PyLong_IsNegative((PyLongObject *)a)) != (_PyLong_IsNegative((PyLongObject *)b)); if (long_divrem((PyLongObject*)a, (PyLongObject*)b, &quo, &rem) < 0) goto error; @@ -5791,7 +5791,7 @@ _PyLong_DivmodNear(PyObject *a, PyObject *b) Py_DECREF(twice_rem); quo_is_odd = Py_SIZE(quo) != 0 && ((quo->long_value.ob_digit[0] & 1) != 0); - if ((_PyLong_IsNegative(b) ? cmp < 0 : cmp > 0) || (cmp == 0 && quo_is_odd)) { + if ((_PyLong_IsNegative((PyLongObject *)b) ? cmp < 0 : cmp > 0) || (cmp == 0 && quo_is_odd)) { /* fix up quotient */ if (quo_is_neg) temp = long_sub(quo, (PyLongObject *)one); @@ -5911,7 +5911,7 @@ int___sizeof___impl(PyObject *self) { /* using Py_MAX(..., 1) because we always allocate space for at least one digit, even though the integer zero has a Py_SIZE of 0 */ - Py_ssize_t ndigits = Py_MAX(Py_ABS(Py_SIZE(self)), 1); + Py_ssize_t ndigits = Py_MAX(_PyLong_DigitCount((PyLongObject *)self), 1); return Py_TYPE(self)->tp_basicsize + Py_TYPE(self)->tp_itemsize * ndigits; } @@ -5938,7 +5938,7 @@ int_bit_length_impl(PyObject *self) assert(self != NULL); assert(PyLong_Check(self)); - ndigits = Py_ABS(Py_SIZE(self)); + ndigits = _PyLong_DigitCount((PyLongObject *)self); if (ndigits == 0) return PyLong_FromLong(0); @@ -6007,7 +6007,7 @@ int_bit_count_impl(PyObject *self) assert(PyLong_Check(self)); PyLongObject *z = (PyLongObject *)self; - Py_ssize_t ndigits = Py_ABS(Py_SIZE(z)); + Py_ssize_t ndigits = _PyLong_DigitCount(z); Py_ssize_t bit_count = 0; /* Each digit has up to PyLong_SHIFT ones, so the accumulated bit count From b56e6da6355bfafbfdacf52425c4202f64fb6cc9 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Tue, 28 Feb 2023 16:01:31 +0000 Subject: [PATCH 05/35] Remove many uses of Py_SIZE in longobject.c --- Include/cpython/longintrepr.h | 2 +- Include/internal/pycore_long.h | 13 +++-- Modules/_decimal/_decimal.c | 4 +- Objects/listobject.c | 6 +-- Objects/longobject.c | 94 +++++++++++----------------------- Python/bltinmodule.c | 2 +- Python/bytecodes.c | 10 ++-- Python/generated_cases.c.h | 12 ++--- Python/specialize.c | 8 +-- 9 files changed, 62 insertions(+), 89 deletions(-) diff --git a/Include/cpython/longintrepr.h b/Include/cpython/longintrepr.h index 55fa50cc7eeddb..b0da013c537779 100644 --- a/Include/cpython/longintrepr.h +++ b/Include/cpython/longintrepr.h @@ -95,7 +95,7 @@ PyAPI_FUNC(PyLongObject *) _PyLong_New(Py_ssize_t); PyAPI_FUNC(PyObject *) _PyLong_Copy(PyLongObject *src); PyAPI_FUNC(PyLongObject *) -_PyLong_FromDigits(int sign, Py_ssize_t digit_count, digit *digits); +_PyLong_FromDigits(int negative, Py_ssize_t digit_count, digit *digits); #ifdef __cplusplus diff --git a/Include/internal/pycore_long.h b/Include/internal/pycore_long.h index d18559f464d0e5..beb6b823903ec8 100644 --- a/Include/internal/pycore_long.h +++ b/Include/internal/pycore_long.h @@ -112,7 +112,7 @@ PyAPI_FUNC(char*) _PyLong_FormatBytesWriter( /* Return 1 if the argument is positive single digit int */ static inline int -_PyLong_IsPositiveSingleDigit(const PyObject* op) { +_PyLong_IsPositiveSingleDigit(const PyLongObject* op) { /* For a positive single digit int, the value of Py_SIZE(sub) is 0 or 1. We perform a fast check using a single comparison by casting from int @@ -131,7 +131,7 @@ _PyLong_IsPositiveSingleDigit(const PyObject* op) { static inline int -_PyLong_IsSingleDigit(const PyObject* op) { +_PyLong_IsSingleDigit(const PyLongObject* op) { assert(PyLong_Check(op)); Py_ssize_t signed_size = Py_SIZE(op); return ((size_t)(signed_size+1)) <= 2; @@ -152,7 +152,6 @@ _PyLong_DigitCount(const PyLongObject *op) return Py_ABS(Py_SIZE(op)); } - static inline bool _PyLong_IsNegative(const PyLongObject *op) { @@ -166,6 +165,14 @@ _PyLong_IsZero(const PyLongObject *op) return Py_SIZE(op) == 0; } +static inline int +_PyLong_NonZeroSign(const PyLongObject *op) +{ + assert(PyLong_Check(op)); + assert(!_PyLong_IsZero(op)); + return ((Py_SIZE(op) > 0) << 1) - 1; +} + static inline bool _PyLong_IsPositive(const PyLongObject *op) { diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 4abd92e326402f..502d3661bae38b 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -2160,7 +2160,7 @@ dec_from_long(PyTypeObject *type, PyObject *v, uint8_t sign = _PyLong_IsNegative(l) ? MPD_NEG : MPD_POS; - if (_PyLong_IsSingleDigit((PyObject *)l)) { + if (_PyLong_IsSingleDigit(l)) { _dec_settriple(dec, sign, l->long_value.ob_digit[0], 0); mpd_qfinalize(MPD(dec), ctx, status); return dec; @@ -3527,7 +3527,7 @@ dec_as_long(PyObject *dec, PyObject *context, int round) assert(n > 0); assert(!mpd_iszero(x)); - pylong = _PyLong_FromDigits(mpd_isnegative(x) ? -1 : 1, n, ob_digit); + pylong = _PyLong_FromDigits(mpd_isnegative(x), n, ob_digit); mpd_free(ob_digit); mpd_del(x); return (PyObject *) pylong; diff --git a/Objects/listobject.c b/Objects/listobject.c index 6d24172c7dc129..caf3043e642b2e 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -2150,8 +2150,8 @@ unsafe_long_compare(PyObject *v, PyObject *w, MergeState *ms) /* Modified from Objects/longobject.c:long_compare, assuming: */ assert(Py_IS_TYPE(v, &PyLong_Type)); assert(Py_IS_TYPE(w, &PyLong_Type)); - assert(_PyLong_IsSingleDigit(v)); - assert(_PyLong_IsSingleDigit(w)); + assert(_PyLong_IsSingleDigit((PyLongObject *)v)); + assert(_PyLong_IsSingleDigit((PyLongObject *)w)); vl = (PyLongObject*)v; wl = (PyLongObject*)w; @@ -2355,7 +2355,7 @@ list_sort_impl(PyListObject *self, PyObject *keyfunc, int reverse) if (keys_are_all_same_type) { if (key_type == &PyLong_Type && ints_are_bounded && - !_PyLong_IsSingleDigit(key)) { + !_PyLong_IsSingleDigit((PyLongObject *)key)) { ints_are_bounded = 0; } diff --git a/Objects/longobject.c b/Objects/longobject.c index da2c3cbe1ac51d..09725576ee3a5b 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -184,7 +184,7 @@ _PyLong_New(Py_ssize_t size) } PyLongObject * -_PyLong_FromDigits(int sign, Py_ssize_t digit_count, digit *digits) +_PyLong_FromDigits(int negative, Py_ssize_t digit_count, digit *digits) { assert(digit_count >= 0); PyLongObject *result = _PyLong_New(digit_count); @@ -192,7 +192,7 @@ _PyLong_FromDigits(int sign, Py_ssize_t digit_count, digit *digits) PyErr_NoMemory(); return NULL; } - assert(sign >= -1 && sign <= 1); + int sign = negative ? -1 : 1; result->long_value.ob_size = sign * digit_count; memcpy(result->long_value.ob_digit, digits, digit_count * sizeof(digit)); return result; @@ -201,22 +201,16 @@ _PyLong_FromDigits(int sign, Py_ssize_t digit_count, digit *digits) PyObject * _PyLong_Copy(PyLongObject *src) { - Py_ssize_t i; - assert(src != NULL); - i = Py_SIZE(src); - int sign = 1; - if (i < 0) { - i = -i; - sign = -1; - } - if (i < 2) { + + if (_PyLong_IsSingleDigit(src)) { stwodigits ival = medium_value(src); if (IS_SMALL_INT(ival)) { return get_small_int((sdigit)ival); } } - return (PyObject *)_PyLong_FromDigits(sign, i, src->long_value.ob_digit); + int size = _PyLong_DigitCount(src); + return (PyObject *)_PyLong_FromDigits(_PyLong_IsNegative(src), size, src->long_value.ob_digit); } static PyObject * @@ -300,7 +294,7 @@ _PyLong_AssignValue(PyObject **target, Py_ssize_t value) return 0; } else if (old != NULL && PyLong_CheckExact(old) && - Py_REFCNT(old) == 1 && _PyLong_IsPositiveSingleDigit(old) && + Py_REFCNT(old) == 1 && _PyLong_IsPositiveSingleDigit((PyLongObject *)old) && (size_t)value <= PyLong_MASK) { // Mutate in place if there are no other references the old @@ -533,27 +527,14 @@ PyLong_AsLongAndOverflow(PyObject *vv, int *overflow) return -1; do_decref = 1; } - - res = -1; - i = Py_SIZE(v); - - switch (i) { - case -1: - res = -(sdigit)v->long_value.ob_digit[0]; - break; - case 0: - res = 0; - break; - case 1: - res = v->long_value.ob_digit[0]; - break; - default: - sign = 1; + if (_PyLong_IsSingleDigit(v)) { + res = _PyLong_SingleDigitValue(v); + } + else { + res = -1; + i = _PyLong_DigitCount(v); + sign = _PyLong_NonZeroSign(v); x = 0; - if (i < 0) { - sign = -1; - i = -(i); - } while (--i >= 0) { prev = x; x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i]; @@ -563,8 +544,8 @@ PyLong_AsLongAndOverflow(PyObject *vv, int *overflow) } } /* Haven't lost any bits, but casting to long requires extra - * care (see comment above). - */ + * care (see comment above). + */ if (x <= (unsigned long)LONG_MAX) { res = (long)x * sign; } @@ -638,18 +619,12 @@ PyLong_AsSsize_t(PyObject *vv) { } v = (PyLongObject *)vv; - i = Py_SIZE(v); - switch (i) { - case -1: return -(sdigit)v->long_value.ob_digit[0]; - case 0: return 0; - case 1: return v->long_value.ob_digit[0]; + if (_PyLong_IsSingleDigit(v)) { + return _PyLong_SingleDigitValue(v); } - sign = 1; + i = _PyLong_DigitCount(v); + sign = _PyLong_NonZeroSign(v); x = 0; - if (i < 0) { - sign = -1; - i = -(i); - } while (--i >= 0) { prev = x; x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i]; @@ -737,17 +712,16 @@ PyLong_AsSize_t(PyObject *vv) } v = (PyLongObject *)vv; - i = Py_SIZE(v); - x = 0; - if (i < 0) { + if (_PyLong_IsPositiveSingleDigit(v)) { + return _PyLong_SingleDigitValue(v); + } + if (_PyLong_IsNegative(v)) { PyErr_SetString(PyExc_OverflowError, "can't convert negative value to size_t"); return (size_t) -1; } - switch (i) { - case 0: return 0; - case 1: return v->long_value.ob_digit[0]; - } + i = _PyLong_DigitCount(v); + x = 0; while (--i >= 0) { prev = x; x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i]; @@ -769,24 +743,18 @@ _PyLong_AsUnsignedLongMask(PyObject *vv) PyLongObject *v; unsigned long x; Py_ssize_t i; - int sign; if (vv == NULL || !PyLong_Check(vv)) { PyErr_BadInternalCall(); return (unsigned long) -1; } v = (PyLongObject *)vv; - i = Py_SIZE(v); - switch (i) { - case 0: return 0; - case 1: return v->long_value.ob_digit[0]; + if (_PyLong_IsPositiveSingleDigit(v)) { + return _PyLong_SingleDigitValue(v); } - sign = 1; + i = _PyLong_DigitCount(v); + int sign = _PyLong_NonZeroSign(v); x = 0; - if (i < 0) { - sign = -1; - i = -i; - } while (--i >= 0) { x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i]; } @@ -4696,7 +4664,7 @@ long_pow(PyObject *v, PyObject *w, PyObject *x) /* if modulus == 1: return 0 */ - if (_PyLong_IsPositiveSingleDigit((PyObject *)c) && (c->long_value.ob_digit[0] == 1)) { + if (_PyLong_IsPositiveSingleDigit(c) && (c->long_value.ob_digit[0] == 1)) { z = (PyLongObject *)PyLong_FromLong(0L); goto Done; } diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index c9ae65855a19e1..038d8344619cb0 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -2507,7 +2507,7 @@ builtin_sum_impl(PyObject *module, PyObject *iterable, PyObject *start) long b; overflow = 0; /* Single digits are common, fast, and cannot overflow on unpacking. */ - if (_PyLong_IsSingleDigit(item)) { + if (_PyLong_IsSingleDigit((PyLongObject *)item)) { b = _PyLong_SingleDigitValue((PyLongObject *)item); } else { diff --git a/Python/bytecodes.c b/Python/bytecodes.c index b85128d6fdea19..d0496838753181 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -356,7 +356,7 @@ dummy_func( DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR); // Deopt unless 0 <= sub < PyList_Size(list) - DEOPT_IF(!_PyLong_IsPositiveSingleDigit(sub), BINARY_SUBSCR); + DEOPT_IF(!_PyLong_IsPositiveSingleDigit((PyLongObject *)sub), BINARY_SUBSCR); Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; DEOPT_IF(index >= PyList_GET_SIZE(list), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); @@ -373,7 +373,7 @@ dummy_func( DEOPT_IF(!PyTuple_CheckExact(tuple), BINARY_SUBSCR); // Deopt unless 0 <= sub < PyTuple_Size(list) - DEOPT_IF(!_PyLong_IsPositiveSingleDigit(sub), BINARY_SUBSCR); + DEOPT_IF(!_PyLong_IsPositiveSingleDigit((PyLongObject *)sub), BINARY_SUBSCR); Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; DEOPT_IF(index >= PyTuple_GET_SIZE(tuple), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); @@ -466,7 +466,7 @@ dummy_func( DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR); // Ensure nonnegative, zero-or-one-digit ints. - DEOPT_IF(!_PyLong_IsPositiveSingleDigit(sub), STORE_SUBSCR); + DEOPT_IF(!_PyLong_IsPositiveSingleDigit((PyLongObject *)sub), STORE_SUBSCR); Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; // Ensure index < len(list) DEOPT_IF(index >= PyList_GET_SIZE(list), STORE_SUBSCR); @@ -1780,8 +1780,8 @@ dummy_func( assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), COMPARE_AND_BRANCH); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_AND_BRANCH); - DEOPT_IF(!_PyLong_IsSingleDigit(left), COMPARE_AND_BRANCH); - DEOPT_IF(!_PyLong_IsSingleDigit(right), COMPARE_AND_BRANCH); + DEOPT_IF(!_PyLong_IsSingleDigit((PyLongObject *)left), COMPARE_AND_BRANCH); + DEOPT_IF(!_PyLong_IsSingleDigit((PyLongObject *)right), COMPARE_AND_BRANCH); STAT_INC(COMPARE_AND_BRANCH, hit); assert(_PyLong_DigitCount((PyLongObject *)left) <= 1 && _PyLong_DigitCount((PyLongObject *)right) <= 1); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 72f04eb5870d0a..4d55f50b3d9680 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -483,8 +483,7 @@ DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR); // Deopt unless 0 <= sub < PyList_Size(list) - DEOPT_IF(!_PyLong_IsPositiveSingleDigit(sub), BINARY_SUBSCR); - assert(((PyLongObject *)_PyLong_GetZero())->long_value.ob_digit[0] == 0); + DEOPT_IF(!_PyLong_IsPositiveSingleDigit((PyLongObject *)sub), BINARY_SUBSCR); Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; DEOPT_IF(index >= PyList_GET_SIZE(list), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); @@ -508,8 +507,7 @@ DEOPT_IF(!PyTuple_CheckExact(tuple), BINARY_SUBSCR); // Deopt unless 0 <= sub < PyTuple_Size(list) - DEOPT_IF(!_PyLong_IsPositiveSingleDigit(sub), BINARY_SUBSCR); - assert(((PyLongObject *)_PyLong_GetZero())->long_value.ob_digit[0] == 0); + DEOPT_IF(!_PyLong_IsPositiveSingleDigit((PyLongObject *)sub), BINARY_SUBSCR); Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; DEOPT_IF(index >= PyTuple_GET_SIZE(tuple), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); @@ -634,7 +632,7 @@ DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR); // Ensure nonnegative, zero-or-one-digit ints. - DEOPT_IF(!_PyLong_IsPositiveSingleDigit(sub), STORE_SUBSCR); + DEOPT_IF(!_PyLong_IsPositiveSingleDigit((PyLongObject *)sub), STORE_SUBSCR); Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; // Ensure index < len(list) DEOPT_IF(index >= PyList_GET_SIZE(list), STORE_SUBSCR); @@ -2242,8 +2240,8 @@ assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), COMPARE_AND_BRANCH); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_AND_BRANCH); - DEOPT_IF(!_PyLong_IsSingleDigit(left), COMPARE_AND_BRANCH); - DEOPT_IF(!_PyLong_IsSingleDigit(right), COMPARE_AND_BRANCH); + DEOPT_IF(!_PyLong_IsSingleDigit((PyLongObject *)left), COMPARE_AND_BRANCH); + DEOPT_IF(!_PyLong_IsSingleDigit((PyLongObject *)right), COMPARE_AND_BRANCH); STAT_INC(COMPARE_AND_BRANCH, hit); assert(_PyLong_DigitCount((PyLongObject *)left) <= 1 && _PyLong_DigitCount((PyLongObject *)right) <= 1); diff --git a/Python/specialize.c b/Python/specialize.c index 1779735550d62d..bb9cc81288f21f 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -1294,7 +1294,7 @@ _Py_Specialize_BinarySubscr( PyTypeObject *container_type = Py_TYPE(container); if (container_type == &PyList_Type) { if (PyLong_CheckExact(sub)) { - if (_PyLong_IsPositiveSingleDigit(sub)) { + if (_PyLong_IsPositiveSingleDigit((PyLongObject *)sub)) { instr->op.code = BINARY_SUBSCR_LIST_INT; goto success; } @@ -1307,7 +1307,7 @@ _Py_Specialize_BinarySubscr( } if (container_type == &PyTuple_Type) { if (PyLong_CheckExact(sub)) { - if (_PyLong_IsPositiveSingleDigit(sub)) { + if (_PyLong_IsPositiveSingleDigit((PyLongObject *)sub)) { instr->op.code = BINARY_SUBSCR_TUPLE_INT; goto success; } @@ -1375,7 +1375,7 @@ _Py_Specialize_StoreSubscr(PyObject *container, PyObject *sub, _Py_CODEUNIT *ins PyTypeObject *container_type = Py_TYPE(container); if (container_type == &PyList_Type) { if (PyLong_CheckExact(sub)) { - if (_PyLong_IsPositiveSingleDigit(sub) + if (_PyLong_IsPositiveSingleDigit((PyLongObject *)sub) && ((PyLongObject *)sub)->long_value.ob_digit[0] < (size_t)PyList_GET_SIZE(container)) { instr->op.code = STORE_SUBSCR_LIST_INT; @@ -1993,7 +1993,7 @@ _Py_Specialize_CompareAndBranch(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *inst goto success; } if (PyLong_CheckExact(lhs)) { - if (_PyLong_IsSingleDigit(lhs) && _PyLong_IsSingleDigit(rhs)) { + if (_PyLong_IsSingleDigit((PyLongObject *)lhs) && _PyLong_IsSingleDigit((PyLongObject *)rhs)) { instr->op.code = COMPARE_AND_BRANCH_INT; goto success; } From 91269fcf216a5c87291bc12327269abae5ba0ca0 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Tue, 28 Feb 2023 16:02:30 +0000 Subject: [PATCH 06/35] Remove _PyLong_AssignValue, as it is no longer used. --- Include/internal/pycore_long.h | 2 -- Objects/longobject.c | 32 -------------------------------- 2 files changed, 34 deletions(-) diff --git a/Include/internal/pycore_long.h b/Include/internal/pycore_long.h index beb6b823903ec8..c155fc5031e7f1 100644 --- a/Include/internal/pycore_long.h +++ b/Include/internal/pycore_long.h @@ -82,8 +82,6 @@ PyObject *_PyLong_Add(PyLongObject *left, PyLongObject *right); PyObject *_PyLong_Multiply(PyLongObject *left, PyLongObject *right); PyObject *_PyLong_Subtract(PyLongObject *left, PyLongObject *right); -int _PyLong_AssignValue(PyObject **target, Py_ssize_t value); - /* Used by Python/mystrtoul.c, _PyBytes_FromHex(), _PyBytes_DecodeEscape(), etc. */ PyAPI_DATA(unsigned char) _PyLong_DigitValue[256]; diff --git a/Objects/longobject.c b/Objects/longobject.c index 09725576ee3a5b..d1681a6adbc750 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -284,38 +284,6 @@ _PyLong_FromSTwoDigits(stwodigits x) return _PyLong_FromLarge(x); } -int -_PyLong_AssignValue(PyObject **target, Py_ssize_t value) -{ - PyObject *old = *target; - if (IS_SMALL_INT(value)) { - *target = get_small_int(Py_SAFE_DOWNCAST(value, Py_ssize_t, sdigit)); - Py_XDECREF(old); - return 0; - } - else if (old != NULL && PyLong_CheckExact(old) && - Py_REFCNT(old) == 1 && _PyLong_IsPositiveSingleDigit((PyLongObject *)old) && - (size_t)value <= PyLong_MASK) - { - // Mutate in place if there are no other references the old - // object. This avoids an allocation in a common case. - // Since the primary use-case is iterating over ranges, which - // are typically positive, only do this optimization - // for positive integers (for now). - ((PyLongObject *)old)->long_value.ob_digit[0] = - Py_SAFE_DOWNCAST(value, Py_ssize_t, digit); - return 0; - } - else { - *target = PyLong_FromSsize_t(value); - Py_XDECREF(old); - if (*target == NULL) { - return -1; - } - return 0; - } -} - /* If a freshly-allocated int is already shared, it must be a small integer, so negating it must go to PyLong_FromLong */ Py_LOCAL_INLINE(void) From c48e8252ba0cb9f9f56ffcaeb78d49adc0a46bd1 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Tue, 28 Feb 2023 17:03:11 +0000 Subject: [PATCH 07/35] Remove some more uses of Py_SIZE in longobject.c. --- Objects/longobject.c | 96 ++++++++++++++++---------------------------- 1 file changed, 35 insertions(+), 61 deletions(-) diff --git a/Objects/longobject.c b/Objects/longobject.c index d1681a6adbc750..eee9ecab9d7606 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -636,17 +636,16 @@ PyLong_AsUnsignedLong(PyObject *vv) } v = (PyLongObject *)vv; - i = Py_SIZE(v); - x = 0; - if (i < 0) { + if (_PyLong_IsPositiveSingleDigit(v)) { + return _PyLong_SingleDigitValue(v); + } + if (_PyLong_IsNegative(v)) { PyErr_SetString(PyExc_OverflowError, "can't convert negative value to unsigned int"); return (unsigned long) -1; } - switch (i) { - case 0: return 0; - case 1: return v->long_value.ob_digit[0]; - } + i = _PyLong_DigitCount(v); + x = 0; while (--i >= 0) { prev = x; x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i]; @@ -931,8 +930,8 @@ _PyLong_AsByteArray(PyLongObject* v, assert(v != NULL && PyLong_Check(v)); + ndigits = _PyLong_DigitCount(v); if (_PyLong_IsNegative(v)) { - ndigits = -(Py_SIZE(v)); if (!is_signed) { PyErr_SetString(PyExc_OverflowError, "can't convert negative int to unsigned"); @@ -941,7 +940,6 @@ _PyLong_AsByteArray(PyLongObject* v, do_twos_comp = 1; } else { - ndigits = Py_SIZE(v); do_twos_comp = 0; } @@ -1211,18 +1209,11 @@ PyLong_AsLongLong(PyObject *vv) do_decref = 1; } - res = 0; - switch(Py_SIZE(v)) { - case -1: - bytes = -(sdigit)v->long_value.ob_digit[0]; - break; - case 0: - bytes = 0; - break; - case 1: - bytes = v->long_value.ob_digit[0]; - break; - default: + if (_PyLong_IsSingleDigit(v)) { + res = 0; + bytes = _PyLong_SingleDigitValue(v); + } + else { res = _PyLong_AsByteArray((PyLongObject *)v, (unsigned char *)&bytes, SIZEOF_LONG_LONG, PY_LITTLE_ENDIAN, 1); } @@ -1257,13 +1248,14 @@ PyLong_AsUnsignedLongLong(PyObject *vv) } v = (PyLongObject*)vv; - switch(Py_SIZE(v)) { - case 0: return 0; - case 1: return v->long_value.ob_digit[0]; + if (_PyLong_IsPositiveSingleDigit(v)) { + res = 0; + bytes = _PyLong_SingleDigitValue(v); } - - res = _PyLong_AsByteArray((PyLongObject *)vv, (unsigned char *)&bytes, + else { + res = _PyLong_AsByteArray((PyLongObject *)vv, (unsigned char *)&bytes, SIZEOF_LONG_LONG, PY_LITTLE_ENDIAN, 0); + } /* Plan 9 can't handle long long in ? : expressions */ if (res < 0) @@ -1288,17 +1280,12 @@ _PyLong_AsUnsignedLongLongMask(PyObject *vv) return (unsigned long long) -1; } v = (PyLongObject *)vv; - switch(Py_SIZE(v)) { - case 0: return 0; - case 1: return v->long_value.ob_digit[0]; + if (_PyLong_IsPositiveSingleDigit(v)) { + return _PyLong_SingleDigitValue(v); } - i = Py_SIZE(v); - sign = 1; + i = _PyLong_DigitCount(v); + sign = _PyLong_NonZeroSign(v); x = 0; - if (i < 0) { - sign = -1; - i = -i; - } while (--i >= 0) { x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i]; } @@ -1365,32 +1352,19 @@ PyLong_AsLongLongAndOverflow(PyObject *vv, int *overflow) return -1; do_decref = 1; } - - res = -1; - i = Py_SIZE(v); - - switch (i) { - case -1: - res = -(sdigit)v->long_value.ob_digit[0]; - break; - case 0: - res = 0; - break; - case 1: - res = v->long_value.ob_digit[0]; - break; - default: - sign = 1; + if (_PyLong_IsSingleDigit(v)) { + res = _PyLong_SingleDigitValue(v); + } + else { + i = _PyLong_DigitCount(v); + sign = _PyLong_NonZeroSign(v); x = 0; - if (i < 0) { - sign = -1; - i = -(i); - } while (--i >= 0) { prev = x; x = (x << PyLong_SHIFT) + v->long_value.ob_digit[i]; if ((x >> PyLong_SHIFT) != prev) { *overflow = sign; + res = -1; goto exit; } } @@ -1405,7 +1379,7 @@ PyLong_AsLongLongAndOverflow(PyObject *vv, int *overflow) } else { *overflow = sign; - /* res is already set to -1 */ + res = -1; } } exit: @@ -2530,7 +2504,7 @@ long_from_non_binary_base(const char *start, const char *end, Py_ssize_t digits, /* Multiply z by convmult, and add c. */ pz = z->long_value.ob_digit; - pzstop = pz + Py_SIZE(z); + pzstop = pz + _PyLong_DigitCount(z); for (; pz < pzstop; ++pz) { c += (twodigits)*pz * convmult; *pz = (digit)(c & PyLong_MASK); @@ -2539,15 +2513,15 @@ long_from_non_binary_base(const char *start, const char *end, Py_ssize_t digits, /* carry off the current end? */ if (c) { assert(c < PyLong_BASE); - if (Py_SIZE(z) < size_z) { + if (_PyLong_DigitCount(z) < size_z) { *pz = (digit)c; assert(!_PyLong_IsNegative(z)); - _PyLong_SetSignAndSize(z, false, Py_SIZE(z) + 1); + _PyLong_SetSignAndSize(z, false, _PyLong_DigitCount(z) + 1); } else { PyLongObject *tmp; /* Extremely rare. Get more space. */ - assert(Py_SIZE(z) == size_z); + assert(_PyLong_DigitCount(z) == size_z); tmp = _PyLong_New(size_z + 1); if (tmp == NULL) { Py_DECREF(z); @@ -2749,7 +2723,7 @@ PyLong_FromString(const char *str, char **pend, int base) /* reset the base to 0, else the exception message doesn't make too much sense */ base = 0; - if (Py_SIZE(z) != 0) { + if (!_PyLong_IsZero(z)) { goto onError; } /* there might still be other problems, therefore base From 449c0e2970aad4ae678990a186de0bf345a4b665 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 1 Mar 2023 10:28:30 +0000 Subject: [PATCH 08/35] Remove a few more uses of Py_SIZE in longobject.c. --- Objects/longobject.c | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/Objects/longobject.c b/Objects/longobject.c index eee9ecab9d7606..99f31372bead8c 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -2872,7 +2872,7 @@ long_divrem(PyLongObject *a, PyLongObject *b, return -1; } } - if (_PyLong_IsNegative(a) && Py_SIZE(*prem) != 0) { + if (_PyLong_IsNegative(a) && !_PyLong_IsZero(*prem)) { _PyLong_Negate(prem); if (*prem == NULL) { Py_DECREF(z); @@ -2916,7 +2916,7 @@ long_rem(PyLongObject *a, PyLongObject *b, PyLongObject **prem) return -1; } /* Set the sign. */ - if (_PyLong_IsNegative(a) && Py_SIZE(*prem) != 0) { + if (_PyLong_IsNegative(a) && !_PyLong_IsZero(*prem)) { _PyLong_Negate(prem); if (*prem == NULL) { Py_CLEAR(*prem); @@ -3259,18 +3259,16 @@ long_hash(PyLongObject *v) Py_ssize_t i; int sign; - i = Py_SIZE(v); - switch(i) { - case -1: return v->long_value.ob_digit[0]==1 ? -2 : -(sdigit)v->long_value.ob_digit[0]; - case 0: return 0; - case 1: return v->long_value.ob_digit[0]; + if (_PyLong_IsSingleDigit(v)) { + x = _PyLong_SingleDigitValue(v); + if (x == (Py_uhash_t)-1) { + x = (Py_uhash_t)-2; + } + return x; } - sign = 1; + i = _PyLong_DigitCount(v); + sign = _PyLong_NonZeroSign(v); x = 0; - if (i < 0) { - sign = -1; - i = -(i); - } while (--i >= 0) { /* Here x is a quantity in the range [0, _PyHASH_MODULUS); we want to compute x * 2**PyLong_SHIFT + v->long_value.ob_digit[i] modulo @@ -3454,7 +3452,7 @@ _PyLong_Subtract(PyLongObject *a, PyLongObject *b) else { z = x_add(a, b); if (z != NULL) { - assert(Py_SIZE(z) == 0 || Py_REFCNT(z) == 1); + assert(_PyLong_IsZero(z) || Py_REFCNT(z) == 1); _PyLong_FlipSign(z); } } @@ -4583,7 +4581,7 @@ long_pow(PyObject *v, PyObject *w, PyObject *x) if (c) { /* if modulus == 0: raise ValueError() */ - if (Py_SIZE(c) == 0) { + if (_PyLong_IsZero(c)) { PyErr_SetString(PyExc_ValueError, "pow() 3rd argument cannot be 0"); goto Error; @@ -4992,7 +4990,7 @@ long_rshift(PyObject *a, PyObject *b) PyErr_SetString(PyExc_ValueError, "negative shift count"); return NULL; } - if (Py_SIZE(a) == 0) { + if (_PyLong_IsZero((PyLongObject *)a)) { return PyLong_FromLong(0); } if (divmod_shift(b, &wordshift, &remshift) < 0) @@ -5008,7 +5006,7 @@ _PyLong_Rshift(PyObject *a, size_t shiftby) digit remshift; assert(PyLong_Check(a)); - if (Py_SIZE(a) == 0) { + if (_PyLong_IsZero((PyLongObject *)a)) { return PyLong_FromLong(0); } wordshift = shiftby / PyLong_SHIFT; @@ -5069,7 +5067,7 @@ long_lshift(PyObject *a, PyObject *b) PyErr_SetString(PyExc_ValueError, "negative shift count"); return NULL; } - if (Py_SIZE(a) == 0) { + if (_PyLong_IsZero((PyLongObject *)a)) { return PyLong_FromLong(0); } if (divmod_shift(b, &wordshift, &remshift) < 0) @@ -5085,7 +5083,7 @@ _PyLong_Lshift(PyObject *a, size_t shiftby) digit remshift; assert(PyLong_Check(a)); - if (Py_SIZE(a) == 0) { + if (_PyLong_IsZero((PyLongObject *)a)) { return PyLong_FromLong(0); } wordshift = shiftby / PyLong_SHIFT; From c5ba601720d99ad723f2460285a523d69546edae Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 1 Mar 2023 10:43:02 +0000 Subject: [PATCH 09/35] Remove some more uses of Py_SIZE, replacing with _PyLong_UnsignedDigitCount(). --- Include/internal/pycore_long.h | 28 +++++++++++++++-------- Objects/longobject.c | 42 +++++++++++++++++----------------- 2 files changed, 39 insertions(+), 31 deletions(-) diff --git a/Include/internal/pycore_long.h b/Include/internal/pycore_long.h index c155fc5031e7f1..7f8994a612bcd2 100644 --- a/Include/internal/pycore_long.h +++ b/Include/internal/pycore_long.h @@ -143,11 +143,10 @@ _PyLong_SingleDigitValue(const PyLongObject *op) return Py_SIZE(op) * op->long_value.ob_digit[0]; } -static inline Py_ssize_t -_PyLong_DigitCount(const PyLongObject *op) +static inline bool +_PyLong_IsPositive(const PyLongObject *op) { - assert(PyLong_Check(op)); - return Py_ABS(Py_SIZE(op)); + return Py_SIZE(op) > 0; } static inline bool @@ -156,6 +155,21 @@ _PyLong_IsNegative(const PyLongObject *op) return Py_SIZE(op) < 0; } +static inline Py_ssize_t +_PyLong_DigitCount(const PyLongObject *op) +{ + assert(PyLong_Check(op)); + return Py_ABS(Py_SIZE(op)); +} + +/* Like _PyLong_DigitCount but asserts that op is non-negative */ +static inline Py_ssize_t +_PyLong_UnsignedDigitCount(const PyLongObject *op) +{ + assert(PyLong_Check(op)); + assert(!_PyLong_IsNegative(op)); + return Py_ABS(Py_SIZE(op)); +} static inline bool _PyLong_IsZero(const PyLongObject *op) @@ -171,12 +185,6 @@ _PyLong_NonZeroSign(const PyLongObject *op) return ((Py_SIZE(op) > 0) << 1) - 1; } -static inline bool -_PyLong_IsPositive(const PyLongObject *op) -{ - return Py_SIZE(op) > 0; -} - #ifdef __cplusplus } diff --git a/Objects/longobject.c b/Objects/longobject.c index 99f31372bead8c..ad5529ed6ff477 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -3488,7 +3488,7 @@ x_mul(PyLongObject *a, PyLongObject *b) if (z == NULL) return NULL; - memset(z->long_value.ob_digit, 0, Py_SIZE(z) * sizeof(digit)); + memset(z->long_value.ob_digit, 0, _PyLong_UnsignedDigitCount(z) * sizeof(digit)); if (a == b) { /* Efficient squaring per HAC, Algorithm 14.16: * http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf @@ -3671,7 +3671,7 @@ k_mul(PyLongObject *a, PyLongObject *b) /* Split a & b into hi & lo pieces. */ shift = bsize >> 1; if (kmul_split(a, shift, &ah, &al) < 0) goto fail; - assert(Py_SIZE(ah) > 0); /* the split isn't degenerate */ + assert(_PyLong_UnsignedDigitCount(ah) > 0); /* the split isn't degenerate */ if (a == b) { bh = (PyLongObject*)Py_NewRef(ah); @@ -3700,20 +3700,20 @@ k_mul(PyLongObject *a, PyLongObject *b) if (ret == NULL) goto fail; #ifdef Py_DEBUG /* Fill with trash, to catch reference to uninitialized digits. */ - memset(ret->long_value.ob_digit, 0xDF, Py_SIZE(ret) * sizeof(digit)); + memset(ret->long_value.ob_digit, 0xDF, _PyLong_UnsignedDigitCount(ret) * sizeof(digit)); #endif /* 2. t1 <- ah*bh, and copy into high digits of result. */ if ((t1 = k_mul(ah, bh)) == NULL) goto fail; - assert(Py_SIZE(t1) >= 0); - assert(2*shift + Py_SIZE(t1) <= Py_SIZE(ret)); + assert(_PyLong_UnsignedDigitCount(t1) >= 0); + assert(2*shift + _PyLong_UnsignedDigitCount(t1) <= _PyLong_UnsignedDigitCount(ret)); memcpy(ret->long_value.ob_digit + 2*shift, t1->long_value.ob_digit, - Py_SIZE(t1) * sizeof(digit)); + _PyLong_UnsignedDigitCount(t1) * sizeof(digit)); /* Zero-out the digits higher than the ah*bh copy. */ - i = Py_SIZE(ret) - 2*shift - Py_SIZE(t1); + i = _PyLong_UnsignedDigitCount(ret) - 2*shift - _PyLong_UnsignedDigitCount(t1); if (i) - memset(ret->long_value.ob_digit + 2*shift + Py_SIZE(t1), 0, + memset(ret->long_value.ob_digit + 2*shift + _PyLong_UnsignedDigitCount(t1), 0, i * sizeof(digit)); /* 3. t2 <- al*bl, and copy into the low digits. */ @@ -3721,23 +3721,23 @@ k_mul(PyLongObject *a, PyLongObject *b) Py_DECREF(t1); goto fail; } - assert(Py_SIZE(t2) >= 0); - assert(Py_SIZE(t2) <= 2*shift); /* no overlap with high digits */ - memcpy(ret->long_value.ob_digit, t2->long_value.ob_digit, Py_SIZE(t2) * sizeof(digit)); + assert(_PyLong_UnsignedDigitCount(t2) >= 0); + assert(_PyLong_UnsignedDigitCount(t2) <= 2*shift); /* no overlap with high digits */ + memcpy(ret->long_value.ob_digit, t2->long_value.ob_digit, _PyLong_UnsignedDigitCount(t2) * sizeof(digit)); /* Zero out remaining digits. */ - i = 2*shift - Py_SIZE(t2); /* number of uninitialized digits */ + i = 2*shift - _PyLong_UnsignedDigitCount(t2); /* number of uninitialized digits */ if (i) - memset(ret->long_value.ob_digit + Py_SIZE(t2), 0, i * sizeof(digit)); + memset(ret->long_value.ob_digit + _PyLong_UnsignedDigitCount(t2), 0, i * sizeof(digit)); /* 4 & 5. Subtract ah*bh (t1) and al*bl (t2). We do al*bl first * because it's fresher in cache. */ - i = Py_SIZE(ret) - shift; /* # digits after shift */ - (void)v_isub(ret->long_value.ob_digit + shift, i, t2->long_value.ob_digit, Py_SIZE(t2)); + i = _PyLong_UnsignedDigitCount(ret) - shift; /* # digits after shift */ + (void)v_isub(ret->long_value.ob_digit + shift, i, t2->long_value.ob_digit, _PyLong_UnsignedDigitCount(t2)); _Py_DECREF_INT(t2); - (void)v_isub(ret->long_value.ob_digit + shift, i, t1->long_value.ob_digit, Py_SIZE(t1)); + (void)v_isub(ret->long_value.ob_digit + shift, i, t1->long_value.ob_digit, _PyLong_UnsignedDigitCount(t1)); _Py_DECREF_INT(t1); /* 6. t3 <- (ah+al)(bh+bl), and add into result. */ @@ -3761,12 +3761,12 @@ k_mul(PyLongObject *a, PyLongObject *b) _Py_DECREF_INT(t1); _Py_DECREF_INT(t2); if (t3 == NULL) goto fail; - assert(Py_SIZE(t3) >= 0); + assert(_PyLong_UnsignedDigitCount(t3) >= 0); /* Add t3. It's not obvious why we can't run out of room here. * See the (*) comment after this function. */ - (void)v_iadd(ret->long_value.ob_digit + shift, i, t3->long_value.ob_digit, Py_SIZE(t3)); + (void)v_iadd(ret->long_value.ob_digit + shift, i, t3->long_value.ob_digit, _PyLong_UnsignedDigitCount(t3)); _Py_DECREF_INT(t3); return long_normalize(ret); @@ -3849,7 +3849,7 @@ k_lopsided_mul(PyLongObject *a, PyLongObject *b) ret = _PyLong_New(asize + bsize); if (ret == NULL) return NULL; - memset(ret->long_value.ob_digit, 0, Py_SIZE(ret) * sizeof(digit)); + memset(ret->long_value.ob_digit, 0, _PyLong_UnsignedDigitCount(ret) * sizeof(digit)); /* Successive slices of b are copied into bslice. */ bslice = _PyLong_New(asize); @@ -3871,8 +3871,8 @@ k_lopsided_mul(PyLongObject *a, PyLongObject *b) goto fail; /* Add into result. */ - (void)v_iadd(ret->long_value.ob_digit + nbdone, Py_SIZE(ret) - nbdone, - product->long_value.ob_digit, Py_SIZE(product)); + (void)v_iadd(ret->long_value.ob_digit + nbdone, _PyLong_UnsignedDigitCount(ret) - nbdone, + product->long_value.ob_digit, _PyLong_UnsignedDigitCount(product)); _Py_DECREF_INT(product); bsize -= nbtouse; From 4b3a3e81102d7343a5c094b357feda7f875e1c53 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 1 Mar 2023 10:59:52 +0000 Subject: [PATCH 10/35] Replace a few Py_SIZE() with _PyLong_SameSign(). --- Include/internal/pycore_long.h | 7 +++++++ Objects/longobject.c | 8 +++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/Include/internal/pycore_long.h b/Include/internal/pycore_long.h index 7f8994a612bcd2..b98d4f793ade2d 100644 --- a/Include/internal/pycore_long.h +++ b/Include/internal/pycore_long.h @@ -185,6 +185,13 @@ _PyLong_NonZeroSign(const PyLongObject *op) return ((Py_SIZE(op) > 0) << 1) - 1; } +/* Do a and b have the same sign? + */ +static inline int +_PyLong_SameSign(const PyLongObject *a, const PyLongObject *b) +{ + return (Py_SIZE(a) ^ Py_SIZE(b)) >= 0; +} #ifdef __cplusplus } diff --git a/Objects/longobject.c b/Objects/longobject.c index ad5529ed6ff477..43bcf7b38f8362 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -3901,7 +3901,7 @@ _PyLong_Multiply(PyLongObject *a, PyLongObject *b) z = k_mul(a, b); /* Negate if exactly one of the inputs is negative. */ - if (((Py_SIZE(a) ^ Py_SIZE(b)) < 0) && z) { + if (!_PyLong_SameSign(a, b) && z) { _PyLong_Negate(&z); if (z == NULL) return NULL; @@ -3927,8 +3927,7 @@ fast_mod(PyLongObject *a, PyLongObject *b) assert(_PyLong_DigitCount(a) == 1); assert(_PyLong_DigitCount(b) == 1); - if (Py_SIZE(a) == Py_SIZE(b)) { - /* 'a' and 'b' have the same sign. */ + if (_PyLong_SameSign(a, b)) { mod = left % right; } else { @@ -3950,8 +3949,7 @@ fast_floor_div(PyLongObject *a, PyLongObject *b) assert(_PyLong_DigitCount(a) == 1); assert(_PyLong_DigitCount(b) == 1); - if (Py_SIZE(a) == Py_SIZE(b)) { - /* 'a' and 'b' have the same sign. */ + if (_PyLong_SameSign(a, b)) { div = left / right; } else { From 9ef9d2c71a8b1a13cb02a5060c89781308faed39 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 1 Mar 2023 11:30:59 +0000 Subject: [PATCH 11/35] Remove a few more Py_SIZE() from longobject.c --- Include/internal/pycore_long.h | 3 +-- Objects/longobject.c | 32 +++++++++++++++----------------- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/Include/internal/pycore_long.h b/Include/internal/pycore_long.h index b98d4f793ade2d..cd3f11c224aa6c 100644 --- a/Include/internal/pycore_long.h +++ b/Include/internal/pycore_long.h @@ -185,8 +185,7 @@ _PyLong_NonZeroSign(const PyLongObject *op) return ((Py_SIZE(op) > 0) << 1) - 1; } -/* Do a and b have the same sign? - */ +/* Do a and b have the same sign? Zero counts as positive. */ static inline int _PyLong_SameSign(const PyLongObject *a, const PyLongObject *b) { diff --git a/Objects/longobject.c b/Objects/longobject.c index 43bcf7b38f8362..3f0074e675d896 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -3926,7 +3926,7 @@ fast_mod(PyLongObject *a, PyLongObject *b) assert(_PyLong_DigitCount(a) == 1); assert(_PyLong_DigitCount(b) == 1); - + sdigit sign = _PyLong_NonZeroSign(b); if (_PyLong_SameSign(a, b)) { mod = left % right; } @@ -3935,7 +3935,7 @@ fast_mod(PyLongObject *a, PyLongObject *b) mod = right - 1 - (left - 1) % right; } - return PyLong_FromLong(mod * (sdigit)Py_SIZE(b)); + return PyLong_FromLong(mod * sign); } /* Fast floor division for single-digit longs. */ @@ -4065,8 +4065,8 @@ l_divmod(PyLongObject *v, PyLongObject *w, #endif if (long_divrem(v, w, &div, &mod) < 0) return -1; - if ((_PyLong_IsNegative(mod) && Py_SIZE(w) > 0) || - (Py_SIZE(mod) > 0 && _PyLong_IsNegative(w))) { + if ((_PyLong_IsNegative(mod) && _PyLong_IsPositive(w)) || + (_PyLong_IsPositive(mod) && _PyLong_IsNegative(w))) { PyLongObject *temp; temp = (PyLongObject *) long_add(mod, w); Py_SETREF(mod, temp); @@ -4112,8 +4112,8 @@ l_mod(PyLongObject *v, PyLongObject *w, PyLongObject **pmod) } if (long_rem(v, w, &mod) < 0) return -1; - if ((_PyLong_IsNegative(mod) && Py_SIZE(w) > 0) || - (Py_SIZE(mod) > 0 && _PyLong_IsNegative(w))) { + if ((_PyLong_IsNegative(mod) && _PyLong_IsPositive(w)) || + (_PyLong_IsPositive(mod) && _PyLong_IsNegative(w))) { PyLongObject *temp; temp = (PyLongObject *) long_add(mod, w); Py_SETREF(mod, temp); @@ -4359,7 +4359,7 @@ long_true_divide(PyObject *v, PyObject *w) Py_SETREF(x, div); if (x == NULL) goto error; - if (Py_SIZE(rem)) + if (!_PyLong_IsZero(rem)) inexact = 1; Py_DECREF(rem); } @@ -4465,7 +4465,7 @@ long_invmod(PyLongObject *a, PyLongObject *n) PyLongObject *b, *c; /* Should only ever be called for positive n */ - assert(Py_SIZE(n) > 0); + assert(_PyLong_IsPositive(n)); b = (PyLongObject *)PyLong_FromLong(1L); if (b == NULL) { @@ -4480,7 +4480,7 @@ long_invmod(PyLongObject *a, PyLongObject *n) Py_INCREF(n); /* references now owned: a, b, c, n */ - while (Py_SIZE(n) != 0) { + while (!_PyLong_IsZero(n)) { PyLongObject *q, *r, *s, *t; if (l_divmod(a, n, &q, &r) == -1) { @@ -4635,7 +4635,7 @@ long_pow(PyObject *v, PyObject *w, PyObject *x) base % modulus instead. We could _always_ do this reduction, but l_mod() isn't cheap, so we only do it when it buys something. */ - if (_PyLong_IsNegative(a) || Py_SIZE(a) > Py_SIZE(c)) { + if (_PyLong_IsNegative(a) || _PyLong_UnsignedDigitCount(a) > _PyLong_UnsignedDigitCount(c)) { if (l_mod(a, c, &temp) < 0) goto Error; Py_SETREF(a, temp); @@ -4850,7 +4850,7 @@ long_abs(PyLongObject *v) static int long_bool(PyLongObject *v) { - return Py_SIZE(v) != 0; + return !_PyLong_IsZero(v); } /* wordshift, remshift = divmod(shiftby, PyLong_SHIFT) */ @@ -4858,7 +4858,7 @@ static int divmod_shift(PyObject *shiftby, Py_ssize_t *wordshift, digit *remshift) { assert(PyLong_Check(shiftby)); - assert(Py_SIZE(shiftby) >= 0); + assert(!_PyLong_IsNegative((PyLongObject *)shiftby)); Py_ssize_t lshiftby = PyLong_AsSsize_t((PyObject *)shiftby); if (lshiftby >= 0) { *wordshift = lshiftby / PyLong_SHIFT; @@ -5568,9 +5568,7 @@ long_subtype_new(PyTypeObject *type, PyObject *x, PyObject *obase) if (tmp == NULL) return NULL; assert(PyLong_Check(tmp)); - n = Py_SIZE(tmp); - if (n < 0) - n = -n; + n = _PyLong_DigitCount(tmp); /* Fast operations for single digit integers (including zero) * assume that there is always at least one digit present. */ if (n == 0) { @@ -5696,7 +5694,7 @@ _PyLong_DivmodNear(PyObject *a, PyObject *b) cmp = long_compare((PyLongObject *)twice_rem, (PyLongObject *)b); Py_DECREF(twice_rem); - quo_is_odd = Py_SIZE(quo) != 0 && ((quo->long_value.ob_digit[0] & 1) != 0); + quo_is_odd = (quo->long_value.ob_digit[0] & 1) != 0; if ((_PyLong_IsNegative((PyLongObject *)b) ? cmp < 0 : cmp > 0) || (cmp == 0 && quo_is_odd)) { /* fix up quotient */ if (quo_is_neg) @@ -5770,7 +5768,7 @@ int___round___impl(PyObject *self, PyObject *o_ndigits) return NULL; /* if ndigits >= 0 then no rounding is necessary; return self unchanged */ - if (Py_SIZE(ndigits) >= 0) { + if (!_PyLong_IsNegative((PyLongObject *)ndigits)) { Py_DECREF(ndigits); return long_long(self); } From 9c408c159aa3d1c8a6e92d60979225db5f039b92 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 1 Mar 2023 11:40:11 +0000 Subject: [PATCH 12/35] Replace uses of IS_MEDIUM_VALUE macro with _PyLong_IsSingleDigit. --- Objects/longobject.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/Objects/longobject.c b/Objects/longobject.c index 3f0074e675d896..be46c3b7a88028 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -22,14 +22,12 @@ class int "PyObject *" "&PyLong_Type" [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=ec0275e3422a36e3]*/ -/* Is this PyLong of size 1, 0 or -1? */ -#define IS_MEDIUM_VALUE(x) (((size_t)Py_SIZE(x)) + 1U < 3U) /* convert a PyLong of size 1, 0 or -1 to a C integer */ static inline stwodigits medium_value(PyLongObject *x) { - assert(IS_MEDIUM_VALUE(x)); + assert(_PyLong_IsSingleDigit(x)); return ((stwodigits)Py_SIZE(x)) * x->long_value.ob_digit[0]; } @@ -81,7 +79,7 @@ get_small_int(sdigit ival) static PyLongObject * maybe_small_long(PyLongObject *v) { - if (v && IS_MEDIUM_VALUE(v)) { + if (v && _PyLong_IsSingleDigit(v)) { stwodigits ival = medium_value(v); if (IS_SMALL_INT(ival)) { _Py_DECREF_INT(v); @@ -3200,7 +3198,7 @@ PyLong_AsDouble(PyObject *v) PyErr_SetString(PyExc_TypeError, "an integer is required"); return -1.0; } - if (IS_MEDIUM_VALUE(v)) { + if (_PyLong_IsSingleDigit((PyLongObject *)v)) { /* Fast path; single digit long (31 bits) will cast safely to double. This improves performance of FP/long operations by 20%. @@ -3401,7 +3399,7 @@ x_sub(PyLongObject *a, PyLongObject *b) PyObject * _PyLong_Add(PyLongObject *a, PyLongObject *b) { - if (IS_MEDIUM_VALUE(a) && IS_MEDIUM_VALUE(b)) { + if (_PyLong_IsSingleDigit(a) && _PyLong_IsSingleDigit(b)) { return _PyLong_FromSTwoDigits(medium_value(a) + medium_value(b)); } @@ -3442,7 +3440,7 @@ _PyLong_Subtract(PyLongObject *a, PyLongObject *b) { PyLongObject *z; - if (IS_MEDIUM_VALUE(a) && IS_MEDIUM_VALUE(b)) { + if (_PyLong_IsSingleDigit(a) && _PyLong_IsSingleDigit(b)) { return _PyLong_FromSTwoDigits(medium_value(a) - medium_value(b)); } if (_PyLong_IsNegative(a)) { @@ -3894,7 +3892,7 @@ _PyLong_Multiply(PyLongObject *a, PyLongObject *b) PyLongObject *z; /* fast path for single-digit multiplication */ - if (IS_MEDIUM_VALUE(a) && IS_MEDIUM_VALUE(b)) { + if (_PyLong_IsSingleDigit(a) && _PyLong_IsSingleDigit(b)) { stwodigits v = medium_value(a) * medium_value(b); return _PyLong_FromSTwoDigits(v); } @@ -4815,7 +4813,7 @@ long_invert(PyLongObject *v) { /* Implement ~x as -(x+1) */ PyLongObject *x; - if (IS_MEDIUM_VALUE(v)) + if (_PyLong_IsSingleDigit(v)) return _PyLong_FromSTwoDigits(~medium_value(v)); x = (PyLongObject *) long_add(v, (PyLongObject *)_PyLong_GetOne()); if (x == NULL) @@ -4830,7 +4828,7 @@ static PyObject * long_neg(PyLongObject *v) { PyLongObject *z; - if (IS_MEDIUM_VALUE(v)) + if (_PyLong_IsSingleDigit(v)) return _PyLong_FromSTwoDigits(-medium_value(v)); z = (PyLongObject *)_PyLong_Copy(v); if (z != NULL) @@ -4903,7 +4901,7 @@ long_rshift1(PyLongObject *a, Py_ssize_t wordshift, digit remshift) assert(remshift < PyLong_SHIFT); /* Fast path for small a. */ - if (IS_MEDIUM_VALUE(a)) { + if (_PyLong_IsSingleDigit(a)) { stwodigits m, x; digit shift; m = medium_value(a); @@ -5019,7 +5017,7 @@ long_lshift1(PyLongObject *a, Py_ssize_t wordshift, digit remshift) Py_ssize_t oldsize, newsize, i, j; twodigits accum; - if (wordshift == 0 && IS_MEDIUM_VALUE(a)) { + if (wordshift == 0 && _PyLong_IsSingleDigit(a)) { stwodigits m = medium_value(a); // bypass undefined shift operator behavior stwodigits x = m < 0 ? -(-m << remshift) : m << remshift; @@ -5235,7 +5233,7 @@ long_and(PyObject *a, PyObject *b) CHECK_BINOP(a, b); PyLongObject *x = (PyLongObject*)a; PyLongObject *y = (PyLongObject*)b; - if (IS_MEDIUM_VALUE(x) && IS_MEDIUM_VALUE(y)) { + if (_PyLong_IsSingleDigit(x) && _PyLong_IsSingleDigit(y)) { return _PyLong_FromSTwoDigits(medium_value(x) & medium_value(y)); } return long_bitwise(x, '&', y); @@ -5247,7 +5245,7 @@ long_xor(PyObject *a, PyObject *b) CHECK_BINOP(a, b); PyLongObject *x = (PyLongObject*)a; PyLongObject *y = (PyLongObject*)b; - if (IS_MEDIUM_VALUE(x) && IS_MEDIUM_VALUE(y)) { + if (_PyLong_IsSingleDigit(x) && _PyLong_IsSingleDigit(y)) { return _PyLong_FromSTwoDigits(medium_value(x) ^ medium_value(y)); } return long_bitwise(x, '^', y); @@ -5259,7 +5257,7 @@ long_or(PyObject *a, PyObject *b) CHECK_BINOP(a, b); PyLongObject *x = (PyLongObject*)a; PyLongObject *y = (PyLongObject*)b; - if (IS_MEDIUM_VALUE(x) && IS_MEDIUM_VALUE(y)) { + if (_PyLong_IsSingleDigit(x) && _PyLong_IsSingleDigit(y)) { return _PyLong_FromSTwoDigits(medium_value(x) | medium_value(y)); } return long_bitwise(x, '|', y); From 548d656bdb43f57b26bb494c9d845c2d19f64e44 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 1 Mar 2023 11:56:36 +0000 Subject: [PATCH 13/35] Remove most of the remaining uses of Py_SIZE in longobject.c --- Include/internal/pycore_long.h | 2 +- Objects/longobject.c | 22 ++++++++++------------ 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/Include/internal/pycore_long.h b/Include/internal/pycore_long.h index cd3f11c224aa6c..b964234b4123ee 100644 --- a/Include/internal/pycore_long.h +++ b/Include/internal/pycore_long.h @@ -168,7 +168,7 @@ _PyLong_UnsignedDigitCount(const PyLongObject *op) { assert(PyLong_Check(op)); assert(!_PyLong_IsNegative(op)); - return Py_ABS(Py_SIZE(op)); + return Py_SIZE(op); } static inline bool diff --git a/Objects/longobject.c b/Objects/longobject.c index be46c3b7a88028..a3b7264bcdb7f8 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -4785,7 +4785,7 @@ long_pow(PyObject *v, PyObject *w, PyObject *x) ABSORB_PENDING; } - if (negativeOutput && (Py_SIZE(z) != 0)) { + if (negativeOutput && !_PyLong_IsZero(z)) { temp = (PyLongObject *)long_sub(z, c); if (temp == NULL) goto Error; @@ -4819,8 +4819,8 @@ long_invert(PyLongObject *v) if (x == NULL) return NULL; _PyLong_Negate(&x); - /* No need for maybe_small_long here, since any small - longs will have been caught in the Py_SIZE <= 1 fast path. */ + /* No need for maybe_small_long here, since any small longs + will have been caught in the _PyLong_IsSingleDigit() fast path. */ return (PyObject *)x; } @@ -5281,14 +5281,11 @@ _PyLong_GCD(PyObject *aarg, PyObject *barg) stwodigits x, y, q, s, t, c_carry, d_carry; stwodigits A, B, C, D, T; int nbits, k; - Py_ssize_t size_a, size_b, alloc_a, alloc_b; digit *a_digit, *b_digit, *c_digit, *d_digit, *a_end, *b_end; a = (PyLongObject *)aarg; b = (PyLongObject *)barg; - size_a = Py_SIZE(a); - size_b = Py_SIZE(b); - if (-2 <= size_a && size_a <= 2 && -2 <= size_b && size_b <= 2) { + if (_PyLong_DigitCount(a) <= 2 && _PyLong_DigitCount(b) <= 2) { Py_INCREF(a); Py_INCREF(b); goto simple; @@ -5310,14 +5307,15 @@ _PyLong_GCD(PyObject *aarg, PyObject *barg) } /* We now own references to a and b */ - alloc_a = Py_SIZE(a); - alloc_b = Py_SIZE(b); + Py_ssize_t size_a, size_b, alloc_a, alloc_b; + alloc_a = _PyLong_UnsignedDigitCount(a); + alloc_b = _PyLong_UnsignedDigitCount(b); /* reduce until a fits into 2 digits */ - while ((size_a = Py_SIZE(a)) > 2) { + while ((size_a = _PyLong_UnsignedDigitCount(a)) > 2) { nbits = bit_length_digit(a->long_value.ob_digit[size_a-1]); /* extract top 2*PyLong_SHIFT bits of a into x, along with corresponding bits of b into y */ - size_b = Py_SIZE(b); + size_b = _PyLong_UnsignedDigitCount(b); assert(size_b <= size_a); if (size_b == 0) { if (size_a < alloc_a) { @@ -5361,7 +5359,7 @@ _PyLong_GCD(PyObject *aarg, PyObject *barg) Py_SETREF(a, b); b = r; alloc_a = alloc_b; - alloc_b = Py_SIZE(b); + alloc_b = _PyLong_UnsignedDigitCount(b); continue; } From 3e3fefd4f26789ad69b3b32e6a8d503ee9669599 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 1 Mar 2023 12:18:12 +0000 Subject: [PATCH 14/35] Replace last remaining uses of Py_SIZE applied to longobject with _PyLong_SignedDigitCount which might not be optimal, but is safe. --- Include/internal/pycore_long.h | 8 ++++++++ Objects/longobject.c | 21 +++++++-------------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/Include/internal/pycore_long.h b/Include/internal/pycore_long.h index b964234b4123ee..b1c9ba218fb01d 100644 --- a/Include/internal/pycore_long.h +++ b/Include/internal/pycore_long.h @@ -162,6 +162,14 @@ _PyLong_DigitCount(const PyLongObject *op) return Py_ABS(Py_SIZE(op)); } +/* Equivalent to _PyLong_DigitCount(op) * _PyLong_NonZeroSign(op) */ +static inline Py_ssize_t +_PyLong_SignedDigitCount(const PyLongObject *op) +{ + assert(PyLong_Check(op)); + return Py_SIZE(op); +} + /* Like _PyLong_DigitCount but asserts that op is non-negative */ static inline Py_ssize_t _PyLong_UnsignedDigitCount(const PyLongObject *op) diff --git a/Objects/longobject.c b/Objects/longobject.c index a3b7264bcdb7f8..d1cf15c45a93df 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -22,14 +22,7 @@ class int "PyObject *" "&PyLong_Type" [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=ec0275e3422a36e3]*/ - -/* convert a PyLong of size 1, 0 or -1 to a C integer */ -static inline stwodigits -medium_value(PyLongObject *x) -{ - assert(_PyLong_IsSingleDigit(x)); - return ((stwodigits)Py_SIZE(x)) * x->long_value.ob_digit[0]; -} +#define medium_value(x) ((stwodigits)_PyLong_SingleDigitValue(x)) #define IS_SMALL_INT(ival) (-_PY_NSMALLNEGINTS <= (ival) && (ival) < _PY_NSMALLPOSINTS) #define IS_SMALL_UINT(ival) ((ival) < _PY_NSMALLPOSINTS) @@ -3223,7 +3216,7 @@ PyLong_AsDouble(PyObject *v) static Py_ssize_t long_compare(PyLongObject *a, PyLongObject *b) { - Py_ssize_t sign = Py_SIZE(a) - Py_SIZE(b); + Py_ssize_t sign = _PyLong_SignedDigitCount(a) - _PyLong_SignedDigitCount(b); if (sign == 0) { Py_ssize_t i = _PyLong_DigitCount(a); sdigit diff = 0; @@ -4340,7 +4333,7 @@ long_true_divide(PyObject *v, PyObject *w) inexact = 1; } long_normalize(x); - x_size = Py_SIZE(x); + x_size = _PyLong_SignedDigitCount(x); /* x //= b. If the remainder is nonzero, set inexact. We own the only reference to x, so it's safe to modify it in-place. */ @@ -4675,7 +4668,7 @@ long_pow(PyObject *v, PyObject *w, PyObject *x) REDUCE(result); \ } while(0) - i = Py_SIZE(b); + i = _PyLong_SignedDigitCount(b); digit bi = i ? b->long_value.ob_digit[i-1] : 0; digit bit; if (i <= 1 && bi <= 3) { @@ -4767,7 +4760,7 @@ long_pow(PyObject *v, PyObject *w, PyObject *x) pending = 0; \ } while(0) - for (i = Py_SIZE(b) - 1; i >= 0; --i) { + for (i = _PyLong_SignedDigitCount(b) - 1; i >= 0; --i) { const digit bi = b->long_value.ob_digit[i]; for (j = PyLong_SHIFT - 1; j >= 0; --j) { const int bit = (bi >> j) & 1; @@ -4863,7 +4856,7 @@ divmod_shift(PyObject *shiftby, Py_ssize_t *wordshift, digit *remshift) *remshift = lshiftby % PyLong_SHIFT; return 0; } - /* PyLong_Check(shiftby) is true and Py_SIZE(shiftby) >= 0, so it must + /* PyLong_Check(shiftby) is true and shiftby is not negative, so it must be that PyLong_AsSsize_t raised an OverflowError. */ assert(PyErr_ExceptionMatches(PyExc_OverflowError)); PyErr_Clear(); @@ -5810,7 +5803,7 @@ int___sizeof___impl(PyObject *self) /*[clinic end generated code: output=3303f008eaa6a0a5 input=9b51620c76fc4507]*/ { /* using Py_MAX(..., 1) because we always allocate space for at least - one digit, even though the integer zero has a Py_SIZE of 0 */ + one digit, even though the integer zero has a digit count of 0 */ Py_ssize_t ndigits = Py_MAX(_PyLong_DigitCount((PyLongObject *)self), 1); return Py_TYPE(self)->tp_basicsize + Py_TYPE(self)->tp_itemsize * ndigits; } From 391fb5184e3506e586cff98f8c5505d746eaaec2 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 1 Mar 2023 12:51:54 +0000 Subject: [PATCH 15/35] Don't use _PyObject_InitVar and move a couple of inline functions to header file. --- Include/internal/pycore_long.h | 14 ++++++++++++++ Objects/longobject.c | 17 +++-------------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/Include/internal/pycore_long.h b/Include/internal/pycore_long.h index b1c9ba218fb01d..b6da9253ad3807 100644 --- a/Include/internal/pycore_long.h +++ b/Include/internal/pycore_long.h @@ -200,6 +200,20 @@ _PyLong_SameSign(const PyLongObject *a, const PyLongObject *b) return (Py_SIZE(a) ^ Py_SIZE(b)) >= 0; } +static inline void +_PyLong_SetSignAndSize(PyLongObject *op, bool negative, Py_ssize_t size) +{ + int sign = 1-negative*2; + assert(sign == -1 || sign == 1); + op->long_value.ob_size = sign * size; +} + +static inline void +_PyLong_FlipSign(PyLongObject *op) { + op->long_value.ob_size = -op->long_value.ob_size; +} + + #ifdef __cplusplus } #endif diff --git a/Objects/longobject.c b/Objects/longobject.c index d1cf15c45a93df..ce9bc6a801364c 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -33,19 +33,6 @@ class int "PyObject *" "&PyLong_Type" /* If defined, use algorithms from the _pylong.py module */ #define WITH_PYLONG_MODULE 1 -static inline void -_PyLong_SetSignAndSize(PyLongObject *op, bool negative, Py_ssize_t size) -{ - int sign = 1-negative*2; - assert(sign == -1 || sign == 1); - op->long_value.ob_size = sign * size; -} - -static inline void -_PyLong_FlipSign(PyLongObject *op) { - op->long_value.ob_size = -op->long_value.ob_size; -} - static inline void _Py_DECREF_INT(PyLongObject *op) { @@ -150,6 +137,7 @@ long_normalize(PyLongObject *v) PyLongObject * _PyLong_New(Py_ssize_t size) { + assert(size >= 0); PyLongObject *result; if (size > (Py_ssize_t)MAX_LONG_DIGITS) { PyErr_SetString(PyExc_OverflowError, @@ -170,7 +158,8 @@ _PyLong_New(Py_ssize_t size) PyErr_NoMemory(); return NULL; } - _PyObject_InitVar((PyVarObject*)result, &PyLong_Type, size); + _PyLong_SetSignAndSize(result, false, size); + _PyObject_Init((PyObject*)result, &PyLong_Type); return result; } From df8c7d3f8563aeee1bb69c1b5780f491c217b093 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 1 Mar 2023 13:09:37 +0000 Subject: [PATCH 16/35] Correct name of inline function. --- Include/internal/pycore_long.h | 3 ++- Objects/longobject.c | 12 ++++++------ Python/bytecodes.c | 6 +++--- Python/generated_cases.c.h | 6 +++--- Python/specialize.c | 6 +++--- 5 files changed, 17 insertions(+), 16 deletions(-) diff --git a/Include/internal/pycore_long.h b/Include/internal/pycore_long.h index b6da9253ad3807..c92a2489419066 100644 --- a/Include/internal/pycore_long.h +++ b/Include/internal/pycore_long.h @@ -108,9 +108,10 @@ PyAPI_FUNC(char*) _PyLong_FormatBytesWriter( int base, int alternate); + /* Return 1 if the argument is positive single digit int */ static inline int -_PyLong_IsPositiveSingleDigit(const PyLongObject* op) { +_PyLong_IsNonNegativeSingleDigit(const PyLongObject* op) { /* For a positive single digit int, the value of Py_SIZE(sub) is 0 or 1. We perform a fast check using a single comparison by casting from int diff --git a/Objects/longobject.c b/Objects/longobject.c index ce9bc6a801364c..26b404bdc9edc3 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -616,7 +616,7 @@ PyLong_AsUnsignedLong(PyObject *vv) } v = (PyLongObject *)vv; - if (_PyLong_IsPositiveSingleDigit(v)) { + if (_PyLong_IsNonNegativeSingleDigit(v)) { return _PyLong_SingleDigitValue(v); } if (_PyLong_IsNegative(v)) { @@ -659,7 +659,7 @@ PyLong_AsSize_t(PyObject *vv) } v = (PyLongObject *)vv; - if (_PyLong_IsPositiveSingleDigit(v)) { + if (_PyLong_IsNonNegativeSingleDigit(v)) { return _PyLong_SingleDigitValue(v); } if (_PyLong_IsNegative(v)) { @@ -696,7 +696,7 @@ _PyLong_AsUnsignedLongMask(PyObject *vv) return (unsigned long) -1; } v = (PyLongObject *)vv; - if (_PyLong_IsPositiveSingleDigit(v)) { + if (_PyLong_IsNonNegativeSingleDigit(v)) { return _PyLong_SingleDigitValue(v); } i = _PyLong_DigitCount(v); @@ -1228,7 +1228,7 @@ PyLong_AsUnsignedLongLong(PyObject *vv) } v = (PyLongObject*)vv; - if (_PyLong_IsPositiveSingleDigit(v)) { + if (_PyLong_IsNonNegativeSingleDigit(v)) { res = 0; bytes = _PyLong_SingleDigitValue(v); } @@ -1260,7 +1260,7 @@ _PyLong_AsUnsignedLongLongMask(PyObject *vv) return (unsigned long long) -1; } v = (PyLongObject *)vv; - if (_PyLong_IsPositiveSingleDigit(v)) { + if (_PyLong_IsNonNegativeSingleDigit(v)) { return _PyLong_SingleDigitValue(v); } i = _PyLong_DigitCount(v); @@ -4582,7 +4582,7 @@ long_pow(PyObject *v, PyObject *w, PyObject *x) /* if modulus == 1: return 0 */ - if (_PyLong_IsPositiveSingleDigit(c) && (c->long_value.ob_digit[0] == 1)) { + if (_PyLong_IsNonNegativeSingleDigit(c) && (c->long_value.ob_digit[0] == 1)) { z = (PyLongObject *)PyLong_FromLong(0L); goto Done; } diff --git a/Python/bytecodes.c b/Python/bytecodes.c index d0496838753181..e51c106deab80e 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -356,7 +356,7 @@ dummy_func( DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR); // Deopt unless 0 <= sub < PyList_Size(list) - DEOPT_IF(!_PyLong_IsPositiveSingleDigit((PyLongObject *)sub), BINARY_SUBSCR); + DEOPT_IF(!_PyLong_IsNonNegativeSingleDigit((PyLongObject *)sub), BINARY_SUBSCR); Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; DEOPT_IF(index >= PyList_GET_SIZE(list), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); @@ -373,7 +373,7 @@ dummy_func( DEOPT_IF(!PyTuple_CheckExact(tuple), BINARY_SUBSCR); // Deopt unless 0 <= sub < PyTuple_Size(list) - DEOPT_IF(!_PyLong_IsPositiveSingleDigit((PyLongObject *)sub), BINARY_SUBSCR); + DEOPT_IF(!_PyLong_IsNonNegativeSingleDigit((PyLongObject *)sub), BINARY_SUBSCR); Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; DEOPT_IF(index >= PyTuple_GET_SIZE(tuple), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); @@ -466,7 +466,7 @@ dummy_func( DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR); // Ensure nonnegative, zero-or-one-digit ints. - DEOPT_IF(!_PyLong_IsPositiveSingleDigit((PyLongObject *)sub), STORE_SUBSCR); + DEOPT_IF(!_PyLong_IsNonNegativeSingleDigit((PyLongObject *)sub), STORE_SUBSCR); Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; // Ensure index < len(list) DEOPT_IF(index >= PyList_GET_SIZE(list), STORE_SUBSCR); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 4d55f50b3d9680..969a8f669dc114 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -483,7 +483,7 @@ DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR); // Deopt unless 0 <= sub < PyList_Size(list) - DEOPT_IF(!_PyLong_IsPositiveSingleDigit((PyLongObject *)sub), BINARY_SUBSCR); + DEOPT_IF(!_PyLong_IsNonNegativeSingleDigit((PyLongObject *)sub), BINARY_SUBSCR); Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; DEOPT_IF(index >= PyList_GET_SIZE(list), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); @@ -507,7 +507,7 @@ DEOPT_IF(!PyTuple_CheckExact(tuple), BINARY_SUBSCR); // Deopt unless 0 <= sub < PyTuple_Size(list) - DEOPT_IF(!_PyLong_IsPositiveSingleDigit((PyLongObject *)sub), BINARY_SUBSCR); + DEOPT_IF(!_PyLong_IsNonNegativeSingleDigit((PyLongObject *)sub), BINARY_SUBSCR); Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; DEOPT_IF(index >= PyTuple_GET_SIZE(tuple), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); @@ -632,7 +632,7 @@ DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR); // Ensure nonnegative, zero-or-one-digit ints. - DEOPT_IF(!_PyLong_IsPositiveSingleDigit((PyLongObject *)sub), STORE_SUBSCR); + DEOPT_IF(!_PyLong_IsNonNegativeSingleDigit((PyLongObject *)sub), STORE_SUBSCR); Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; // Ensure index < len(list) DEOPT_IF(index >= PyList_GET_SIZE(list), STORE_SUBSCR); diff --git a/Python/specialize.c b/Python/specialize.c index bb9cc81288f21f..c35c8b553475fb 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -1294,7 +1294,7 @@ _Py_Specialize_BinarySubscr( PyTypeObject *container_type = Py_TYPE(container); if (container_type == &PyList_Type) { if (PyLong_CheckExact(sub)) { - if (_PyLong_IsPositiveSingleDigit((PyLongObject *)sub)) { + if (_PyLong_IsNonNegativeSingleDigit((PyLongObject *)sub)) { instr->op.code = BINARY_SUBSCR_LIST_INT; goto success; } @@ -1307,7 +1307,7 @@ _Py_Specialize_BinarySubscr( } if (container_type == &PyTuple_Type) { if (PyLong_CheckExact(sub)) { - if (_PyLong_IsPositiveSingleDigit((PyLongObject *)sub)) { + if (_PyLong_IsNonNegativeSingleDigit((PyLongObject *)sub)) { instr->op.code = BINARY_SUBSCR_TUPLE_INT; goto success; } @@ -1375,7 +1375,7 @@ _Py_Specialize_StoreSubscr(PyObject *container, PyObject *sub, _Py_CODEUNIT *ins PyTypeObject *container_type = Py_TYPE(container); if (container_type == &PyList_Type) { if (PyLong_CheckExact(sub)) { - if (_PyLong_IsPositiveSingleDigit((PyLongObject *)sub) + if (_PyLong_IsNonNegativeSingleDigit((PyLongObject *)sub) && ((PyLongObject *)sub)->long_value.ob_digit[0] < (size_t)PyList_GET_SIZE(container)) { instr->op.code = STORE_SUBSCR_LIST_INT; From bc14fa66e6497f236f7ef58aa474491a1a9ab9fe Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 1 Mar 2023 18:12:05 +0000 Subject: [PATCH 17/35] Eliminate all remaining uses of Py_SIZE and Py_SET_SIZE on PyLongObject. --- Include/cpython/longintrepr.h | 2 +- Include/internal/pycore_long.h | 42 +++++++++++++++++--------- Include/internal/pycore_object.h | 3 +- Include/internal/pycore_runtime_init.h | 10 +----- Include/object.h | 5 ++- Modules/_testcapi/mem.c | 2 +- Modules/_tkinter.c | 8 +++-- Objects/boolobject.c | 9 ++++-- Objects/longobject.c | 7 ++--- Objects/typeobject.c | 3 +- Python/ast_opt.c | 13 ++++++-- Python/marshal.c | 2 +- Tools/build/deepfreeze.py | 10 +++--- 13 files changed, 70 insertions(+), 46 deletions(-) diff --git a/Include/cpython/longintrepr.h b/Include/cpython/longintrepr.h index b0da013c537779..69085118dd2f0d 100644 --- a/Include/cpython/longintrepr.h +++ b/Include/cpython/longintrepr.h @@ -80,7 +80,7 @@ typedef long stwodigits; /* signed variant of twodigits */ */ typedef struct _PyLongValue { - Py_ssize_t ob_size; /* Number of items in variable part */ + intptr_t ob_size; /* Number of digits, sign and flags */ digit ob_digit[1]; } _PyLongValue; diff --git a/Include/internal/pycore_long.h b/Include/internal/pycore_long.h index c92a2489419066..badb299932b849 100644 --- a/Include/internal/pycore_long.h +++ b/Include/internal/pycore_long.h @@ -112,9 +112,7 @@ PyAPI_FUNC(char*) _PyLong_FormatBytesWriter( /* Return 1 if the argument is positive single digit int */ static inline int _PyLong_IsNonNegativeSingleDigit(const PyLongObject* op) { - /* For a positive single digit int, the value of Py_SIZE(sub) is 0 or 1. - - We perform a fast check using a single comparison by casting from int + /* We perform a fast check using a single comparison by casting from int to uint which casts negative numbers to large positive numbers. For details see Section 14.2 "Bounds Checking" in the Agner Fog optimization manual found at: @@ -124,7 +122,7 @@ _PyLong_IsNonNegativeSingleDigit(const PyLongObject* op) { compiler options of GCC and clang */ assert(PyLong_Check(op)); - Py_ssize_t signed_size = Py_SIZE(op); + Py_ssize_t signed_size = op->long_value.ob_size; return ((size_t)signed_size) <= 1; } @@ -132,7 +130,7 @@ _PyLong_IsNonNegativeSingleDigit(const PyLongObject* op) { static inline int _PyLong_IsSingleDigit(const PyLongObject* op) { assert(PyLong_Check(op)); - Py_ssize_t signed_size = Py_SIZE(op); + Py_ssize_t signed_size = op->long_value.ob_size; return ((size_t)(signed_size+1)) <= 2; } @@ -140,27 +138,27 @@ static inline Py_ssize_t _PyLong_SingleDigitValue(const PyLongObject *op) { assert(PyLong_Check(op)); - assert(Py_SIZE(op) >= -1 && Py_SIZE(op) <= 1); - return Py_SIZE(op) * op->long_value.ob_digit[0]; + assert(op->long_value.ob_size >= -1 && op->long_value.ob_size <= 1); + return op->long_value.ob_size * op->long_value.ob_digit[0]; } static inline bool _PyLong_IsPositive(const PyLongObject *op) { - return Py_SIZE(op) > 0; + return op->long_value.ob_size > 0; } static inline bool _PyLong_IsNegative(const PyLongObject *op) { - return Py_SIZE(op) < 0; + return op->long_value.ob_size < 0; } static inline Py_ssize_t _PyLong_DigitCount(const PyLongObject *op) { assert(PyLong_Check(op)); - return Py_ABS(Py_SIZE(op)); + return Py_ABS(op->long_value.ob_size); } /* Equivalent to _PyLong_DigitCount(op) * _PyLong_NonZeroSign(op) */ @@ -168,7 +166,7 @@ static inline Py_ssize_t _PyLong_SignedDigitCount(const PyLongObject *op) { assert(PyLong_Check(op)); - return Py_SIZE(op); + return op->long_value.ob_size; } /* Like _PyLong_DigitCount but asserts that op is non-negative */ @@ -177,13 +175,13 @@ _PyLong_UnsignedDigitCount(const PyLongObject *op) { assert(PyLong_Check(op)); assert(!_PyLong_IsNegative(op)); - return Py_SIZE(op); + return op->long_value.ob_size; } static inline bool _PyLong_IsZero(const PyLongObject *op) { - return Py_SIZE(op) == 0; + return op->long_value.ob_size == 0; } static inline int @@ -191,14 +189,14 @@ _PyLong_NonZeroSign(const PyLongObject *op) { assert(PyLong_Check(op)); assert(!_PyLong_IsZero(op)); - return ((Py_SIZE(op) > 0) << 1) - 1; + return ((op->long_value.ob_size > 0) << 1) - 1; } /* Do a and b have the same sign? Zero counts as positive. */ static inline int _PyLong_SameSign(const PyLongObject *a, const PyLongObject *b) { - return (Py_SIZE(a) ^ Py_SIZE(b)) >= 0; + return (a->long_value.ob_size ^ b->long_value.ob_size) >= 0; } static inline void @@ -214,6 +212,20 @@ _PyLong_FlipSign(PyLongObject *op) { op->long_value.ob_size = -op->long_value.ob_size; } +#define _PyLong_DIGIT_INIT(val) \ + { \ + .ob_base = _PyObject_IMMORTAL_INIT(&PyLong_Type), \ + .long_value = { \ + .ob_size = (val) == 0 ? 0 : ((val) < 0 ? -1 : 1), \ + { ((val) >= 0 ? (val) : -(val)) }, \ + } \ + } + +#define TAG_FROM_SIGN_AND_SIZE(neg, size) (neg ? -(size) : (size)) + +#define _PyLong_FALSE_TAG 0 +#define _PyLong_TRUE_TAG 1 + #ifdef __cplusplus } diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index 8796dfe2f6b8cf..e158665eb64b0d 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -118,8 +118,9 @@ static inline void _PyObject_InitVar(PyVarObject *op, PyTypeObject *typeobj, Py_ssize_t size) { assert(op != NULL); - Py_SET_SIZE(op, size); + assert(typeobj != &PyLong_Type); _PyObject_Init((PyObject *)op, typeobj); + Py_SET_SIZE(op, size); } diff --git a/Include/internal/pycore_runtime_init.h b/Include/internal/pycore_runtime_init.h index a8d5953ff98b0b..dfd76ac2adf4fd 100644 --- a/Include/internal/pycore_runtime_init.h +++ b/Include/internal/pycore_runtime_init.h @@ -8,6 +8,7 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif +#include "pycore_long.h" #include "pycore_object.h" #include "pycore_parser.h" #include "pycore_pymem_init.h" @@ -134,15 +135,6 @@ extern "C" { // global objects -#define _PyLong_DIGIT_INIT(val) \ - { \ - .ob_base = _PyObject_IMMORTAL_INIT(&PyLong_Type), \ - .long_value = { \ - ((val) == 0 ? 0 : ((val) > 0 ? 1 : -1)), \ - { ((val) >= 0 ? (val) : -(val)) }, \ - } \ - } - #define _PyBytes_SIMPLE_INIT(CH, LEN) \ { \ _PyVarObject_IMMORTAL_INIT(&PyBytes_Type, (LEN)), \ diff --git a/Include/object.h b/Include/object.h index 3774f126730005..df84d4aee4603e 100644 --- a/Include/object.h +++ b/Include/object.h @@ -138,8 +138,11 @@ static inline PyTypeObject* Py_TYPE(PyObject *ob) { # define Py_TYPE(ob) Py_TYPE(_PyObject_CAST(ob)) #endif +extern PyTypeObject PyLong_Type; + // bpo-39573: The Py_SET_SIZE() function must be used to set an object size. static inline Py_ssize_t Py_SIZE(PyObject *ob) { + assert(ob->ob_type != &PyLong_Type); PyVarObject *var_ob = _PyVarObject_CAST(ob); return var_ob->ob_size; } @@ -171,8 +174,8 @@ static inline void Py_SET_TYPE(PyObject *ob, PyTypeObject *type) { # define Py_SET_TYPE(ob, type) Py_SET_TYPE(_PyObject_CAST(ob), type) #endif - static inline void Py_SET_SIZE(PyVarObject *ob, Py_ssize_t size) { + assert(ob->ob_base.ob_type != &PyLong_Type); ob->ob_size = size; } #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000 diff --git a/Modules/_testcapi/mem.c b/Modules/_testcapi/mem.c index ae3f7a4372dcd8..af32e9668dda2d 100644 --- a/Modules/_testcapi/mem.c +++ b/Modules/_testcapi/mem.c @@ -347,7 +347,7 @@ test_pyobject_new(PyObject *self, PyObject *Py_UNUSED(ignored)) { PyObject *obj; PyTypeObject *type = &PyBaseObject_Type; - PyTypeObject *var_type = &PyLong_Type; + PyTypeObject *var_type = &PyBytes_Type; // PyObject_New() obj = PyObject_New(PyObject, type); diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index d4a129058702a2..c3bda9529229e2 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -32,6 +32,8 @@ Copyright (C) 1994 Steen Lumholt. # include "pycore_fileutils.h" // _Py_stat() #endif +#include "pycore_long.h" + #ifdef MS_WINDOWS #include #endif @@ -887,8 +889,8 @@ asBignumObj(PyObject *value) PyObject *hexstr; const char *hexchars; mp_int bigValue; - - neg = Py_SIZE(value) < 0; + assert(PyLong_Check(value)); + neg = _PyLong_IsNegative((PyLongObject *)value); hexstr = _PyLong_Format(value, 16); if (hexstr == NULL) return NULL; @@ -1960,7 +1962,7 @@ _tkinter_tkapp_getboolean(TkappObject *self, PyObject *arg) int v; if (PyLong_Check(arg)) { /* int or bool */ - return PyBool_FromLong(Py_SIZE(arg) != 0); + return PyBool_FromLong(!_PyLong_IsZero((PyLongObject *)arg)); } if (PyTclObject_Check(arg)) { diff --git a/Objects/boolobject.c b/Objects/boolobject.c index a035f463323823..4c23cda3f3433c 100644 --- a/Objects/boolobject.c +++ b/Objects/boolobject.c @@ -2,6 +2,7 @@ #include "Python.h" #include "pycore_object.h" // _Py_FatalRefcountError() +#include "pycore_long.h" // FALSE_TAG TRUE_TAG #include "pycore_runtime.h" // _Py_ID() #include @@ -198,10 +199,14 @@ PyTypeObject PyBool_Type = { struct _longobject _Py_FalseStruct = { PyObject_HEAD_INIT(&PyBool_Type) - { 0, { 0 } } + { .ob_size = _PyLong_FALSE_TAG, + { 0 } + } }; struct _longobject _Py_TrueStruct = { PyObject_HEAD_INIT(&PyBool_Type) - { 1, { 1 } } + { .ob_size = _PyLong_TRUE_TAG, + { 1 } + } }; diff --git a/Objects/longobject.c b/Objects/longobject.c index 26b404bdc9edc3..1a3c243b68631d 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -172,8 +172,7 @@ _PyLong_FromDigits(int negative, Py_ssize_t digit_count, digit *digits) PyErr_NoMemory(); return NULL; } - int sign = negative ? -1 : 1; - result->long_value.ob_size = sign * digit_count; + _PyLong_SetSignAndSize(result, negative, digit_count); memcpy(result->long_value.ob_digit, digits, digit_count * sizeof(digit)); return result; } @@ -204,9 +203,9 @@ _PyLong_FromMedium(sdigit x) PyErr_NoMemory(); return NULL; } - Py_ssize_t sign = x < 0 ? -1: 1; digit abs_x = x < 0 ? -x : x; - _PyObject_InitVar((PyVarObject*)v, &PyLong_Type, sign); + _PyLong_SetSignAndSize(v, x < 0, 1); + _PyObject_Init((PyObject*)v, &PyLong_Type); v->long_value.ob_digit[0] = abs_x; return (PyObject*)v; } diff --git a/Objects/typeobject.c b/Objects/typeobject.c index b3f1429debc58b..b969817e732e58 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -8,6 +8,7 @@ #include "pycore_initconfig.h" // _PyStatus_OK() #include "pycore_moduleobject.h" // _PyModule_GetDef() #include "pycore_object.h" // _PyType_HasFeature() +#include "pycore_long.h" // _PyLong_IsNegative() #include "pycore_pyerrors.h" // _PyErr_Occurred() #include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_typeobject.h" // struct type_cache @@ -7850,7 +7851,7 @@ slot_sq_length(PyObject *self) return -1; assert(PyLong_Check(res)); - if (Py_SIZE(res) < 0) { + if (_PyLong_IsNegative((PyLongObject *)res)) { Py_DECREF(res); PyErr_SetString(PyExc_ValueError, "__len__() should return >= 0"); diff --git a/Python/ast_opt.c b/Python/ast_opt.c index 1a0b2a05b1c713..8270fa8e372d93 100644 --- a/Python/ast_opt.c +++ b/Python/ast_opt.c @@ -2,6 +2,7 @@ #include "Python.h" #include "pycore_ast.h" // _PyAST_GetDocString() #include "pycore_compile.h" // _PyASTOptimizeState +#include "pycore_long.h" // _PyLong #include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_format.h" // F_LJUST @@ -152,7 +153,9 @@ check_complexity(PyObject *obj, Py_ssize_t limit) static PyObject * safe_multiply(PyObject *v, PyObject *w) { - if (PyLong_Check(v) && PyLong_Check(w) && Py_SIZE(v) && Py_SIZE(w)) { + if (PyLong_Check(v) && PyLong_Check(w) && + !_PyLong_IsZero((PyLongObject *)v) && !_PyLong_IsZero((PyLongObject *)w) + ) { size_t vbits = _PyLong_NumBits(v); size_t wbits = _PyLong_NumBits(w); if (vbits == (size_t)-1 || wbits == (size_t)-1) { @@ -198,7 +201,9 @@ safe_multiply(PyObject *v, PyObject *w) static PyObject * safe_power(PyObject *v, PyObject *w) { - if (PyLong_Check(v) && PyLong_Check(w) && Py_SIZE(v) && Py_SIZE(w) > 0) { + if (PyLong_Check(v) && PyLong_Check(w) && + !_PyLong_IsZero((PyLongObject *)v) && _PyLong_IsPositive((PyLongObject *)w) + ) { size_t vbits = _PyLong_NumBits(v); size_t wbits = PyLong_AsSize_t(w); if (vbits == (size_t)-1 || wbits == (size_t)-1) { @@ -215,7 +220,9 @@ safe_power(PyObject *v, PyObject *w) static PyObject * safe_lshift(PyObject *v, PyObject *w) { - if (PyLong_Check(v) && PyLong_Check(w) && Py_SIZE(v) && Py_SIZE(w)) { + if (PyLong_Check(v) && PyLong_Check(w) && + !_PyLong_IsZero((PyLongObject *)v) && !_PyLong_IsZero((PyLongObject *)w) + ) { size_t vbits = _PyLong_NumBits(v); size_t wbits = PyLong_AsSize_t(w); if (vbits == (size_t)-1 || wbits == (size_t)-1) { diff --git a/Python/marshal.c b/Python/marshal.c index 1ccf1c06d20b3c..3c43b6d53ba8be 100644 --- a/Python/marshal.c +++ b/Python/marshal.c @@ -840,7 +840,7 @@ r_PyLong(RFILE *p) if (ob == NULL) return NULL; - Py_SET_SIZE(ob, n > 0 ? size : -size); + _PyLong_SetSignAndSize(ob, n < 0, size); for (i = 0; i < size-1; i++) { d = 0; diff --git a/Tools/build/deepfreeze.py b/Tools/build/deepfreeze.py index 511b26a5ce3dc7..7d2be412363b78 100644 --- a/Tools/build/deepfreeze.py +++ b/Tools/build/deepfreeze.py @@ -309,7 +309,7 @@ def generate_tuple(self, name: str, t: Tuple[object, ...]) -> str: return f"& {name}._object.ob_base.ob_base" def _generate_int_for_bits(self, name: str, i: int, digit: int) -> None: - sign = -1 if i < 0 else 0 if i == 0 else +1 + negative = int(i < 0) i = abs(i) digits: list[int] = [] while i: @@ -318,10 +318,12 @@ def _generate_int_for_bits(self, name: str, i: int, digit: int) -> None: self.write("static") with self.indent(): with self.block("struct"): - self.write("PyObject_VAR_HEAD") + self.write("PyObject ob_base;") + self.write("uintptr_t ob_size;") self.write(f"digit ob_digit[{max(1, len(digits))}];") with self.block(f"{name} =", ";"): - self.object_var_head("PyLong_Type", sign*len(digits)) + self.object_head("PyLong_Type") + self.write(f".ob_size = TAG_FROM_SIGN_AND_SIZE({negative}, {len(digits)}),") if digits: ds = ", ".join(map(str, digits)) self.write(f".ob_digit = {{ {ds} }},") @@ -345,7 +347,7 @@ def generate_int(self, name: str, i: int) -> str: self.write('#error "PYLONG_BITS_IN_DIGIT should be 15 or 30"') self.write("#endif") # If neither clause applies, it won't compile - return f"& {name}.ob_base.ob_base" + return f"& {name}.ob_base" def generate_float(self, name: str, x: float) -> str: with self.block(f"static PyFloatObject {name} =", ";"): From 54c6f1b1021010e29ec6c349603f1e209baabb46 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Thu, 2 Mar 2023 16:26:33 +0000 Subject: [PATCH 18/35] Change layout of size/sign bits in longobject to support future addition of immortal ints and tagged medium ints. --- Include/cpython/longintrepr.h | 2 +- Include/internal/pycore_long.h | 136 +++++++++++++++++++++++---------- Include/object.h | 3 + Objects/boolobject.c | 4 +- Objects/longobject.c | 70 ++++++++++------- Python/marshal.c | 2 +- Tools/build/deepfreeze.py | 6 +- Tools/build/umarshal.py | 2 + Tools/gdb/libpython.py | 26 ++++--- 9 files changed, 165 insertions(+), 86 deletions(-) diff --git a/Include/cpython/longintrepr.h b/Include/cpython/longintrepr.h index 69085118dd2f0d..c4cf820da5e4f2 100644 --- a/Include/cpython/longintrepr.h +++ b/Include/cpython/longintrepr.h @@ -80,7 +80,7 @@ typedef long stwodigits; /* signed variant of twodigits */ */ typedef struct _PyLongValue { - intptr_t ob_size; /* Number of digits, sign and flags */ + uintptr_t lv_tag; /* Number of digits, sign and flags */ digit ob_digit[1]; } _PyLongValue; diff --git a/Include/internal/pycore_long.h b/Include/internal/pycore_long.h index badb299932b849..0e6f47e59c80aa 100644 --- a/Include/internal/pycore_long.h +++ b/Include/internal/pycore_long.h @@ -108,57 +108,88 @@ PyAPI_FUNC(char*) _PyLong_FormatBytesWriter( int base, int alternate); +/* Long value tag bits: + * 0-1: Sign bits value = (1-sign), ie. negative=2, positive=0, zero=1. + * 2: Reserved for immortality bit + * 3+ Unsigned digit count + */ +#define SIGN_MASK 3 +#define SIGN_ZERO 1 +#define SIGN_NEGATIVE 2 +#define NON_SIZE_BITS 3 + +static int +unused_bits_are_zero(const PyLongObject* op) { + return (op->long_value.lv_tag & 4) == 0; +} + +static int +inconsistent_zero(const PyLongObject* op) { + return + ((op->long_value.lv_tag & SIGN_MASK) == SIGN_ZERO + && (op->long_value.lv_tag >> NON_SIZE_BITS) != 0) + || + ((op->long_value.lv_tag & SIGN_MASK) != SIGN_ZERO + && (op->long_value.lv_tag >> NON_SIZE_BITS) == 0); +} /* Return 1 if the argument is positive single digit int */ static inline int _PyLong_IsNonNegativeSingleDigit(const PyLongObject* op) { - /* We perform a fast check using a single comparison by casting from int - to uint which casts negative numbers to large positive numbers. - For details see Section 14.2 "Bounds Checking" in the Agner Fog - optimization manual found at: - https://www.agner.org/optimize/optimizing_cpp.pdf - - The function is not affected by -fwrapv, -fno-wrapv and -ftrapv - compiler options of GCC and clang - */ assert(PyLong_Check(op)); - Py_ssize_t signed_size = op->long_value.ob_size; - return ((size_t)signed_size) <= 1; + assert(unused_bits_are_zero(op)); + assert(!inconsistent_zero(op)); + return op->long_value.lv_tag <= (1 << NON_SIZE_BITS); } - static inline int _PyLong_IsSingleDigit(const PyLongObject* op) { assert(PyLong_Check(op)); - Py_ssize_t signed_size = op->long_value.ob_size; - return ((size_t)(signed_size+1)) <= 2; + assert(unused_bits_are_zero(op)); + assert(!inconsistent_zero(op)); + return op->long_value.lv_tag < (2 << NON_SIZE_BITS); } static inline Py_ssize_t _PyLong_SingleDigitValue(const PyLongObject *op) { assert(PyLong_Check(op)); - assert(op->long_value.ob_size >= -1 && op->long_value.ob_size <= 1); - return op->long_value.ob_size * op->long_value.ob_digit[0]; + assert(_PyLong_IsSingleDigit(op)); + assert(unused_bits_are_zero(op)); + Py_ssize_t sign = 1 - (op->long_value.lv_tag & SIGN_MASK); + return sign * (Py_ssize_t)op->long_value.ob_digit[0]; } static inline bool -_PyLong_IsPositive(const PyLongObject *op) +_PyLong_IsZero(const PyLongObject *op) { - return op->long_value.ob_size > 0; + assert(unused_bits_are_zero(op)); + assert(!inconsistent_zero(op)); + return (op->long_value.lv_tag & SIGN_MASK) == SIGN_ZERO; } static inline bool _PyLong_IsNegative(const PyLongObject *op) { - return op->long_value.ob_size < 0; + assert(unused_bits_are_zero(op)); + assert(!inconsistent_zero(op)); + return (op->long_value.lv_tag & SIGN_MASK) == SIGN_NEGATIVE; +} + +static inline bool +_PyLong_IsPositive(const PyLongObject *op) +{ + assert(unused_bits_are_zero(op)); + assert(!inconsistent_zero(op)); + return (op->long_value.lv_tag & SIGN_MASK) == 0; } static inline Py_ssize_t _PyLong_DigitCount(const PyLongObject *op) { assert(PyLong_Check(op)); - return Py_ABS(op->long_value.ob_size); + assert(unused_bits_are_zero(op)); + return op->long_value.lv_tag >> NON_SIZE_BITS; } /* Equivalent to _PyLong_DigitCount(op) * _PyLong_NonZeroSign(op) */ @@ -166,7 +197,10 @@ static inline Py_ssize_t _PyLong_SignedDigitCount(const PyLongObject *op) { assert(PyLong_Check(op)); - return op->long_value.ob_size; + assert(unused_bits_are_zero(op)); + Py_ssize_t sign = 1 - (op->long_value.lv_tag & SIGN_MASK); + assert(!inconsistent_zero(op)); + return sign * (Py_ssize_t)(op->long_value.lv_tag >> NON_SIZE_BITS); } /* Like _PyLong_DigitCount but asserts that op is non-negative */ @@ -175,57 +209,77 @@ _PyLong_UnsignedDigitCount(const PyLongObject *op) { assert(PyLong_Check(op)); assert(!_PyLong_IsNegative(op)); - return op->long_value.ob_size; -} - -static inline bool -_PyLong_IsZero(const PyLongObject *op) -{ - return op->long_value.ob_size == 0; + assert(unused_bits_are_zero(op)); + assert(!inconsistent_zero(op)); + return op->long_value.lv_tag >> NON_SIZE_BITS; } static inline int _PyLong_NonZeroSign(const PyLongObject *op) { assert(PyLong_Check(op)); - assert(!_PyLong_IsZero(op)); - return ((op->long_value.ob_size > 0) << 1) - 1; + assert(unused_bits_are_zero(op)); + assert(!inconsistent_zero(op)); + return 1 - (op->long_value.lv_tag & SIGN_MASK); } /* Do a and b have the same sign? Zero counts as positive. */ static inline int _PyLong_SameSign(const PyLongObject *a, const PyLongObject *b) { - return (a->long_value.ob_size ^ b->long_value.ob_size) >= 0; + return (a->long_value.lv_tag & SIGN_MASK) == (b->long_value.lv_tag & SIGN_MASK); } +//#define TAG_FROM_SIGN_AND_SIZE(neg, size) ((neg) ? -(size) : (size)) +#define TAG_FROM_SIGN_AND_SIZE(sign, size) ((1 - (sign)) | ((size) << NON_SIZE_BITS)) + static inline void -_PyLong_SetSignAndSize(PyLongObject *op, bool negative, Py_ssize_t size) +_PyLong_SetSignAndSize(PyLongObject *op, int sign, Py_ssize_t size) { - int sign = 1-negative*2; - assert(sign == -1 || sign == 1); - op->long_value.ob_size = sign * size; + assert(size >= 0); + assert(-1 <= sign && sign <= 1); + assert(sign != 0 || size == 0); + op->long_value.lv_tag = TAG_FROM_SIGN_AND_SIZE(sign, size); + assert(!inconsistent_zero(op)); +} + +static inline void +_PyLong_SetSize(PyLongObject *op, Py_ssize_t size) +{ + assert(size >= 0); + assert(!inconsistent_zero(op)); + op->long_value.lv_tag = (size << NON_SIZE_BITS) | (op->long_value.lv_tag & SIGN_MASK); + assert(!inconsistent_zero(op)); } static inline void _PyLong_FlipSign(PyLongObject *op) { - op->long_value.ob_size = -op->long_value.ob_size; + assert(unused_bits_are_zero(op)); + assert(!inconsistent_zero(op)); + int flipped_sign = 2 - (op->long_value.lv_tag & SIGN_MASK); + op->long_value.lv_tag &= ~7; + op->long_value.lv_tag |= flipped_sign; + assert(unused_bits_are_zero(op)); + assert(!inconsistent_zero(op)); } #define _PyLong_DIGIT_INIT(val) \ { \ .ob_base = _PyObject_IMMORTAL_INIT(&PyLong_Type), \ .long_value = { \ - .ob_size = (val) == 0 ? 0 : ((val) < 0 ? -1 : 1), \ + .lv_tag = TAG_FROM_SIGN_AND_SIZE( \ + (val) == 0 ? 0 : ((val) < 0 ? -1 : 1), \ + (val) == 0 ? 0 : 1), \ { ((val) >= 0 ? (val) : -(val)) }, \ } \ } -#define TAG_FROM_SIGN_AND_SIZE(neg, size) (neg ? -(size) : (size)) - -#define _PyLong_FALSE_TAG 0 -#define _PyLong_TRUE_TAG 1 +#define _PyLong_FALSE_TAG TAG_FROM_SIGN_AND_SIZE(0, 0) +#define _PyLong_TRUE_TAG TAG_FROM_SIGN_AND_SIZE(1, 1) +static_assert(TAG_FROM_SIGN_AND_SIZE(0, 0) == 1); +static_assert(TAG_FROM_SIGN_AND_SIZE(1, 1) == 8); +static_assert(TAG_FROM_SIGN_AND_SIZE(-1, 1) == 10); #ifdef __cplusplus } diff --git a/Include/object.h b/Include/object.h index df84d4aee4603e..a59836f7ab358d 100644 --- a/Include/object.h +++ b/Include/object.h @@ -139,10 +139,12 @@ static inline PyTypeObject* Py_TYPE(PyObject *ob) { #endif extern PyTypeObject PyLong_Type; +extern PyTypeObject PyBool_Type; // bpo-39573: The Py_SET_SIZE() function must be used to set an object size. static inline Py_ssize_t Py_SIZE(PyObject *ob) { assert(ob->ob_type != &PyLong_Type); + assert(ob->ob_type != &PyBool_Type); PyVarObject *var_ob = _PyVarObject_CAST(ob); return var_ob->ob_size; } @@ -176,6 +178,7 @@ static inline void Py_SET_TYPE(PyObject *ob, PyTypeObject *type) { static inline void Py_SET_SIZE(PyVarObject *ob, Py_ssize_t size) { assert(ob->ob_base.ob_type != &PyLong_Type); + assert(ob->ob_base.ob_type != &PyBool_Type); ob->ob_size = size; } #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000 diff --git a/Objects/boolobject.c b/Objects/boolobject.c index 4c23cda3f3433c..9d8e956e06f712 100644 --- a/Objects/boolobject.c +++ b/Objects/boolobject.c @@ -199,14 +199,14 @@ PyTypeObject PyBool_Type = { struct _longobject _Py_FalseStruct = { PyObject_HEAD_INIT(&PyBool_Type) - { .ob_size = _PyLong_FALSE_TAG, + { .lv_tag = _PyLong_FALSE_TAG, { 0 } } }; struct _longobject _Py_TrueStruct = { PyObject_HEAD_INIT(&PyBool_Type) - { .ob_size = _PyLong_TRUE_TAG, + { .lv_tag = _PyLong_TRUE_TAG, { 1 } } }; diff --git a/Objects/longobject.c b/Objects/longobject.c index 1a3c243b68631d..3d3b21c5e25be8 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -6,7 +6,7 @@ #include "pycore_bitutils.h" // _Py_popcount32() #include "pycore_initconfig.h" // _PyStatus_OK() #include "pycore_long.h" // _Py_SmallInts -#include "pycore_object.h" // _PyObject_InitVar() +#include "pycore_object.h" // _PyObject_Init() #include "pycore_pystate.h" // _Py_IsMainInterpreter() #include "pycore_runtime.h" // _PY_NSMALLPOSINTS #include "pycore_structseq.h" // _PyStructSequence_FiniType() @@ -123,7 +123,12 @@ long_normalize(PyLongObject *v) while (i > 0 && v->long_value.ob_digit[i-1] == 0) --i; if (i != j) { - _PyLong_SetSignAndSize(v, _PyLong_IsNegative(v), i); + if (i == 0) { + _PyLong_SetSignAndSize(v, 0, 0); + } + else { + _PyLong_SetSize(v, i); + } } return v; } @@ -149,8 +154,8 @@ _PyLong_New(Py_ssize_t size) Py_ssize_t ndigits = size ? size : 1; /* Number of bytes needed is: offsetof(PyLongObject, ob_digit) + sizeof(digit)*size. Previous incarnations of this code used - sizeof(PyVarObject) instead of the offsetof, but this risks being - incorrect in the presence of padding between the PyVarObject header + sizeof() instead of the offsetof, but this risks being + incorrect in the presence of padding between the header and the digits. */ result = PyObject_Malloc(offsetof(PyLongObject, long_value.ob_digit) + ndigits*sizeof(digit)); @@ -158,7 +163,7 @@ _PyLong_New(Py_ssize_t size) PyErr_NoMemory(); return NULL; } - _PyLong_SetSignAndSize(result, false, size); + _PyLong_SetSignAndSize(result, size != 0, size); _PyObject_Init((PyObject*)result, &PyLong_Type); return result; } @@ -167,12 +172,15 @@ PyLongObject * _PyLong_FromDigits(int negative, Py_ssize_t digit_count, digit *digits) { assert(digit_count >= 0); + if (digit_count == 0) { + return (PyLongObject *)Py_NewRef(_PyLong_GetZero()); + } PyLongObject *result = _PyLong_New(digit_count); if (result == NULL) { PyErr_NoMemory(); return NULL; } - _PyLong_SetSignAndSize(result, negative, digit_count); + _PyLong_SetSignAndSize(result, negative?-1:1, digit_count); memcpy(result->long_value.ob_digit, digits, digit_count * sizeof(digit)); return result; } @@ -204,7 +212,7 @@ _PyLong_FromMedium(sdigit x) return NULL; } digit abs_x = x < 0 ? -x : x; - _PyLong_SetSignAndSize(v, x < 0, 1); + _PyLong_SetSignAndSize(v, x<0?-1:1, 1); _PyObject_Init((PyObject*)v, &PyLong_Type); v->long_value.ob_digit[0] = abs_x; return (PyObject*)v; @@ -214,18 +222,18 @@ static PyObject * _PyLong_FromLarge(stwodigits ival) { twodigits abs_ival; - bool negative; + int sign; assert(!is_medium_int(ival)); if (ival < 0) { /* negate: can't write this as abs_ival = -ival since that invokes undefined behaviour when ival is LONG_MIN */ abs_ival = 0U-(twodigits)ival; - negative = true; + sign = -1; } else { abs_ival = (twodigits)ival; - negative = false; + sign = 1; } /* Must be at least two digits */ assert(abs_ival >> PyLong_SHIFT != 0); @@ -238,7 +246,7 @@ _PyLong_FromLarge(stwodigits ival) PyLongObject *v = _PyLong_New(ndigits); if (v != NULL) { digit *p = v->long_value.ob_digit; - _PyLong_SetSignAndSize(v, negative, ndigits); + _PyLong_SetSignAndSize(v, sign, ndigits); t = abs_ival; while (t) { *p++ = Py_SAFE_DOWNCAST( @@ -311,7 +319,7 @@ PyLong_FromLong(long ival) v = _PyLong_New(ndigits); if (v != NULL) { digit *p = v->long_value.ob_digit; - _PyLong_SetSignAndSize(v, ival < 0, ndigits); + _PyLong_SetSignAndSize(v, ival < 0 ? -1 : 1, ndigits); t = abs_ival; while (t) { *p++ = (digit)(t & PyLong_MASK); @@ -738,7 +746,7 @@ _PyLong_Sign(PyObject *vv) assert(v != NULL); assert(PyLong_Check(v)); - return _PyLong_IsPositive(v) - _PyLong_IsNegative(v); + return _PyLong_NonZeroSign(v); } static int @@ -888,7 +896,11 @@ _PyLong_FromByteArray(const unsigned char* bytes, size_t n, } } - _PyLong_SetSignAndSize(v, is_signed, idigit); + int sign = is_signed ? -1: 1; + if (idigit == 0) { + sign = 0; + } + _PyLong_SetSignAndSize(v, sign, idigit); return (PyObject *)maybe_small_long(long_normalize(v)); } @@ -898,7 +910,7 @@ _PyLong_AsByteArray(PyLongObject* v, int little_endian, int is_signed) { Py_ssize_t i; /* index into v->long_value.ob_digit */ - Py_ssize_t ndigits; /* |v->ob_size| */ + Py_ssize_t ndigits; /* number of digits */ twodigits accum; /* sliding register */ unsigned int accumbits; /* # bits in accum */ int do_twos_comp; /* store 2's-comp? is_signed and v < 0 */ @@ -1109,7 +1121,7 @@ PyLong_FromLongLong(long long ival) v = _PyLong_New(ndigits); if (v != NULL) { digit *p = v->long_value.ob_digit; - _PyLong_SetSignAndSize(v, ival < 0, ndigits); + _PyLong_SetSignAndSize(v, ival < 0 ? -1 : 1, ndigits); t = abs_ival; while (t) { *p++ = (digit)(t & PyLong_MASK); @@ -1152,7 +1164,7 @@ PyLong_FromSsize_t(Py_ssize_t ival) v = _PyLong_New(ndigits); if (v != NULL) { digit *p = v->long_value.ob_digit; - _PyLong_SetSignAndSize(v, negative, ndigits); + _PyLong_SetSignAndSize(v, negative ? -1 : 1, ndigits); t = abs_ival; while (t) { *p++ = (digit)(t & PyLong_MASK); @@ -2443,7 +2455,7 @@ long_from_non_binary_base(const char *start, const char *end, Py_ssize_t digits, *res = NULL; return 0; } - _PyLong_SetSignAndSize(z, false, 0); + _PyLong_SetSignAndSize(z, 0, 0); /* `convwidth` consecutive input digits are treated as a single * digit in base `convmultmax`. @@ -2495,7 +2507,7 @@ long_from_non_binary_base(const char *start, const char *end, Py_ssize_t digits, if (_PyLong_DigitCount(z) < size_z) { *pz = (digit)c; assert(!_PyLong_IsNegative(z)); - _PyLong_SetSignAndSize(z, false, _PyLong_DigitCount(z) + 1); + _PyLong_SetSignAndSize(z, 1, _PyLong_DigitCount(z) + 1); } else { PyLongObject *tmp; @@ -3641,7 +3653,7 @@ k_mul(PyLongObject *a, PyLongObject *b) /* If a is small compared to b, splitting on b gives a degenerate * case with ah==0, and Karatsuba may be (even much) less efficient * than "grade school" then. However, we can still win, by viewing - * b as a string of "big digits", each of width a->ob_size. That + * b as a string of "big digits", each of the same width as a. That * leads to a sequence of balanced calls to k_mul. */ if (2 * asize <= bsize) @@ -3806,9 +3818,9 @@ ah*bh and al*bl too. /* b has at least twice the digits of a, and a is big enough that Karatsuba * would pay off *if* the inputs had balanced sizes. View b as a sequence - * of slices, each with a->ob_size digits, and multiply the slices by a, - * one at a time. This gives k_mul balanced inputs to work with, and is - * also cache-friendly (we compute one double-width slice of the result + * of slices, each with the same number of digits as a, and multiply the + * slices by a, one at a time. This gives k_mul balanced inputs to work with, + * and is also cache-friendly (we compute one double-width slice of the result * at a time, then move on, never backtracking except for the helpful * single-width slice overlap between successive partial sums). */ @@ -3844,7 +3856,7 @@ k_lopsided_mul(PyLongObject *a, PyLongObject *b) memcpy(bslice->long_value.ob_digit, b->long_value.ob_digit + nbdone, nbtouse * sizeof(digit)); assert(nbtouse >= 0); - _PyLong_SetSignAndSize(bslice, false, nbtouse); + _PyLong_SetSignAndSize(bslice, 1, nbtouse); product = k_mul(a, bslice); if (product == NULL) goto fail; @@ -4933,7 +4945,7 @@ long_rshift1(PyLongObject *a, Py_ssize_t wordshift, digit remshift) significant `wordshift` digits of `a` is nonzero. Digit `wordshift` of `2**shift - 1` has value `PyLong_MASK >> hishift`. */ - _PyLong_SetSignAndSize(z, true, newsize); + _PyLong_SetSignAndSize(z, -1, newsize); digit sticky = 0; for (Py_ssize_t j = 0; j < wordshift; j++) { @@ -5354,7 +5366,7 @@ _PyLong_GCD(PyObject *aarg, PyObject *barg) } if (c != NULL) { assert(size_a >= 0); - _PyLong_SetSignAndSize(c, false, size_a); + _PyLong_SetSignAndSize(c, 1, size_a); } else if (Py_REFCNT(a) == 1) { c = (PyLongObject*)Py_NewRef(a); @@ -5368,12 +5380,12 @@ _PyLong_GCD(PyObject *aarg, PyObject *barg) if (d != NULL) { assert(size_a >= 0); - _PyLong_SetSignAndSize(d, false, size_a); + _PyLong_SetSignAndSize(d, 1, size_a); } else if (Py_REFCNT(b) == 1 && size_a <= alloc_b) { d = (PyLongObject*)Py_NewRef(b); assert(size_a >= 0); - _PyLong_SetSignAndSize(d, false, size_a); + _PyLong_SetSignAndSize(d, 1, size_a); } else { alloc_b = size_a; @@ -5557,7 +5569,7 @@ long_subtype_new(PyTypeObject *type, PyObject *x, PyObject *obase) return NULL; } assert(PyLong_Check(newobj)); - newobj->long_value.ob_size = tmp->long_value.ob_size; + newobj->long_value.lv_tag = tmp->long_value.lv_tag; for (i = 0; i < n; i++) { newobj->long_value.ob_digit[i] = tmp->long_value.ob_digit[i]; } diff --git a/Python/marshal.c b/Python/marshal.c index 3c43b6d53ba8be..4ec544a7befa74 100644 --- a/Python/marshal.c +++ b/Python/marshal.c @@ -840,7 +840,7 @@ r_PyLong(RFILE *p) if (ob == NULL) return NULL; - _PyLong_SetSignAndSize(ob, n < 0, size); + _PyLong_SetSignAndSize(ob, n < 0 ? -1 : 1, size); for (i = 0; i < size-1; i++) { d = 0; diff --git a/Tools/build/deepfreeze.py b/Tools/build/deepfreeze.py index 7d2be412363b78..ec808526b7bbb7 100644 --- a/Tools/build/deepfreeze.py +++ b/Tools/build/deepfreeze.py @@ -309,7 +309,7 @@ def generate_tuple(self, name: str, t: Tuple[object, ...]) -> str: return f"& {name}._object.ob_base.ob_base" def _generate_int_for_bits(self, name: str, i: int, digit: int) -> None: - negative = int(i < 0) + sign = (i > 0) - (i < 0) i = abs(i) digits: list[int] = [] while i: @@ -319,11 +319,11 @@ def _generate_int_for_bits(self, name: str, i: int, digit: int) -> None: with self.indent(): with self.block("struct"): self.write("PyObject ob_base;") - self.write("uintptr_t ob_size;") + self.write("uintptr_t lv_tag;") self.write(f"digit ob_digit[{max(1, len(digits))}];") with self.block(f"{name} =", ";"): self.object_head("PyLong_Type") - self.write(f".ob_size = TAG_FROM_SIGN_AND_SIZE({negative}, {len(digits)}),") + self.write(f".lv_tag = TAG_FROM_SIGN_AND_SIZE({sign}, {len(digits)}),") if digits: ds = ", ".join(map(str, digits)) self.write(f".ob_digit = {{ {ds} }},") diff --git a/Tools/build/umarshal.py b/Tools/build/umarshal.py index f61570cbaff751..a6fa623bd1b266 100644 --- a/Tools/build/umarshal.py +++ b/Tools/build/umarshal.py @@ -94,6 +94,8 @@ def __init__(self, data: bytes): self.level: int = 0 def r_string(self, n: int) -> bytes: + if not (0 <= n <= self.end - self.pos): + print(n, self.end, self.pos) assert 0 <= n <= self.end - self.pos buf = self.data[self.pos : self.pos + n] self.pos += n diff --git a/Tools/gdb/libpython.py b/Tools/gdb/libpython.py index 56d6970b29249c..e38bd59e20a305 100755 --- a/Tools/gdb/libpython.py +++ b/Tools/gdb/libpython.py @@ -882,10 +882,16 @@ class PyLongObjectPtr(PyObjectPtr): def proxyval(self, visited): ''' Python's Include/longobjrep.h has this declaration: - struct _longobject { - PyObject_VAR_HEAD - digit ob_digit[1]; - }; + + typedef struct _PyLongValue { + uintptr_t lv_tag; /* Number of digits, sign and flags */ + digit ob_digit[1]; + } _PyLongValue; + + struct _longobject { + PyObject_HEAD + _PyLongValue long_value; + }; with this description: The absolute value of a number is equal to @@ -897,11 +903,13 @@ def proxyval(self, visited): #define PyLong_SHIFT 30 #define PyLong_SHIFT 15 ''' - ob_size = int(self.field('ob_size')) - if ob_size == 0: + long_value = self.field('long_value') + lv_tag = int(long_value['lv_tag']) + size = lv_tag >> 3 + if size == 0: return 0 - ob_digit = self.field('long_value')['ob_digit'] + ob_digit = long_value['ob_digit'] if gdb.lookup_type('digit').sizeof == 2: SHIFT = 15 @@ -909,9 +917,9 @@ def proxyval(self, visited): SHIFT = 30 digits = [int(ob_digit[i]) * 2**(SHIFT*i) - for i in safe_range(abs(ob_size))] + for i in safe_range(size)] result = sum(digits) - if ob_size < 0: + if (lv_tag & 3) == 2: result = -result return result From ce6bfb28f624070dc26ae0bbc49b0a753c4481a3 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Thu, 2 Mar 2023 16:33:50 +0000 Subject: [PATCH 19/35] Test pairs of longs together on fast path of add/mul/sub. --- Include/internal/pycore_long.h | 7 +++++++ Objects/longobject.c | 9 ++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/Include/internal/pycore_long.h b/Include/internal/pycore_long.h index 0e6f47e59c80aa..cc3d55a01fea3c 100644 --- a/Include/internal/pycore_long.h +++ b/Include/internal/pycore_long.h @@ -150,6 +150,13 @@ _PyLong_IsSingleDigit(const PyLongObject* op) { return op->long_value.lv_tag < (2 << NON_SIZE_BITS); } +static inline int +_PyLong_BothAreSingleDigit(const PyLongObject* a, PyLongObject* b) { + assert(PyLong_Check(a)); + assert(PyLong_Check(b)); + return (a->long_value.lv_tag | b->long_value.lv_tag) < (2 << NON_SIZE_BITS); +} + static inline Py_ssize_t _PyLong_SingleDigitValue(const PyLongObject *op) { diff --git a/Objects/longobject.c b/Objects/longobject.c index 3d3b21c5e25be8..86606ce0b0a3f6 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -3216,6 +3216,9 @@ PyLong_AsDouble(PyObject *v) static Py_ssize_t long_compare(PyLongObject *a, PyLongObject *b) { + if (_PyLong_BothAreSingleDigit(a, b)) { + return _PyLong_SingleDigitValue(a) - _PyLong_SingleDigitValue(b); + } Py_ssize_t sign = _PyLong_SignedDigitCount(a) - _PyLong_SignedDigitCount(b); if (sign == 0) { Py_ssize_t i = _PyLong_DigitCount(a); @@ -3392,7 +3395,7 @@ x_sub(PyLongObject *a, PyLongObject *b) PyObject * _PyLong_Add(PyLongObject *a, PyLongObject *b) { - if (_PyLong_IsSingleDigit(a) && _PyLong_IsSingleDigit(b)) { + if (_PyLong_BothAreSingleDigit(a, b)) { return _PyLong_FromSTwoDigits(medium_value(a) + medium_value(b)); } @@ -3433,7 +3436,7 @@ _PyLong_Subtract(PyLongObject *a, PyLongObject *b) { PyLongObject *z; - if (_PyLong_IsSingleDigit(a) && _PyLong_IsSingleDigit(b)) { + if (_PyLong_BothAreSingleDigit(a, b)) { return _PyLong_FromSTwoDigits(medium_value(a) - medium_value(b)); } if (_PyLong_IsNegative(a)) { @@ -3885,7 +3888,7 @@ _PyLong_Multiply(PyLongObject *a, PyLongObject *b) PyLongObject *z; /* fast path for single-digit multiplication */ - if (_PyLong_IsSingleDigit(a) && _PyLong_IsSingleDigit(b)) { + if (_PyLong_BothAreSingleDigit(a, b)) { stwodigits v = medium_value(a) * medium_value(b); return _PyLong_FromSTwoDigits(v); } From 4c1956bf658a6f77ab5ec20e3113065a70528ec3 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Mon, 6 Mar 2023 09:56:25 +0000 Subject: [PATCH 20/35] Tidy up comment and delete commented out code. --- Include/internal/pycore_long.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Include/internal/pycore_long.h b/Include/internal/pycore_long.h index cc3d55a01fea3c..010e032164c121 100644 --- a/Include/internal/pycore_long.h +++ b/Include/internal/pycore_long.h @@ -230,14 +230,13 @@ _PyLong_NonZeroSign(const PyLongObject *op) return 1 - (op->long_value.lv_tag & SIGN_MASK); } -/* Do a and b have the same sign? Zero counts as positive. */ +/* Do a and b have the same sign? */ static inline int _PyLong_SameSign(const PyLongObject *a, const PyLongObject *b) { return (a->long_value.lv_tag & SIGN_MASK) == (b->long_value.lv_tag & SIGN_MASK); } -//#define TAG_FROM_SIGN_AND_SIZE(neg, size) ((neg) ? -(size) : (size)) #define TAG_FROM_SIGN_AND_SIZE(sign, size) ((1 - (sign)) | ((size) << NON_SIZE_BITS)) static inline void From 301158bf4b1b7ccc3404fd52216c80dcb3f39b1b Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Mon, 6 Mar 2023 10:02:41 +0000 Subject: [PATCH 21/35] Add news. --- .../2023-03-06-10-02-22.gh-issue-101291.0FT2QS.rst | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-03-06-10-02-22.gh-issue-101291.0FT2QS.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-06-10-02-22.gh-issue-101291.0FT2QS.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-06-10-02-22.gh-issue-101291.0FT2QS.rst new file mode 100644 index 00000000000000..d701db4809649b --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-06-10-02-22.gh-issue-101291.0FT2QS.rst @@ -0,0 +1,7 @@ +Rearrage bits in first field (after header) of PyLongObject. * Bits 0 and 1: +1- sign. I.e. 0 for positive numbers, 1 for zero and 2 for negative numbers. +* Bit 2 reserved (probably for the immortal bit) * Bits 3+ the unsigned +size. + +This makes a few operations slightly more efficient, and will enable a more +compact and faster 2s-complement representation of most ints in future. From 1aa18914ad1f361575da7157c16e44fa9e9e6faa Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Mon, 6 Mar 2023 10:03:46 +0000 Subject: [PATCH 22/35] Remove debugging asserts. --- Include/internal/pycore_long.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Include/internal/pycore_long.h b/Include/internal/pycore_long.h index 010e032164c121..e8fc17ba863344 100644 --- a/Include/internal/pycore_long.h +++ b/Include/internal/pycore_long.h @@ -283,10 +283,6 @@ _PyLong_FlipSign(PyLongObject *op) { #define _PyLong_FALSE_TAG TAG_FROM_SIGN_AND_SIZE(0, 0) #define _PyLong_TRUE_TAG TAG_FROM_SIGN_AND_SIZE(1, 1) -static_assert(TAG_FROM_SIGN_AND_SIZE(0, 0) == 1); -static_assert(TAG_FROM_SIGN_AND_SIZE(1, 1) == 8); -static_assert(TAG_FROM_SIGN_AND_SIZE(-1, 1) == 10); - #ifdef __cplusplus } #endif From bf2a9af2b9795094f554cbbdff3c11e4635a66a9 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Mon, 6 Mar 2023 10:39:26 +0000 Subject: [PATCH 23/35] Fix storage classes. --- Include/object.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Include/object.h b/Include/object.h index a59836f7ab358d..c509a6a40eac23 100644 --- a/Include/object.h +++ b/Include/object.h @@ -138,8 +138,8 @@ static inline PyTypeObject* Py_TYPE(PyObject *ob) { # define Py_TYPE(ob) Py_TYPE(_PyObject_CAST(ob)) #endif -extern PyTypeObject PyLong_Type; -extern PyTypeObject PyBool_Type; +PyAPI_DATA(PyTypeObject) PyLong_Type; +PyAPI_DATA(PyTypeObject) PyBool_Type; // bpo-39573: The Py_SET_SIZE() function must be used to set an object size. static inline Py_ssize_t Py_SIZE(PyObject *ob) { From 169f52172ddac02ec0614307df6c48ad65203440 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Mon, 6 Mar 2023 13:31:58 +0000 Subject: [PATCH 24/35] Remove development debug functions. --- Include/internal/pycore_long.h | 40 ---------------------------------- 1 file changed, 40 deletions(-) diff --git a/Include/internal/pycore_long.h b/Include/internal/pycore_long.h index e8fc17ba863344..8ee12d466549e5 100644 --- a/Include/internal/pycore_long.h +++ b/Include/internal/pycore_long.h @@ -118,35 +118,16 @@ PyAPI_FUNC(char*) _PyLong_FormatBytesWriter( #define SIGN_NEGATIVE 2 #define NON_SIZE_BITS 3 -static int -unused_bits_are_zero(const PyLongObject* op) { - return (op->long_value.lv_tag & 4) == 0; -} - -static int -inconsistent_zero(const PyLongObject* op) { - return - ((op->long_value.lv_tag & SIGN_MASK) == SIGN_ZERO - && (op->long_value.lv_tag >> NON_SIZE_BITS) != 0) - || - ((op->long_value.lv_tag & SIGN_MASK) != SIGN_ZERO - && (op->long_value.lv_tag >> NON_SIZE_BITS) == 0); -} - /* Return 1 if the argument is positive single digit int */ static inline int _PyLong_IsNonNegativeSingleDigit(const PyLongObject* op) { assert(PyLong_Check(op)); - assert(unused_bits_are_zero(op)); - assert(!inconsistent_zero(op)); return op->long_value.lv_tag <= (1 << NON_SIZE_BITS); } static inline int _PyLong_IsSingleDigit(const PyLongObject* op) { assert(PyLong_Check(op)); - assert(unused_bits_are_zero(op)); - assert(!inconsistent_zero(op)); return op->long_value.lv_tag < (2 << NON_SIZE_BITS); } @@ -162,7 +143,6 @@ _PyLong_SingleDigitValue(const PyLongObject *op) { assert(PyLong_Check(op)); assert(_PyLong_IsSingleDigit(op)); - assert(unused_bits_are_zero(op)); Py_ssize_t sign = 1 - (op->long_value.lv_tag & SIGN_MASK); return sign * (Py_ssize_t)op->long_value.ob_digit[0]; } @@ -170,24 +150,18 @@ _PyLong_SingleDigitValue(const PyLongObject *op) static inline bool _PyLong_IsZero(const PyLongObject *op) { - assert(unused_bits_are_zero(op)); - assert(!inconsistent_zero(op)); return (op->long_value.lv_tag & SIGN_MASK) == SIGN_ZERO; } static inline bool _PyLong_IsNegative(const PyLongObject *op) { - assert(unused_bits_are_zero(op)); - assert(!inconsistent_zero(op)); return (op->long_value.lv_tag & SIGN_MASK) == SIGN_NEGATIVE; } static inline bool _PyLong_IsPositive(const PyLongObject *op) { - assert(unused_bits_are_zero(op)); - assert(!inconsistent_zero(op)); return (op->long_value.lv_tag & SIGN_MASK) == 0; } @@ -195,7 +169,6 @@ static inline Py_ssize_t _PyLong_DigitCount(const PyLongObject *op) { assert(PyLong_Check(op)); - assert(unused_bits_are_zero(op)); return op->long_value.lv_tag >> NON_SIZE_BITS; } @@ -204,9 +177,7 @@ static inline Py_ssize_t _PyLong_SignedDigitCount(const PyLongObject *op) { assert(PyLong_Check(op)); - assert(unused_bits_are_zero(op)); Py_ssize_t sign = 1 - (op->long_value.lv_tag & SIGN_MASK); - assert(!inconsistent_zero(op)); return sign * (Py_ssize_t)(op->long_value.lv_tag >> NON_SIZE_BITS); } @@ -216,8 +187,6 @@ _PyLong_UnsignedDigitCount(const PyLongObject *op) { assert(PyLong_Check(op)); assert(!_PyLong_IsNegative(op)); - assert(unused_bits_are_zero(op)); - assert(!inconsistent_zero(op)); return op->long_value.lv_tag >> NON_SIZE_BITS; } @@ -225,8 +194,6 @@ static inline int _PyLong_NonZeroSign(const PyLongObject *op) { assert(PyLong_Check(op)); - assert(unused_bits_are_zero(op)); - assert(!inconsistent_zero(op)); return 1 - (op->long_value.lv_tag & SIGN_MASK); } @@ -246,27 +213,20 @@ _PyLong_SetSignAndSize(PyLongObject *op, int sign, Py_ssize_t size) assert(-1 <= sign && sign <= 1); assert(sign != 0 || size == 0); op->long_value.lv_tag = TAG_FROM_SIGN_AND_SIZE(sign, size); - assert(!inconsistent_zero(op)); } static inline void _PyLong_SetSize(PyLongObject *op, Py_ssize_t size) { assert(size >= 0); - assert(!inconsistent_zero(op)); op->long_value.lv_tag = (size << NON_SIZE_BITS) | (op->long_value.lv_tag & SIGN_MASK); - assert(!inconsistent_zero(op)); } static inline void _PyLong_FlipSign(PyLongObject *op) { - assert(unused_bits_are_zero(op)); - assert(!inconsistent_zero(op)); int flipped_sign = 2 - (op->long_value.lv_tag & SIGN_MASK); op->long_value.lv_tag &= ~7; op->long_value.lv_tag |= flipped_sign; - assert(unused_bits_are_zero(op)); - assert(!inconsistent_zero(op)); } #define _PyLong_DIGIT_INIT(val) \ From 90f907295d18cd57446c001534a2c5994eaeb8c3 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 8 Mar 2023 00:35:27 +0000 Subject: [PATCH 25/35] Avoid casting to smaller int. --- Python/bltinmodule.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 038d8344619cb0..b751494779a763 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -2490,7 +2490,7 @@ builtin_sum_impl(PyObject *module, PyObject *iterable, PyObject *start) */ if (PyLong_CheckExact(result)) { int overflow; - long i_result = PyLong_AsLongAndOverflow(result, &overflow); + Py_ssize_t i_result = PyLong_AsLongAndOverflow(result, &overflow); /* If this already overflowed, don't even enter the loop. */ if (overflow == 0) { Py_SETREF(result, NULL); @@ -2504,7 +2504,7 @@ builtin_sum_impl(PyObject *module, PyObject *iterable, PyObject *start) return PyLong_FromLong(i_result); } if (PyLong_CheckExact(item) || PyBool_Check(item)) { - long b; + Py_ssize_t b; overflow = 0; /* Single digits are common, fast, and cannot overflow on unpacking. */ if (_PyLong_IsSingleDigit((PyLongObject *)item)) { From f143443232b8c8b5270daffd02f2f5f5525ed118 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 8 Mar 2023 17:35:49 +0000 Subject: [PATCH 26/35] Apply suggestions from code review. --- Include/internal/pycore_long.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Include/internal/pycore_long.h b/Include/internal/pycore_long.h index 8ee12d466549e5..1f00d9ac0942a4 100644 --- a/Include/internal/pycore_long.h +++ b/Include/internal/pycore_long.h @@ -132,7 +132,7 @@ _PyLong_IsSingleDigit(const PyLongObject* op) { } static inline int -_PyLong_BothAreSingleDigit(const PyLongObject* a, PyLongObject* b) { +_PyLong_BothAreSingleDigit(const PyLongObject* a, const PyLongObject* b) { assert(PyLong_Check(a)); assert(PyLong_Check(b)); return (a->long_value.lv_tag | b->long_value.lv_tag) < (2 << NON_SIZE_BITS); @@ -212,19 +212,19 @@ _PyLong_SetSignAndSize(PyLongObject *op, int sign, Py_ssize_t size) assert(size >= 0); assert(-1 <= sign && sign <= 1); assert(sign != 0 || size == 0); - op->long_value.lv_tag = TAG_FROM_SIGN_AND_SIZE(sign, size); + op->long_value.lv_tag = TAG_FROM_SIGN_AND_SIZE(sign, (size_t)size); } static inline void _PyLong_SetSize(PyLongObject *op, Py_ssize_t size) { assert(size >= 0); - op->long_value.lv_tag = (size << NON_SIZE_BITS) | (op->long_value.lv_tag & SIGN_MASK); + op->long_value.lv_tag = (((size_t)size) << NON_SIZE_BITS) | (op->long_value.lv_tag & SIGN_MASK); } static inline void _PyLong_FlipSign(PyLongObject *op) { - int flipped_sign = 2 - (op->long_value.lv_tag & SIGN_MASK); + unsigned int flipped_sign = 2 - (op->long_value.lv_tag & SIGN_MASK); op->long_value.lv_tag &= ~7; op->long_value.lv_tag |= flipped_sign; } From a0d661e8bc5c4f25b4dc65e4c73fb5d53b7999b0 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 8 Mar 2023 17:38:40 +0000 Subject: [PATCH 27/35] Widen types to avoid data loss. --- Include/internal/pycore_long.h | 8 ++++++++ Objects/listobject.c | 4 +++- Objects/longobject.c | 33 ++++++++++++++++++++++++++------- 3 files changed, 37 insertions(+), 8 deletions(-) diff --git a/Include/internal/pycore_long.h b/Include/internal/pycore_long.h index 1f00d9ac0942a4..a064d5f64e6041 100644 --- a/Include/internal/pycore_long.h +++ b/Include/internal/pycore_long.h @@ -118,6 +118,10 @@ PyAPI_FUNC(char*) _PyLong_FormatBytesWriter( #define SIGN_NEGATIVE 2 #define NON_SIZE_BITS 3 +/* All "single digit" values are guaranteed to fit into + * a Py_ssize_t with at least one bit to spare. + */ + /* Return 1 if the argument is positive single digit int */ static inline int _PyLong_IsNonNegativeSingleDigit(const PyLongObject* op) { @@ -138,6 +142,10 @@ _PyLong_BothAreSingleDigit(const PyLongObject* a, const PyLongObject* b) { return (a->long_value.lv_tag | b->long_value.lv_tag) < (2 << NON_SIZE_BITS); } +/* The value returned by this function will have at least one bit to spare, + * so that addition and subtraction can be performed on the values + * without risk of overflow. + */ static inline Py_ssize_t _PyLong_SingleDigitValue(const PyLongObject *op) { diff --git a/Objects/listobject.c b/Objects/listobject.c index caf3043e642b2e..5ac5a9170ca152 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -2145,7 +2145,9 @@ unsafe_latin_compare(PyObject *v, PyObject *w, MergeState *ms) static int unsafe_long_compare(PyObject *v, PyObject *w, MergeState *ms) { - PyLongObject *vl, *wl; sdigit v0, w0; int res; + PyLongObject *vl, *wl; + intptr_t v0, w0; + int res; /* Modified from Objects/longobject.c:long_compare, assuming: */ assert(Py_IS_TYPE(v, &PyLong_Type)); diff --git a/Objects/longobject.c b/Objects/longobject.c index 86606ce0b0a3f6..72a5694c223918 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -196,7 +196,7 @@ _PyLong_Copy(PyLongObject *src) return get_small_int((sdigit)ival); } } - int size = _PyLong_DigitCount(src); + Py_ssize_t size = _PyLong_DigitCount(src); return (PyObject *)_PyLong_FromDigits(_PyLong_IsNegative(src), size, src->long_value.ob_digit); } @@ -483,7 +483,15 @@ PyLong_AsLongAndOverflow(PyObject *vv, int *overflow) do_decref = 1; } if (_PyLong_IsSingleDigit(v)) { +#if SIZEOF_LONG < SIZEOF_VOID_P + intptr_t tmp = _PyLong_SingleDigitValue(v); + res = (long)tmp; + if (res != tmp) { + *overflow = tmp < 0 ? -1 : 1; + } +#else res = _PyLong_SingleDigitValue(v); +#endif } else { res = -1; @@ -624,7 +632,16 @@ PyLong_AsUnsignedLong(PyObject *vv) v = (PyLongObject *)vv; if (_PyLong_IsNonNegativeSingleDigit(v)) { +#if SIZEOF_LONG < SIZEOF_VOID_P + intptr_t tmp = _PyLong_SingleDigitValue(v); + unsigned long res = tmp + res = (long)tmp; + if (res != tmp) { + goto overflow; + } +#else return _PyLong_SingleDigitValue(v); +#endif } if (_PyLong_IsNegative(v)) { PyErr_SetString(PyExc_OverflowError, @@ -637,13 +654,15 @@ PyLong_AsUnsignedLong(PyObject *vv) prev = x; x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i]; if ((x >> PyLong_SHIFT) != prev) { - PyErr_SetString(PyExc_OverflowError, - "Python int too large to convert " - "to C unsigned long"); - return (unsigned long) -1; + goto overflow; } } return x; +overflow: + PyErr_SetString(PyExc_OverflowError, + "Python int too large to convert " + "to C unsigned long"); + return (unsigned long) -1; } /* Get a C size_t from an int object. Returns (size_t)-1 and sets @@ -704,7 +723,7 @@ _PyLong_AsUnsignedLongMask(PyObject *vv) } v = (PyLongObject *)vv; if (_PyLong_IsNonNegativeSingleDigit(v)) { - return _PyLong_SingleDigitValue(v); + return (unsigned long)_PyLong_SingleDigitValue(v); } i = _PyLong_DigitCount(v); int sign = _PyLong_NonZeroSign(v); @@ -4243,7 +4262,7 @@ long_true_divide(PyObject *v, PyObject *w) /* Reduce to case where a and b are both positive. */ a_size = _PyLong_DigitCount(a); b_size = _PyLong_DigitCount(b); - negate = (_PyLong_IsNegative(a)) ^ (_PyLong_IsNegative(b)); + negate = (_PyLong_IsNegative(a)) != (_PyLong_IsNegative(b)); if (b_size == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "division by zero"); From 145a2e4fd2ae067854b8985f04b0b3caa8589541 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 8 Mar 2023 18:31:52 +0000 Subject: [PATCH 28/35] Fix syntax error. --- Objects/longobject.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Objects/longobject.c b/Objects/longobject.c index 72a5694c223918..df192dcabc33b0 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -634,8 +634,7 @@ PyLong_AsUnsignedLong(PyObject *vv) if (_PyLong_IsNonNegativeSingleDigit(v)) { #if SIZEOF_LONG < SIZEOF_VOID_P intptr_t tmp = _PyLong_SingleDigitValue(v); - unsigned long res = tmp - res = (long)tmp; + unsigned long res = (unsigned long)tmp; if (res != tmp) { goto overflow; } From 638a98f44c9a649d6b51143f8c9775fe11d87d1e Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Thu, 9 Mar 2023 04:35:52 +0000 Subject: [PATCH 29/35] Replace 'SingleDigit' with 'Compact' as the term 'single digit' seems to provoke endless discussion on digit size, which is irrelevant to this API. --- Include/internal/pycore_long.h | 10 ++--- Modules/_decimal/_decimal.c | 2 +- Objects/listobject.c | 10 ++--- Objects/longobject.c | 80 +++++++++++++++++----------------- Python/bltinmodule.c | 6 +-- Python/bytecodes.c | 14 +++--- Python/generated_cases.c.h | 14 +++--- Python/specialize.c | 8 ++-- 8 files changed, 72 insertions(+), 72 deletions(-) diff --git a/Include/internal/pycore_long.h b/Include/internal/pycore_long.h index a064d5f64e6041..5bfb465de1a8f7 100644 --- a/Include/internal/pycore_long.h +++ b/Include/internal/pycore_long.h @@ -124,19 +124,19 @@ PyAPI_FUNC(char*) _PyLong_FormatBytesWriter( /* Return 1 if the argument is positive single digit int */ static inline int -_PyLong_IsNonNegativeSingleDigit(const PyLongObject* op) { +_PyLong_IsNonNegativeCompact(const PyLongObject* op) { assert(PyLong_Check(op)); return op->long_value.lv_tag <= (1 << NON_SIZE_BITS); } static inline int -_PyLong_IsSingleDigit(const PyLongObject* op) { +_PyLong_IsCompact(const PyLongObject* op) { assert(PyLong_Check(op)); return op->long_value.lv_tag < (2 << NON_SIZE_BITS); } static inline int -_PyLong_BothAreSingleDigit(const PyLongObject* a, const PyLongObject* b) { +_PyLong_BothAreCompact(const PyLongObject* a, const PyLongObject* b) { assert(PyLong_Check(a)); assert(PyLong_Check(b)); return (a->long_value.lv_tag | b->long_value.lv_tag) < (2 << NON_SIZE_BITS); @@ -147,10 +147,10 @@ _PyLong_BothAreSingleDigit(const PyLongObject* a, const PyLongObject* b) { * without risk of overflow. */ static inline Py_ssize_t -_PyLong_SingleDigitValue(const PyLongObject *op) +_PyLong_CompactValue(const PyLongObject *op) { assert(PyLong_Check(op)); - assert(_PyLong_IsSingleDigit(op)); + assert(_PyLong_IsCompact(op)); Py_ssize_t sign = 1 - (op->long_value.lv_tag & SIGN_MASK); return sign * (Py_ssize_t)op->long_value.ob_digit[0]; } diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 502d3661bae38b..0e11c879732ab6 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -2160,7 +2160,7 @@ dec_from_long(PyTypeObject *type, PyObject *v, uint8_t sign = _PyLong_IsNegative(l) ? MPD_NEG : MPD_POS; - if (_PyLong_IsSingleDigit(l)) { + if (_PyLong_IsCompact(l)) { _dec_settriple(dec, sign, l->long_value.ob_digit[0], 0); mpd_qfinalize(MPD(dec), ctx, status); return dec; diff --git a/Objects/listobject.c b/Objects/listobject.c index 5ac5a9170ca152..f1edfb3a9a039d 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -2152,14 +2152,14 @@ unsafe_long_compare(PyObject *v, PyObject *w, MergeState *ms) /* Modified from Objects/longobject.c:long_compare, assuming: */ assert(Py_IS_TYPE(v, &PyLong_Type)); assert(Py_IS_TYPE(w, &PyLong_Type)); - assert(_PyLong_IsSingleDigit((PyLongObject *)v)); - assert(_PyLong_IsSingleDigit((PyLongObject *)w)); + assert(_PyLong_IsCompact((PyLongObject *)v)); + assert(_PyLong_IsCompact((PyLongObject *)w)); vl = (PyLongObject*)v; wl = (PyLongObject*)w; - v0 = _PyLong_SingleDigitValue(vl); - w0 = _PyLong_SingleDigitValue(wl); + v0 = _PyLong_CompactValue(vl); + w0 = _PyLong_CompactValue(wl); res = v0 < w0; assert(res == PyObject_RichCompareBool(v, w, Py_LT)); @@ -2357,7 +2357,7 @@ list_sort_impl(PyListObject *self, PyObject *keyfunc, int reverse) if (keys_are_all_same_type) { if (key_type == &PyLong_Type && ints_are_bounded && - !_PyLong_IsSingleDigit((PyLongObject *)key)) { + !_PyLong_IsCompact((PyLongObject *)key)) { ints_are_bounded = 0; } diff --git a/Objects/longobject.c b/Objects/longobject.c index df192dcabc33b0..87d820319db7bb 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -22,7 +22,7 @@ class int "PyObject *" "&PyLong_Type" [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=ec0275e3422a36e3]*/ -#define medium_value(x) ((stwodigits)_PyLong_SingleDigitValue(x)) +#define medium_value(x) ((stwodigits)_PyLong_CompactValue(x)) #define IS_SMALL_INT(ival) (-_PY_NSMALLNEGINTS <= (ival) && (ival) < _PY_NSMALLPOSINTS) #define IS_SMALL_UINT(ival) ((ival) < _PY_NSMALLPOSINTS) @@ -59,7 +59,7 @@ get_small_int(sdigit ival) static PyLongObject * maybe_small_long(PyLongObject *v) { - if (v && _PyLong_IsSingleDigit(v)) { + if (v && _PyLong_IsCompact(v)) { stwodigits ival = medium_value(v); if (IS_SMALL_INT(ival)) { _Py_DECREF_INT(v); @@ -190,7 +190,7 @@ _PyLong_Copy(PyLongObject *src) { assert(src != NULL); - if (_PyLong_IsSingleDigit(src)) { + if (_PyLong_IsCompact(src)) { stwodigits ival = medium_value(src); if (IS_SMALL_INT(ival)) { return get_small_int((sdigit)ival); @@ -482,15 +482,15 @@ PyLong_AsLongAndOverflow(PyObject *vv, int *overflow) return -1; do_decref = 1; } - if (_PyLong_IsSingleDigit(v)) { + if (_PyLong_IsCompact(v)) { #if SIZEOF_LONG < SIZEOF_VOID_P - intptr_t tmp = _PyLong_SingleDigitValue(v); + intptr_t tmp = _PyLong_CompactValue(v); res = (long)tmp; if (res != tmp) { *overflow = tmp < 0 ? -1 : 1; } #else - res = _PyLong_SingleDigitValue(v); + res = _PyLong_CompactValue(v); #endif } else { @@ -582,8 +582,8 @@ PyLong_AsSsize_t(PyObject *vv) { } v = (PyLongObject *)vv; - if (_PyLong_IsSingleDigit(v)) { - return _PyLong_SingleDigitValue(v); + if (_PyLong_IsCompact(v)) { + return _PyLong_CompactValue(v); } i = _PyLong_DigitCount(v); sign = _PyLong_NonZeroSign(v); @@ -631,15 +631,15 @@ PyLong_AsUnsignedLong(PyObject *vv) } v = (PyLongObject *)vv; - if (_PyLong_IsNonNegativeSingleDigit(v)) { + if (_PyLong_IsNonNegativeCompact(v)) { #if SIZEOF_LONG < SIZEOF_VOID_P - intptr_t tmp = _PyLong_SingleDigitValue(v); + intptr_t tmp = _PyLong_CompactValue(v); unsigned long res = (unsigned long)tmp; if (res != tmp) { goto overflow; } #else - return _PyLong_SingleDigitValue(v); + return _PyLong_CompactValue(v); #endif } if (_PyLong_IsNegative(v)) { @@ -684,8 +684,8 @@ PyLong_AsSize_t(PyObject *vv) } v = (PyLongObject *)vv; - if (_PyLong_IsNonNegativeSingleDigit(v)) { - return _PyLong_SingleDigitValue(v); + if (_PyLong_IsNonNegativeCompact(v)) { + return _PyLong_CompactValue(v); } if (_PyLong_IsNegative(v)) { PyErr_SetString(PyExc_OverflowError, @@ -721,8 +721,8 @@ _PyLong_AsUnsignedLongMask(PyObject *vv) return (unsigned long) -1; } v = (PyLongObject *)vv; - if (_PyLong_IsNonNegativeSingleDigit(v)) { - return (unsigned long)_PyLong_SingleDigitValue(v); + if (_PyLong_IsNonNegativeCompact(v)) { + return (unsigned long)_PyLong_CompactValue(v); } i = _PyLong_DigitCount(v); int sign = _PyLong_NonZeroSign(v); @@ -1218,9 +1218,9 @@ PyLong_AsLongLong(PyObject *vv) do_decref = 1; } - if (_PyLong_IsSingleDigit(v)) { + if (_PyLong_IsCompact(v)) { res = 0; - bytes = _PyLong_SingleDigitValue(v); + bytes = _PyLong_CompactValue(v); } else { res = _PyLong_AsByteArray((PyLongObject *)v, (unsigned char *)&bytes, @@ -1257,9 +1257,9 @@ PyLong_AsUnsignedLongLong(PyObject *vv) } v = (PyLongObject*)vv; - if (_PyLong_IsNonNegativeSingleDigit(v)) { + if (_PyLong_IsNonNegativeCompact(v)) { res = 0; - bytes = _PyLong_SingleDigitValue(v); + bytes = _PyLong_CompactValue(v); } else { res = _PyLong_AsByteArray((PyLongObject *)vv, (unsigned char *)&bytes, @@ -1289,8 +1289,8 @@ _PyLong_AsUnsignedLongLongMask(PyObject *vv) return (unsigned long long) -1; } v = (PyLongObject *)vv; - if (_PyLong_IsNonNegativeSingleDigit(v)) { - return _PyLong_SingleDigitValue(v); + if (_PyLong_IsNonNegativeCompact(v)) { + return _PyLong_CompactValue(v); } i = _PyLong_DigitCount(v); sign = _PyLong_NonZeroSign(v); @@ -1361,8 +1361,8 @@ PyLong_AsLongLongAndOverflow(PyObject *vv, int *overflow) return -1; do_decref = 1; } - if (_PyLong_IsSingleDigit(v)) { - res = _PyLong_SingleDigitValue(v); + if (_PyLong_IsCompact(v)) { + res = _PyLong_CompactValue(v); } else { i = _PyLong_DigitCount(v); @@ -3209,7 +3209,7 @@ PyLong_AsDouble(PyObject *v) PyErr_SetString(PyExc_TypeError, "an integer is required"); return -1.0; } - if (_PyLong_IsSingleDigit((PyLongObject *)v)) { + if (_PyLong_IsCompact((PyLongObject *)v)) { /* Fast path; single digit long (31 bits) will cast safely to double. This improves performance of FP/long operations by 20%. @@ -3234,8 +3234,8 @@ PyLong_AsDouble(PyObject *v) static Py_ssize_t long_compare(PyLongObject *a, PyLongObject *b) { - if (_PyLong_BothAreSingleDigit(a, b)) { - return _PyLong_SingleDigitValue(a) - _PyLong_SingleDigitValue(b); + if (_PyLong_BothAreCompact(a, b)) { + return _PyLong_CompactValue(a) - _PyLong_CompactValue(b); } Py_ssize_t sign = _PyLong_SignedDigitCount(a) - _PyLong_SignedDigitCount(b); if (sign == 0) { @@ -3271,8 +3271,8 @@ long_hash(PyLongObject *v) Py_ssize_t i; int sign; - if (_PyLong_IsSingleDigit(v)) { - x = _PyLong_SingleDigitValue(v); + if (_PyLong_IsCompact(v)) { + x = _PyLong_CompactValue(v); if (x == (Py_uhash_t)-1) { x = (Py_uhash_t)-2; } @@ -3413,7 +3413,7 @@ x_sub(PyLongObject *a, PyLongObject *b) PyObject * _PyLong_Add(PyLongObject *a, PyLongObject *b) { - if (_PyLong_BothAreSingleDigit(a, b)) { + if (_PyLong_BothAreCompact(a, b)) { return _PyLong_FromSTwoDigits(medium_value(a) + medium_value(b)); } @@ -3454,7 +3454,7 @@ _PyLong_Subtract(PyLongObject *a, PyLongObject *b) { PyLongObject *z; - if (_PyLong_BothAreSingleDigit(a, b)) { + if (_PyLong_BothAreCompact(a, b)) { return _PyLong_FromSTwoDigits(medium_value(a) - medium_value(b)); } if (_PyLong_IsNegative(a)) { @@ -3906,7 +3906,7 @@ _PyLong_Multiply(PyLongObject *a, PyLongObject *b) PyLongObject *z; /* fast path for single-digit multiplication */ - if (_PyLong_BothAreSingleDigit(a, b)) { + if (_PyLong_BothAreCompact(a, b)) { stwodigits v = medium_value(a) * medium_value(b); return _PyLong_FromSTwoDigits(v); } @@ -4614,7 +4614,7 @@ long_pow(PyObject *v, PyObject *w, PyObject *x) /* if modulus == 1: return 0 */ - if (_PyLong_IsNonNegativeSingleDigit(c) && (c->long_value.ob_digit[0] == 1)) { + if (_PyLong_IsNonNegativeCompact(c) && (c->long_value.ob_digit[0] == 1)) { z = (PyLongObject *)PyLong_FromLong(0L); goto Done; } @@ -4827,14 +4827,14 @@ long_invert(PyLongObject *v) { /* Implement ~x as -(x+1) */ PyLongObject *x; - if (_PyLong_IsSingleDigit(v)) + if (_PyLong_IsCompact(v)) return _PyLong_FromSTwoDigits(~medium_value(v)); x = (PyLongObject *) long_add(v, (PyLongObject *)_PyLong_GetOne()); if (x == NULL) return NULL; _PyLong_Negate(&x); /* No need for maybe_small_long here, since any small longs - will have been caught in the _PyLong_IsSingleDigit() fast path. */ + will have been caught in the _PyLong_IsCompact() fast path. */ return (PyObject *)x; } @@ -4842,7 +4842,7 @@ static PyObject * long_neg(PyLongObject *v) { PyLongObject *z; - if (_PyLong_IsSingleDigit(v)) + if (_PyLong_IsCompact(v)) return _PyLong_FromSTwoDigits(-medium_value(v)); z = (PyLongObject *)_PyLong_Copy(v); if (z != NULL) @@ -4915,7 +4915,7 @@ long_rshift1(PyLongObject *a, Py_ssize_t wordshift, digit remshift) assert(remshift < PyLong_SHIFT); /* Fast path for small a. */ - if (_PyLong_IsSingleDigit(a)) { + if (_PyLong_IsCompact(a)) { stwodigits m, x; digit shift; m = medium_value(a); @@ -5031,7 +5031,7 @@ long_lshift1(PyLongObject *a, Py_ssize_t wordshift, digit remshift) Py_ssize_t oldsize, newsize, i, j; twodigits accum; - if (wordshift == 0 && _PyLong_IsSingleDigit(a)) { + if (wordshift == 0 && _PyLong_IsCompact(a)) { stwodigits m = medium_value(a); // bypass undefined shift operator behavior stwodigits x = m < 0 ? -(-m << remshift) : m << remshift; @@ -5247,7 +5247,7 @@ long_and(PyObject *a, PyObject *b) CHECK_BINOP(a, b); PyLongObject *x = (PyLongObject*)a; PyLongObject *y = (PyLongObject*)b; - if (_PyLong_IsSingleDigit(x) && _PyLong_IsSingleDigit(y)) { + if (_PyLong_IsCompact(x) && _PyLong_IsCompact(y)) { return _PyLong_FromSTwoDigits(medium_value(x) & medium_value(y)); } return long_bitwise(x, '&', y); @@ -5259,7 +5259,7 @@ long_xor(PyObject *a, PyObject *b) CHECK_BINOP(a, b); PyLongObject *x = (PyLongObject*)a; PyLongObject *y = (PyLongObject*)b; - if (_PyLong_IsSingleDigit(x) && _PyLong_IsSingleDigit(y)) { + if (_PyLong_IsCompact(x) && _PyLong_IsCompact(y)) { return _PyLong_FromSTwoDigits(medium_value(x) ^ medium_value(y)); } return long_bitwise(x, '^', y); @@ -5271,7 +5271,7 @@ long_or(PyObject *a, PyObject *b) CHECK_BINOP(a, b); PyLongObject *x = (PyLongObject*)a; PyLongObject *y = (PyLongObject*)b; - if (_PyLong_IsSingleDigit(x) && _PyLong_IsSingleDigit(y)) { + if (_PyLong_IsCompact(x) && _PyLong_IsCompact(y)) { return _PyLong_FromSTwoDigits(medium_value(x) | medium_value(y)); } return long_bitwise(x, '|', y); diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index b751494779a763..4887950b9074fa 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -5,7 +5,7 @@ #include "pycore_ast.h" // _PyAST_Validate() #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_compile.h" // _PyAST_Compile() -#include "pycore_long.h" // _PyLong_SingleDigitValue +#include "pycore_long.h" // _PyLong_CompactValue #include "pycore_object.h" // _Py_AddToAllObjects() #include "pycore_pyerrors.h" // _PyErr_NoMemory() #include "pycore_pystate.h" // _PyThreadState_GET() @@ -2507,8 +2507,8 @@ builtin_sum_impl(PyObject *module, PyObject *iterable, PyObject *start) Py_ssize_t b; overflow = 0; /* Single digits are common, fast, and cannot overflow on unpacking. */ - if (_PyLong_IsSingleDigit((PyLongObject *)item)) { - b = _PyLong_SingleDigitValue((PyLongObject *)item); + if (_PyLong_IsCompact((PyLongObject *)item)) { + b = _PyLong_CompactValue((PyLongObject *)item); } else { b = PyLong_AsLongAndOverflow(item, &overflow); diff --git a/Python/bytecodes.c b/Python/bytecodes.c index e51c106deab80e..bb75abcf2a0217 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -356,7 +356,7 @@ dummy_func( DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR); // Deopt unless 0 <= sub < PyList_Size(list) - DEOPT_IF(!_PyLong_IsNonNegativeSingleDigit((PyLongObject *)sub), BINARY_SUBSCR); + DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), BINARY_SUBSCR); Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; DEOPT_IF(index >= PyList_GET_SIZE(list), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); @@ -373,7 +373,7 @@ dummy_func( DEOPT_IF(!PyTuple_CheckExact(tuple), BINARY_SUBSCR); // Deopt unless 0 <= sub < PyTuple_Size(list) - DEOPT_IF(!_PyLong_IsNonNegativeSingleDigit((PyLongObject *)sub), BINARY_SUBSCR); + DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), BINARY_SUBSCR); Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; DEOPT_IF(index >= PyTuple_GET_SIZE(tuple), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); @@ -466,7 +466,7 @@ dummy_func( DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR); // Ensure nonnegative, zero-or-one-digit ints. - DEOPT_IF(!_PyLong_IsNonNegativeSingleDigit((PyLongObject *)sub), STORE_SUBSCR); + DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), STORE_SUBSCR); Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; // Ensure index < len(list) DEOPT_IF(index >= PyList_GET_SIZE(list), STORE_SUBSCR); @@ -1780,13 +1780,13 @@ dummy_func( assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), COMPARE_AND_BRANCH); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_AND_BRANCH); - DEOPT_IF(!_PyLong_IsSingleDigit((PyLongObject *)left), COMPARE_AND_BRANCH); - DEOPT_IF(!_PyLong_IsSingleDigit((PyLongObject *)right), COMPARE_AND_BRANCH); + DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_AND_BRANCH); + DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)right), COMPARE_AND_BRANCH); STAT_INC(COMPARE_AND_BRANCH, hit); assert(_PyLong_DigitCount((PyLongObject *)left) <= 1 && _PyLong_DigitCount((PyLongObject *)right) <= 1); - Py_ssize_t ileft = _PyLong_SingleDigitValue((PyLongObject *)left); - Py_ssize_t iright = _PyLong_SingleDigitValue((PyLongObject *)right); + Py_ssize_t ileft = _PyLong_CompactValue((PyLongObject *)left); + Py_ssize_t iright = _PyLong_CompactValue((PyLongObject *)right); // 2 if <, 4 if >, 8 if ==; this matches the low 4 bits of the oparg int sign_ish = COMPARISON_BIT(ileft, iright); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 969a8f669dc114..7e6bb01c70f18f 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -483,7 +483,7 @@ DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR); // Deopt unless 0 <= sub < PyList_Size(list) - DEOPT_IF(!_PyLong_IsNonNegativeSingleDigit((PyLongObject *)sub), BINARY_SUBSCR); + DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), BINARY_SUBSCR); Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; DEOPT_IF(index >= PyList_GET_SIZE(list), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); @@ -507,7 +507,7 @@ DEOPT_IF(!PyTuple_CheckExact(tuple), BINARY_SUBSCR); // Deopt unless 0 <= sub < PyTuple_Size(list) - DEOPT_IF(!_PyLong_IsNonNegativeSingleDigit((PyLongObject *)sub), BINARY_SUBSCR); + DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), BINARY_SUBSCR); Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; DEOPT_IF(index >= PyTuple_GET_SIZE(tuple), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); @@ -632,7 +632,7 @@ DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR); // Ensure nonnegative, zero-or-one-digit ints. - DEOPT_IF(!_PyLong_IsNonNegativeSingleDigit((PyLongObject *)sub), STORE_SUBSCR); + DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), STORE_SUBSCR); Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; // Ensure index < len(list) DEOPT_IF(index >= PyList_GET_SIZE(list), STORE_SUBSCR); @@ -2240,13 +2240,13 @@ assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), COMPARE_AND_BRANCH); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_AND_BRANCH); - DEOPT_IF(!_PyLong_IsSingleDigit((PyLongObject *)left), COMPARE_AND_BRANCH); - DEOPT_IF(!_PyLong_IsSingleDigit((PyLongObject *)right), COMPARE_AND_BRANCH); + DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_AND_BRANCH); + DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)right), COMPARE_AND_BRANCH); STAT_INC(COMPARE_AND_BRANCH, hit); assert(_PyLong_DigitCount((PyLongObject *)left) <= 1 && _PyLong_DigitCount((PyLongObject *)right) <= 1); - Py_ssize_t ileft = _PyLong_SingleDigitValue((PyLongObject *)left); - Py_ssize_t iright = _PyLong_SingleDigitValue((PyLongObject *)right); + Py_ssize_t ileft = _PyLong_CompactValue((PyLongObject *)left); + Py_ssize_t iright = _PyLong_CompactValue((PyLongObject *)right); // 2 if <, 4 if >, 8 if ==; this matches the low 4 bits of the oparg int sign_ish = COMPARISON_BIT(ileft, iright); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); diff --git a/Python/specialize.c b/Python/specialize.c index c35c8b553475fb..f4d454ff553922 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -1294,7 +1294,7 @@ _Py_Specialize_BinarySubscr( PyTypeObject *container_type = Py_TYPE(container); if (container_type == &PyList_Type) { if (PyLong_CheckExact(sub)) { - if (_PyLong_IsNonNegativeSingleDigit((PyLongObject *)sub)) { + if (_PyLong_IsNonNegativeCompact((PyLongObject *)sub)) { instr->op.code = BINARY_SUBSCR_LIST_INT; goto success; } @@ -1307,7 +1307,7 @@ _Py_Specialize_BinarySubscr( } if (container_type == &PyTuple_Type) { if (PyLong_CheckExact(sub)) { - if (_PyLong_IsNonNegativeSingleDigit((PyLongObject *)sub)) { + if (_PyLong_IsNonNegativeCompact((PyLongObject *)sub)) { instr->op.code = BINARY_SUBSCR_TUPLE_INT; goto success; } @@ -1375,7 +1375,7 @@ _Py_Specialize_StoreSubscr(PyObject *container, PyObject *sub, _Py_CODEUNIT *ins PyTypeObject *container_type = Py_TYPE(container); if (container_type == &PyList_Type) { if (PyLong_CheckExact(sub)) { - if (_PyLong_IsNonNegativeSingleDigit((PyLongObject *)sub) + if (_PyLong_IsNonNegativeCompact((PyLongObject *)sub) && ((PyLongObject *)sub)->long_value.ob_digit[0] < (size_t)PyList_GET_SIZE(container)) { instr->op.code = STORE_SUBSCR_LIST_INT; @@ -1993,7 +1993,7 @@ _Py_Specialize_CompareAndBranch(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *inst goto success; } if (PyLong_CheckExact(lhs)) { - if (_PyLong_IsSingleDigit((PyLongObject *)lhs) && _PyLong_IsSingleDigit((PyLongObject *)rhs)) { + if (_PyLong_IsCompact((PyLongObject *)lhs) && _PyLong_IsCompact((PyLongObject *)rhs)) { instr->op.code = COMPARE_AND_BRANCH_INT; goto success; } From 7f5acc0eba93a4c5b38642792464eae927774e62 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Thu, 16 Mar 2023 15:14:13 +0000 Subject: [PATCH 30/35] Address review comments. --- Include/internal/pycore_long.h | 23 +++++--- ...-03-06-10-02-22.gh-issue-101291.0FT2QS.rst | 2 +- Objects/longobject.c | 56 +++++++++---------- Python/marshal.c | 2 +- Tools/build/umarshal.py | 2 - 5 files changed, 45 insertions(+), 40 deletions(-) diff --git a/Include/internal/pycore_long.h b/Include/internal/pycore_long.h index 5bfb465de1a8f7..2f7f24b058cfe6 100644 --- a/Include/internal/pycore_long.h +++ b/Include/internal/pycore_long.h @@ -118,11 +118,13 @@ PyAPI_FUNC(char*) _PyLong_FormatBytesWriter( #define SIGN_NEGATIVE 2 #define NON_SIZE_BITS 3 -/* All "single digit" values are guaranteed to fit into +/* All *compact" values are guaranteed to fit into * a Py_ssize_t with at least one bit to spare. + * In other words, for 64 bit machines, compact + * will be signed 63 (or fewer) bit values */ -/* Return 1 if the argument is positive single digit int */ +/* Return 1 if the argument is compact int */ static inline int _PyLong_IsNonNegativeCompact(const PyLongObject* op) { assert(PyLong_Check(op)); @@ -142,7 +144,9 @@ _PyLong_BothAreCompact(const PyLongObject* a, const PyLongObject* b) { return (a->long_value.lv_tag | b->long_value.lv_tag) < (2 << NON_SIZE_BITS); } -/* The value returned by this function will have at least one bit to spare, +/* Returns a *compact* value, iff `_PyLong_IsCompact` is true for `op`. + * + * "Compact" values have at least one bit to spare, * so that addition and subtraction can be performed on the values * without risk of overflow. */ @@ -180,7 +184,7 @@ _PyLong_DigitCount(const PyLongObject *op) return op->long_value.lv_tag >> NON_SIZE_BITS; } -/* Equivalent to _PyLong_DigitCount(op) * _PyLong_NonZeroSign(op) */ +/* Equivalent to _PyLong_DigitCount(op) * _PyLong_NonCompactSign(op) */ static inline Py_ssize_t _PyLong_SignedDigitCount(const PyLongObject *op) { @@ -199,9 +203,10 @@ _PyLong_UnsignedDigitCount(const PyLongObject *op) } static inline int -_PyLong_NonZeroSign(const PyLongObject *op) +_PyLong_NonCompactSign(const PyLongObject *op) { assert(PyLong_Check(op)); + assert(!_PyLong_IsCompact(op)); return 1 - (op->long_value.lv_tag & SIGN_MASK); } @@ -215,7 +220,7 @@ _PyLong_SameSign(const PyLongObject *a, const PyLongObject *b) #define TAG_FROM_SIGN_AND_SIZE(sign, size) ((1 - (sign)) | ((size) << NON_SIZE_BITS)) static inline void -_PyLong_SetSignAndSize(PyLongObject *op, int sign, Py_ssize_t size) +_PyLong_SetSignAndDigitCount(PyLongObject *op, int sign, Py_ssize_t size) { assert(size >= 0); assert(-1 <= sign && sign <= 1); @@ -224,16 +229,18 @@ _PyLong_SetSignAndSize(PyLongObject *op, int sign, Py_ssize_t size) } static inline void -_PyLong_SetSize(PyLongObject *op, Py_ssize_t size) +_PyLong_SetDigitCount(PyLongObject *op, Py_ssize_t size) { assert(size >= 0); op->long_value.lv_tag = (((size_t)size) << NON_SIZE_BITS) | (op->long_value.lv_tag & SIGN_MASK); } +#define NON_SIZE_MASK ~((1 << NON_SIZE_BITS) - 1) + static inline void _PyLong_FlipSign(PyLongObject *op) { unsigned int flipped_sign = 2 - (op->long_value.lv_tag & SIGN_MASK); - op->long_value.lv_tag &= ~7; + op->long_value.lv_tag &= NON_SIZE_MASK; op->long_value.lv_tag |= flipped_sign; } diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-06-10-02-22.gh-issue-101291.0FT2QS.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-06-10-02-22.gh-issue-101291.0FT2QS.rst index d701db4809649b..aa24846c1aa3d0 100644 --- a/Misc/NEWS.d/next/Core and Builtins/2023-03-06-10-02-22.gh-issue-101291.0FT2QS.rst +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-06-10-02-22.gh-issue-101291.0FT2QS.rst @@ -1,5 +1,5 @@ Rearrage bits in first field (after header) of PyLongObject. * Bits 0 and 1: -1- sign. I.e. 0 for positive numbers, 1 for zero and 2 for negative numbers. +1 - sign. I.e. 0 for positive numbers, 1 for zero and 2 for negative numbers. * Bit 2 reserved (probably for the immortal bit) * Bits 3+ the unsigned size. diff --git a/Objects/longobject.c b/Objects/longobject.c index 87d820319db7bb..407e0cbecdf93e 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -124,10 +124,10 @@ long_normalize(PyLongObject *v) --i; if (i != j) { if (i == 0) { - _PyLong_SetSignAndSize(v, 0, 0); + _PyLong_SetSignAndDigitCount(v, 0, 0); } else { - _PyLong_SetSize(v, i); + _PyLong_SetDigitCount(v, i); } } return v; @@ -163,7 +163,7 @@ _PyLong_New(Py_ssize_t size) PyErr_NoMemory(); return NULL; } - _PyLong_SetSignAndSize(result, size != 0, size); + _PyLong_SetSignAndDigitCount(result, size != 0, size); _PyObject_Init((PyObject*)result, &PyLong_Type); return result; } @@ -180,7 +180,7 @@ _PyLong_FromDigits(int negative, Py_ssize_t digit_count, digit *digits) PyErr_NoMemory(); return NULL; } - _PyLong_SetSignAndSize(result, negative?-1:1, digit_count); + _PyLong_SetSignAndDigitCount(result, negative?-1:1, digit_count); memcpy(result->long_value.ob_digit, digits, digit_count * sizeof(digit)); return result; } @@ -212,7 +212,7 @@ _PyLong_FromMedium(sdigit x) return NULL; } digit abs_x = x < 0 ? -x : x; - _PyLong_SetSignAndSize(v, x<0?-1:1, 1); + _PyLong_SetSignAndDigitCount(v, x<0?-1:1, 1); _PyObject_Init((PyObject*)v, &PyLong_Type); v->long_value.ob_digit[0] = abs_x; return (PyObject*)v; @@ -246,7 +246,7 @@ _PyLong_FromLarge(stwodigits ival) PyLongObject *v = _PyLong_New(ndigits); if (v != NULL) { digit *p = v->long_value.ob_digit; - _PyLong_SetSignAndSize(v, sign, ndigits); + _PyLong_SetSignAndDigitCount(v, sign, ndigits); t = abs_ival; while (t) { *p++ = Py_SAFE_DOWNCAST( @@ -319,7 +319,7 @@ PyLong_FromLong(long ival) v = _PyLong_New(ndigits); if (v != NULL) { digit *p = v->long_value.ob_digit; - _PyLong_SetSignAndSize(v, ival < 0 ? -1 : 1, ndigits); + _PyLong_SetSignAndDigitCount(v, ival < 0 ? -1 : 1, ndigits); t = abs_ival; while (t) { *p++ = (digit)(t & PyLong_MASK); @@ -496,7 +496,7 @@ PyLong_AsLongAndOverflow(PyObject *vv, int *overflow) else { res = -1; i = _PyLong_DigitCount(v); - sign = _PyLong_NonZeroSign(v); + sign = _PyLong_NonCompactSign(v); x = 0; while (--i >= 0) { prev = x; @@ -586,7 +586,7 @@ PyLong_AsSsize_t(PyObject *vv) { return _PyLong_CompactValue(v); } i = _PyLong_DigitCount(v); - sign = _PyLong_NonZeroSign(v); + sign = _PyLong_NonCompactSign(v); x = 0; while (--i >= 0) { prev = x; @@ -721,11 +721,11 @@ _PyLong_AsUnsignedLongMask(PyObject *vv) return (unsigned long) -1; } v = (PyLongObject *)vv; - if (_PyLong_IsNonNegativeCompact(v)) { + if (_PyLong_IsCompact(v)) { return (unsigned long)_PyLong_CompactValue(v); } i = _PyLong_DigitCount(v); - int sign = _PyLong_NonZeroSign(v); + int sign = _PyLong_NonCompactSign(v); x = 0; while (--i >= 0) { x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i]; @@ -764,7 +764,7 @@ _PyLong_Sign(PyObject *vv) assert(v != NULL); assert(PyLong_Check(v)); - return _PyLong_NonZeroSign(v); + return _PyLong_NonCompactSign(v); } static int @@ -918,7 +918,7 @@ _PyLong_FromByteArray(const unsigned char* bytes, size_t n, if (idigit == 0) { sign = 0; } - _PyLong_SetSignAndSize(v, sign, idigit); + _PyLong_SetSignAndDigitCount(v, sign, idigit); return (PyObject *)maybe_small_long(long_normalize(v)); } @@ -1139,7 +1139,7 @@ PyLong_FromLongLong(long long ival) v = _PyLong_New(ndigits); if (v != NULL) { digit *p = v->long_value.ob_digit; - _PyLong_SetSignAndSize(v, ival < 0 ? -1 : 1, ndigits); + _PyLong_SetSignAndDigitCount(v, ival < 0 ? -1 : 1, ndigits); t = abs_ival; while (t) { *p++ = (digit)(t & PyLong_MASK); @@ -1182,7 +1182,7 @@ PyLong_FromSsize_t(Py_ssize_t ival) v = _PyLong_New(ndigits); if (v != NULL) { digit *p = v->long_value.ob_digit; - _PyLong_SetSignAndSize(v, negative ? -1 : 1, ndigits); + _PyLong_SetSignAndDigitCount(v, negative ? -1 : 1, ndigits); t = abs_ival; while (t) { *p++ = (digit)(t & PyLong_MASK); @@ -1289,11 +1289,11 @@ _PyLong_AsUnsignedLongLongMask(PyObject *vv) return (unsigned long long) -1; } v = (PyLongObject *)vv; - if (_PyLong_IsNonNegativeCompact(v)) { - return _PyLong_CompactValue(v); + if (_PyLong_IsCompact(v)) { + return (unsigned long long)(signed long long)_PyLong_CompactValue(v); } i = _PyLong_DigitCount(v); - sign = _PyLong_NonZeroSign(v); + sign = _PyLong_NonCompactSign(v); x = 0; while (--i >= 0) { x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i]; @@ -1366,7 +1366,7 @@ PyLong_AsLongLongAndOverflow(PyObject *vv, int *overflow) } else { i = _PyLong_DigitCount(v); - sign = _PyLong_NonZeroSign(v); + sign = _PyLong_NonCompactSign(v); x = 0; while (--i >= 0) { prev = x; @@ -2473,7 +2473,7 @@ long_from_non_binary_base(const char *start, const char *end, Py_ssize_t digits, *res = NULL; return 0; } - _PyLong_SetSignAndSize(z, 0, 0); + _PyLong_SetSignAndDigitCount(z, 0, 0); /* `convwidth` consecutive input digits are treated as a single * digit in base `convmultmax`. @@ -2525,7 +2525,7 @@ long_from_non_binary_base(const char *start, const char *end, Py_ssize_t digits, if (_PyLong_DigitCount(z) < size_z) { *pz = (digit)c; assert(!_PyLong_IsNegative(z)); - _PyLong_SetSignAndSize(z, 1, _PyLong_DigitCount(z) + 1); + _PyLong_SetSignAndDigitCount(z, 1, _PyLong_DigitCount(z) + 1); } else { PyLongObject *tmp; @@ -3279,7 +3279,7 @@ long_hash(PyLongObject *v) return x; } i = _PyLong_DigitCount(v); - sign = _PyLong_NonZeroSign(v); + sign = _PyLong_NonCompactSign(v); x = 0; while (--i >= 0) { /* Here x is a quantity in the range [0, _PyHASH_MODULUS); we @@ -3877,7 +3877,7 @@ k_lopsided_mul(PyLongObject *a, PyLongObject *b) memcpy(bslice->long_value.ob_digit, b->long_value.ob_digit + nbdone, nbtouse * sizeof(digit)); assert(nbtouse >= 0); - _PyLong_SetSignAndSize(bslice, 1, nbtouse); + _PyLong_SetSignAndDigitCount(bslice, 1, nbtouse); product = k_mul(a, bslice); if (product == NULL) goto fail; @@ -3938,7 +3938,7 @@ fast_mod(PyLongObject *a, PyLongObject *b) assert(_PyLong_DigitCount(a) == 1); assert(_PyLong_DigitCount(b) == 1); - sdigit sign = _PyLong_NonZeroSign(b); + sdigit sign = _PyLong_NonCompactSign(b); if (_PyLong_SameSign(a, b)) { mod = left % right; } @@ -4966,7 +4966,7 @@ long_rshift1(PyLongObject *a, Py_ssize_t wordshift, digit remshift) significant `wordshift` digits of `a` is nonzero. Digit `wordshift` of `2**shift - 1` has value `PyLong_MASK >> hishift`. */ - _PyLong_SetSignAndSize(z, -1, newsize); + _PyLong_SetSignAndDigitCount(z, -1, newsize); digit sticky = 0; for (Py_ssize_t j = 0; j < wordshift; j++) { @@ -5387,7 +5387,7 @@ _PyLong_GCD(PyObject *aarg, PyObject *barg) } if (c != NULL) { assert(size_a >= 0); - _PyLong_SetSignAndSize(c, 1, size_a); + _PyLong_SetSignAndDigitCount(c, 1, size_a); } else if (Py_REFCNT(a) == 1) { c = (PyLongObject*)Py_NewRef(a); @@ -5401,12 +5401,12 @@ _PyLong_GCD(PyObject *aarg, PyObject *barg) if (d != NULL) { assert(size_a >= 0); - _PyLong_SetSignAndSize(d, 1, size_a); + _PyLong_SetSignAndDigitCount(d, 1, size_a); } else if (Py_REFCNT(b) == 1 && size_a <= alloc_b) { d = (PyLongObject*)Py_NewRef(b); assert(size_a >= 0); - _PyLong_SetSignAndSize(d, 1, size_a); + _PyLong_SetSignAndDigitCount(d, 1, size_a); } else { alloc_b = size_a; diff --git a/Python/marshal.c b/Python/marshal.c index 4ec544a7befa74..2966139cec9ae9 100644 --- a/Python/marshal.c +++ b/Python/marshal.c @@ -840,7 +840,7 @@ r_PyLong(RFILE *p) if (ob == NULL) return NULL; - _PyLong_SetSignAndSize(ob, n < 0 ? -1 : 1, size); + _PyLong_SetSignAndDigitCount(ob, n < 0 ? -1 : 1, size); for (i = 0; i < size-1; i++) { d = 0; diff --git a/Tools/build/umarshal.py b/Tools/build/umarshal.py index a6fa623bd1b266..f61570cbaff751 100644 --- a/Tools/build/umarshal.py +++ b/Tools/build/umarshal.py @@ -94,8 +94,6 @@ def __init__(self, data: bytes): self.level: int = 0 def r_string(self, n: int) -> bytes: - if not (0 <= n <= self.end - self.pos): - print(n, self.end, self.pos) assert 0 <= n <= self.end - self.pos buf = self.data[self.pos : self.pos + n] self.pos += n From 87f49b27d14a3b91b9ddd22bf140fafcab0159bd Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Thu, 16 Mar 2023 19:09:50 +0000 Subject: [PATCH 31/35] Fix _PyLong_Sign --- Include/internal/pycore_long.h | 8 ++++++++ Objects/longobject.c | 3 +++ 2 files changed, 11 insertions(+) diff --git a/Include/internal/pycore_long.h b/Include/internal/pycore_long.h index 2f7f24b058cfe6..c2d20fd54b5f88 100644 --- a/Include/internal/pycore_long.h +++ b/Include/internal/pycore_long.h @@ -202,6 +202,14 @@ _PyLong_UnsignedDigitCount(const PyLongObject *op) return op->long_value.lv_tag >> NON_SIZE_BITS; } +static inline int +_PyLong_CompactSign(const PyLongObject *op) +{ + assert(PyLong_Check(op)); + assert(_PyLong_IsCompact(op)); + return 1 - (op->long_value.lv_tag & SIGN_MASK); +} + static inline int _PyLong_NonCompactSign(const PyLongObject *op) { diff --git a/Objects/longobject.c b/Objects/longobject.c index 407e0cbecdf93e..36bd15be5c8d44 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -764,6 +764,9 @@ _PyLong_Sign(PyObject *vv) assert(v != NULL); assert(PyLong_Check(v)); + if (_PyLong_IsCompact(v)) { + return _PyLong_CompactSign(v); + } return _PyLong_NonCompactSign(v); } From f764aa8b8146be271299160b2e7a46749b89367f Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Thu, 16 Mar 2023 19:26:51 +0000 Subject: [PATCH 32/35] Replace _PyLong_Sign(x) < 0 with _PyLong_IsNegative(x). --- Modules/mathmodule.c | 4 ++-- Objects/abstract.c | 3 ++- Objects/longobject.c | 22 +++++++++++++--------- Objects/rangeobject.c | 2 +- Objects/sliceobject.c | 6 +++--- 5 files changed, 21 insertions(+), 16 deletions(-) diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index 84097687fe2490..8f058c3ad5115f 100644 --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -1726,13 +1726,13 @@ math_isqrt(PyObject *module, PyObject *n) return NULL; } - if (_PyLong_Sign(n) < 0) { + if (_PyLong_IsNegative((PyLongObject *)n)) { PyErr_SetString( PyExc_ValueError, "isqrt() argument must be nonnegative"); goto error; } - if (_PyLong_Sign(n) == 0) { + if (_PyLong_IsZero((PyLongObject *)n)) { Py_DECREF(n); return PyLong_FromLong(0); } diff --git a/Objects/abstract.c b/Objects/abstract.c index 9dc74fb9c2608c..e95785900c9c5f 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -5,6 +5,7 @@ #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_ceval.h" // _Py_EnterRecursiveCallTstate() #include "pycore_object.h" // _Py_CheckSlotResult() +#include "pycore_long.h" // _Py_IsNegative #include "pycore_pyerrors.h" // _PyErr_Occurred() #include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_unionobject.h" // _PyUnion_Check() @@ -1483,7 +1484,7 @@ PyNumber_AsSsize_t(PyObject *item, PyObject *err) /* Whether or not it is less than or equal to zero is determined by the sign of ob_size */ - if (_PyLong_Sign(value) < 0) + if (_PyLong_IsNegative((PyLongObject *)value)) result = PY_SSIZE_T_MIN; else result = PY_SSIZE_T_MAX; diff --git a/Objects/longobject.c b/Objects/longobject.c index 36bd15be5c8d44..c5bb89906985c7 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -1082,10 +1082,12 @@ PyLong_AsVoidPtr(PyObject *vv) #if SIZEOF_VOID_P <= SIZEOF_LONG long x; - if (PyLong_Check(vv) && _PyLong_Sign(vv) < 0) + if (PyLong_Check(vv) && _PyLong_IsNegative((PyLongObject *)vv)) { x = PyLong_AsLong(vv); - else + } + else { x = PyLong_AsUnsignedLong(vv); + } #else #if SIZEOF_LONG_LONG < SIZEOF_VOID_P @@ -1093,10 +1095,12 @@ PyLong_AsVoidPtr(PyObject *vv) #endif long long x; - if (PyLong_Check(vv) && _PyLong_Sign(vv) < 0) + if (PyLong_Check(vv) && _PyLong_IsNegative((PyLongObject *)vv)) { x = PyLong_AsLongLong(vv); - else + } + else { x = PyLong_AsUnsignedLongLong(vv); + } #endif /* SIZEOF_VOID_P <= SIZEOF_LONG */ @@ -1406,7 +1410,7 @@ _PyLong_UnsignedShort_Converter(PyObject *obj, void *ptr) { unsigned long uval; - if (PyLong_Check(obj) && _PyLong_Sign(obj) < 0) { + if (PyLong_Check(obj) && _PyLong_IsNegative((PyLongObject *)obj)) { PyErr_SetString(PyExc_ValueError, "value must be positive"); return 0; } @@ -1428,7 +1432,7 @@ _PyLong_UnsignedInt_Converter(PyObject *obj, void *ptr) { unsigned long uval; - if (PyLong_Check(obj) && _PyLong_Sign(obj) < 0) { + if (PyLong_Check(obj) && _PyLong_IsNegative((PyLongObject *)obj)) { PyErr_SetString(PyExc_ValueError, "value must be positive"); return 0; } @@ -1450,7 +1454,7 @@ _PyLong_UnsignedLong_Converter(PyObject *obj, void *ptr) { unsigned long uval; - if (PyLong_Check(obj) && _PyLong_Sign(obj) < 0) { + if (PyLong_Check(obj) && _PyLong_IsNegative((PyLongObject *)obj)) { PyErr_SetString(PyExc_ValueError, "value must be positive"); return 0; } @@ -1467,7 +1471,7 @@ _PyLong_UnsignedLongLong_Converter(PyObject *obj, void *ptr) { unsigned long long uval; - if (PyLong_Check(obj) && _PyLong_Sign(obj) < 0) { + if (PyLong_Check(obj) && _PyLong_IsNegative((PyLongObject *)obj)) { PyErr_SetString(PyExc_ValueError, "value must be positive"); return 0; } @@ -1484,7 +1488,7 @@ _PyLong_Size_t_Converter(PyObject *obj, void *ptr) { size_t uval; - if (PyLong_Check(obj) && _PyLong_Sign(obj) < 0) { + if (PyLong_Check(obj) && _PyLong_IsNegative((PyLongObject *)obj)) { PyErr_SetString(PyExc_ValueError, "value must be positive"); return 0; } diff --git a/Objects/rangeobject.c b/Objects/rangeobject.c index b4d0bbf32c84c8..beb86b9623bdbc 100644 --- a/Objects/rangeobject.c +++ b/Objects/rangeobject.c @@ -33,7 +33,7 @@ validate_step(PyObject *step) return PyLong_FromLong(1); step = PyNumber_Index(step); - if (step && _PyLong_Sign(step) == 0) { + if (step && _PyLong_IsZero((PyLongObject *)step)) { PyErr_SetString(PyExc_ValueError, "range() arg 3 must not be zero"); Py_CLEAR(step); diff --git a/Objects/sliceobject.c b/Objects/sliceobject.c index 5d2e6ad522bcf2..584ebce721faed 100644 --- a/Objects/sliceobject.c +++ b/Objects/sliceobject.c @@ -445,7 +445,7 @@ _PySlice_GetLongIndices(PySliceObject *self, PyObject *length, if (start == NULL) goto error; - if (_PyLong_Sign(start) < 0) { + if (_PyLong_IsNegative((PyLongObject *)start)) { /* start += length */ PyObject *tmp = PyNumber_Add(start, length); Py_SETREF(start, tmp); @@ -478,7 +478,7 @@ _PySlice_GetLongIndices(PySliceObject *self, PyObject *length, if (stop == NULL) goto error; - if (_PyLong_Sign(stop) < 0) { + if (_PyLong_IsNegative((PyLongObject *)stop)) { /* stop += length */ PyObject *tmp = PyNumber_Add(stop, length); Py_SETREF(stop, tmp); @@ -533,7 +533,7 @@ slice_indices(PySliceObject* self, PyObject* len) if (length == NULL) return NULL; - if (_PyLong_Sign(length) < 0) { + if (_PyLong_IsNegative((PyLongObject *)length)) { PyErr_SetString(PyExc_ValueError, "length should not be negative"); Py_DECREF(length); From 9843ac09c282e5ede19763fad7f6e4468070fb2e Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Thu, 16 Mar 2023 19:29:33 +0000 Subject: [PATCH 33/35] fix sign check --- Objects/longobject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Objects/longobject.c b/Objects/longobject.c index c5bb89906985c7..393b9b55b7f756 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -3945,7 +3945,7 @@ fast_mod(PyLongObject *a, PyLongObject *b) assert(_PyLong_DigitCount(a) == 1); assert(_PyLong_DigitCount(b) == 1); - sdigit sign = _PyLong_NonCompactSign(b); + sdigit sign = _PyLong_CompactSign(b); if (_PyLong_SameSign(a, b)) { mod = left % right; } From d6cb91763031bdab50c6d46f5a02d80fdf96e058 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 22 Mar 2023 11:23:46 +0000 Subject: [PATCH 34/35] Address some review comments. --- Include/internal/pycore_long.h | 9 --- ...-03-06-10-02-22.gh-issue-101291.0FT2QS.rst | 8 +-- Modules/_tkinter.c | 1 + Objects/longobject.c | 58 +++++++++---------- 4 files changed, 34 insertions(+), 42 deletions(-) diff --git a/Include/internal/pycore_long.h b/Include/internal/pycore_long.h index c2d20fd54b5f88..137a0465d5ec60 100644 --- a/Include/internal/pycore_long.h +++ b/Include/internal/pycore_long.h @@ -193,15 +193,6 @@ _PyLong_SignedDigitCount(const PyLongObject *op) return sign * (Py_ssize_t)(op->long_value.lv_tag >> NON_SIZE_BITS); } -/* Like _PyLong_DigitCount but asserts that op is non-negative */ -static inline Py_ssize_t -_PyLong_UnsignedDigitCount(const PyLongObject *op) -{ - assert(PyLong_Check(op)); - assert(!_PyLong_IsNegative(op)); - return op->long_value.lv_tag >> NON_SIZE_BITS; -} - static inline int _PyLong_CompactSign(const PyLongObject *op) { diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-06-10-02-22.gh-issue-101291.0FT2QS.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-06-10-02-22.gh-issue-101291.0FT2QS.rst index aa24846c1aa3d0..46f0f325f91630 100644 --- a/Misc/NEWS.d/next/Core and Builtins/2023-03-06-10-02-22.gh-issue-101291.0FT2QS.rst +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-06-10-02-22.gh-issue-101291.0FT2QS.rst @@ -1,7 +1,7 @@ -Rearrage bits in first field (after header) of PyLongObject. * Bits 0 and 1: -1 - sign. I.e. 0 for positive numbers, 1 for zero and 2 for negative numbers. -* Bit 2 reserved (probably for the immortal bit) * Bits 3+ the unsigned -size. +Rearrage bits in first field (after header) of PyLongObject. +* Bits 0 and 1: 1 - sign. I.e. 0 for positive numbers, 1 for zero and 2 for negative numbers. +* Bit 2 reserved (probably for the immortal bit) +* Bits 3+ the unsigned size. This makes a few operations slightly more efficient, and will enable a more compact and faster 2s-complement representation of most ints in future. diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index 164946f1594fb8..606e578a1f3116 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -887,6 +887,7 @@ asBignumObj(PyObject *value) PyObject *hexstr; const char *hexchars; mp_int bigValue; + assert(PyLong_Check(value)); neg = _PyLong_IsNegative((PyLongObject *)value); hexstr = _PyLong_Format(value, 16); diff --git a/Objects/longobject.c b/Objects/longobject.c index 393b9b55b7f756..a4776b113dae0c 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -507,8 +507,8 @@ PyLong_AsLongAndOverflow(PyObject *vv, int *overflow) } } /* Haven't lost any bits, but casting to long requires extra - * care (see comment above). - */ + * care (see comment above). + */ if (x <= (unsigned long)LONG_MAX) { res = (long)x * sign; } @@ -3507,7 +3507,7 @@ x_mul(PyLongObject *a, PyLongObject *b) if (z == NULL) return NULL; - memset(z->long_value.ob_digit, 0, _PyLong_UnsignedDigitCount(z) * sizeof(digit)); + memset(z->long_value.ob_digit, 0, _PyLong_DigitCount(z) * sizeof(digit)); if (a == b) { /* Efficient squaring per HAC, Algorithm 14.16: * http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf @@ -3690,7 +3690,7 @@ k_mul(PyLongObject *a, PyLongObject *b) /* Split a & b into hi & lo pieces. */ shift = bsize >> 1; if (kmul_split(a, shift, &ah, &al) < 0) goto fail; - assert(_PyLong_UnsignedDigitCount(ah) > 0); /* the split isn't degenerate */ + assert(_PyLong_DigitCount(ah) > 0); /* the split isn't degenerate */ if (a == b) { bh = (PyLongObject*)Py_NewRef(ah); @@ -3719,20 +3719,20 @@ k_mul(PyLongObject *a, PyLongObject *b) if (ret == NULL) goto fail; #ifdef Py_DEBUG /* Fill with trash, to catch reference to uninitialized digits. */ - memset(ret->long_value.ob_digit, 0xDF, _PyLong_UnsignedDigitCount(ret) * sizeof(digit)); + memset(ret->long_value.ob_digit, 0xDF, _PyLong_DigitCount(ret) * sizeof(digit)); #endif /* 2. t1 <- ah*bh, and copy into high digits of result. */ if ((t1 = k_mul(ah, bh)) == NULL) goto fail; - assert(_PyLong_UnsignedDigitCount(t1) >= 0); - assert(2*shift + _PyLong_UnsignedDigitCount(t1) <= _PyLong_UnsignedDigitCount(ret)); + assert(_PyLong_DigitCount(t1) >= 0); + assert(2*shift + _PyLong_DigitCount(t1) <= _PyLong_DigitCount(ret)); memcpy(ret->long_value.ob_digit + 2*shift, t1->long_value.ob_digit, - _PyLong_UnsignedDigitCount(t1) * sizeof(digit)); + _PyLong_DigitCount(t1) * sizeof(digit)); /* Zero-out the digits higher than the ah*bh copy. */ - i = _PyLong_UnsignedDigitCount(ret) - 2*shift - _PyLong_UnsignedDigitCount(t1); + i = _PyLong_DigitCount(ret) - 2*shift - _PyLong_DigitCount(t1); if (i) - memset(ret->long_value.ob_digit + 2*shift + _PyLong_UnsignedDigitCount(t1), 0, + memset(ret->long_value.ob_digit + 2*shift + _PyLong_DigitCount(t1), 0, i * sizeof(digit)); /* 3. t2 <- al*bl, and copy into the low digits. */ @@ -3740,23 +3740,23 @@ k_mul(PyLongObject *a, PyLongObject *b) Py_DECREF(t1); goto fail; } - assert(_PyLong_UnsignedDigitCount(t2) >= 0); - assert(_PyLong_UnsignedDigitCount(t2) <= 2*shift); /* no overlap with high digits */ - memcpy(ret->long_value.ob_digit, t2->long_value.ob_digit, _PyLong_UnsignedDigitCount(t2) * sizeof(digit)); + assert(_PyLong_DigitCount(t2) >= 0); + assert(_PyLong_DigitCount(t2) <= 2*shift); /* no overlap with high digits */ + memcpy(ret->long_value.ob_digit, t2->long_value.ob_digit, _PyLong_DigitCount(t2) * sizeof(digit)); /* Zero out remaining digits. */ - i = 2*shift - _PyLong_UnsignedDigitCount(t2); /* number of uninitialized digits */ + i = 2*shift - _PyLong_DigitCount(t2); /* number of uninitialized digits */ if (i) - memset(ret->long_value.ob_digit + _PyLong_UnsignedDigitCount(t2), 0, i * sizeof(digit)); + memset(ret->long_value.ob_digit + _PyLong_DigitCount(t2), 0, i * sizeof(digit)); /* 4 & 5. Subtract ah*bh (t1) and al*bl (t2). We do al*bl first * because it's fresher in cache. */ - i = _PyLong_UnsignedDigitCount(ret) - shift; /* # digits after shift */ - (void)v_isub(ret->long_value.ob_digit + shift, i, t2->long_value.ob_digit, _PyLong_UnsignedDigitCount(t2)); + i = _PyLong_DigitCount(ret) - shift; /* # digits after shift */ + (void)v_isub(ret->long_value.ob_digit + shift, i, t2->long_value.ob_digit, _PyLong_DigitCount(t2)); _Py_DECREF_INT(t2); - (void)v_isub(ret->long_value.ob_digit + shift, i, t1->long_value.ob_digit, _PyLong_UnsignedDigitCount(t1)); + (void)v_isub(ret->long_value.ob_digit + shift, i, t1->long_value.ob_digit, _PyLong_DigitCount(t1)); _Py_DECREF_INT(t1); /* 6. t3 <- (ah+al)(bh+bl), and add into result. */ @@ -3780,12 +3780,12 @@ k_mul(PyLongObject *a, PyLongObject *b) _Py_DECREF_INT(t1); _Py_DECREF_INT(t2); if (t3 == NULL) goto fail; - assert(_PyLong_UnsignedDigitCount(t3) >= 0); + assert(_PyLong_DigitCount(t3) >= 0); /* Add t3. It's not obvious why we can't run out of room here. * See the (*) comment after this function. */ - (void)v_iadd(ret->long_value.ob_digit + shift, i, t3->long_value.ob_digit, _PyLong_UnsignedDigitCount(t3)); + (void)v_iadd(ret->long_value.ob_digit + shift, i, t3->long_value.ob_digit, _PyLong_DigitCount(t3)); _Py_DECREF_INT(t3); return long_normalize(ret); @@ -3868,7 +3868,7 @@ k_lopsided_mul(PyLongObject *a, PyLongObject *b) ret = _PyLong_New(asize + bsize); if (ret == NULL) return NULL; - memset(ret->long_value.ob_digit, 0, _PyLong_UnsignedDigitCount(ret) * sizeof(digit)); + memset(ret->long_value.ob_digit, 0, _PyLong_DigitCount(ret) * sizeof(digit)); /* Successive slices of b are copied into bslice. */ bslice = _PyLong_New(asize); @@ -3890,8 +3890,8 @@ k_lopsided_mul(PyLongObject *a, PyLongObject *b) goto fail; /* Add into result. */ - (void)v_iadd(ret->long_value.ob_digit + nbdone, _PyLong_UnsignedDigitCount(ret) - nbdone, - product->long_value.ob_digit, _PyLong_UnsignedDigitCount(product)); + (void)v_iadd(ret->long_value.ob_digit + nbdone, _PyLong_DigitCount(ret) - nbdone, + product->long_value.ob_digit, _PyLong_DigitCount(product)); _Py_DECREF_INT(product); bsize -= nbtouse; @@ -4654,7 +4654,7 @@ long_pow(PyObject *v, PyObject *w, PyObject *x) base % modulus instead. We could _always_ do this reduction, but l_mod() isn't cheap, so we only do it when it buys something. */ - if (_PyLong_IsNegative(a) || _PyLong_UnsignedDigitCount(a) > _PyLong_UnsignedDigitCount(c)) { + if (_PyLong_IsNegative(a) || _PyLong_DigitCount(a) > _PyLong_DigitCount(c)) { if (l_mod(a, c, &temp) < 0) goto Error; Py_SETREF(a, temp); @@ -5329,14 +5329,14 @@ _PyLong_GCD(PyObject *aarg, PyObject *barg) /* We now own references to a and b */ Py_ssize_t size_a, size_b, alloc_a, alloc_b; - alloc_a = _PyLong_UnsignedDigitCount(a); - alloc_b = _PyLong_UnsignedDigitCount(b); + alloc_a = _PyLong_DigitCount(a); + alloc_b = _PyLong_DigitCount(b); /* reduce until a fits into 2 digits */ - while ((size_a = _PyLong_UnsignedDigitCount(a)) > 2) { + while ((size_a = _PyLong_DigitCount(a)) > 2) { nbits = bit_length_digit(a->long_value.ob_digit[size_a-1]); /* extract top 2*PyLong_SHIFT bits of a into x, along with corresponding bits of b into y */ - size_b = _PyLong_UnsignedDigitCount(b); + size_b = _PyLong_DigitCount(b); assert(size_b <= size_a); if (size_b == 0) { if (size_a < alloc_a) { @@ -5380,7 +5380,7 @@ _PyLong_GCD(PyObject *aarg, PyObject *barg) Py_SETREF(a, b); b = r; alloc_a = alloc_b; - alloc_b = _PyLong_UnsignedDigitCount(b); + alloc_b = _PyLong_DigitCount(b); continue; } From 469d26f2ca6a36efd63fbb0cc0d5024ca42a67b6 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 22 Mar 2023 11:31:08 +0000 Subject: [PATCH 35/35] Change asserts on digit counts to asserts on sign where applicable. --- Objects/longobject.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Objects/longobject.c b/Objects/longobject.c index a4776b113dae0c..bb4eac0d932bb8 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -3690,7 +3690,7 @@ k_mul(PyLongObject *a, PyLongObject *b) /* Split a & b into hi & lo pieces. */ shift = bsize >> 1; if (kmul_split(a, shift, &ah, &al) < 0) goto fail; - assert(_PyLong_DigitCount(ah) > 0); /* the split isn't degenerate */ + assert(_PyLong_IsPositive(ah)); /* the split isn't degenerate */ if (a == b) { bh = (PyLongObject*)Py_NewRef(ah); @@ -3724,7 +3724,7 @@ k_mul(PyLongObject *a, PyLongObject *b) /* 2. t1 <- ah*bh, and copy into high digits of result. */ if ((t1 = k_mul(ah, bh)) == NULL) goto fail; - assert(_PyLong_DigitCount(t1) >= 0); + assert(!_PyLong_IsNegative(t1)); assert(2*shift + _PyLong_DigitCount(t1) <= _PyLong_DigitCount(ret)); memcpy(ret->long_value.ob_digit + 2*shift, t1->long_value.ob_digit, _PyLong_DigitCount(t1) * sizeof(digit)); @@ -3740,7 +3740,7 @@ k_mul(PyLongObject *a, PyLongObject *b) Py_DECREF(t1); goto fail; } - assert(_PyLong_DigitCount(t2) >= 0); + assert(!_PyLong_IsNegative(t2)); assert(_PyLong_DigitCount(t2) <= 2*shift); /* no overlap with high digits */ memcpy(ret->long_value.ob_digit, t2->long_value.ob_digit, _PyLong_DigitCount(t2) * sizeof(digit)); @@ -3780,7 +3780,7 @@ k_mul(PyLongObject *a, PyLongObject *b) _Py_DECREF_INT(t1); _Py_DECREF_INT(t2); if (t3 == NULL) goto fail; - assert(_PyLong_DigitCount(t3) >= 0); + assert(!_PyLong_IsNegative(t3)); /* Add t3. It's not obvious why we can't run out of room here. * See the (*) comment after this function.