From c8749b578324ad4089c8d014d9136bc42b065343 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Thu, 9 Dec 2021 12:59:26 -0700 Subject: [PATCH] bpo-46008: Make runtime-global object/type lifecycle functions and state consistent. (gh-29998) This change is strictly renames and moving code around. It helps in the following ways: * ensures type-related init functions focus strictly on one of the three aspects (state, objects, types) * passes in PyInterpreterState * to all those functions, simplifying work on moving types/objects/state to the interpreter * consistent naming conventions help make what's going on more clear * keeping API related to a type in the corresponding header file makes it more obvious where to look for it https://bugs.python.org/issue46008 --- Include/internal/pycore_bytesobject.h | 30 ++++ Include/internal/pycore_context.h | 29 +++- Include/internal/pycore_dict.h | 26 ++++ Include/internal/pycore_exceptions.h | 37 +++++ Include/internal/pycore_floatobject.h | 29 ++++ Include/internal/pycore_frame.h | 8 ++ Include/internal/pycore_genobject.h | 46 ++++++ Include/internal/pycore_hamt.h | 11 +- Include/internal/pycore_interp.h | 183 ++---------------------- Include/internal/pycore_list.h | 24 ++++ Include/internal/pycore_long.h | 16 ++- Include/internal/pycore_long_state.h | 33 +++++ Include/internal/pycore_pyerrors.h | 8 ++ Include/internal/pycore_pylifecycle.h | 28 ---- Include/internal/pycore_runtime.h | 24 +--- Include/internal/pycore_sliceobject.h | 20 +++ Include/internal/pycore_structseq.h | 7 + Include/internal/pycore_tuple.h | 37 +++++ Include/internal/pycore_typeobject.h | 47 ++++++ Include/internal/pycore_unicodeobject.h | 71 +++++++++ Makefile.pre.in | 7 + Objects/bytesobject.c | 22 ++- Objects/exceptions.c | 44 ++++-- Objects/floatobject.c | 24 +++- Objects/genobject.c | 1 + Objects/listobject.c | 1 + Objects/longobject.c | 53 ++++--- Objects/object.c | 28 ++-- Objects/structseq.c | 14 +- Objects/tupleobject.c | 21 ++- Objects/typeobject.c | 3 +- Objects/unicodeobject.c | 54 ++++--- PCbuild/pythoncore.vcxproj | 7 + PCbuild/pythoncore.vcxproj.filters | 21 +++ Python/context.c | 22 +-- Python/errors.c | 6 +- Python/hamt.c | 15 +- Python/pylifecycle.c | 122 ++++++++++------ 38 files changed, 818 insertions(+), 361 deletions(-) create mode 100644 Include/internal/pycore_bytesobject.h create mode 100644 Include/internal/pycore_exceptions.h create mode 100644 Include/internal/pycore_genobject.h create mode 100644 Include/internal/pycore_long_state.h create mode 100644 Include/internal/pycore_sliceobject.h create mode 100644 Include/internal/pycore_typeobject.h create mode 100644 Include/internal/pycore_unicodeobject.h diff --git a/Include/internal/pycore_bytesobject.h b/Include/internal/pycore_bytesobject.h new file mode 100644 index 00000000000..b00ed9784ef --- /dev/null +++ b/Include/internal/pycore_bytesobject.h @@ -0,0 +1,30 @@ +#ifndef Py_INTERNAL_BYTESOBJECT_H +#define Py_INTERNAL_BYTESOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef Py_BUILD_CORE +# error "this header requires Py_BUILD_CORE define" +#endif + + +/* runtime lifecycle */ + +extern PyStatus _PyBytes_InitGlobalObjects(PyInterpreterState *); +extern PyStatus _PyBytes_InitTypes(PyInterpreterState *); +extern void _PyBytes_Fini(PyInterpreterState *); + + +/* other API */ + +struct _Py_bytes_state { + PyObject *empty_string; + PyBytesObject *characters[256]; +}; + + +#ifdef __cplusplus +} +#endif +#endif /* !Py_INTERNAL_BYTESOBJECT_H */ diff --git a/Include/internal/pycore_context.h b/Include/internal/pycore_context.h index a482dd42122..31ca0a43fae 100644 --- a/Include/internal/pycore_context.h +++ b/Include/internal/pycore_context.h @@ -7,6 +7,32 @@ #include "pycore_hamt.h" /* PyHamtObject */ + +/* runtime lifecycle */ + +PyStatus _PyContext_InitTypes(PyInterpreterState *); +void _PyContext_Fini(PyInterpreterState *); + + +/* other API */ + +#ifndef WITH_FREELISTS +// without freelists +# define PyContext_MAXFREELIST 0 +#endif + +#ifndef PyContext_MAXFREELIST +# define PyContext_MAXFREELIST 255 +#endif + +struct _Py_context_state { +#if PyContext_MAXFREELIST > 0 + // List of free PyContext objects + PyContext *freelist; + int numfree; +#endif +}; + struct _pycontextobject { PyObject_HEAD PyContext *ctx_prev; @@ -36,7 +62,4 @@ struct _pycontexttokenobject { }; -int _PyContext_Init(void); -void _PyContext_Fini(PyInterpreterState *interp); - #endif /* !Py_INTERNAL_CONTEXT_H */ diff --git a/Include/internal/pycore_dict.h b/Include/internal/pycore_dict.h index 2f0536801ec..faa8bb49bb7 100644 --- a/Include/internal/pycore_dict.h +++ b/Include/internal/pycore_dict.h @@ -10,6 +10,32 @@ extern "C" { #endif +/* runtime lifecycle */ + +extern void _PyDict_Fini(PyInterpreterState *interp); + + +/* other API */ + +#ifndef WITH_FREELISTS +// without freelists +# define PyDict_MAXFREELIST 0 +#endif + +#ifndef PyDict_MAXFREELIST +# define PyDict_MAXFREELIST 80 +#endif + +struct _Py_dict_state { +#if PyDict_MAXFREELIST > 0 + /* Dictionary reuse scheme to save calls to malloc and free */ + PyDictObject *free_list[PyDict_MAXFREELIST]; + int numfree; + PyDictKeysObject *keys_free_list[PyDict_MAXFREELIST]; + int keys_numfree; +#endif +}; + typedef struct { /* Cached hash code of me_key. */ Py_hash_t me_hash; diff --git a/Include/internal/pycore_exceptions.h b/Include/internal/pycore_exceptions.h new file mode 100644 index 00000000000..1651966dad9 --- /dev/null +++ b/Include/internal/pycore_exceptions.h @@ -0,0 +1,37 @@ +#ifndef Py_INTERNAL_EXCEPTIONS_H +#define Py_INTERNAL_EXCEPTIONS_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef Py_BUILD_CORE +# error "this header requires Py_BUILD_CORE define" +#endif + + +/* runtime lifecycle */ + +extern PyStatus _PyExc_InitState(PyInterpreterState *); +extern PyStatus _PyExc_InitGlobalObjects(PyInterpreterState *); +extern PyStatus _PyExc_InitTypes(PyInterpreterState *); +extern void _PyExc_Fini(PyInterpreterState *); + + +/* other API */ + +struct _Py_exc_state { + // The dict mapping from errno codes to OSError subclasses + PyObject *errnomap; + PyBaseExceptionObject *memerrors_freelist; + int memerrors_numfree; + // The ExceptionGroup type + PyObject *PyExc_ExceptionGroup; +}; + +extern void _PyExc_ClearExceptionGroupType(PyInterpreterState *); + + +#ifdef __cplusplus +} +#endif +#endif /* !Py_INTERNAL_EXCEPTIONS_H */ diff --git a/Include/internal/pycore_floatobject.h b/Include/internal/pycore_floatobject.h index 18227c9e369..be6045587de 100644 --- a/Include/internal/pycore_floatobject.h +++ b/Include/internal/pycore_floatobject.h @@ -8,6 +8,35 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif + +/* runtime lifecycle */ + +extern void _PyFloat_InitState(PyInterpreterState *); +extern PyStatus _PyFloat_InitTypes(PyInterpreterState *); +extern void _PyFloat_Fini(PyInterpreterState *); + + +/* other API */ + +#ifndef WITH_FREELISTS +// without freelists +# define PyFloat_MAXFREELIST 0 +#endif + +#ifndef PyFloat_MAXFREELIST +# define PyFloat_MAXFREELIST 100 +#endif + +struct _Py_float_state { +#if PyFloat_MAXFREELIST > 0 + /* Special free list + free_list is a singly-linked list of available PyFloatObjects, + linked via abuse of their ob_type members. */ + int numfree; + PyFloatObject *free_list; +#endif +}; + /* _PyFloat_{Pack,Unpack}{4,8} * * The struct and pickle (at least) modules need an efficient platform- diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h index f4f7ab942c1..a55877b55fb 100644 --- a/Include/internal/pycore_frame.h +++ b/Include/internal/pycore_frame.h @@ -4,6 +4,14 @@ extern "C" { #endif + +/* runtime lifecycle */ + +extern void _PyFrame_Fini(PyInterpreterState *interp); + + +/* other API */ + /* These values are chosen so that the inline functions below all * compare f_state to zero. */ diff --git a/Include/internal/pycore_genobject.h b/Include/internal/pycore_genobject.h new file mode 100644 index 00000000000..74a676df4ad --- /dev/null +++ b/Include/internal/pycore_genobject.h @@ -0,0 +1,46 @@ +#ifndef Py_INTERNAL_GENOBJECT_H +#define Py_INTERNAL_GENOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef Py_BUILD_CORE +# error "this header requires Py_BUILD_CORE define" +#endif + + +/* runtime lifecycle */ + +extern void _PyAsyncGen_Fini(PyInterpreterState *); + + +/* other API */ + +#ifndef WITH_FREELISTS +// without freelists +# define _PyAsyncGen_MAXFREELIST 0 +#endif + +#ifndef _PyAsyncGen_MAXFREELIST +# define _PyAsyncGen_MAXFREELIST 80 +#endif + +struct _Py_async_gen_state { +#if _PyAsyncGen_MAXFREELIST > 0 + /* Freelists boost performance 6-10%; they also reduce memory + fragmentation, as _PyAsyncGenWrappedValue and PyAsyncGenASend + are short-living objects that are instantiated for every + __anext__() call. */ + struct _PyAsyncGenWrappedValue* value_freelist[_PyAsyncGen_MAXFREELIST]; + int value_numfree; + + struct PyAsyncGenASend* asend_freelist[_PyAsyncGen_MAXFREELIST]; + int asend_numfree; +#endif +}; + + +#ifdef __cplusplus +} +#endif +#endif /* !Py_INTERNAL_GENOBJECT_H */ diff --git a/Include/internal/pycore_hamt.h b/Include/internal/pycore_hamt.h index aaf65590955..cf9c19e022d 100644 --- a/Include/internal/pycore_hamt.h +++ b/Include/internal/pycore_hamt.h @@ -8,6 +8,14 @@ #define _Py_HAMT_MAX_TREE_DEPTH 7 +/* runtime lifecycle */ + +PyStatus _PyHamt_InitTypes(PyInterpreterState *); +void _PyHamt_Fini(PyInterpreterState *); + + +/* other API */ + #define PyHamt_Check(o) Py_IS_TYPE(o, &_PyHamt_Type) @@ -110,7 +118,4 @@ PyObject * _PyHamt_NewIterValues(PyHamtObject *o); /* Return a Items iterator over "o". */ PyObject * _PyHamt_NewIterItems(PyHamtObject *o); -int _PyHamt_Init(void); -void _PyHamt_Fini(void); - #endif /* !Py_INTERNAL_HAMT_H */ diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index e421aa4bc4d..e4d7b1b8752 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -10,8 +10,18 @@ extern "C" { #include "pycore_atomic.h" // _Py_atomic_address #include "pycore_ast_state.h" // struct ast_state +#include "pycore_bytesobject.h" // struct _Py_bytes_state +#include "pycore_context.h" // struct _Py_context_state +#include "pycore_dict.h" // struct _Py_dict_state +#include "pycore_exceptions.h" // struct _Py_exc_state +#include "pycore_floatobject.h" // struct _Py_float_state +#include "pycore_genobject.h" // struct _Py_async_gen_state #include "pycore_gil.h" // struct _gil_runtime_state #include "pycore_gc.h" // struct _gc_runtime_state +#include "pycore_list.h" // struct _Py_list_state +#include "pycore_tuple.h" // struct _Py_tuple_state +#include "pycore_typeobject.h" // struct type_cache +#include "pycore_unicodeobject.h" // struct _Py_unicode_state #include "pycore_warnings.h" // struct _warnings_runtime_state struct _pending_calls { @@ -44,158 +54,6 @@ struct _ceval_state { #endif }; -/* fs_codec.encoding is initialized to NULL. - Later, it is set to a non-NULL string by _PyUnicode_InitEncodings(). */ -struct _Py_unicode_fs_codec { - char *encoding; // Filesystem encoding (encoded to UTF-8) - int utf8; // encoding=="utf-8"? - char *errors; // Filesystem errors (encoded to UTF-8) - _Py_error_handler error_handler; -}; - -struct _Py_bytes_state { - PyObject *empty_string; - PyBytesObject *characters[256]; -}; - -struct _Py_unicode_ids { - Py_ssize_t size; - PyObject **array; -}; - -struct _Py_unicode_state { - // The empty Unicode object is a singleton to improve performance. - PyObject *empty_string; - /* Single character Unicode strings in the Latin-1 range are being - shared as well. */ - PyObject *latin1[256]; - struct _Py_unicode_fs_codec fs_codec; - - /* This dictionary holds all interned unicode strings. Note that references - to strings in this dictionary are *not* counted in the string's ob_refcnt. - When the interned string reaches a refcnt of 0 the string deallocation - function will delete the reference from this dictionary. - - Another way to look at this is that to say that the actual reference - count of a string is: s->ob_refcnt + (s->state ? 2 : 0) - */ - PyObject *interned; - - // Unicode identifiers (_Py_Identifier): see _PyUnicode_FromId() - struct _Py_unicode_ids ids; -}; - -#ifndef WITH_FREELISTS -// without freelists -# define PyFloat_MAXFREELIST 0 -// for tuples only store empty tuple singleton -# define PyTuple_MAXSAVESIZE 1 -# define PyTuple_MAXFREELIST 1 -# define PyList_MAXFREELIST 0 -# define PyDict_MAXFREELIST 0 -# define _PyAsyncGen_MAXFREELIST 0 -# define PyContext_MAXFREELIST 0 -#endif - -#ifndef PyFloat_MAXFREELIST -# define PyFloat_MAXFREELIST 100 -#endif - -struct _Py_float_state { -#if PyFloat_MAXFREELIST > 0 - /* Special free list - free_list is a singly-linked list of available PyFloatObjects, - linked via abuse of their ob_type members. */ - int numfree; - PyFloatObject *free_list; -#endif -}; - -/* Speed optimization to avoid frequent malloc/free of small tuples */ -#ifndef PyTuple_MAXSAVESIZE - // Largest tuple to save on free list -# define PyTuple_MAXSAVESIZE 20 -#endif -#ifndef PyTuple_MAXFREELIST - // Maximum number of tuples of each size to save -# define PyTuple_MAXFREELIST 2000 -#endif - -struct _Py_tuple_state { -#if PyTuple_MAXSAVESIZE > 0 - /* Entries 1 up to PyTuple_MAXSAVESIZE are free lists, - entry 0 is the empty tuple () of which at most one instance - will be allocated. */ - PyTupleObject *free_list[PyTuple_MAXSAVESIZE]; - int numfree[PyTuple_MAXSAVESIZE]; -#endif -}; - -/* Empty list reuse scheme to save calls to malloc and free */ -#ifndef PyList_MAXFREELIST -# define PyList_MAXFREELIST 80 -#endif - -struct _Py_list_state { -#if PyList_MAXFREELIST > 0 - PyListObject *free_list[PyList_MAXFREELIST]; - int numfree; -#endif -}; - -#ifndef PyDict_MAXFREELIST -# define PyDict_MAXFREELIST 80 -#endif - -struct _Py_dict_state { -#if PyDict_MAXFREELIST > 0 - /* Dictionary reuse scheme to save calls to malloc and free */ - PyDictObject *free_list[PyDict_MAXFREELIST]; - int numfree; - PyDictKeysObject *keys_free_list[PyDict_MAXFREELIST]; - int keys_numfree; -#endif -}; - -#ifndef _PyAsyncGen_MAXFREELIST -# define _PyAsyncGen_MAXFREELIST 80 -#endif - -struct _Py_async_gen_state { -#if _PyAsyncGen_MAXFREELIST > 0 - /* Freelists boost performance 6-10%; they also reduce memory - fragmentation, as _PyAsyncGenWrappedValue and PyAsyncGenASend - are short-living objects that are instantiated for every - __anext__() call. */ - struct _PyAsyncGenWrappedValue* value_freelist[_PyAsyncGen_MAXFREELIST]; - int value_numfree; - - struct PyAsyncGenASend* asend_freelist[_PyAsyncGen_MAXFREELIST]; - int asend_numfree; -#endif -}; - -#ifndef PyContext_MAXFREELIST -# define PyContext_MAXFREELIST 255 -#endif - -struct _Py_context_state { -#if PyContext_MAXFREELIST > 0 - // List of free PyContext objects - PyContext *freelist; - int numfree; -#endif -}; - -struct _Py_exc_state { - // The dict mapping from errno codes to OSError subclasses - PyObject *errnomap; - PyBaseExceptionObject *memerrors_freelist; - int memerrors_numfree; - // The ExceptionGroup type - PyObject *PyExc_ExceptionGroup; -}; - // atexit state typedef struct { @@ -211,27 +69,6 @@ struct atexit_state { }; -// Type attribute lookup cache: speed up attribute and method lookups, -// see _PyType_Lookup(). -struct type_cache_entry { - unsigned int version; // initialized from type->tp_version_tag - PyObject *name; // reference to exactly a str or None - PyObject *value; // borrowed reference or NULL -}; - -#define MCACHE_SIZE_EXP 12 -#define MCACHE_STATS 0 - -struct type_cache { - struct type_cache_entry hashtable[1 << MCACHE_SIZE_EXP]; -#if MCACHE_STATS - size_t hits; - size_t misses; - size_t collisions; -#endif -}; - - /* interpreter state */ // The PyInterpreterState typedef is in Include/pystate.h. diff --git a/Include/internal/pycore_list.h b/Include/internal/pycore_list.h index f18fb052c49..0717a1f9563 100644 --- a/Include/internal/pycore_list.h +++ b/Include/internal/pycore_list.h @@ -11,6 +11,30 @@ extern "C" { #include "listobject.h" // _PyList_CAST() +/* runtime lifecycle */ + +extern void _PyList_Fini(PyInterpreterState *); + + +/* other API */ + +#ifndef WITH_FREELISTS +// without freelists +# define PyList_MAXFREELIST 0 +#endif + +/* Empty list reuse scheme to save calls to malloc and free */ +#ifndef PyList_MAXFREELIST +# define PyList_MAXFREELIST 80 +#endif + +struct _Py_list_state { +#if PyList_MAXFREELIST > 0 + PyListObject *free_list[PyList_MAXFREELIST]; + int numfree; +#endif +}; + #define _PyList_ITEMS(op) (_PyList_CAST(op)->ob_item) diff --git a/Include/internal/pycore_long.h b/Include/internal/pycore_long.h index b9f926996d8..a5639ceb692 100644 --- a/Include/internal/pycore_long.h +++ b/Include/internal/pycore_long.h @@ -8,18 +8,28 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif -#include "pycore_interp.h" // PyInterpreterState.small_ints +#include "pycore_long_state.h" // _PyLong_SMALL_INTS #include "pycore_pystate.h" // _PyThreadState_GET() +#include "pycore_runtime.h" // _PyRuntime + + +/* runtime lifecycle */ + +extern void _PyLong_InitGlobalObjects(PyInterpreterState *); +extern PyStatus _PyLong_InitTypes(PyInterpreterState *); + + +/* other API */ // Return a borrowed reference to the zero singleton. // The function cannot return NULL. static inline PyObject* _PyLong_GetZero(void) -{ return (PyObject *)&_PyRuntime.small_ints[_PY_NSMALLNEGINTS]; } +{ return (PyObject *)&_PyLong_SMALL_INTS[_PY_NSMALLNEGINTS]; } // Return a borrowed reference to the one singleton. // The function cannot return NULL. static inline PyObject* _PyLong_GetOne(void) -{ return (PyObject *)&_PyRuntime.small_ints[_PY_NSMALLNEGINTS+1]; } +{ return (PyObject *)&_PyLong_SMALL_INTS[_PY_NSMALLNEGINTS+1]; } PyObject *_PyLong_Add(PyLongObject *left, PyLongObject *right); PyObject *_PyLong_Multiply(PyLongObject *left, PyLongObject *right); diff --git a/Include/internal/pycore_long_state.h b/Include/internal/pycore_long_state.h new file mode 100644 index 00000000000..5fe8e623a9e --- /dev/null +++ b/Include/internal/pycore_long_state.h @@ -0,0 +1,33 @@ +#ifndef Py_INTERNAL_LONG_STATE_H +#define Py_INTERNAL_LONG_STATE_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef Py_BUILD_CORE +# error "this header requires Py_BUILD_CORE define" +#endif + +#define _PY_NSMALLPOSINTS 257 +#define _PY_NSMALLNEGINTS 5 + +// _PyLong_GetZero() and _PyLong_GetOne() must always be available +#if _PY_NSMALLPOSINTS < 2 +# error "_PY_NSMALLPOSINTS must be greater than 1" +#endif + +struct _Py_long_state { + /* Small integers are preallocated in this array so that they + * can be shared. + * The integers that are preallocated are those in the range + *-_PY_NSMALLNEGINTS (inclusive) to _PY_NSMALLPOSINTS (not inclusive). + */ + PyLongObject small_ints[_PY_NSMALLNEGINTS + _PY_NSMALLPOSINTS]; +}; + +#define _PyLong_SMALL_INTS _PyRuntime.int_state.small_ints + +#ifdef __cplusplus +} +#endif +#endif /* !Py_INTERNAL_LONG_STATE_H */ diff --git a/Include/internal/pycore_pyerrors.h b/Include/internal/pycore_pyerrors.h index 14ea182f4f4..3134afeb864 100644 --- a/Include/internal/pycore_pyerrors.h +++ b/Include/internal/pycore_pyerrors.h @@ -8,6 +8,14 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif + +/* runtime lifecycle */ + +extern PyStatus _PyErr_InitTypes(PyInterpreterState *); + + +/* other API */ + static inline PyObject* _PyErr_Occurred(PyThreadState *tstate) { assert(tstate != NULL); diff --git a/Include/internal/pycore_pylifecycle.h b/Include/internal/pycore_pylifecycle.h index 5e0f36ab2ae..766e889f237 100644 --- a/Include/internal/pycore_pylifecycle.h +++ b/Include/internal/pycore_pylifecycle.h @@ -49,13 +49,6 @@ PyAPI_FUNC(int) _Py_IsLocaleCoercionTarget(const char *ctype_loc); /* Various one-time initializers */ -extern PyStatus _PyUnicode_Init(PyInterpreterState *interp); -extern PyStatus _PyUnicode_InitTypes(void); -extern PyStatus _PyBytes_Init(PyInterpreterState *interp); -extern int _PyStructSequence_Init(void); -extern void _PyLong_Init(PyInterpreterState *interp); -extern int _PyLong_InitTypes(void); -extern PyStatus _PyTuple_Init(PyInterpreterState *interp); extern PyStatus _PyFaulthandler_Init(int enable); extern int _PyTraceMalloc_Init(int enable); extern PyObject * _PyBuiltin_Init(PyInterpreterState *interp); @@ -65,15 +58,9 @@ extern PyStatus _PySys_Create( extern PyStatus _PySys_ReadPreinitWarnOptions(PyWideStringList *options); extern PyStatus _PySys_ReadPreinitXOptions(PyConfig *config); extern int _PySys_UpdateConfig(PyThreadState *tstate); -extern PyStatus _PyExc_Init(PyInterpreterState *interp); -extern PyStatus _PyErr_InitTypes(void); extern PyStatus _PyBuiltins_AddExceptions(PyObject * bltinmod); -extern void _PyFloat_Init(void); -extern int _PyFloat_InitTypes(void); extern PyStatus _Py_HashRandomization_Init(const PyConfig *); -extern PyStatus _PyTypes_Init(void); -extern PyStatus _PyTypes_InitSlotDefs(void); extern PyStatus _PyImportZip_Init(PyThreadState *tstate); extern PyStatus _PyGC_Init(PyInterpreterState *interp); extern PyStatus _PyAtExit_Init(PyInterpreterState *interp); @@ -81,28 +68,13 @@ extern PyStatus _PyAtExit_Init(PyInterpreterState *interp); /* Various internal finalizers */ -extern void _PyFrame_Fini(PyInterpreterState *interp); -extern void _PyDict_Fini(PyInterpreterState *interp); -extern void _PyTuple_Fini(PyInterpreterState *interp); -extern void _PyList_Fini(PyInterpreterState *interp); -extern void _PyBytes_Fini(PyInterpreterState *interp); -extern void _PyFloat_Fini(PyInterpreterState *interp); -extern void _PySlice_Fini(PyInterpreterState *interp); -extern void _PyAsyncGen_Fini(PyInterpreterState *interp); - extern int _PySignal_Init(int install_signal_handlers); extern void _PySignal_Fini(void); -extern void _PyExc_ClearExceptionGroupType(PyInterpreterState *interp); -extern void _PyExc_Fini(PyInterpreterState *interp); extern void _PyImport_Fini(void); extern void _PyImport_Fini2(void); extern void _PyGC_Fini(PyInterpreterState *interp); -extern void _PyType_Fini(PyInterpreterState *interp); extern void _Py_HashRandomization_Fini(void); -extern void _PyUnicode_Fini(PyInterpreterState *interp); -extern void _PyUnicode_ClearInterned(PyInterpreterState *interp); -extern void _PyLong_Fini(PyInterpreterState *interp); extern void _PyFaulthandler_Fini(void); extern void _PyHash_Fini(void); extern void _PyTraceMalloc_Fini(void); diff --git a/Include/internal/pycore_runtime.h b/Include/internal/pycore_runtime.h index 39e30b785a3..bd88510d1f0 100644 --- a/Include/internal/pycore_runtime.h +++ b/Include/internal/pycore_runtime.h @@ -10,14 +10,8 @@ extern "C" { #include "pycore_atomic.h" /* _Py_atomic_address */ #include "pycore_gil.h" // struct _gil_runtime_state - -#define _PY_NSMALLPOSINTS 257 -#define _PY_NSMALLNEGINTS 5 - -// _PyLong_GetZero() and _PyLong_GetOne() must always be available -#if _PY_NSMALLPOSINTS < 2 -# error "_PY_NSMALLPOSINTS must be greater than 1" -#endif +#include "pycore_long_state.h" // struct _Py_long_state +#include "pycore_unicodeobject.h" // struct _Py_unicode_runtime_ids /* ceval state */ @@ -57,13 +51,6 @@ typedef struct _Py_AuditHookEntry { void *userData; } _Py_AuditHookEntry; -struct _Py_unicode_runtime_ids { - PyThread_type_lock lock; - // next_index value must be preserved when Py_Initialize()/Py_Finalize() - // is called multiple times: see _PyUnicode_FromId() implementation. - Py_ssize_t next_index; -}; - /* Full Python runtime state */ typedef struct pyruntimestate { @@ -114,12 +101,7 @@ typedef struct pyruntimestate { unsigned long main_thread; - /* Small integers are preallocated in this array so that they - * can be shared. - * The integers that are preallocated are those in the range - *-_PY_NSMALLNEGINTS (inclusive) to _PY_NSMALLPOSINTS (not inclusive). - */ - PyLongObject small_ints[_PY_NSMALLNEGINTS + _PY_NSMALLPOSINTS]; + struct _Py_long_state int_state; #define NEXITFUNCS 32 void (*exitfuncs[NEXITFUNCS])(void); diff --git a/Include/internal/pycore_sliceobject.h b/Include/internal/pycore_sliceobject.h new file mode 100644 index 00000000000..e81834c041e --- /dev/null +++ b/Include/internal/pycore_sliceobject.h @@ -0,0 +1,20 @@ +#ifndef Py_INTERNAL_SLICEOBJECT_H +#define Py_INTERNAL_SLICEOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef Py_BUILD_CORE +# error "this header requires Py_BUILD_CORE define" +#endif + + +/* runtime lifecycle */ + +extern void _PySlice_Fini(PyInterpreterState *); + + +#ifdef __cplusplus +} +#endif +#endif /* !Py_INTERNAL_SLICEOBJECT_H */ diff --git a/Include/internal/pycore_structseq.h b/Include/internal/pycore_structseq.h index 84c8d477e0d..3a61cb9a126 100644 --- a/Include/internal/pycore_structseq.h +++ b/Include/internal/pycore_structseq.h @@ -9,6 +9,13 @@ extern "C" { #endif +/* runtime lifecycle */ + +extern PyStatus _PyStructSequence_InitState(PyInterpreterState *); + + +/* other API */ + PyAPI_FUNC(int) _PyStructSequence_InitType( PyTypeObject *type, PyStructSequence_Desc *desc, diff --git a/Include/internal/pycore_tuple.h b/Include/internal/pycore_tuple.h index 79c827fe880..624c21caec1 100644 --- a/Include/internal/pycore_tuple.h +++ b/Include/internal/pycore_tuple.h @@ -10,6 +10,43 @@ extern "C" { #include "tupleobject.h" /* _PyTuple_CAST() */ + +/* runtime lifecycle */ + +extern PyStatus _PyTuple_InitGlobalObjects(PyInterpreterState *); +extern PyStatus _PyTuple_InitTypes(PyInterpreterState *); +extern void _PyTuple_Fini(PyInterpreterState *); + + +/* other API */ + +#ifndef WITH_FREELISTS +// without freelists +// for tuples only store empty tuple singleton +# define PyTuple_MAXSAVESIZE 1 +# define PyTuple_MAXFREELIST 1 +#endif + +/* Speed optimization to avoid frequent malloc/free of small tuples */ +#ifndef PyTuple_MAXSAVESIZE + // Largest tuple to save on free list +# define PyTuple_MAXSAVESIZE 20 +#endif +#ifndef PyTuple_MAXFREELIST + // Maximum number of tuples of each size to save +# define PyTuple_MAXFREELIST 2000 +#endif + +struct _Py_tuple_state { +#if PyTuple_MAXSAVESIZE > 0 + /* Entries 1 up to PyTuple_MAXSAVESIZE are free lists, + entry 0 is the empty tuple () of which at most one instance + will be allocated. */ + PyTupleObject *free_list[PyTuple_MAXSAVESIZE]; + int numfree[PyTuple_MAXSAVESIZE]; +#endif +}; + #define _PyTuple_ITEMS(op) (_PyTuple_CAST(op)->ob_item) extern PyObject *_PyTuple_FromArray(PyObject *const *, Py_ssize_t); diff --git a/Include/internal/pycore_typeobject.h b/Include/internal/pycore_typeobject.h new file mode 100644 index 00000000000..7fd8a1f3509 --- /dev/null +++ b/Include/internal/pycore_typeobject.h @@ -0,0 +1,47 @@ +#ifndef Py_INTERNAL_TYPEOBJECT_H +#define Py_INTERNAL_TYPEOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef Py_BUILD_CORE +# error "this header requires Py_BUILD_CORE define" +#endif + + +/* runtime lifecycle */ + +extern PyStatus _PyTypes_InitState(PyInterpreterState *); +extern PyStatus _PyTypes_InitTypes(PyInterpreterState *); +extern void _PyTypes_Fini(PyInterpreterState *); + + +/* other API */ + +// Type attribute lookup cache: speed up attribute and method lookups, +// see _PyType_Lookup(). +struct type_cache_entry { + unsigned int version; // initialized from type->tp_version_tag + PyObject *name; // reference to exactly a str or None + PyObject *value; // borrowed reference or NULL +}; + +#define MCACHE_SIZE_EXP 12 +#define MCACHE_STATS 0 + +struct type_cache { + struct type_cache_entry hashtable[1 << MCACHE_SIZE_EXP]; +#if MCACHE_STATS + size_t hits; + size_t misses; + size_t collisions; +#endif +}; + +extern PyStatus _PyTypes_InitSlotDefs(void); + + +#ifdef __cplusplus +} +#endif +#endif /* !Py_INTERNAL_TYPEOBJECT_H */ diff --git a/Include/internal/pycore_unicodeobject.h b/Include/internal/pycore_unicodeobject.h new file mode 100644 index 00000000000..c50c42011a9 --- /dev/null +++ b/Include/internal/pycore_unicodeobject.h @@ -0,0 +1,71 @@ +#ifndef Py_INTERNAL_UNICODEOBJECT_H +#define Py_INTERNAL_UNICODEOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef Py_BUILD_CORE +# error "this header requires Py_BUILD_CORE define" +#endif + + +/* runtime lifecycle */ + +extern void _PyUnicode_InitState(PyInterpreterState *); +extern PyStatus _PyUnicode_InitGlobalObjects(PyInterpreterState *); +extern PyStatus _PyUnicode_InitTypes(PyInterpreterState *); +extern void _PyUnicode_Fini(PyInterpreterState *); + + +/* other API */ + +struct _Py_unicode_runtime_ids { + PyThread_type_lock lock; + // next_index value must be preserved when Py_Initialize()/Py_Finalize() + // is called multiple times: see _PyUnicode_FromId() implementation. + Py_ssize_t next_index; +}; + +/* fs_codec.encoding is initialized to NULL. + Later, it is set to a non-NULL string by _PyUnicode_InitEncodings(). */ +struct _Py_unicode_fs_codec { + char *encoding; // Filesystem encoding (encoded to UTF-8) + int utf8; // encoding=="utf-8"? + char *errors; // Filesystem errors (encoded to UTF-8) + _Py_error_handler error_handler; +}; + +struct _Py_unicode_ids { + Py_ssize_t size; + PyObject **array; +}; + +struct _Py_unicode_state { + // The empty Unicode object is a singleton to improve performance. + PyObject *empty_string; + /* Single character Unicode strings in the Latin-1 range are being + shared as well. */ + PyObject *latin1[256]; + struct _Py_unicode_fs_codec fs_codec; + + /* This dictionary holds all interned unicode strings. Note that references + to strings in this dictionary are *not* counted in the string's ob_refcnt. + When the interned string reaches a refcnt of 0 the string deallocation + function will delete the reference from this dictionary. + + Another way to look at this is that to say that the actual reference + count of a string is: s->ob_refcnt + (s->state ? 2 : 0) + */ + PyObject *interned; + + // Unicode identifiers (_Py_Identifier): see _PyUnicode_FromId() + struct _Py_unicode_ids ids; +}; + +extern void _PyUnicode_ClearInterned(PyInterpreterState *); + + +#ifdef __cplusplus +} +#endif +#endif /* !Py_INTERNAL_UNICODEOBJECT_H */ diff --git a/Makefile.pre.in b/Makefile.pre.in index f6801353cfe..57928eead43 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1576,6 +1576,7 @@ PYTHON_HEADERS= \ $(srcdir)/Include/internal/pycore_atomic_funcs.h \ $(srcdir)/Include/internal/pycore_bitutils.h \ $(srcdir)/Include/internal/pycore_bytes_methods.h \ + $(srcdir)/Include/internal/pycore_bytesobject.h \ $(srcdir)/Include/internal/pycore_call.h \ $(srcdir)/Include/internal/pycore_ceval.h \ $(srcdir)/Include/internal/pycore_code.h \ @@ -1584,10 +1585,12 @@ PYTHON_HEADERS= \ $(srcdir)/Include/internal/pycore_context.h \ $(srcdir)/Include/internal/pycore_dict.h \ $(srcdir)/Include/internal/pycore_dtoa.h \ + $(srcdir)/Include/internal/pycore_exceptions.h \ $(srcdir)/Include/internal/pycore_fileutils.h \ $(srcdir)/Include/internal/pycore_floatobject.h \ $(srcdir)/Include/internal/pycore_format.h \ $(srcdir)/Include/internal/pycore_function.h \ + $(srcdir)/Include/internal/pycore_genobject.h \ $(srcdir)/Include/internal/pycore_getopt.h \ $(srcdir)/Include/internal/pycore_gil.h \ $(srcdir)/Include/internal/pycore_hamt.h \ @@ -1598,6 +1601,7 @@ PYTHON_HEADERS= \ $(srcdir)/Include/internal/pycore_interpreteridobject.h \ $(srcdir)/Include/internal/pycore_list.h \ $(srcdir)/Include/internal/pycore_long.h \ + $(srcdir)/Include/internal/pycore_long_state.h \ $(srcdir)/Include/internal/pycore_moduleobject.h \ $(srcdir)/Include/internal/pycore_namespace.h \ $(srcdir)/Include/internal/pycore_object.h \ @@ -1609,14 +1613,17 @@ PYTHON_HEADERS= \ $(srcdir)/Include/internal/pycore_pymem.h \ $(srcdir)/Include/internal/pycore_pystate.h \ $(srcdir)/Include/internal/pycore_runtime.h \ + $(srcdir)/Include/internal/pycore_sliceobject.h \ $(srcdir)/Include/internal/pycore_strhex.h \ $(srcdir)/Include/internal/pycore_structseq.h \ $(srcdir)/Include/internal/pycore_symtable.h \ $(srcdir)/Include/internal/pycore_sysmodule.h \ $(srcdir)/Include/internal/pycore_traceback.h \ $(srcdir)/Include/internal/pycore_tuple.h \ + $(srcdir)/Include/internal/pycore_typeobject.h \ $(srcdir)/Include/internal/pycore_ucnhash.h \ $(srcdir)/Include/internal/pycore_unionobject.h \ + $(srcdir)/Include/internal/pycore_unicodeobject.h \ $(srcdir)/Include/internal/pycore_warnings.h \ $(DTRACE_HEADERS) \ \ diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index 66fd2ecc3c4..2f7e0a6dde6 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -5,6 +5,7 @@ #include "Python.h" #include "pycore_abstract.h" // _PyIndex_Check() #include "pycore_bytes_methods.h" // _Py_bytes_startswith() +#include "pycore_bytesobject.h" // struct _Py_bytes_state #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_format.h" // F_LJUST #include "pycore_initconfig.h" // _PyStatus_OK() @@ -3086,7 +3087,7 @@ error: PyStatus -_PyBytes_Init(PyInterpreterState *interp) +_PyBytes_InitGlobalObjects(PyInterpreterState *interp) { struct _Py_bytes_state *state = &interp->bytes; if (bytes_create_empty_string_singleton(state) < 0) { @@ -3096,6 +3097,25 @@ _PyBytes_Init(PyInterpreterState *interp) } +PyStatus +_PyBytes_InitTypes(PyInterpreterState *interp) +{ + if (!_Py_IsMainInterpreter(interp)) { + return _PyStatus_OK(); + } + + if (PyType_Ready(&PyBytes_Type) < 0) { + return _PyStatus_ERR("Can't initialize bytes type"); + } + + if (PyType_Ready(&PyBytesIter_Type) < 0) { + return _PyStatus_ERR("Can't initialize bytes iterator type"); + } + + return _PyStatus_OK(); +} + + void _PyBytes_Fini(PyInterpreterState *interp) { diff --git a/Objects/exceptions.c b/Objects/exceptions.c index e1a8c1363ef..13401575256 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -7,6 +7,7 @@ #define PY_SSIZE_T_CLEAN #include #include +#include "pycore_exceptions.h" // struct _Py_exc_state #include "pycore_initconfig.h" #include "pycore_object.h" #include "structmember.h" // PyMemberDef @@ -3189,10 +3190,8 @@ SimpleExtendsException(PyExc_Warning, ResourceWarning, #endif /* MS_WINDOWS */ PyStatus -_PyExc_Init(PyInterpreterState *interp) +_PyExc_InitTypes(PyInterpreterState *interp) { - struct _Py_exc_state *state = &interp->exc_state; - #define PRE_INIT(TYPE) \ if (!(_PyExc_ ## TYPE.tp_flags & Py_TPFLAGS_READY)) { \ if (PyType_Ready(&_PyExc_ ## TYPE) < 0) { \ @@ -3201,17 +3200,6 @@ _PyExc_Init(PyInterpreterState *interp) Py_INCREF(PyExc_ ## TYPE); \ } -#define ADD_ERRNO(TYPE, CODE) \ - do { \ - PyObject *_code = PyLong_FromLong(CODE); \ - assert(_PyObject_RealIsSubclass(PyExc_ ## TYPE, PyExc_OSError)); \ - if (!_code || PyDict_SetItem(state->errnomap, _code, PyExc_ ## TYPE)) { \ - Py_XDECREF(_code); \ - return _PyStatus_ERR("errmap insertion problem."); \ - } \ - Py_DECREF(_code); \ - } while (0) - PRE_INIT(BaseException); PRE_INIT(BaseExceptionGroup); PRE_INIT(Exception); @@ -3282,10 +3270,37 @@ _PyExc_Init(PyInterpreterState *interp) PRE_INIT(ProcessLookupError); PRE_INIT(TimeoutError); + return _PyStatus_OK(); + +#undef PRE_INIT +} + +PyStatus +_PyExc_InitGlobalObjects(PyInterpreterState *interp) +{ if (preallocate_memerrors() < 0) { return _PyStatus_NO_MEMORY(); } + return _PyStatus_OK(); +} + +PyStatus +_PyExc_InitState(PyInterpreterState *interp) +{ + struct _Py_exc_state *state = &interp->exc_state; + +#define ADD_ERRNO(TYPE, CODE) \ + do { \ + PyObject *_code = PyLong_FromLong(CODE); \ + assert(_PyObject_RealIsSubclass(PyExc_ ## TYPE, PyExc_OSError)); \ + if (!_code || PyDict_SetItem(state->errnomap, _code, PyExc_ ## TYPE)) { \ + Py_XDECREF(_code); \ + return _PyStatus_ERR("errmap insertion problem."); \ + } \ + Py_DECREF(_code); \ + } while (0) + /* Add exceptions to errnomap */ assert(state->errnomap == NULL); state->errnomap = PyDict_New(); @@ -3317,7 +3332,6 @@ _PyExc_Init(PyInterpreterState *interp) return _PyStatus_OK(); -#undef PRE_INIT #undef ADD_ERRNO } diff --git a/Objects/floatobject.c b/Objects/floatobject.c index 7fc192e7201..f8620d6f8ef 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -6,6 +6,7 @@ #include "Python.h" #include "pycore_dtoa.h" // _Py_dg_dtoa() #include "pycore_floatobject.h" // _PyFloat_FormatAdvancedWriter() +#include "pycore_initconfig.h" // _PyStatus_OK() #include "pycore_interp.h" // _PyInterpreterState.float_state #include "pycore_long.h" // _PyLong_GetOne() #include "pycore_object.h" // _PyObject_Init() @@ -1981,8 +1982,12 @@ PyTypeObject PyFloat_Type = { }; void -_PyFloat_Init(void) +_PyFloat_InitState(PyInterpreterState *interp) { + if (!_Py_IsMainInterpreter(interp)) { + return; + } + /* We attempt to determine if this machine is using IEEE floating point formats by peering at the bits of some carefully chosen values. If it looks like we are on an @@ -2030,16 +2035,25 @@ _PyFloat_Init(void) float_format = detected_float_format; } -int -_PyFloat_InitTypes(void) +PyStatus +_PyFloat_InitTypes(PyInterpreterState *interp) { + if (!_Py_IsMainInterpreter(interp)) { + return _PyStatus_OK(); + } + + if (PyType_Ready(&PyFloat_Type) < 0) { + return _PyStatus_ERR("Can't initialize float type"); + } + /* Init float info */ if (FloatInfoType.tp_name == NULL) { if (PyStructSequence_InitType2(&FloatInfoType, &floatinfo_desc) < 0) { - return -1; + return _PyStatus_ERR("can't init float info type"); } } - return 0; + + return _PyStatus_OK(); } void diff --git a/Objects/genobject.c b/Objects/genobject.c index 147194c38a0..1b08b43ac22 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -3,6 +3,7 @@ #include "Python.h" #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_ceval.h" // _PyEval_EvalFrame() +#include "pycore_genobject.h" // struct _Py_async_gen_state #include "pycore_object.h" // _PyObject_GC_UNTRACK() #include "pycore_pyerrors.h" // _PyErr_ClearExcState() #include "pycore_pystate.h" // _PyThreadState_GET() diff --git a/Objects/listobject.c b/Objects/listobject.c index be84cf9c330..e7023fb9eb1 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -3,6 +3,7 @@ #include "Python.h" #include "pycore_abstract.h" // _PyIndex_Check() #include "pycore_interp.h" // PyInterpreterState.list +#include "pycore_list.h" // struct _Py_list_state #include "pycore_object.h" // _PyObject_GC_TRACK() #include "pycore_tuple.h" // _PyTuple_FromArray() #include diff --git a/Objects/longobject.c b/Objects/longobject.c index ce4f0d72540..f6d5e7648be 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -4,10 +4,11 @@ #include "Python.h" #include "pycore_bitutils.h" // _Py_popcount32() -#include "pycore_runtime.h" // _PY_NSMALLPOSINTS +#include "pycore_initconfig.h" // _PyStatus_OK() #include "pycore_long.h" // _Py_SmallInts #include "pycore_object.h" // _PyObject_InitVar() #include "pycore_pystate.h" // _Py_IsMainInterpreter() +#include "pycore_runtime.h" // _PY_NSMALLPOSINTS #include #include @@ -48,7 +49,7 @@ static PyObject * get_small_int(sdigit ival) { assert(IS_SMALL_INT(ival)); - PyObject *v = (PyObject *)&_PyRuntime.small_ints[_PY_NSMALLNEGINTS + ival]; + PyObject *v = (PyObject *)&_PyLong_SMALL_INTS[_PY_NSMALLNEGINTS + ival]; Py_INCREF(v); return v; } @@ -5828,31 +5829,51 @@ PyLong_GetInfo(void) return int_info; } + +/* runtime lifecycle */ + void -_PyLong_Init(PyInterpreterState *interp) +_PyLong_InitGlobalObjects(PyInterpreterState *interp) { - if (_PyRuntime.small_ints[0].ob_base.ob_base.ob_refcnt == 0) { - for (Py_ssize_t i=0; i < _PY_NSMALLNEGINTS + _PY_NSMALLPOSINTS; i++) { - sdigit ival = (sdigit)i - _PY_NSMALLNEGINTS; - int size = (ival < 0) ? -1 : ((ival == 0) ? 0 : 1); - _PyRuntime.small_ints[i].ob_base.ob_base.ob_refcnt = 1; - _PyRuntime.small_ints[i].ob_base.ob_base.ob_type = &PyLong_Type; - _PyRuntime.small_ints[i].ob_base.ob_size = size; - _PyRuntime.small_ints[i].ob_digit[0] = (digit)abs(ival); - } + if (!_Py_IsMainInterpreter(interp)) { + return; + } + + PyLongObject *small_ints = _PyLong_SMALL_INTS; + if (small_ints[0].ob_base.ob_base.ob_refcnt != 0) { + // Py_Initialize() must be running a second time. + return; + } + + for (Py_ssize_t i=0; i < _PY_NSMALLNEGINTS + _PY_NSMALLPOSINTS; i++) { + sdigit ival = (sdigit)i - _PY_NSMALLNEGINTS; + int size = (ival < 0) ? -1 : ((ival == 0) ? 0 : 1); + small_ints[i].ob_base.ob_base.ob_refcnt = 1; + small_ints[i].ob_base.ob_base.ob_type = &PyLong_Type; + small_ints[i].ob_base.ob_size = size; + small_ints[i].ob_digit[0] = (digit)abs(ival); } } -int -_PyLong_InitTypes(void) +PyStatus +_PyLong_InitTypes(PyInterpreterState *interp) { + if (!_Py_IsMainInterpreter(interp)) { + return _PyStatus_OK(); + } + + if (PyType_Ready(&PyLong_Type) < 0) { + return _PyStatus_ERR("Can't initialize int type"); + } + /* initialize int_info */ if (Int_InfoType.tp_name == NULL) { if (PyStructSequence_InitType2(&Int_InfoType, &int_info_desc) < 0) { - return -1; + return _PyStatus_ERR("can't init int info type"); } } - return 0; + + return _PyStatus_OK(); } void diff --git a/Objects/object.c b/Objects/object.c index a1c2e16b6fa..124485d64ab 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -10,10 +10,10 @@ #include "pycore_namespace.h" // _PyNamespace_Type #include "pycore_object.h" // _PyType_CheckConsistency() #include "pycore_pyerrors.h" // _PyErr_Occurred() -#include "pycore_pylifecycle.h" // _PyTypes_InitSlotDefs() #include "pycore_pymem.h" // _PyMem_IsPtrFreed() #include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_symtable.h" // PySTEntry_Type +#include "pycore_typeobject.h" // _PyTypes_InitSlotDefs() #include "pycore_unionobject.h" // _PyUnion_Type #include "frameobject.h" // PyFrame_Type #include "pycore_interpreteridobject.h" // _PyInterpreterID_Type @@ -1823,13 +1823,27 @@ PyObject _Py_NotImplementedStruct = { }; PyStatus -_PyTypes_Init(void) +_PyTypes_InitState(PyInterpreterState *interp) { + if (!_Py_IsMainInterpreter(interp)) { + return _PyStatus_OK(); + } + PyStatus status = _PyTypes_InitSlotDefs(); if (_PyStatus_EXCEPTION(status)) { return status; } + return _PyStatus_OK(); +} + +PyStatus +_PyTypes_InitTypes(PyInterpreterState *interp) +{ + if (!_Py_IsMainInterpreter(interp)) { + return _PyStatus_OK(); + } + #define INIT_TYPE(TYPE) \ do { \ if (PyType_Ready(&(TYPE)) < 0) { \ @@ -1843,13 +1857,11 @@ _PyTypes_Init(void) assert(PyBaseObject_Type.tp_base == NULL); assert(PyType_Type.tp_base == &PyBaseObject_Type); - // All other static types + // All other static types (unless initialized elsewhere) INIT_TYPE(PyAsyncGen_Type); INIT_TYPE(PyBool_Type); INIT_TYPE(PyByteArrayIter_Type); INIT_TYPE(PyByteArray_Type); - INIT_TYPE(PyBytesIter_Type); - INIT_TYPE(PyBytes_Type); INIT_TYPE(PyCFunction_Type); INIT_TYPE(PyCMethod_Type); INIT_TYPE(PyCallIter_Type); @@ -1873,7 +1885,6 @@ _PyTypes_Init(void) INIT_TYPE(PyDict_Type); INIT_TYPE(PyEllipsis_Type); INIT_TYPE(PyEnum_Type); - INIT_TYPE(PyFloat_Type); INIT_TYPE(PyFrame_Type); INIT_TYPE(PyFrozenSet_Type); INIT_TYPE(PyFunction_Type); @@ -1884,7 +1895,6 @@ _PyTypes_Init(void) INIT_TYPE(PyListRevIter_Type); INIT_TYPE(PyList_Type); INIT_TYPE(PyLongRangeIter_Type); - INIT_TYPE(PyLong_Type); INIT_TYPE(PyMemberDescr_Type); INIT_TYPE(PyMemoryView_Type); INIT_TYPE(PyMethodDescr_Type); @@ -1910,10 +1920,6 @@ _PyTypes_Init(void) INIT_TYPE(PyStdPrinter_Type); INIT_TYPE(PySuper_Type); INIT_TYPE(PyTraceBack_Type); - INIT_TYPE(PyTupleIter_Type); - INIT_TYPE(PyTuple_Type); - INIT_TYPE(PyUnicodeIter_Type); - INIT_TYPE(PyUnicode_Type); INIT_TYPE(PyWrapperDescr_Type); INIT_TYPE(Py_GenericAliasType); INIT_TYPE(_PyAnextAwaitable_Type); diff --git a/Objects/structseq.c b/Objects/structseq.c index 73795b677b4..a2eefb0455a 100644 --- a/Objects/structseq.c +++ b/Objects/structseq.c @@ -12,6 +12,7 @@ #include "pycore_object.h" // _PyObject_GC_TRACK() #include "structmember.h" // PyMemberDef #include "pycore_structseq.h" // PyStructSequence_InitType() +#include "pycore_initconfig.h" // _PyStatus_OK() static const char visible_length_key[] = "n_sequence_fields"; static const char real_length_key[] = "n_fields"; @@ -583,13 +584,20 @@ PyStructSequence_NewType(PyStructSequence_Desc *desc) return type; } -int _PyStructSequence_Init(void) + +/* runtime lifecycle */ + +PyStatus _PyStructSequence_InitState(PyInterpreterState *interp) { + if (!_Py_IsMainInterpreter(interp)) { + return _PyStatus_OK(); + } + if (_PyUnicode_FromId(&PyId_n_sequence_fields) == NULL || _PyUnicode_FromId(&PyId_n_fields) == NULL || _PyUnicode_FromId(&PyId_n_unnamed_fields) == NULL) { - return -1; + return _PyStatus_ERR("can't initialize structseq state"); } - return 0; + return _PyStatus_OK(); } diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c index e9d1b5926ab..cb34c5eb15e 100644 --- a/Objects/tupleobject.c +++ b/Objects/tupleobject.c @@ -7,6 +7,7 @@ #include "pycore_initconfig.h" // _PyStatus_OK() #include "pycore_object.h" // _PyObject_GC_TRACK() #include "pycore_pyerrors.h" // _Py_FatalRefcountError() +#include "pycore_tuple.h" // struct _Py_tuple_state() /*[clinic input] class tuple "PyTupleObject *" "&PyTuple_Type" @@ -1066,7 +1067,7 @@ _PyTuple_ClearFreeList(PyInterpreterState *interp) PyStatus -_PyTuple_Init(PyInterpreterState *interp) +_PyTuple_InitGlobalObjects(PyInterpreterState *interp) { struct _Py_tuple_state *state = &interp->tuple; if (tuple_create_empty_tuple_singleton(state) < 0) { @@ -1076,6 +1077,24 @@ _PyTuple_Init(PyInterpreterState *interp) } +PyStatus +_PyTuple_InitTypes(PyInterpreterState *interp) +{ + if (!_Py_IsMainInterpreter(interp)) { + return _PyStatus_OK(); + } + + if (PyType_Ready(&PyTuple_Type) < 0) { + return _PyStatus_ERR("Can't initialize tuple type"); + } + + if (PyType_Ready(&PyTupleIter_Type) < 0) { + return _PyStatus_ERR("Can't initialize tuple iterator type"); + } + + return _PyStatus_OK(); +} + void _PyTuple_Fini(PyInterpreterState *interp) { diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 2fd93b61c0b..af35180cdb9 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -9,6 +9,7 @@ #include "pycore_object.h" // _PyType_HasFeature() #include "pycore_pyerrors.h" // _PyErr_Occurred() #include "pycore_pystate.h" // _PyThreadState_GET() +#include "pycore_typeobject.h" // struct type_cache #include "pycore_unionobject.h" // _Py_union_type_or #include "frameobject.h" // PyFrameObject #include "pycore_frame.h" // InterpreterFrame @@ -294,7 +295,7 @@ PyType_ClearCache(void) void -_PyType_Fini(PyInterpreterState *interp) +_PyTypes_Fini(PyInterpreterState *interp) { struct type_cache *cache = &interp->type_cache; type_cache_clear(cache, NULL); diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 532c48ad4d4..14449bce708 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -53,6 +53,7 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "pycore_pylifecycle.h" // _Py_SetFileSystemEncoding() #include "pycore_pystate.h" // _PyInterpreterState_GET() #include "pycore_ucnhash.h" // _PyUnicode_Name_CAPI +#include "pycore_unicodeobject.h" // struct _Py_unicode_state #include "stringlib/eq.h" // unicode_eq() #ifdef MS_WINDOWS @@ -15504,41 +15505,56 @@ PyTypeObject PyUnicode_Type = { /* Initialize the Unicode implementation */ +void +_PyUnicode_InitState(PyInterpreterState *interp) +{ + if (!_Py_IsMainInterpreter(interp)) { + return; + } + + /* initialize the linebreak bloom filter */ + const Py_UCS2 linebreak[] = { + 0x000A, /* LINE FEED */ + 0x000D, /* CARRIAGE RETURN */ + 0x001C, /* FILE SEPARATOR */ + 0x001D, /* GROUP SEPARATOR */ + 0x001E, /* RECORD SEPARATOR */ + 0x0085, /* NEXT LINE */ + 0x2028, /* LINE SEPARATOR */ + 0x2029, /* PARAGRAPH SEPARATOR */ + }; + bloom_linebreak = make_bloom_mask( + PyUnicode_2BYTE_KIND, linebreak, + Py_ARRAY_LENGTH(linebreak)); +} + + PyStatus -_PyUnicode_Init(PyInterpreterState *interp) +_PyUnicode_InitGlobalObjects(PyInterpreterState *interp) { struct _Py_unicode_state *state = &interp->unicode; if (unicode_create_empty_string_singleton(state) < 0) { return _PyStatus_NO_MEMORY(); } - if (_Py_IsMainInterpreter(interp)) { - /* initialize the linebreak bloom filter */ - const Py_UCS2 linebreak[] = { - 0x000A, /* LINE FEED */ - 0x000D, /* CARRIAGE RETURN */ - 0x001C, /* FILE SEPARATOR */ - 0x001D, /* GROUP SEPARATOR */ - 0x001E, /* RECORD SEPARATOR */ - 0x0085, /* NEXT LINE */ - 0x2028, /* LINE SEPARATOR */ - 0x2029, /* PARAGRAPH SEPARATOR */ - }; - bloom_linebreak = make_bloom_mask( - PyUnicode_2BYTE_KIND, linebreak, - Py_ARRAY_LENGTH(linebreak)); - } - return _PyStatus_OK(); } PyStatus -_PyUnicode_InitTypes(void) +_PyUnicode_InitTypes(PyInterpreterState *interp) { + if (!_Py_IsMainInterpreter(interp)) { + return _PyStatus_OK(); + } + if (PyType_Ready(&PyUnicode_Type) < 0) { return _PyStatus_ERR("Can't initialize unicode type"); } + if (PyType_Ready(&PyUnicodeIter_Type) < 0) { + return _PyStatus_ERR("Can't initialize unicode iterator type"); + } + if (PyType_Ready(&EncodingMapType) < 0) { return _PyStatus_ERR("Can't initialize encoding map type"); } diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index a2ee95e0ae9..e3a71ca6451 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -196,6 +196,7 @@ + @@ -203,11 +204,13 @@ + + @@ -218,6 +221,7 @@ + @@ -229,14 +233,17 @@ + + + diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters index c1667e3fb74..c99595755e3 100644 --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -468,6 +468,9 @@ Include\cpython + + Include\internal + Include\internal @@ -498,6 +501,9 @@ Include\internal + + Include\internal + Include\internal @@ -519,6 +525,9 @@ Include\internal + + Include\internal + Include\internal @@ -531,6 +540,9 @@ Include\internal + + Include\internal + Include\internal @@ -561,6 +573,9 @@ Include\internal + + Include\internal + Include\internal @@ -594,6 +609,9 @@ Include\internal + + Include\internal + Include\internal @@ -609,6 +627,9 @@ Include\internal + + Include\internal + Include\internal diff --git a/Python/context.c b/Python/context.c index a20ec712373..9ed73b7444d 100644 --- a/Python/context.c +++ b/Python/context.c @@ -3,6 +3,7 @@ #include "pycore_context.h" #include "pycore_gc.h" // _PyObject_GC_MAY_BE_TRACKED() #include "pycore_hamt.h" +#include "pycore_initconfig.h" // _PyStatus_OK() #include "pycore_object.h" #include "pycore_pyerrors.h" #include "pycore_pystate.h" // _PyThreadState_GET() @@ -1317,15 +1318,20 @@ _PyContext_Fini(PyInterpreterState *interp) struct _Py_context_state *state = &interp->context; state->numfree = -1; #endif - _PyHamt_Fini(); + _PyHamt_Fini(interp); } -int -_PyContext_Init(void) +PyStatus +_PyContext_InitTypes(PyInterpreterState *interp) { - if (!_PyHamt_Init()) { - return 0; + if (!_Py_IsMainInterpreter(interp)) { + return _PyStatus_OK(); + } + + PyStatus status = _PyHamt_InitTypes(interp); + if (_PyStatus_EXCEPTION(status)) { + return status; } if ((PyType_Ready(&PyContext_Type) < 0) || @@ -1333,7 +1339,7 @@ _PyContext_Init(void) (PyType_Ready(&PyContextToken_Type) < 0) || (PyType_Ready(&PyContextTokenMissing_Type) < 0)) { - return 0; + return _PyStatus_ERR("can't init context types"); } PyObject *missing = get_token_missing(); @@ -1341,9 +1347,9 @@ _PyContext_Init(void) PyContextToken_Type.tp_dict, "MISSING", missing)) { Py_DECREF(missing); - return 0; + return _PyStatus_ERR("can't init context types"); } Py_DECREF(missing); - return 1; + return _PyStatus_OK(); } diff --git a/Python/errors.c b/Python/errors.c index 44d2773acdb..5be15e54db2 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -1241,8 +1241,12 @@ static PyStructSequence_Desc UnraisableHookArgs_desc = { PyStatus -_PyErr_InitTypes(void) +_PyErr_InitTypes(PyInterpreterState *interp) { + if (!_Py_IsMainInterpreter(interp)) { + return _PyStatus_OK(); + } + if (UnraisableHookArgsType.tp_name == NULL) { if (PyStructSequence_InitType2(&UnraisableHookArgsType, &UnraisableHookArgs_desc) < 0) { diff --git a/Python/hamt.c b/Python/hamt.c index e272e8808fd..8c8e025a3ef 100644 --- a/Python/hamt.c +++ b/Python/hamt.c @@ -2,6 +2,7 @@ #include "pycore_bitutils.h" // _Py_popcount32 #include "pycore_hamt.h" +#include "pycore_initconfig.h" // _PyStatus_OK() #include "pycore_object.h" // _PyObject_GC_TRACK() #include // offsetof() @@ -2952,9 +2953,13 @@ PyTypeObject _PyHamt_CollisionNode_Type = { }; -int -_PyHamt_Init(void) +PyStatus +_PyHamt_InitTypes(PyInterpreterState *interp) { + if (!_Py_IsMainInterpreter(interp)) { + return _PyStatus_OK(); + } + if ((PyType_Ready(&_PyHamt_Type) < 0) || (PyType_Ready(&_PyHamt_ArrayNode_Type) < 0) || (PyType_Ready(&_PyHamt_BitmapNode_Type) < 0) || @@ -2963,14 +2968,14 @@ _PyHamt_Init(void) (PyType_Ready(&_PyHamtValues_Type) < 0) || (PyType_Ready(&_PyHamtItems_Type) < 0)) { - return 0; + return _PyStatus_ERR("can't init hamt types"); } - return 1; + return _PyStatus_OK(); } void -_PyHamt_Fini(void) +_PyHamt_Fini(PyInterpreterState *interp) { Py_CLEAR(_empty_hamt); Py_CLEAR(_empty_bitmap_node); diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 2b386a11f9f..b6d73a9ce22 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -2,18 +2,31 @@ #include "Python.h" +#include "pycore_bytesobject.h" // _PyBytes_InitTypes() #include "pycore_ceval.h" // _PyEval_FiniGIL() #include "pycore_context.h" // _PyContext_Init() +#include "pycore_exceptions.h" // _PyExc_InitTypes() +#include "pycore_dict.h" // _PyDict_Fini() #include "pycore_fileutils.h" // _Py_ResetForceASCII() +#include "pycore_floatobject.h" // _PyFloat_InitTypes() +#include "pycore_frame.h" // _PyFrame_Fini() +#include "pycore_genobject.h" // _PyAsyncGen_Fini() #include "pycore_import.h" // _PyImport_BootstrapImp() #include "pycore_initconfig.h" // _PyStatus_OK() +#include "pycore_list.h" // _PyList_Fini() +#include "pycore_long.h" // _PyLong_InitTypes() #include "pycore_object.h" // _PyDebug_PrintTotalRefs() #include "pycore_pathconfig.h" // _PyConfig_WritePathConfig() #include "pycore_pyerrors.h" // _PyErr_Occurred() #include "pycore_pylifecycle.h" // _PyErr_Print() #include "pycore_pystate.h" // _PyThreadState_GET() +#include "pycore_sliceobject.h" // _PySlice_Fini() +#include "pycore_structseq.h" // _PyStructSequence_InitState() #include "pycore_sysmodule.h" // _PySys_ClearAuditHooks() #include "pycore_traceback.h" // _Py_DumpTracebackThreads() +#include "pycore_tuple.h" // _PyTuple_InitTypes() +#include "pycore_typeobject.h" // _PyTypes_InitTypes() +#include "pycore_unicodeobject.h" // _PyUnicode_InitTypes() #include // setlocale() #include // getenv() @@ -659,27 +672,27 @@ pycore_create_interpreter(_PyRuntimeState *runtime, static PyStatus -pycore_init_singletons(PyInterpreterState *interp) +pycore_init_global_objects(PyInterpreterState *interp) { PyStatus status; - _PyLong_Init(interp); + _PyLong_InitGlobalObjects(interp); - if (_Py_IsMainInterpreter(interp)) { - _PyFloat_Init(); - } + _PyFloat_InitState(interp); - status = _PyBytes_Init(interp); + status = _PyBytes_InitGlobalObjects(interp); if (_PyStatus_EXCEPTION(status)) { return status; } - status = _PyUnicode_Init(interp); + status = _PyUnicode_InitGlobalObjects(interp); if (_PyStatus_EXCEPTION(status)) { return status; } - status = _PyTuple_Init(interp); + _PyUnicode_InitState(interp); + + status = _PyTuple_InitGlobalObjects(interp); if (_PyStatus_EXCEPTION(status)) { return status; } @@ -692,48 +705,70 @@ static PyStatus pycore_init_types(PyInterpreterState *interp) { PyStatus status; - int is_main_interp = _Py_IsMainInterpreter(interp); - if (is_main_interp) { - if (_PyStructSequence_Init() < 0) { - return _PyStatus_ERR("can't initialize structseq"); - } - - status = _PyTypes_Init(); - if (_PyStatus_EXCEPTION(status)) { - return status; - } - - if (_PyLong_InitTypes() < 0) { - return _PyStatus_ERR("can't init int type"); - } - - status = _PyUnicode_InitTypes(); - if (_PyStatus_EXCEPTION(status)) { - return status; - } - } - - if (is_main_interp) { - if (_PyFloat_InitTypes() < 0) { - return _PyStatus_ERR("can't init float"); - } - } - - status = _PyExc_Init(interp); + status = _PyStructSequence_InitState(interp); if (_PyStatus_EXCEPTION(status)) { return status; } - status = _PyErr_InitTypes(); + status = _PyTypes_InitState(interp); if (_PyStatus_EXCEPTION(status)) { return status; } - if (is_main_interp) { - if (!_PyContext_Init()) { - return _PyStatus_ERR("can't init context"); - } + status = _PyTypes_InitTypes(interp); + if (_PyStatus_EXCEPTION(status)) { + return status; + } + + status = _PyBytes_InitTypes(interp); + if (_PyStatus_EXCEPTION(status)) { + return status; + } + + status = _PyLong_InitTypes(interp); + if (_PyStatus_EXCEPTION(status)) { + return status; + } + + status = _PyUnicode_InitTypes(interp); + if (_PyStatus_EXCEPTION(status)) { + return status; + } + + status = _PyFloat_InitTypes(interp); + if (_PyStatus_EXCEPTION(status)) { + return status; + } + + status = _PyTuple_InitTypes(interp); + if (_PyStatus_EXCEPTION(status)) { + return status; + } + + status = _PyExc_InitTypes(interp); + if (_PyStatus_EXCEPTION(status)) { + return status; + } + + status = _PyExc_InitGlobalObjects(interp); + if (_PyStatus_EXCEPTION(status)) { + return status; + } + + status = _PyExc_InitState(interp); + if (_PyStatus_EXCEPTION(status)) { + return status; + } + + status = _PyErr_InitTypes(interp); + if (_PyStatus_EXCEPTION(status)) { + return status; + } + + status = _PyContext_InitTypes(interp); + if (_PyStatus_EXCEPTION(status)) { + return status; } return _PyStatus_OK(); @@ -799,7 +834,7 @@ pycore_interp_init(PyThreadState *tstate) // Create singletons before the first PyType_Ready() call, since // PyType_Ready() uses singletons like the Unicode empty string (tp_doc) // and the empty tuple singletons (tp_bases). - status = pycore_init_singletons(interp); + status = pycore_init_global_objects(interp); if (_PyStatus_EXCEPTION(status)) { return status; } @@ -1641,7 +1676,7 @@ finalize_interp_types(PyInterpreterState *interp) _PyFrame_Fini(interp); _PyAsyncGen_Fini(interp); _PyContext_Fini(interp); - _PyType_Fini(interp); + _PyTypes_Fini(interp); // Call _PyUnicode_ClearInterned() before _PyDict_Fini() since it uses // a dict internally. _PyUnicode_ClearInterned(interp); @@ -1655,7 +1690,6 @@ finalize_interp_types(PyInterpreterState *interp) _PyBytes_Fini(interp); _PyUnicode_Fini(interp); _PyFloat_Fini(interp); - _PyLong_Fini(interp); }