8000 Use int immortality bit for small int check · python/cpython@4639642 · GitHub
[go: up one dir, main page]

Skip to content

Commit 4639642

Browse files
committed
Use int immortality bit for small int check
1 parent cfb70cb commit 4639642

File tree

3 files changed

+18
-5
lines changed

3 files changed

+18
-5
lines changed

Include/internal/pycore_long.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,13 +157,14 @@ PyAPI_FUNC(int) _PyLong_Size_t_Converter(PyObject *, void *);
157157

158158
/* Long value tag bits:
159159
* 0-1: Sign bits value = (1-sign), ie. negative=2, positive=0, zero=1.
160-
* 2: Reserved for immortality bit
160+
* 2: Reserved for immortality bit. Set to 1 for the small ints
161161
* 3+ Unsigned digit count
162162
*/
163163
#define SIGN_MASK 3
164164
#define SIGN_ZERO 1
165165
#define SIGN_NEGATIVE 2
166166
#define NON_SIZE_BITS 3
167+
#define IMMORTALITY_BIT_MASK (1 << 2)
167168

168169
/* The functions _PyLong_IsCompact and _PyLong_CompactValue are defined
169170
* in Include/cpython/longobject.h, since they need to be inline.
@@ -262,6 +263,8 @@ _PyLong_SameSign(const PyLongObject *a, const PyLongObject *b)
262263
return (a->long_value.lv_tag & SIGN_MASK) == (b->long_value.lv_tag & SIGN_MASK);
263264
}
264265

266+
#define IMMORTAL_BIT(val) ((_PY_NSMALLNEGINTS <= val < _PY_NSMALLPOSINTS) * IMMORTALITY_BIT_MASK)
267+
265268
#define TAG_FROM_SIGN_AND_SIZE(sign, size) \
266269
((uintptr_t)(1 - (sign)) | ((uintptr_t)(size) << NON_SIZE_BITS))
267270

@@ -296,7 +299,7 @@ _PyLong_FlipSign(PyLongObject *op) {
296299
.long_value = { \
297300
.lv_tag = TAG_FROM_SIGN_AND_SIZE( \
298301
(val) == 0 ? 0 : ((val) < 0 ? -1 : 1), \
299-
(val) == 0 ? 0 : 1), \
302+
(val) == 0 ? 0 : 1) | IMMORTAL_BIT(val), \
300303
{ ((val) >= 0 ? (val) : -(val)) }, \
301304
} \
302305
}

Modules/_testcapi/immortal.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,15 @@ static PyObject *
2626
test_immortal_small_ints(PyObject *self, PyObject *Py_UNUSED(ignored))
2727
{
2828
for (int i = -5; i <= 256; i++) {
29-
assert(verify_immortality(PyLong_FromLong(i)));
29+
PyObject *obj = PyLong_FromLong(i);
30+
assert(verify_immortality(obj));
31+
int has_int_immortal_bit = ((PyLongObject *)obj)->long_value.lv_tag & (1 << 2);
32+
assert(has_int_immortal_bit);
33+
}
34+
for (int i = 257; i <= 260; i++) {
35+
PyObject *obj = PyLong_FromLong(i);
36+
int has_int_immortal_bit = ((PyLongObject *)obj)->long_value.lv_tag & (1 << 2);
37+
assert(!has_int_immortal_bit);
3038
}
3139
Py_RETURN_NONE;
3240
}

Objects/longobject.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3615,9 +3615,11 @@ static inline int
36153615
/// Return 1 if the object is one of the immortal small ints
36163616
_long_is_small_int(PyObject *op)
36173617
{
3618-
return (((PyObject *)(&_PyLong_SMALL_INTS[0]) <= op)
3619-
&& (op <= (PyObject *)&_PyLong_SMALL_INTS[_PY_NSMALLNEGINTS +_PY_NSMALLPOSINTS]));
3618+
PyLongObject *long_object = (PyLongObject *)op;
3619+
3620+
return long_object->long_value.lv_tag | IMMORTALITY_BIT_MASK;
36203621
}
3622+
36213623
static void
36223624
long_dealloc(PyObject *self)
36233625
{

0 commit comments

Comments
 (0)
0