bpo-38858: Allocate small integers on the heap (GH-17301)

Allocate small Python integers (small_ints of longobject.c) on the
heap, rather than using static objects.
This commit is contained in:
Victor Stinner 2019-11-21 08:51:59 +01:00 committed by GitHub
parent d67279147a
commit 5dcc06f6e0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 18 additions and 35 deletions

View File

@ -40,7 +40,7 @@ PyObject *_PyLong_One = NULL;
The integers that are preallocated are those in the range The integers that are preallocated are those in the range
-NSMALLNEGINTS (inclusive) to NSMALLPOSINTS (not inclusive). -NSMALLNEGINTS (inclusive) to NSMALLPOSINTS (not inclusive).
*/ */
static PyLongObject small_ints[NSMALLNEGINTS + NSMALLPOSINTS]; static PyLongObject* small_ints[NSMALLNEGINTS + NSMALLPOSINTS] = {0};
#define IS_SMALL_INT(ival) (-NSMALLNEGINTS <= (ival) && (ival) < NSMALLPOSINTS) #define IS_SMALL_INT(ival) (-NSMALLNEGINTS <= (ival) && (ival) < NSMALLPOSINTS)
#define IS_SMALL_UINT(ival) ((ival) < NSMALLPOSINTS) #define IS_SMALL_UINT(ival) ((ival) < NSMALLPOSINTS)
@ -52,9 +52,8 @@ Py_ssize_t _Py_quick_int_allocs, _Py_quick_neg_int_allocs;
static PyObject * static PyObject *
get_small_int(sdigit ival) get_small_int(sdigit ival)
{ {
PyObject *v;
assert(IS_SMALL_INT(ival)); assert(IS_SMALL_INT(ival));
v = (PyObject *)&small_ints[ival + NSMALLNEGINTS]; PyObject *v = (PyObject*)small_ints[ival + NSMALLNEGINTS];
Py_INCREF(v); Py_INCREF(v);
#ifdef COUNT_ALLOCS #ifdef COUNT_ALLOCS
if (ival >= 0) if (ival >= 0)
@ -5784,40 +5783,30 @@ int
_PyLong_Init(void) _PyLong_Init(void)
{ {
#if NSMALLNEGINTS + NSMALLPOSINTS > 0 #if NSMALLNEGINTS + NSMALLPOSINTS > 0
int ival, size; for (Py_ssize_t i=0; i < NSMALLNEGINTS + NSMALLPOSINTS; i++) {
PyLongObject *v = small_ints; sdigit ival = (sdigit)i - NSMALLNEGINTS;
int size = (ival < 0) ? -1 : ((ival == 0) ? 0 : 1);
for (ival = -NSMALLNEGINTS; ival < NSMALLPOSINTS; ival++, v++) { PyLongObject *v = _PyLong_New(1);
size = (ival < 0) ? -1 : ((ival == 0) ? 0 : 1); if (!v) {
if (Py_TYPE(v) == &PyLong_Type) { return -1;
/* The element is already initialized, most likely }
* the Python interpreter was initialized before.
*/
Py_ssize_t refcnt;
PyObject* op = (PyObject*)v;
refcnt = Py_REFCNT(op) < 0 ? 0 : Py_REFCNT(op);
_Py_NewReference(op);
/* _Py_NewReference sets the ref count to 1 but
* the ref count might be larger. Set the refcnt
* to the original refcnt + 1 */
Py_REFCNT(op) = refcnt + 1;
assert(Py_SIZE(op) == size);
assert(v->ob_digit[0] == (digit)abs(ival));
}
else {
(void)PyObject_INIT(v, &PyLong_Type);
}
Py_SIZE(v) = size; Py_SIZE(v) = size;
v->ob_digit[0] = (digit)abs(ival); v->ob_digit[0] = (digit)abs(ival);
small_ints[i] = v;
} }
#endif #endif
_PyLong_Zero = PyLong_FromLong(0); _PyLong_Zero = PyLong_FromLong(0);
if (_PyLong_Zero == NULL) if (_PyLong_Zero == NULL) {
return 0; return 0;
}
_PyLong_One = PyLong_FromLong(1); _PyLong_One = PyLong_FromLong(1);
if (_PyLong_One == NULL) if (_PyLong_One == NULL) {
return 0; return 0;
}
/* initialize int_info */ /* initialize int_info */
if (Int_InfoType.tp_name == NULL) { if (Int_InfoType.tp_name == NULL) {
@ -5832,17 +5821,11 @@ _PyLong_Init(void)
void void
_PyLong_Fini(void) _PyLong_Fini(void)
{ {
/* Integers are currently statically allocated. Py_DECREF is not
needed, but Python must forget about the reference or multiple
reinitializations will fail. */
Py_CLEAR(_PyLong_One); Py_CLEAR(_PyLong_One);
Py_CLEAR(_PyLong_Zero); Py_CLEAR(_PyLong_Zero);
#if NSMALLNEGINTS + NSMALLPOSINTS > 0 #if NSMALLNEGINTS + NSMALLPOSINTS > 0
int i; for (Py_ssize_t i = 0; i < NSMALLNEGINTS + NSMALLPOSINTS; i++) {
PyLongObject *v = small_ints; Py_CLEAR(small_ints[i]);
for (i = 0; i < NSMALLNEGINTS + NSMALLPOSINTS; i++, v++) {
_Py_DEC_REFTOTAL;
_Py_ForgetReference((PyObject*)v);
} }
#endif #endif
} }