summaryrefslogtreecommitdiffstats
path: root/Objects/longobject.c
diff options
context:
space:
mode:
Diffstat (limited to 'Objects/longobject.c')
-rw-r--r--Objects/longobject.c78
1 files changed, 59 insertions, 19 deletions
diff --git a/Objects/longobject.c b/Objects/longobject.c
index 4aa3568..96d59f5 100644
--- a/Objects/longobject.c
+++ b/Objects/longobject.c
@@ -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
@@ -42,7 +43,7 @@ static inline void
_Py_DECREF_INT(PyLongObject *op)
{
assert(PyLong_CheckExact(op));
- _Py_DECREF_SPECIALIZED((PyObject *)op, (destructor)PyObject_Free);
+ _Py_DECREF_SPECIALIZED((PyObject *)op, _PyLong_ExactDealloc);
}
static inline int
@@ -220,15 +221,18 @@ _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 = (PyLongObject *)_Py_FREELIST_POP(PyLongObject, ints);
if (v == NULL) {
- PyErr_NoMemory();
- return NULL;
+ v = PyObject_Malloc(sizeof(PyLongObject));
+ if (v == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ _PyObject_Init((PyObject*)v, &PyLong_Type);
}
digit abs_x = x < 0 ? -x : x;
_PyLong_SetSignAndDigitCount(v, x<0?-1:1, 1);
- _PyObject_Init((PyObject*)v, &PyLong_Type);
v->long_value.ob_digit[0] = abs_x;
return (PyObject*)v;
}
@@ -3611,24 +3615,60 @@ long_richcompare(PyObject *self, PyObject *other, int op)
Py_RETURN_RICHCOMPARE(result, 0, op);
}
+static inline int
+compact_int_is_small(PyObject *self)
+{
+ PyLongObject *pylong = (PyLongObject *)self;
+ assert(_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) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void
+_PyLong_ExactDealloc(PyObject *self)
+{
+ assert(PyLong_CheckExact(self));
+ if (_PyLong_IsCompact((PyLongObject *)self)) {
+ #ifndef Py_GIL_DISABLED
+ if (compact_int_is_small(self)) {
+ // See PEP 683, section Accidental De-Immortalizing for details
+ _Py_SetImmortal(self);
+ return;
+ }
+ #endif
+ _Py_FREELIST_FREE(ints, self, PyObject_Free);
+ return;
+ }
+ PyObject_Free(self);
+}
+
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;
- }
+ assert(self);
+ if (_PyLong_IsCompact((PyLongObject *)self)) {
+ if (compact_int_is_small(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.
+ *
+ * See PEP 683, section Accidental De-Immortalizing for details
+ */
+ _Py_SetImmortal(self);
+ return;
+ }
+ if (PyLong_CheckExact(self)) {
+ _Py_FREELIST_FREE(ints, self, PyObject_Free);
+ return;
}
}
+
Py_TYPE(self)->tp_free(self);
}