-
-
Notifications
You must be signed in to change notification settings - Fork 31.6k
bpo-45947: Place dict and values pointer at fixed (negative) offset just before GC header. #29879
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
ee59772
72b71cc
cd22dac
4c83f77
8a8593c
34b5cea
e8c74ab
1bf13b0
a025dfb
5a012a8
e7734b8
14d41ab
123171a
48d6a58
79e61bf
ce0f65b
98ddaed
0f376b5
d724812
9435bae
302f46f
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,3 @@ | ||
Place pointers to dict and values immediately before GC header. This reduces | ||
number of dependent memory loads to access either dict or values from 3 to | ||
1. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -69,10 +69,10 @@ module gc | |
#define NEXT_MASK_UNREACHABLE (1) | ||
|
||
/* Get an object's GC head */ | ||
#define AS_GC(o) ((PyGC_Head *)(o)-1) | ||
#define AS_GC(o) ((PyGC_Head *)(((char *)(o))-sizeof(PyGC_Head))) | ||
|
||
/* Get the object given the GC head */ | ||
#define FROM_GC(g) ((PyObject *)(((PyGC_Head *)g)+1)) | ||
#define FROM_GC(g) ((PyObject *)(((char *)(g))+sizeof(PyGC_Head))) | ||
|
||
static inline int | ||
gc_is_collecting(PyGC_Head *g) | ||
|
@@ -2231,28 +2231,14 @@ PyObject_IS_GC(PyObject *obj) | |
return _PyObject_IS_GC(obj); | ||
} | ||
|
||
static PyObject * | ||
_PyObject_GC_Alloc(int use_calloc, size_t basicsize) | ||
void | ||
_PyObject_GC_Link(PyObject *op) | ||
{ | ||
PyGC_Head *g = AS_GC(op); | ||
assert(((uintptr_t)g & (sizeof(uintptr_t)-1)) == 0); // g must be correctly aligned | ||
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. Wow, you can use & on pointers. I didn't know that. :-) 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. Only after you've cast it to an int. You can do anything with a cast 🙂 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. Oh, somehow I thought uintptr_t was a pointer. :-/ |
||
|
||
PyThreadState *tstate = _PyThreadState_GET(); | ||
GCState *gcstate = &tstate->interp->gc; | ||
if (basicsize > PY_SSIZE_T_MAX - sizeof(PyGC_Head)) { | ||
return _PyErr_NoMemory(tstate); | ||
} | ||
size_t size = sizeof(PyGC_Head) + basicsize; | ||
|
||
PyGC_Head *g; | ||
if (use_calloc) { | ||
g = (PyGC_Head *)PyObject_Calloc(1, size); | ||
} | ||
else { | ||
g = (PyGC_Head *)PyObject_Malloc(size); | ||
} | ||
if (g == NULL) { | ||
return _PyErr_NoMemory(tstate); | ||
} | ||
assert(((uintptr_t)g & 3) == 0); // g must be aligned 4bytes boundary | ||
|
||
g->_gc_next = 0; | ||
g->_gc_prev = 0; | ||
gcstate->generations[0].count++; /* number of allocated GC objects */ | ||
|
@@ -2266,26 +2252,32 @@ _PyObject_GC_Alloc(int use_calloc, size_t basicsize) | |
gc_collect_generations(tstate); | ||
gcstate->collecting = 0; | ||
} | ||
PyObject *op = FROM_GC(g); | ||
return op; | ||
} | ||
|
||
PyObject * | ||
_PyObject_GC_Malloc(size_t basicsize) | ||
{ | ||
return _PyObject_GC_Alloc(0, basicsize); | ||
} | ||
|
||
PyObject * | ||
_PyObject_GC_Calloc(size_t basicsize) | ||
static PyObject * | ||
gc_alloc(size_t basicsize, size_t presize) | ||
{ | ||
return _PyObject_GC_Alloc(1, basicsize); | ||
PyThreadState *tstate = _PyThreadState_GET(); | ||
if (basicsize > PY_SSIZE_T_MAX - presize) { | ||
return _PyErr_NoMemory(tstate); | ||
} | ||
size_t size = presize + basicsize; | ||
char *mem = PyObject_Malloc(size); | ||
if (mem == NULL) { | ||
return _PyErr_NoMemory(tstate); | ||
} | ||
((PyObject **)mem)[0] = NULL; | ||
((PyObject **)mem)[1] = NULL; | ||
PyObject *op = (PyObject *)(mem + presize); | ||
_PyObject_GC_Link(op); | ||
return op; | ||
} | ||
|
||
PyObject * | ||
_PyObject_GC_New(PyTypeObject *tp) | ||
{ | ||
PyObject *op = _PyObject_GC_Malloc(_PyObject_SIZE(tp)); | ||
size_t presize = _PyType_PreHeaderSize(tp); | ||
PyObject *op = gc_alloc(_PyObject_SIZE(tp), presize); | ||
if (op == NULL) { | ||
return NULL; | ||
} | ||
|
@@ -2303,8 +2295,9 @@ _PyObject_GC_NewVar(PyTypeObject *tp, Py_ssize_t nitems) | |
PyErr_BadInternalCall(); | ||
return NULL; | ||
} | ||
size_t presize = _PyType_PreHeaderSize(tp); | ||
size = _PyObject_VAR_SIZE(tp, nitems); | ||
op = (PyVarObject *) _PyObject_GC_Malloc(size); | ||
op = (PyVarObject *)gc_alloc(size, presize); | ||
if (op == NULL) { | ||
return NULL; | ||
} | ||
|
@@ -2333,6 +2326,7 @@ _PyObject_GC_Resize(PyVarObject *op, Py_ssize_t nitems) | |
void | ||
PyObject_GC_Del(void *op) | ||
{ | ||
size_t presize = _PyType_PreHeaderSize(((PyObject *)op)->ob_type); | ||
PyGC_Head *g = AS_GC(op); | ||
if (_PyObject_GC_IS_TRACKED(op)) { | ||
gc_list_remove(g); | ||
|
@@ -2341,7 +2335,7 @@ PyObject_GC_Del(void *op) | |
if (gcstate->generations[0].count > 0) { | ||
gcstate->generations[0].count--; | ||
} | ||
PyObject_Free(g); | ||
PyObject_Free(((char *)op)-presize); | ||
} | ||
|
||
int | ||
|
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.
_PyObject_GC_Malloc
is part of stable ABI. AFAIK the function cannot be removed.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 not part of the stable ABI. It starts with an underscore.
https://www.python.org/dev/peps/pep-0384/#excluded-functions
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.
Misc/stable_abi.txt
define it as stable ABI.On the other hand, no public macro in Python/C API use it. So I doubt it is actually stable abi.
As far as this repo, only one package in top4000 packages uses it.
https://github.com/hpyproject/top4000-pypi-packages/search?q=_PyObject_GC_Malloc
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 sent an email to python-dev asking for clarification of the status of this functions and others that start with _ but are listed in Misc/stable_abi.txt. (It is not listed in Doc/data/stable_abi.dat.)