10000 bpo-46541: Replace core use of _Py_IDENTIFIER() with statically initi… · python/cpython@81c7204 · GitHub
[go: up one dir, main page]

Skip to content

Commit 81c7204

Browse files
bpo-46541: Replace core use of _Py_IDENTIFIER() with statically initialized global objects. (gh-30928)
We're no longer using _Py_IDENTIFIER() (or _Py_static_string()) in any core CPython code. It is still used in a number of non-builtin stdlib modules. The replacement is: PyUnicodeObject (not pointer) fields under _PyRuntimeState, statically initialized as part of _PyRuntime. A new _Py_GET_GLOBAL_IDENTIFIER() macro facilitates lookup of the fields (along with _Py_GET_GLOBAL_STRING() for non-identifier strings). https://bugs.python.org/issue46541#msg411799 explains the rationale for this change. The core of the change is in: * (new) Include/internal/pycore_global_strings.h - the declarations for the global strings, along with the macros * Include/internal/pycore_runtime_init.h - added the static initializers for the global strings * Include/internal/pycore_global_objects.h - where the struct in pycore_global_strings.h is hooked into _PyRuntimeState * Tools/scripts/generate_global_objects.py - added generation of the global string declarations and static initializers I've also added a --check flag to generate_global_objects.py (along with make check-global-objects) to check for unused global strings. That check is added to the PR CI config. The remainder of this change updates the core code to use _Py_GET_GLOBAL_IDENTIFIER() instead of _Py_IDENTIFIER() and the related _Py*Id functions (likewise for _Py_GET_GLOBAL_STRING() instead of _Py_static_string()). This includes adding a few functions where there wasn't already an alternative to _Py*Id(), replacing the _Py_Identifier * parameter with PyObject *. The following are not changed (yet): * stop using _Py_IDENTIFIER() in the stdlib modules * (maybe) get rid of _Py_IDENTIFIER(), etc. entirely -- this may not be doable as at least one package on PyPI using this (private) API * (maybe) intern the strings during runtime init https://bugs.python.org/issue46541
1 parent c018d30 commit 81c7204
  • cjkcodecs
  • Objects
  • Parser
  • Programs
  • Python
  • Tools
  • Some content is hidden

    Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

    108 files changed

    +2282
    -1573
    lines changed

    .github/workflows/build.yml

    Lines changed: 2 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -100,6 +100,8 @@ jobs:
    100100
    run: make smelly
    101101
    - name: Check limited ABI symbols
    102102
    run: make check-limited-abi
    103+
    - name: Check global objects
    104+
    run: make check-global-objects
    103105

    104106
    build_win32:
    105107
    name: 'Windows (x86)'

    Include/cpython/abstract.h

    Lines changed: 4 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -116,6 +116,10 @@ PyObject_CallMethodOneArg(PyObject *self, PyObject *name, PyObject *arg)
    116116
    2 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL);
    117117
    }
    118118

    119+
    PyAPI_FUNC(PyObject *) _PyObject_CallMethod(PyObject *obj,
    120+
    PyObject *name,
    121+
    const char *format, ...);
    122+
    119123
    /* Like PyObject_CallMethod(), but expect a _Py_Identifier*
    120124
    as the method name. */
    121125
    PyAPI_FUNC(PyObject *) _PyObject_CallMethodId(PyObject *obj,

    Include/cpython/ceval.h

    Lines changed: 1 addition & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -15,6 +15,7 @@ PyAPI_FUNC(int) _PyEval_SetAsyncGenFinalizer(PyObject *);
    1515
    PyAPI_FUNC(PyObject *) _PyEval_GetAsyncGenFinalizer(void);
    1616

    1717
    /* Helper to look up a builtin object */
    18+
    PyAPI_FUNC(PyObject *) _PyEval_GetBuiltin(PyObject *);
    1819
    PyAPI_FUNC(PyObject *) _PyEval_GetBuiltinId(_Py_Identifier *);
    1920
    /* Look at the current frame's (if any) code's co_flags, and turn on
    2021
    the corresponding compiler flags in cf->cf_flags. Return 1 if any

    Include/cpython/dictobject.h

    Lines changed: 1 addition & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -30,6 +30,7 @@ typedef struct {
    3030

    3131
    PyAPI_FUNC(PyObject *) _PyDict_GetItem_KnownHash(PyObject *mp, PyObject *key,
    3232
    Py_hash_t hash);
    33+
    PyAPI_FUNC(PyObject *) _PyDict_GetItemWithError(PyObject *dp, PyObject *key);
    3334
    PyAPI_FUNC(PyObject *) _PyDict_GetItemIdWithError(PyObject *dp,
    3435
    struct _Py_Identifier *key);
    3536
    PyAPI_FUNC(PyObject *) _PyDict_GetItemStringWithError(PyObject *, const char *);

    Include/cpython/object.h

    Lines changed: 12 additions & 1 deletion
    Original file line numberDiff line numberDiff line change
    @@ -43,10 +43,16 @@ typedef struct _Py_Identifier {
    4343
    Py_ssize_t index;
    4444
    } _Py_Identifier;
    4545

    46+
    #if defined(NEEDS_PY_IDENTIFIER) || !defined(Py_BUILD_CORE)
    47+
    // For now we are keeping _Py_IDENTIFIER for continued use
    48+
    // in non-builtin extensions (and naughty PyPI modules).
    49+
    4650
    #define _Py_static_string_init(value) { .string = value, .index = -1 }
    4751
    #define _Py_static_string(varname, value) static _Py_Identifier varname = _Py_static_string_init(value)
    4852
    #define _Py_IDENTIFIER(varname) _Py_static_string(PyId_##varname, #varname)
    4953

    54+
    #endif /* NEEDS_PY_IDENTIFIER */
    55+
    5056
    typedef int (*getbufferproc)(PyObject *, Py_buffer *, int);
    5157
    typedef void (*releasebufferproc)(PyObject *, Py_buffer *);
    5258

    @@ -249,7 +255,12 @@ typedef struct _heaptypeobject {
    249255
    PyAPI_FUNC(const char *) _PyType_Name(PyTypeObject *);
    250256
    PyAPI_FUNC(PyObject *) _PyType_Lookup(PyTypeObject *, PyObject *);
    251257
    PyAPI_FUNC(PyObject *) _PyType_LookupId(PyTypeObject *, _Py_Identifier *);
    252-
    PyAPI_FUNC(PyObject *) _PyObject_LookupSpecial(PyObject *, _Py_Identifier *);
    258+
    PyAPI_FUNC(PyObject *) _PyObject_LookupSpecialId(PyObject *, _Py_Identifier *);
    259+
    #ifndef Py_BUILD_CORE
    260+
    // Backward compatibility for 3rd-party extensions
    261+
    // that may be using the old name.
    262+
    #define _PyObject_LookupSpecial _PyObject_LookupSpecialId
    263+
    #endif
    253264
    PyAPI_FUNC(PyTypeObject *) _PyType_CalculateMetaclass(PyTypeObject *, PyObject *);
    254265
    PyAPI_FUNC(PyObject *) _PyType_GetDocFromInternalDoc(const char *, const char *);
    255266
    PyAPI_FUNC(PyObject *) _PyType_GetTextSignatureFromInternalDoc(const char *, const char *);

    Include/cpython/sysmodule.h

    Lines changed: 2 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -2,6 +2,8 @@
    22
    # error "this header file must not be included directly"
    33
    #endif
    44

    5+
    PyAPI_FUNC(PyObject *) _PySys_GetAttr(PyThreadState *tstate,
    6+
    PyObject *name);
    57
    PyAPI_FUNC(PyObject *) _PySys_GetObjectId(_Py_Identifier *key);
    68
    PyAPI_FUNC(int) _PySys_SetObjectId(_Py_Identifier *key, PyObject *);
    79

    Include/internal/pycore_call.h

    Lines changed: 3 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -30,6 +30,9 @@ PyAPI_FUNC(PyObject *) _PyObject_Call(
    3030
    PyObject *args,
    3131
    PyObject *kwargs);
    3232

    33+
    extern PyObject * _PyObject_CallMethodFormat(
    34+
    PyThreadState *tstate, PyObject *callable, const char *format, ...);
    35+
    3336

    3437
    // Static inline variant of public PyVectorcall_Function().
    3538
    static inline vectorcallfunc

    Include/internal/pycore_global_objects.h

    Lines changed: 4 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -8,6 +8,8 @@ extern "C" {
    88
    # error "this header requires Py_BUILD_CORE define"
    99
    #endif
    1010

    11+
    #include "pycore_global_strings.h" // struct _Py_global_strings
    12+
    1113

    1214
    // These would be in pycore_long.h if it weren't for an include cycle.
    1315
    #define _PY_NSMALLPOSINTS 257
    @@ -36,6 +38,8 @@ struct _Py_global_objects {
    3638
    PyBytesObject ob;
    3739
    char eos;
    3840
    } bytes_characters[256];
    41+
    42+
    struct _Py_global_strings strings;
    3943
    } singletons;
    4044
    };
    4145

    0 commit comments

    Comments
     (0)
    0