gh-84436: Implement Immortal Objects (gh-19474)

This is the implementation of PEP683

Motivation:

The PR introduces the ability to immortalize instances in CPython which bypasses reference counting. Tagging objects as immortal allows up to skip certain operations when we know that the object will be around for the entire execution of the runtime.

Note that this by itself will bring a performance regression to the runtime due to the extra reference count checks. However, this brings the ability of having truly immutable objects that are useful in other contexts such as immutable data sharing between sub-interpreters.
This commit is contained in:
Eddie Elizondo 2023-04-22 15:39:37 -04:00 committed by GitHub
parent 916de04fd1
commit ea2c001650
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
35 changed files with 483 additions and 171 deletions

View file

@ -52,8 +52,7 @@ static PyObject *
get_small_int(sdigit ival)
{
assert(IS_SMALL_INT(ival));
PyObject *v = (PyObject *)&_PyLong_SMALL_INTS[_PY_NSMALLNEGINTS + ival];
return Py_NewRef(v);
return (PyObject *)&_PyLong_SMALL_INTS[_PY_NSMALLNEGINTS + ival];
}
static PyLongObject *
@ -3271,6 +3270,27 @@ long_richcompare(PyObject *self, PyObject *other, int op)
Py_RETURN_RICHCOMPARE(result, 0, 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);
}
static Py_hash_t
long_hash(PyLongObject *v)
{
@ -6233,7 +6253,7 @@ PyTypeObject PyLong_Type = {
"int", /* tp_name */
offsetof(PyLongObject, long_value.ob_digit), /* tp_basicsize */
sizeof(digit), /* tp_itemsize */
0, /* tp_dealloc */
long_dealloc, /* tp_dealloc */
0, /* tp_vectorcall_offset */
0, /* tp_getattr */
0, /* tp_setattr */