Skip to content

Commit b456cb2

Browse files
skirpichevvstinner
andauthored
gh-143050: Add helper _PyLong_InitTag() (#147956)
With this we can assume, that _PyLong_SetSignAndDigitCount() and _PyLong_SetDigitCount() operate on non-immortal integers. Co-authored-by: Victor Stinner <vstinner@python.org>
1 parent 4810bed commit b456cb2

File tree

2 files changed

+33
-14
lines changed

2 files changed

+33
-14
lines changed

Include/internal/pycore_long.h

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -238,11 +238,12 @@ _PyLong_IsSmallInt(const PyLongObject *op)
238238
{
239239
assert(PyLong_Check(op));
240240
bool is_small_int = (op->long_value.lv_tag & IMMORTALITY_BIT_MASK) != 0;
241-
assert(PyLong_CheckExact(op) || (!is_small_int));
242-
assert(_Py_IsImmortal(op) || (!is_small_int));
243-
assert((_PyLong_IsCompact(op)
244-
&& _PY_IS_SMALL_INT(_PyLong_CompactValue(op)))
245-
|| (!is_small_int));
241+
if (is_small_int) {
242+
assert(PyLong_CheckExact(op));
243+
assert(_Py_IsImmortal(op));
244+
assert((_PyLong_IsCompact(op)
245+
&& _PY_IS_SMALL_INT(_PyLong_CompactValue(op))));
246+
}
246247
return is_small_int;
247248
}
248249

@@ -285,6 +286,14 @@ _PyLong_SameSign(const PyLongObject *a, const PyLongObject *b)
285286
return (a->long_value.lv_tag & SIGN_MASK) == (b->long_value.lv_tag & SIGN_MASK);
286287
}
287288

289+
/* Initialize the tag of a freshly-allocated int. */
290+
static inline void
291+
_PyLong_InitTag(PyLongObject *op)
292+
{
293+
assert(PyLong_Check(op));
294+
op->long_value.lv_tag = SIGN_ZERO; /* non-immortal zero */
295+
}
296+
288297
#define TAG_FROM_SIGN_AND_SIZE(sign, size) \
289298
((uintptr_t)(1 - (sign)) | ((uintptr_t)(size) << NON_SIZE_BITS))
290299

@@ -294,13 +303,15 @@ _PyLong_SetSignAndDigitCount(PyLongObject *op, int sign, Py_ssize_t size)
294303
assert(size >= 0);
295304
assert(-1 <= sign && sign <= 1);
296305
assert(sign != 0 || size == 0);
306+
assert(!_PyLong_IsSmallInt(op));
297307
op->long_value.lv_tag = TAG_FROM_SIGN_AND_SIZE(sign, size);
298308
}
299309

300310
static inline void
301311
_PyLong_SetDigitCount(PyLongObject *op, Py_ssize_t size)
302312
{
303313
assert(size >= 0);
314+
assert(!_PyLong_IsSmallInt(op));
304315
op->long_value.lv_tag = (((size_t)size) << NON_SIZE_BITS) | (op->long_value.lv_tag & SIGN_MASK);
305316
}
306317

Objects/longobject.c

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ long_alloc(Py_ssize_t size)
185185
return NULL;
186186
}
187187
_PyObject_Init((PyObject*)result, &PyLong_Type);
188+
_PyLong_InitTag(result);
188189
}
189190
_PyLong_SetSignAndDigitCount(result, size != 0, size);
190191
/* The digit has to be initialized explicitly to avoid
@@ -258,6 +259,7 @@ _PyLong_FromMedium(sdigit x)
258259
return NULL;
259260
}
260261
_PyObject_Init((PyObject*)v, &PyLong_Type);
262+
_PyLong_InitTag(v);
261263
}
262264
digit abs_x = x < 0 ? -x : x;
263265
_PyLong_SetSignAndDigitCount(v, x<0?-1:1, 1);
@@ -337,6 +339,7 @@ medium_from_stwodigits(stwodigits x)
337339
return PyStackRef_NULL;
338340
}
339341
_PyObject_Init((PyObject*)v, &PyLong_Type);
342+
_PyLong_InitTag(v);
340343
}
341344
digit abs_x = x < 0 ? (digit)(-x) : (digit)x;
342345
_PyLong_SetSignAndDigitCount(v, x<0?-1:1, 1);
@@ -6011,29 +6014,34 @@ static PyObject *
60116014
long_subtype_new(PyTypeObject *type, PyObject *x, PyObject *obase)
60126015
{
60136016
PyLongObject *tmp, *newobj;
6014-
Py_ssize_t i, n;
6017+
Py_ssize_t size, ndigits;
6018+
int sign;
60156019

60166020
assert(PyType_IsSubtype(type, &PyLong_Type));
60176021
tmp = (PyLongObject *)long_new_impl(&PyLong_Type, x, obase);
60186022
if (tmp == NULL)
60196023
return NULL;
60206024
assert(PyLong_Check(tmp));
6021-
n = _PyLong_DigitCount(tmp);
6025+
size = _PyLong_DigitCount(tmp);
60226026
/* Fast operations for single digit integers (including zero)
60236027
* assume that there is always at least one digit present. */
6024-
if (n == 0) {
6025-
n = 1;
6026-
}
6027-
newobj = (PyLongObject *)type->tp_alloc(type, n);
6028+
ndigits = size ? size : 1;
6029+
newobj = (PyLongObject *)type->tp_alloc(type, ndigits);
60286030
if (newobj == NULL) {
60296031
Py_DECREF(tmp);
60306032
return NULL;
60316033
}
60326034
assert(PyLong_Check(newobj));
6033-
newobj->long_value.lv_tag = tmp->long_value.lv_tag & ~IMMORTALITY_BIT_MASK;
6034-
for (i = 0; i < n; i++) {
6035-
newobj->long_value.ob_digit[i] = tmp->long_value.ob_digit[i];
6035+
if (_PyLong_IsCompact(tmp)) {
6036+
sign = _PyLong_CompactSign(tmp);
6037+
}
6038+
else {
6039+
sign = _PyLong_NonCompactSign(tmp);
60366040
}
6041+
_PyLong_InitTag(newobj);
6042+
_PyLong_SetSignAndDigitCount(newobj, sign, size);
6043+
memcpy(newobj->long_value.ob_digit, tmp->long_value.ob_digit,
6044+
ndigits * sizeof(digit));
60376045
Py_DECREF(tmp);
60386046
return (PyObject *)newobj;
60396047
}

0 commit comments

Comments
 (0)