Skip to content

Commit

Permalink
bpo-37340: remove free_list for bound method objects (pythonGH-14232)
Browse files Browse the repository at this point in the history
  • Loading branch information
methane authored Jul 26, 2019
1 parent 76b6451 commit 3e54b57
Show file tree
Hide file tree
Showing 5 changed files with 14 additions and 101 deletions.
5 changes: 0 additions & 5 deletions Include/methodobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,6 @@ typedef struct {

PyAPI_FUNC(int) PyCFunction_ClearFreeList(void);

#ifndef Py_LIMITED_API
PyAPI_FUNC(void) _PyCFunction_DebugMallocStats(FILE *out);
PyAPI_FUNC(void) _PyMethod_DebugMallocStats(FILE *out);
#endif

#ifdef __cplusplus
}
#endif
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Removed object cache (``free_list``) for bound method objects. Temporary
bound method objects are less used than before thanks to the ``LOAD_METHOD``
opcode and the ``_PyObject_VectorcallMethod`` C API.
52 changes: 5 additions & 47 deletions Objects/classobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,6 @@

#define TP_DESCR_GET(t) ((t)->tp_descr_get)

/* Free list for method objects to safe malloc/free overhead
* The im_self element is used to chain the elements.
*/
static PyMethodObject *free_list;
static int numfree = 0;
#ifndef PyMethod_MAXFREELIST
#define PyMethod_MAXFREELIST 256
#endif

_Py_IDENTIFIER(__name__);
_Py_IDENTIFIER(__qualname__);

Expand Down Expand Up @@ -103,21 +94,13 @@ method_vectorcall(PyObject *method, PyObject *const *args,
PyObject *
PyMethod_New(PyObject *func, PyObject *self)
{
PyMethodObject *im;
if (self == NULL) {
PyErr_BadInternalCall();
return NULL;
}
im = free_list;
if (im != NULL) {
free_list = (PyMethodObject *)(im->im_self);
(void)PyObject_INIT(im, &PyMethod_Type);
numfree--;
}
else {
im = PyObject_GC_New(PyMethodObject, &PyMethod_Type);
if (im == NULL)
return NULL;
PyMethodObject *im = PyObject_GC_New(PyMethodObject, &PyMethod_Type);
if (im == NULL) {
return NULL;
}
im->im_weakreflist = NULL;
Py_INCREF(func);
Expand Down Expand Up @@ -252,14 +235,7 @@ method_dealloc(PyMethodObject *im)
PyObject_ClearWeakRefs((PyObject *)im);
Py_DECREF(im->im_func);
Py_XDECREF(im->im_self);
if (numfree < PyMethod_MAXFREELIST) {
im->im_self = (PyObject *)free_list;
free_list = im;
numfree++;
}
else {
PyObject_GC_Del(im);
}
PyObject_GC_Del(im);
}

static PyObject *
Expand Down Expand Up @@ -395,16 +371,7 @@ PyTypeObject PyMethod_Type = {
int
PyMethod_ClearFreeList(void)
{
int freelist_size = numfree;

while (free_list) {
PyMethodObject *im = free_list;
free_list = (PyMethodObject *)(im->im_self);
PyObject_GC_Del(im);
numfree--;
}
assert(numfree == 0);
return freelist_size;
return 0;
}

void
Expand All @@ -413,15 +380,6 @@ PyMethod_Fini(void)
(void)PyMethod_ClearFreeList();
}

/* Print summary info about the state of the optimized allocator */
void
_PyMethod_DebugMallocStats(FILE *out)
{
_PyDebugAllocatorStats(out,
"free PyMethodObject",
numfree, sizeof(PyMethodObject));
}

/* ------------------------------------------------------------------------
* instance method
*/
Expand Down
53 changes: 6 additions & 47 deletions Objects/methodobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,6 @@
#include "pycore_pystate.h"
#include "structmember.h"

/* Free list for method objects to safe malloc/free overhead
* The m_self element is used to chain the objects.
*/
static PyCFunctionObject *free_list = NULL;
static int numfree = 0;
#ifndef PyCFunction_MAXFREELIST
#define PyCFunction_MAXFREELIST 256
#endif

/* undefine macro trampoline to PyCFunction_NewEx */
#undef PyCFunction_New

Expand Down Expand Up @@ -66,17 +57,10 @@ PyCFunction_NewEx(PyMethodDef *ml, PyObject *self, PyObject *module)
return NULL;
}

PyCFunctionObject *op;
op = free_list;
if (op != NULL) {
free_list = (PyCFunctionObject *)(op->m_self);
(void)PyObject_INIT(op, &PyCFunction_Type);
numfree--;
}
else {
op = PyObject_GC_New(PyCFunctionObject, &PyCFunction_Type);
if (op == NULL)
return NULL;
PyCFunctionObject *op =
PyObject_GC_New(PyCFunctionObject, &PyCFunction_Type);
if (op == NULL) {
return NULL;
}
op->m_weakreflist = NULL;
op->m_ml = ml;
Expand Down Expand Up @@ -130,14 +114,7 @@ meth_dealloc(PyCFunctionObject *m)
}
Py_XDECREF(m->m_self);
Py_XDECREF(m->m_module);
if (numfree < PyCFunction_MAXFREELIST) {
m->m_self = (PyObject *)free_list;
free_list = m;
numfree++;
}
else {
PyObject_GC_Del(m);
}
PyObject_GC_Del(m);
}

static PyObject *
Expand Down Expand Up @@ -338,16 +315,7 @@ PyTypeObject PyCFunction_Type = {
int
PyCFunction_ClearFreeList(void)
{
int freelist_size = numfree;

while (free_list) {
PyCFunctionObject *v = free_list;
free_list = (PyCFunctionObject *)(v->m_self);
PyObject_GC_Del(v);
numfree--;
}
assert(numfree == 0);
return freelist_size;
return 0;
}

void
Expand All @@ -356,15 +324,6 @@ PyCFunction_Fini(void)
(void)PyCFunction_ClearFreeList();
}

/* Print summary info about the state of the optimized allocator */
void
_PyCFunction_DebugMallocStats(FILE *out)
{
_PyDebugAllocatorStats(out,
"free PyCFunctionObject",
numfree, sizeof(PyCFunctionObject));
}


/* Vectorcall functions for each of the PyCFunction calling conventions,
* except for METH_VARARGS (possibly combined with METH_KEYWORDS) which
Expand Down
2 changes: 0 additions & 2 deletions Objects/object.c
Original file line number Diff line number Diff line change
Expand Up @@ -1959,12 +1959,10 @@ Py_ssize_t (*_Py_abstract_hack)(PyObject *) = PyObject_Size;
void
_PyObject_DebugTypeStats(FILE *out)
{
_PyCFunction_DebugMallocStats(out);
_PyDict_DebugMallocStats(out);
_PyFloat_DebugMallocStats(out);
_PyFrame_DebugMallocStats(out);
_PyList_DebugMallocStats(out);
_PyMethod_DebugMallocStats(out);
_PyTuple_DebugMallocStats(out);
}

Expand Down

0 comments on commit 3e54b57

Please sign in to comment.