Skip to content

Commit 0713034

Browse files
committed
Add freelist of compact int objects
1 parent cae9d9d commit 0713034

File tree

4 files changed

+32
-29
lines changed

4 files changed

+32
-29
lines changed

Include/internal/pycore_freelist_state.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ extern "C" {
1414
# define Py_dicts_MAXFREELIST 80
1515
# define Py_dictkeys_MAXFREELIST 80
1616
# define Py_floats_MAXFREELIST 100
17+
# define Py_ints_MAXFREELIST 100
1718
# define Py_slices_MAXFREELIST 1
1819
# define Py_contexts_MAXFREELIST 255
1920
# define Py_async_gens_MAXFREELIST 80
@@ -35,6 +36,7 @@ struct _Py_freelist {
3536

3637
struct _Py_freelists {
3738
struct _Py_freelist floats;
39+
struct _Py_freelist ints;
3840
struct _Py_freelist tuples[PyTuple_MAXSAVESIZE];
3941
struct _Py_freelist lists;
4042
struct _Py_freelist dicts;

Include/internal/pycore_long.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ extern void _PyLong_FiniTypes(PyInterpreterState *interp);
5555

5656
/* other API */
5757

58+
void _PyLong_Free(PyLongObject *op);
59+
5860
#define _PyLong_SMALL_INTS _Py_SINGLETON(small_ints)
5961

6062
// _PyLong_GetZero() and _PyLong_GetOne() must always be available

Objects/longobject.c

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "pycore_bitutils.h" // _Py_popcount32()
77
#include "pycore_initconfig.h" // _PyStatus_OK()
88
#include "pycore_call.h" // _PyObject_MakeTpCall
9+
#include "pycore_freelist.h" // _Py_FREELIST_FREE(), _Py_FREELIST_POP()
910
#include "pycore_long.h" // _Py_SmallInts
1011
#include "pycore_object.h" // _PyObject_Init()
1112
#include "pycore_runtime.h" // _PY_NSMALLPOSINTS
@@ -221,10 +222,14 @@ _PyLong_FromMedium(sdigit x)
221222
assert(!IS_SMALL_INT(x));
222223
assert(is_medium_int(x));
223224
/* We could use a freelist here */
224-
PyLongObject *v = PyObject_Malloc(sizeof(PyLongObject));
225+
226+
PyLongObject *v = _Py_FREELIST_POP(PyLongObject, ints);
225227
if (v == NULL) {
226-
PyErr_NoMemory();
227-
return NULL;
228+
v = PyObject_Malloc(sizeof(PyLongObject));
229+
if (v == NULL) {
230+
PyErr_NoMemory();
231+
return NULL;
232+
}
228233
}
229234
digit abs_x = x < 0 ? -x : x;
230235
_PyLong_SetSignAndDigitCount(v, x<0?-1:1, 1);
@@ -3614,24 +3619,17 @@ long_richcompare(PyObject *self, PyObject *other, int op)
36143619
static void
36153620
long_dealloc(PyObject *self)
36163621
{
3617-
/* This should never get called, but we also don't want to SEGV if
3618-
* we accidentally decref small Ints out of existence. Instead,
3619-
* since small Ints are immortal, re-set the reference count.
3620-
*/
3621-
PyLongObject *pylong = (PyLongObject*)self;
3622-
if (pylong && _PyLong_IsCompact(pylong)) {
3623-
stwodigits ival = medium_value(pylong);
3624-
if (IS_SMALL_INT(ival)) {
3625-
PyLongObject *small_pylong = (PyLongObject *)get_small_int((sdigit)ival);
3626-
if (pylong == small_pylong) {
3627-
_Py_SetImmortal(self);
3628-
return;
3629-
}
3630-
}
3631-
}
36323622
Py_TYPE(self)->tp_free(self);
36333623
}
36343624

3625+
void _PyLong_Free(PyLongObject *op) {
3626+
if (_PyLong_IsCompact(op)) {
3627+
_Py_FREELIST_FREE(ints, op, PyObject_Free);
3628+
return;
3629+
}
3630+
PyObject_Free(op);
3631+
}
3632+
36353633
static Py_hash_t
36363634
long_hash(PyObject *obj)
36373635
{
@@ -6615,7 +6613,7 @@ PyTypeObject PyLong_Type = {
66156613
0, /* tp_init */
66166614
0, /* tp_alloc */
66176615
long_new, /* tp_new */
6618-
PyObject_Free, /* tp_free */
6616+
_PyLong_Free, /* tp_free */
66196617
.tp_vectorcall = long_vectorcall,
66206618
.tp_version_tag = _Py_TYPE_VERSION_INT,
66216619
};

Python/bytecodes.c

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "pycore_pyerrors.h" // _PyErr_GetRaisedException()
2727
#include "pycore_pystate.h" // _PyInterpreterState_GET()
2828
#include "pycore_range.h" // _PyRangeIterObject
29+
#include "pycore_long.h" // void _PyLong_Free(PyLongObject *op);
2930
#include "pycore_setobject.h" // _PySet_NextEntry()
3031
#include "pycore_sliceobject.h" // _PyBuildSlice_ConsumeRefs
3132
#include "pycore_tuple.h" // _PyTuple_ITEMS()
@@ -514,8 +515,8 @@ dummy_func(
514515

515516
STAT_INC(BINARY_OP, hit);
516517
PyObject *res_o = _PyLong_Multiply((PyLongObject *)left_o, (PyLongObject *)right_o);
517-
PyStackRef_CLOSE_SPECIALIZED(right, (destructor)PyObject_Free);
518-
PyStackRef_CLOSE_SPECIALIZED(left, (destructor)PyObject_Free);
518+
PyStackRef_CLOSE_SPECIALIZED(right, (destructor)_PyLong_Free);
519+
PyStackRef_CLOSE_SPECIALIZED(left, (destructor)_PyLong_Free);
519520
INPUTS_DEAD();
520521
ERROR_IF(res_o == NULL, error);
521522
res = PyStackRef_FromPyObjectSteal(res_o);
@@ -527,8 +528,8 @@ dummy_func(
527528

528529
STAT_INC(BINARY_OP, hit);
529530
PyObject *res_o = _PyLong_Add((PyLongObject *)left_o, (PyLongObject *)right_o);
530-
PyStackRef_CLOSE_SPECIALIZED(right, (destructor)PyObject_Free);
531-
PyStackRef_CLOSE_SPECIALIZED(left, (destructor)PyObject_Free);
531+
PyStackRef_CLOSE_SPECIALIZED(right, (destructor)_PyLong_Free);
532+
PyStackRef_CLOSE_SPECIALIZED(left, (destructor)_PyLong_Free);
532533
INPUTS_DEAD();
533534
ERROR_IF(res_o == NULL, error);
534535
res = PyStackRef_FromPyObjectSteal(res_o);
@@ -540,8 +541,8 @@ dummy_func(
540541

541542
STAT_INC(BINARY_OP, hit);
542543
PyObject *res_o = _PyLong_Subtract((PyLongObject *)left_o, (PyLongObject *)right_o);
543-
PyStackRef_CLOSE_SPECIALIZED(right, (destructor)PyObject_Free);
544-
PyStackRef_CLOSE_SPECIALIZED(left, (destructor)PyObject_Free);
544+
PyStackRef_CLOSE_SPECIALIZED(right, (destructor)_PyLong_Free);
545+
PyStackRef_CLOSE_SPECIALIZED(left, (destructor)_PyLong_Free);
545546
INPUTS_DEAD();
546547
ERROR_IF(res_o == NULL, error);
547548
res = PyStackRef_FromPyObjectSteal(res_o);
@@ -797,7 +798,7 @@ dummy_func(
797798
PyObject *res_o = PyList_GET_ITEM(list, index);
798799
assert(res_o != NULL);
799800
Py_INCREF(res_o);
800-
PyStackRef_CLOSE_SPECIALIZED(sub_st, (destructor)PyObject_Free);
801+
PyStackRef_CLOSE_SPECIALIZED(sub_st, (destructor)_PyLong_Free);
801802
DEAD(sub_st);
802803
PyStackRef_CLOSE(list_st);
803804
res = PyStackRef_FromPyObjectSteal(res_o);
@@ -817,7 +818,7 @@ dummy_func(
817818
DEOPT_IF(Py_ARRAY_LENGTH(_Py_SINGLETON(strings).ascii) <= c);
818819
STAT_INC(BINARY_SUBSCR, hit);
819820
PyObject *res_o = (PyObject*)&_Py_SINGLETON(strings).ascii[c];
820-
PyStackRef_CLOSE_SPECIALIZED(sub_st, (destructor)PyObject_Free);
821+
PyStackRef_CLOSE_SPECIALIZED(sub_st, (destructor)_PyLong_Free);
821822
DEAD(sub_st);
822823
PyStackRef_CLOSE(str_st);
823824
res = PyStackRef_FromPyObjectSteal(res_o);
@@ -838,7 +839,7 @@ dummy_func(
838839
PyObject *res_o = PyTuple_GET_ITEM(tuple, index);
839840
assert(res_o != NULL);
840841
Py_INCREF(res_o);
841-
PyStackRef_CLOSE_SPECIALIZED(sub_st, (destructor)PyObject_Free);
842+
PyStackRef_CLOSE_SPECIALIZED(sub_st, (destructor)_PyLong_Free);
842843
DEAD(sub_st);
843844
PyStackRef_CLOSE(tuple_st);
844845
res = PyStackRef_FromPyObjectSteal(res_o);
@@ -950,7 +951,7 @@ dummy_func(
950951
PyList_SET_ITEM(list, index, PyStackRef_AsPyObjectSteal(value));
951952
assert(old_value != NULL);
952953
Py_DECREF(old_value);
953-
PyStackRef_CLOSE_SPECIALIZED(sub_st, (destructor)PyObject_Free);
954+
PyStackRef_CLOSE_SPECIALIZED(sub_st, (destructor)_PyLong_Free );
954955
DEAD(sub_st);
955956
PyStackRef_CLOSE(list_st);
956957
}

0 commit comments

Comments
 (0)