-
-
Notifications
You must be signed in to change notification settings - Fork 31.8k
bpo-43503: Make limited API objects effectively immutable. #24828
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
4951703
4b1eea3
a34f285
3966551
1a3b4da
728f24b
2536e8b
518e9e8
277e1ea
edef342
4d22e00
838f88f
00948a0
00504d9
e6fc84f
f103804
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
There is now internal support for "immortal" objects (with a "private" | ||
C-API). Those are objects that will never be deleted, like the | ||
singletons and static types. This will benefit the C-API and | ||
subinterpreters. For now the API is currently intended only | ||
for internal use. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -136,6 +136,30 @@ Py_DecRef(PyObject *o) | |
Py_XDECREF(o); | ||
} | ||
|
||
void | ||
_Py_SET_REFCNT(PyObject *ob, Py_ssize_t refcnt) { | ||
if (_PyObject_IsImmortal(ob)) { | ||
// XXX It may be worth emitting a warning here. | ||
return; | ||
} | ||
ob->ob_refcnt = refcnt; | ||
} | ||
|
||
int | ||
_PyObject_IsImmortal(PyObject *ob) | ||
{ | ||
if ((ob->ob_refcnt & _PyObject_IMMORTAL_BIT) == 0) { | ||
return 0; | ||
} | ||
return 1; | ||
} | ||
|
||
void | ||
_PyObject_SetImmortal(PyObject *ob) | ||
{ | ||
ob->ob_refcnt = _PyObject_IMMORTAL_INIT_REFCNT; | ||
} | ||
|
||
PyObject * | ||
PyObject_Init(PyObject *op, PyTypeObject *tp) | ||
{ | ||
|
@@ -1728,11 +1752,14 @@ _PyTypes_Init(void) | |
return status; | ||
} | ||
|
||
// XXX We can stop calling _PyObject_SetImmortal() once we change | ||
// all the static types to use PyVarObject_HEAD_IMMORTAL_INIT. | ||
#define INIT_TYPE(TYPE, NAME) \ | ||
do { \ | ||
if (PyType_Ready(TYPE) < 0) { \ | ||
return _PyStatus_ERR("Can't initialize " NAME " type"); \ | ||
} \ | ||
_PyObject_SetImmortal((PyObject *)TYPE); \ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't do that: using static types from multiple interpreters in parallel is unsafe. See for example the PyTypeObject.tp_subclasses issue. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yuck, but yes. This detail seems to be a particular problem for the lofty idea of sub-interpreters one day eventually having their own GIL... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right. This is something that has to be addressed before this PR can proceed. |
||
} while (0) | ||
|
||
INIT_TYPE(&PyBaseObject_Type, "object"); | ||
|
@@ -1807,10 +1834,19 @@ _PyTypes_Init(void) | |
#undef INIT_TYPE | ||
} | ||
|
||
/* _Py_NewReference() is called in the following situations: | ||
* - for newly allocatoed objects, via _PyObject_Init() | ||
* - when resizing immutable objects (bytes, unicode, tuple) | ||
* - when "allocating" from a freelist | ||
* - when resurrecting an object | ||
*/ | ||
|
||
void | ||
_Py_NewReference(PyObject *op) | ||
{ | ||
// None of the cases above should ever apply to immortal objects. | ||
assert(!_PyObject_IsImmortal(op)); | ||
|
||
if (_Py_tracemalloc_config.tracing) { | ||
_PyTraceMalloc_NewReference(op); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't get the purpose of this macro since it's always defined.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's there only as a marker relative to the public API. However, it is not necessary at this point and I'll drop it.