Skip to content

Commit

Permalink
Add freelist of compact int objects
Browse files Browse the repository at this point in the history
  • Loading branch information
eendebakpt committed Nov 15, 2024
1 parent cae9d9d commit 0713034
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 29 deletions.
2 changes: 2 additions & 0 deletions Include/internal/pycore_freelist_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ extern "C" {
# define Py_dicts_MAXFREELIST 80
# define Py_dictkeys_MAXFREELIST 80
# define Py_floats_MAXFREELIST 100
# define Py_ints_MAXFREELIST 100
# define Py_slices_MAXFREELIST 1
# define Py_contexts_MAXFREELIST 255
# define Py_async_gens_MAXFREELIST 80
Expand All @@ -35,6 +36,7 @@ struct _Py_freelist {

struct _Py_freelists {
struct _Py_freelist floats;
struct _Py_freelist ints;
struct _Py_freelist tuples[PyTuple_MAXSAVESIZE];
struct _Py_freelist lists;
struct _Py_freelist dicts;
Expand Down
2 changes: 2 additions & 0 deletions Include/internal/pycore_long.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ extern void _PyLong_FiniTypes(PyInterpreterState *interp);

/* other API */

void _PyLong_Free(PyLongObject *op);

#define _PyLong_SMALL_INTS _Py_SINGLETON(small_ints)

// _PyLong_GetZero() and _PyLong_GetOne() must always be available
Expand Down
36 changes: 17 additions & 19 deletions Objects/longobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "pycore_bitutils.h" // _Py_popcount32()
#include "pycore_initconfig.h" // _PyStatus_OK()
#include "pycore_call.h" // _PyObject_MakeTpCall
#include "pycore_freelist.h" // _Py_FREELIST_FREE(), _Py_FREELIST_POP()
#include "pycore_long.h" // _Py_SmallInts
#include "pycore_object.h" // _PyObject_Init()
#include "pycore_runtime.h" // _PY_NSMALLPOSINTS
Expand Down Expand Up @@ -221,10 +222,14 @@ _PyLong_FromMedium(sdigit x)
assert(!IS_SMALL_INT(x));
assert(is_medium_int(x));
/* We could use a freelist here */
PyLongObject *v = PyObject_Malloc(sizeof(PyLongObject));

PyLongObject *v = _Py_FREELIST_POP(PyLongObject, ints);
if (v == NULL) {
PyErr_NoMemory();
return NULL;
v = PyObject_Malloc(sizeof(PyLongObject));
if (v == NULL) {
PyErr_NoMemory();
return NULL;
}
}
digit abs_x = x < 0 ? -x : x;
_PyLong_SetSignAndDigitCount(v, x<0?-1:1, 1);
Expand Down Expand Up @@ -3614,24 +3619,17 @@ long_richcompare(PyObject *self, PyObject *other, int op)
static void
long_dealloc(PyObject *self)
{
/* This should never get called, but we also don't want to SEGV if
* we accidentally decref small Ints out of existence. Instead,
* since small Ints are immortal, re-set the reference count.
*/
PyLongObject *pylong = (PyLongObject*)self;
if (pylong && _PyLong_IsCompact(pylong)) {
stwodigits ival = medium_value(pylong);
if (IS_SMALL_INT(ival)) {
PyLongObject *small_pylong = (PyLongObject *)get_small_int((sdigit)ival);
if (pylong == small_pylong) {
_Py_SetImmortal(self);
return;
}
}
}
Py_TYPE(self)->tp_free(self);
}

void _PyLong_Free(PyLongObject *op) {
if (_PyLong_IsCompact(op)) {
_Py_FREELIST_FREE(ints, op, PyObject_Free);
return;
}
PyObject_Free(op);
}

static Py_hash_t
long_hash(PyObject *obj)
{
Expand Down Expand Up @@ -6615,7 +6613,7 @@ PyTypeObject PyLong_Type = {
0, /* tp_init */
0, /* tp_alloc */
long_new, /* tp_new */
PyObject_Free, /* tp_free */
_PyLong_Free, /* tp_free */
.tp_vectorcall = long_vectorcall,
.tp_version_tag = _Py_TYPE_VERSION_INT,
};
Expand Down
21 changes: 11 additions & 10 deletions Python/bytecodes.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "pycore_pyerrors.h" // _PyErr_GetRaisedException()
#include "pycore_pystate.h" // _PyInterpreterState_GET()
#include "pycore_range.h" // _PyRangeIterObject
#include "pycore_long.h" // void _PyLong_Free(PyLongObject *op);
#include "pycore_setobject.h" // _PySet_NextEntry()
#include "pycore_sliceobject.h" // _PyBuildSlice_ConsumeRefs
#include "pycore_tuple.h" // _PyTuple_ITEMS()
Expand Down Expand Up @@ -514,8 +515,8 @@ dummy_func(

STAT_INC(BINARY_OP, hit);
PyObject *res_o = _PyLong_Multiply((PyLongObject *)left_o, (PyLongObject *)right_o);
PyStackRef_CLOSE_SPECIALIZED(right, (destructor)PyObject_Free);
PyStackRef_CLOSE_SPECIALIZED(left, (destructor)PyObject_Free);
PyStackRef_CLOSE_SPECIALIZED(right, (destructor)_PyLong_Free);
PyStackRef_CLOSE_SPECIALIZED(left, (destructor)_PyLong_Free);
INPUTS_DEAD();
ERROR_IF(res_o == NULL, error);
res = PyStackRef_FromPyObjectSteal(res_o);
Expand All @@ -527,8 +528,8 @@ dummy_func(

STAT_INC(BINARY_OP, hit);
PyObject *res_o = _PyLong_Add((PyLongObject *)left_o, (PyLongObject *)right_o);
PyStackRef_CLOSE_SPECIALIZED(right, (destructor)PyObject_Free);
PyStackRef_CLOSE_SPECIALIZED(left, (destructor)PyObject_Free);
PyStackRef_CLOSE_SPECIALIZED(right, (destructor)_PyLong_Free);
PyStackRef_CLOSE_SPECIALIZED(left, (destructor)_PyLong_Free);
INPUTS_DEAD();
ERROR_IF(res_o == NULL, error);
res = PyStackRef_FromPyObjectSteal(res_o);
Expand All @@ -540,8 +541,8 @@ dummy_func(

STAT_INC(BINARY_OP, hit);
PyObject *res_o = _PyLong_Subtract((PyLongObject *)left_o, (PyLongObject *)right_o);
PyStackRef_CLOSE_SPECIALIZED(right, (destructor)PyObject_Free);
PyStackRef_CLOSE_SPECIALIZED(left, (destructor)PyObject_Free);
PyStackRef_CLOSE_SPECIALIZED(right, (destructor)_PyLong_Free);
PyStackRef_CLOSE_SPECIALIZED(left, (destructor)_PyLong_Free);
INPUTS_DEAD();
ERROR_IF(res_o == NULL, error);
res = PyStackRef_FromPyObjectSteal(res_o);
Expand Down Expand Up @@ -797,7 +798,7 @@ dummy_func(
PyObject *res_o = PyList_GET_ITEM(list, index);
assert(res_o != NULL);
Py_INCREF(res_o);
PyStackRef_CLOSE_SPECIALIZED(sub_st, (destructor)PyObject_Free);
PyStackRef_CLOSE_SPECIALIZED(sub_st, (destructor)_PyLong_Free);
DEAD(sub_st);
PyStackRef_CLOSE(list_st);
res = PyStackRef_FromPyObjectSteal(res_o);
Expand All @@ -817,7 +818,7 @@ dummy_func(
DEOPT_IF(Py_ARRAY_LENGTH(_Py_SINGLETON(strings).ascii) <= c);
STAT_INC(BINARY_SUBSCR, hit);
PyObject *res_o = (PyObject*)&_Py_SINGLETON(strings).ascii[c];
PyStackRef_CLOSE_SPECIALIZED(sub_st, (destructor)PyObject_Free);
PyStackRef_CLOSE_SPECIALIZED(sub_st, (destructor)_PyLong_Free);
DEAD(sub_st);
PyStackRef_CLOSE(str_st);
res = PyStackRef_FromPyObjectSteal(res_o);
Expand All @@ -838,7 +839,7 @@ dummy_func(
PyObject *res_o = PyTuple_GET_ITEM(tuple, index);
assert(res_o != NULL);
Py_INCREF(res_o);
PyStackRef_CLOSE_SPECIALIZED(sub_st, (destructor)PyObject_Free);
PyStackRef_CLOSE_SPECIALIZED(sub_st, (destructor)_PyLong_Free);
DEAD(sub_st);
PyStackRef_CLOSE(tuple_st);
res = PyStackRef_FromPyObjectSteal(res_o);
Expand Down Expand Up @@ -950,7 +951,7 @@ dummy_func(
PyList_SET_ITEM(list, index, PyStackRef_AsPyObjectSteal(value));
assert(old_value != NULL);
Py_DECREF(old_value);
PyStackRef_CLOSE_SPECIALIZED(sub_st, (destructor)PyObject_Free);
PyStackRef_CLOSE_SPECIALIZED(sub_st, (destructor)_PyLong_Free );
DEAD(sub_st);
PyStackRef_CLOSE(list_st);
}
Expand Down

0 comments on commit 0713034

Please sign in to comment.