Browse Source
bpo-40428: Remove PyTuple_ClearFreeList() function (GH-19769)
Remove the following function from the C API:
* PyAsyncGen_ClearFreeLists()
* PyContext_ClearFreeList()
* PyDict_ClearFreeList()
* PyFloat_ClearFreeList()
* PyFrame_ClearFreeList()
* PyList_ClearFreeList()
* PySet_ClearFreeList()
* PyTuple_ClearFreeList()
Make these functions private, move them to the internal C API and
change their return type to void.
Call explicitly PyGC_Collect() to free all free lists.
Note: PySet_ClearFreeList() did nothing.
pull/19781/head
Victor Stinner
6 years ago
committed by
GitHub
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with
71 additions and
86 deletions
Doc/whatsnew/3.9.rst
Include/context.h
Include/cpython/dictobject.h
Include/cpython/frameobject.h
Include/cpython/listobject.h
Include/floatobject.h
Include/genobject.h
Include/internal/pycore_gc.h
Include/setobject.h
Include/tupleobject.h
Misc/NEWS.d/next/C API/2020-04-28-23-17-27.bpo-40428.rmtpru.rst
Modules/gcmodule.c
Objects/dictobject.c
Objects/floatobject.c
Objects/frameobject.c
Objects/genobject.c
Objects/listobject.c
Objects/setobject.c
Objects/tupleobject.c
PC/python3.def
Python/context.c
@ -672,6 +672,19 @@ Build and C API Changes
the garbage collector respectively. (Contributed by Pablo Galindo in
:issue: `40241` .)
* Remove the following functions from the C API. Call :c:func: `PyGC_Collect`
explicitly to free all free lists.
(Contributed by Victor Stinner in :issue: `40428` .)
* `` PyAsyncGen_ClearFreeLists() ``
* `` PyContext_ClearFreeList() ``
* `` PyDict_ClearFreeList() ``
* `` PyFloat_ClearFreeList() ``
* `` PyFrame_ClearFreeList() ``
* `` PyList_ClearFreeList() ``
* `` PySet_ClearFreeList() ``
* `` PyTuple_ClearFreeList() ``
Deprecated
==========
@ -73,9 +73,6 @@ PyAPI_FUNC(int) PyContextVar_Reset(PyObject *var, PyObject *token);
PyAPI_FUNC ( PyObject * ) _PyContext_NewHamtForTests ( void ) ;
PyAPI_FUNC ( int ) PyContext_ClearFreeList ( void ) ;
# endif /* !Py_LIMITED_API */
# ifdef __cplusplus
@ -62,8 +62,6 @@ PyObject *_PyDict_Pop_KnownHash(PyObject *, PyObject *, Py_hash_t, PyObject *);
PyObject * _PyDict_FromKeys ( PyObject * , PyObject * , PyObject * ) ;
# define _PyDict_HasSplitTable(d) ((d)->ma_values != NULL)
PyAPI_FUNC ( int ) PyDict_ClearFreeList ( void ) ;
/* Like PyDict_Merge, but override can be 0, 1 or 2. If override is 0,
the first occurrence of a key wins , if override is 1 , the last occurrence
of a key wins , if override is 2 , a KeyError with conflicting key as
@ -75,8 +75,6 @@ PyAPI_FUNC(void) PyFrame_LocalsToFast(PyFrameObject *, int);
PyAPI_FUNC ( int ) PyFrame_FastToLocalsWithError ( PyFrameObject * f ) ;
PyAPI_FUNC ( void ) PyFrame_FastToLocals ( PyFrameObject * ) ;
PyAPI_FUNC ( int ) PyFrame_ClearFreeList ( void ) ;
PyAPI_FUNC ( void ) _PyFrame_DebugMallocStats ( FILE * out ) ;
# ifdef __cplusplus
@ -26,7 +26,6 @@ typedef struct {
} PyListObject ;
PyAPI_FUNC ( PyObject * ) _PyList_Extend ( PyListObject * , PyObject * ) ;
PyAPI_FUNC ( int ) PyList_ClearFreeList ( void ) ;
PyAPI_FUNC ( void ) _PyList_DebugMallocStats ( FILE * out ) ;
/* Macro, trading safety for speed */
@ -100,9 +100,6 @@ PyAPI_FUNC(double) _PyFloat_Unpack2(const unsigned char *p, int le);
PyAPI_FUNC ( double ) _PyFloat_Unpack4 ( const unsigned char * p , int le ) ;
PyAPI_FUNC ( double ) _PyFloat_Unpack8 ( const unsigned char * p , int le ) ;
/* free list api */
PyAPI_FUNC ( int ) PyFloat_ClearFreeList ( void ) ;
PyAPI_FUNC ( void ) _PyFloat_DebugMallocStats ( FILE * out ) ;
/* Format the object based on the format_spec, as defined in PEP 3101
@ -91,8 +91,6 @@ PyAPI_FUNC(PyObject *) PyAsyncGen_New(PyFrameObject *,
PyObject * _PyAsyncGenValueWrapperNew ( PyObject * ) ;
int PyAsyncGen_ClearFreeLists ( void ) ;
# endif
# undef _PyGenObject_HEAD
@ -163,6 +163,16 @@ struct _gc_runtime_state {
PyAPI_FUNC ( void ) _PyGC_InitState ( struct _gc_runtime_state * ) ;
/ / Functions to clear types free lists
extern void _PyFrame_ClearFreeList ( void ) ;
extern void _PyTuple_ClearFreeList ( void ) ;
extern void _PyFloat_ClearFreeList ( void ) ;
extern void _PyList_ClearFreeList ( void ) ;
extern void _PyDict_ClearFreeList ( void ) ;
extern void _PyAsyncGen_ClearFreeLists ( void ) ;
extern void _PyContext_ClearFreeList ( void ) ;
# ifdef __cplusplus
}
# endif
@ -70,7 +70,6 @@ PyAPI_DATA(PyObject *) _PySet_Dummy;
PyAPI_FUNC ( int ) _PySet_NextEntry ( PyObject * set , Py_ssize_t * pos , PyObject * * key , Py_hash_t * hash ) ;
PyAPI_FUNC ( int ) _PySet_Update ( PyObject * set , PyObject * iterable ) ;
PyAPI_FUNC ( int ) PySet_ClearFreeList ( void ) ;
# endif /* Section excluded by Py_LIMITED_API */
@ -34,8 +34,6 @@ PyAPI_FUNC(int) PyTuple_SetItem(PyObject *, Py_ssize_t, PyObject *);
PyAPI_FUNC ( PyObject * ) PyTuple_GetSlice ( PyObject * , Py_ssize_t , Py_ssize_t ) ;
PyAPI_FUNC ( PyObject * ) PyTuple_Pack ( Py_ssize_t , . . . ) ;
PyAPI_FUNC ( int ) PyTuple_ClearFreeList ( void ) ;
# ifndef Py_LIMITED_API
# define Py_CPYTHON_TUPLEOBJECT_H
# include "cpython / tupleobject.h"
@ -0,0 +1,11 @@
Remove the following functions from the C API. Call :c:func: `PyGC_Collect`
explicitly to free all free lists.
* `` PyAsyncGen_ClearFreeLists() ``
* `` PyContext_ClearFreeList() ``
* `` PyDict_ClearFreeList() ``
* `` PyFloat_ClearFreeList() ``
* `` PyFrame_ClearFreeList() ``
* `` PyList_ClearFreeList() ``
* `` PySet_ClearFreeList() ``
* `` PyTuple_ClearFreeList() ``
@ -30,7 +30,6 @@
# include "pycore_object.h"
# include "pycore_pyerrors.h"
# include "pycore_pystate.h" // _PyThreadState_GET()
# include "frameobject.h" // PyFrame_ClearFreeList
# include "pydtrace.h"
# include "pytime.h" // _PyTime_GetMonotonicClock()
@ -1026,14 +1025,13 @@ delete_garbage(PyThreadState *tstate, GCState *gcstate,
static void
clear_freelists ( void )
{
( void ) PyFrame_ClearFreeList ( ) ;
( void ) PyTuple_ClearFreeList ( ) ;
( void ) PyFloat_ClearFreeList ( ) ;
( void ) PyList_ClearFreeList ( ) ;
( void ) PyDict_ClearFreeList ( ) ;
( void ) PySet_ClearFreeList ( ) ;
( void ) PyAsyncGen_ClearFreeLists ( ) ;
( void ) PyContext_ClearFreeList ( ) ;
_PyFrame_ClearFreeList ( ) ;
_PyTuple_ClearFreeList ( ) ;
_PyFloat_ClearFreeList ( ) ;
_PyList_ClearFreeList ( ) ;
_PyDict_ClearFreeList ( ) ;
_PyAsyncGen_ClearFreeLists ( ) ;
_PyContext_ClearFreeList ( ) ;
}
/ / Show stats for objects in each generations
@ -257,20 +257,17 @@ static int numfreekeys = 0;
# include "clinic/dictobject.c.h"
int
PyDict_ClearFreeList ( void )
void
_ PyDict_ClearFreeList( void )
{
PyDictObject * op ;
int ret = numfree + numfreekeys ;
while ( numfree ) {
op = free_list [ - - numfree ] ;
PyDictObject * op = free_list [ - - numfree ] ;
assert ( PyDict_CheckExact ( op ) ) ;
PyObject_GC_Del ( op ) ;
}
while ( numfreekeys ) {
PyObject_FREE ( keys_free_list [ - - numfreekeys ] ) ;
}
return ret ;
}
/* Print summary info about the state of the optimized allocator */
@ -285,7 +282,7 @@ _PyDict_DebugMallocStats(FILE *out)
void
_PyDict_Fini ( void )
{
PyDict_ClearFreeList ( ) ;
_ PyDict_ClearFreeList( ) ;
}
# define DK_SIZE(dk) ((dk)->dk_size)
@ -1998,25 +1998,22 @@ _PyFloat_Init(void)
return 1 ;
}
int
PyFloat_ClearFreeList ( void )
void
_ PyFloat_ClearFreeList( void )
{
PyFloatObject * f = free_list , * next ;
int i = numfree ;
while ( f ) {
for ( ; f ; f = next ) {
next = ( PyFloatObject * ) Py_TYPE ( f ) ;
PyObject_FREE ( f ) ;
f = next ;
}
free_list = NULL ;
numfree = 0 ;
return i ;
}
void
_PyFloat_Fini ( void )
{
( void ) PyFloat_ClearFreeList ( ) ;
_ PyFloat_ClearFreeList( ) ;
}
/* Print summary info about the state of the optimized allocator */
@ -1200,11 +1200,9 @@ PyFrame_LocalsToFast(PyFrameObject *f, int clear)
}
/* Clear out the free list */
int
PyFrame_ClearFreeList ( void )
void
_ PyFrame_ClearFreeList( void )
{
int freelist_size = numfree ;
while ( free_list ! = NULL ) {
PyFrameObject * f = free_list ;
free_list = free_list - > f_back ;
@ -1212,13 +1210,12 @@ PyFrame_ClearFreeList(void)
- - numfree ;
}
assert ( numfree = = 0 ) ;
return freelist_size ;
}
void
_PyFrame_Fini ( void )
{
( void ) PyFrame_ClearFreeList ( ) ;
_ PyFrame_ClearFreeList( ) ;
}
/* Print summary info about the state of the optimized allocator */
@ -1429,11 +1429,9 @@ PyAsyncGen_New(PyFrameObject *f, PyObject *name, PyObject *qualname)
}
int
PyAsyncGen_ClearFreeLists ( void )
void
_ PyAsyncGen_ClearFreeLists( void )
{
int ret = ag_value_freelist_free + ag_asend_freelist_free ;
while ( ag_value_freelist_free ) {
_PyAsyncGenWrappedValue * o ;
o = ag_value_freelist [ - - ag_value_freelist_free ] ;
@ -1447,14 +1445,12 @@ PyAsyncGen_ClearFreeLists(void)
assert ( Py_IS_TYPE ( o , & _PyAsyncGenASend_Type ) ) ;
PyObject_GC_Del ( o ) ;
}
return ret ;
}
void
_PyAsyncGen_Fini ( void )
{
PyAsyncGen_ClearFreeLists ( ) ;
_ PyAsyncGen_ClearFreeLists( ) ;
}
@ -103,23 +103,20 @@ list_preallocate_exact(PyListObject *self, Py_ssize_t size)
static PyListObject * free_list [ PyList_MAXFREELIST ] ;
static int numfree = 0 ;
int
PyList_ClearFreeList ( void )
void
_ PyList_ClearFreeList( void )
{
PyListObject * op ;
int ret = numfree ;
while ( numfree ) {
op = free_list [ - - numfree ] ;
PyListObject * op = free_list [ - - numfree ] ;
assert ( PyList_CheckExact ( op ) ) ;
PyObject_GC_Del ( op ) ;
}
return ret ;
}
void
_PyList_Fini ( void )
{
PyList_ClearFreeList ( ) ;
_ PyList_ClearFreeList( ) ;
}
/* Print summary info about the state of the optimized allocator */
@ -2384,12 +2384,6 @@ PySet_Add(PyObject *anyset, PyObject *key)
return set_add_key ( ( PySetObject * ) anyset , key ) ;
}
int
PySet_ClearFreeList ( void )
{
return 0 ;
}
void
_PySet_Fini ( void )
{
@ -955,26 +955,22 @@ _PyTuple_Resize(PyObject **pv, Py_ssize_t newsize)
return 0 ;
}
int
PyTuple_ClearFreeList ( void )
void
_ PyTuple_ClearFreeList( void )
{
int freelist_size = 0 ;
# if PyTuple_MAXSAVESIZE > 0
int i ;
for ( i = 1 ; i < PyTuple_MAXSAVESIZE ; i + + ) {
PyTupleObject * p , * q ;
p = free_list [ i ] ;
freelist_size + = numfree [ i ] ;
for ( Py_ssize_t i = 1 ; i < PyTuple_MAXSAVESIZE ; i + + ) {
PyTupleObject * p = free_list [ i ] ;
free_list [ i ] = NULL ;
numfree [ i ] = 0 ;
while ( p ) {
q = p ;
PyTupleObject * q = p ;
p = ( PyTupleObject * ) ( p - > ob_item [ 0 ] ) ;
PyObject_GC_Del ( q ) ;
}
}
/ / the empty tuple singleton is only cleared by _PyTuple_Fini ( )
# endif
return freelist_size ;
}
void
@ -985,7 +981,7 @@ _PyTuple_Fini(void)
* rely on the fact that an empty tuple is a singleton . */
Py_CLEAR ( free_list [ 0 ] ) ;
( void ) PyTuple_ClearFreeList ( ) ;
_ PyTuple_ClearFreeList( ) ;
# endif
}
@ -35,7 +35,6 @@ EXPORTS
PyBytes_Size = python39 . PyBytes_Size
PyBytes_Type = python39 . PyBytes_Type DATA
PyCFunction_Call = python39 . PyCFunction_Call
PyCFunction_ClearFreeList = python39 . PyCFunction_ClearFreeList
PyCFunction_GetFlags = python39 . PyCFunction_GetFlags
PyCFunction_GetFunction = python39 . PyCFunction_GetFunction
PyCFunction_GetSelf = python39 . PyCFunction_GetSelf
@ -584,7 +583,6 @@ EXPORTS
PyTraceBack_Print = python39 . PyTraceBack_Print
PyTraceBack_Type = python39 . PyTraceBack_Type DATA
PyTupleIter_Type = python39 . PyTupleIter_Type DATA
PyTuple_ClearFreeList = python39 . PyTuple_ClearFreeList
PyTuple_GetItem = python39 . PyTuple_GetItem
PyTuple_GetSlice = python39 . PyTuple_GetSlice
PyTuple_New = python39 . PyTuple_New
@ -1270,18 +1270,15 @@ get_token_missing(void)
/ / / / / / / / / / / / / / / / / / / / / / / / / / /
int
PyContext_ClearFreeList ( void )
void
_ PyContext_ClearFreeList( void )
{
int size = ctx_freelist_len ;
while ( ctx_freelist_len ) {
for ( ; ctx_freelist_len ; ctx_freelist_len - - ) {
PyContext * ctx = ctx_freelist ;
ctx_freelist = ( PyContext * ) ctx - > ctx_weakreflist ;
ctx - > ctx_weakreflist = NULL ;
PyObject_GC_Del ( ctx ) ;
ctx_freelist_len - - ;
}
return size ;
}
@ -1289,8 +1286,8 @@ void
_PyContext_Fini ( void )
{
Py_CLEAR ( _token_missing ) ;
( void ) PyContext_ClearFreeList ( ) ;
( void ) _PyHamt_Fini ( ) ;
_ PyContext_ClearFreeList( ) ;
_PyHamt_Fini ( ) ;
}