diff --git a/Include/internal/pycore_long.h b/Include/internal/pycore_long.h index 137a0465d5ec60..c6416520e6c031 100644 --- a/Include/internal/pycore_long.h +++ b/Include/internal/pycore_long.h @@ -116,8 +116,14 @@ PyAPI_FUNC(char*) _PyLong_FormatBytesWriter( #define SIGN_MASK 3 #define SIGN_ZERO 1 #define SIGN_NEGATIVE 2 +#define SIGN_STATIC 4 #define NON_SIZE_BITS 3 +static inline uintptr_t +_PyLong_ClearStaticFlag(uintptr_t lv_tag) { + return lv_tag & ~SIGN_STATIC; +} + /* 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 @@ -128,20 +134,20 @@ PyAPI_FUNC(char*) _PyLong_FormatBytesWriter( static inline int _PyLong_IsNonNegativeCompact(const PyLongObject* op) { assert(PyLong_Check(op)); - return op->long_value.lv_tag <= (1 << NON_SIZE_BITS); + return _PyLong_ClearStaticFlag(op->long_value.lv_tag) <= (1 << NON_SIZE_BITS); } static inline int _PyLong_IsCompact(const PyLongObject* op) { assert(PyLong_Check(op)); - return op->long_value.lv_tag < (2 << NON_SIZE_BITS); + return _PyLong_ClearStaticFlag(op->long_value.lv_tag) < (2 << NON_SIZE_BITS); } static inline int _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); + return _PyLong_ClearStaticFlag(a->long_value.lv_tag | b->long_value.lv_tag) < (2 << NON_SIZE_BITS); } /* Returns a *compact* value, iff `_PyLong_IsCompact` is true for `op`. @@ -177,6 +183,12 @@ _PyLong_IsPositive(const PyLongObject *op) return (op->long_value.lv_tag & SIGN_MASK) == 0; } +static inline bool +_PyLong_IsStatic(const PyLongObject *op) +{ + return (op->long_value.lv_tag & SIGN_STATIC) == SIGN_STATIC; +} + static inline Py_ssize_t _PyLong_DigitCount(const PyLongObject *op) { @@ -217,6 +229,7 @@ _PyLong_SameSign(const PyLongObject *a, const PyLongObject *b) } #define TAG_FROM_SIGN_AND_SIZE(sign, size) ((1 - (sign)) | ((size) << NON_SIZE_BITS)) +#define TAG_STATIC_FROM_SIGN_AND_SIZE(sign, size) TAG_FROM_SIGN_AND_SIZE(sign, size) | SIGN_STATIC static inline void _PyLong_SetSignAndDigitCount(PyLongObject *op, int sign, Py_ssize_t size) @@ -224,14 +237,17 @@ _PyLong_SetSignAndDigitCount(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_t)size); + op->long_value.lv_tag = TAG_FROM_SIGN_AND_SIZE(sign, (size_t)size) | + (op->long_value.lv_tag & SIGN_STATIC); } static inline void _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); + op->long_value.lv_tag = (((size_t)size) << NON_SIZE_BITS) | + (op->long_value.lv_tag & SIGN_MASK) | + (op->long_value.lv_tag & SIGN_STATIC); } #define NON_SIZE_MASK ~((1 << NON_SIZE_BITS) - 1) @@ -247,15 +263,15 @@ _PyLong_FlipSign(PyLongObject *op) { { \ .ob_base = _PyObject_IMMORTAL_INIT(&PyLong_Type), \ .long_value = { \ - .lv_tag = TAG_FROM_SIGN_AND_SIZE( \ + .lv_tag = TAG_STATIC_FROM_SIGN_AND_SIZE( \ (val) == 0 ? 0 : ((val) < 0 ? -1 : 1), \ (val) == 0 ? 0 : 1), \ { ((val) >= 0 ? (val) : -(val)) }, \ } \ } -#define _PyLong_FALSE_TAG TAG_FROM_SIGN_AND_SIZE(0, 0) -#define _PyLong_TRUE_TAG TAG_FROM_SIGN_AND_SIZE(1, 1) +#define _PyLong_FALSE_TAG TAG_STATIC_FROM_SIGN_AND_SIZE(0, 0) +#define _PyLong_TRUE_TAG TAG_STATIC_FROM_SIGN_AND_SIZE(1, 1) #ifdef __cplusplus } diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-09-23-02-10.gh-issue-84436.IIBB5W.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-09-23-02-10.gh-issue-84436.IIBB5W.rst new file mode 100644 index 00000000000000..f157251b71cc18 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-04-09-23-02-10.gh-issue-84436.IIBB5W.rst @@ -0,0 +1,3 @@ +Add a static flag in PyLongObject's lv_tag and rework the respective +functions to correctly account for it. This also initializes small ints, +False, and True with the static flag set.