bpo-24165: Add a freelist for long objects by methane · Pull Request #22884 · python/cpython
/* Speed optimization to avoid frequent malloc/free of small ints */ #ifndef PyLong_MAXFREELIST # define PyLong_MAXFREELIST 100 #endif
/* 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)
PyLongObject *result; /* 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 and the digits. */ if (size > (Py_ssize_t)MAX_LONG_DIGITS) { PyErr_SetString(PyExc_OverflowError, "too many digits in integer"); return NULL; if (size == 1 && (result = (PyLongObject*)state->free_list) != NULL) { state->free_list = (PyLongObject *)Py_TYPE(result); state->numfree--; } result = PyObject_MALLOC(offsetof(PyLongObject, ob_digit) + size*sizeof(digit)); if (!result) { PyErr_NoMemory(); return NULL; else { /* 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 and the digits. */ if (size > (Py_ssize_t)MAX_LONG_DIGITS) { PyErr_SetString(PyExc_OverflowError, "too many digits in integer"); return NULL; } result = PyObject_MALLOC(offsetof(PyLongObject, ob_digit) + size*sizeof(digit)); if (!result) { PyErr_NoMemory(); return NULL; } } _PyObject_InitVar((PyVarObject*)result, &PyLong_Type, size); return result;
/* Fast path for single-digit ints */ if (!(abs_ival >> PyLong_SHIFT)) { if (abs_ival < (1UL << PyLong_SHIFT)) { v = _PyLong_New(1); if (v) { Py_SET_SIZE(v, sign);
#if PyLong_SHIFT==15 #if 2*PyLong_SHIFT < 8*PY_LONG_SIZE /* 2 digits */ if (!(abs_ival >> 2*PyLong_SHIFT)) { if (abs_ival < (1UL << 2*PyLong_SHIFT)) { v = _PyLong_New(2); if (v) { Py_SET_SIZE(v, 2 * sign);
static void long_dealloc(PyObject *v) { if (PyLong_CheckExact(v)) { struct _Py_long_state *state = &_PyInterpreterState_GET()->long_state; #ifdef Py_DEBUG // long_dealloc() must not be called after _PyLong_Fini() assert(state->numfree != -1); #endif Py_ssize_t size = Py_SIZE(v); if ((size == 1 || size == -1) && state->numfree < PyLong_MAXFREELIST) { Py_SET_TYPE(v, (PyTypeObject *)state->free_list); state->free_list = (PyLongObject *)v; state->numfree++; return; } } Py_TYPE(v)->tp_free(v); }
/* Methods */
/* if a < b, return a negative number
void _PyLong_ClearFreeList(PyThreadState *tstate) { struct _Py_long_state *state = &tstate->interp->long_state; PyLongObject *f = state->free_list; while (f != NULL) { PyLongObject *next = (PyLongObject*) Py_TYPE(f); PyObject_FREE(f); f = next; } state->free_list = NULL; state->numfree = 0; }
void _PyLong_Fini(PyThreadState *tstate) {
_PyLong_ClearFreeList(tstate); #ifdef Py_DEBUG struct _Py_long_state *state = &tstate->interp->long_state; state->numfree = -1; #endif }