From 7e8a1b5061313e03f99bc2ffa2062702bcc76426 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Wed, 14 Jan 2026 10:54:45 +0100 Subject: [PATCH 1/2] gh-141004: Document old provisional names for vectorcall/code API (GH-143568) gh-141004: Document old provisional names for vectorcall & code API For vectorcall API, the underscore-prefixed provisional names continue to be available per PEP 590: https://peps.python.org/pep-0590/#finalizing-the-api Use `versionadded`, `versionchanged`, and `:no-typesetting:` to mark this up. For PyCode API, use `:no-typesetting:` rather than `index::` so that these are semantically documented as C functions. --- Doc/c-api/call.rst | 9 ++++++++- Doc/c-api/code.rst | 20 ++++++++++++-------- Doc/c-api/typeobj.rst | 10 +++++++++- 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/Doc/c-api/call.rst b/Doc/c-api/call.rst index 7198d6bc056eb4..9838879a528934 100644 --- a/Doc/c-api/call.rst +++ b/Doc/c-api/call.rst @@ -347,6 +347,8 @@ please see individual documentation for details. .. versionadded:: 3.9 +.. c:function:: PyObject* _PyObject_Vectorcall(PyObject *callable, PyObject *const *args, size_t nargsf, PyObject *kwnames) + :no-typesetting: .. c:function:: PyObject* PyObject_Vectorcall(PyObject *callable, PyObject *const *args, size_t nargsf, PyObject *kwnames) @@ -358,7 +360,12 @@ please see individual documentation for details. Return the result of the call on success, or raise an exception and return *NULL* on failure. - .. versionadded:: 3.9 + .. versionadded:: 3.8 as ``_PyObject_Vectorcall`` + + .. versionchanged:: 3.9 + + Renamed to the current name, without the leading underscore. + The old provisional name is :term:`soft deprecated`. .. c:function:: PyObject* PyObject_VectorcallDict(PyObject *callable, PyObject *const *args, size_t nargsf, PyObject *kwdict) diff --git a/Doc/c-api/code.rst b/Doc/c-api/code.rst index 45f5e83adc48c6..048bc2c2154e77 100644 --- a/Doc/c-api/code.rst +++ b/Doc/c-api/code.rst @@ -69,13 +69,14 @@ bound into a function. The old name is deprecated, but will remain available until the signature changes again. +.. c:function:: PyCodeObject* PyCode_NewWithPosOnlyArgs(...) + :no-typesetting: + .. c:function:: PyCodeObject* PyUnstable_Code_NewWithPosOnlyArgs(int argcount, int posonlyargcount, int kwonlyargcount, int nlocals, int stacksize, int flags, PyObject *code, PyObject *consts, PyObject *names, PyObject *varnames, PyObject *freevars, PyObject *cellvars, PyObject *filename, PyObject *name, PyObject *qualname, int firstlineno, PyObject *linetable, PyObject *exceptiontable) Similar to :c:func:`PyUnstable_Code_New`, but with an extra "posonlyargcount" for positional-only arguments. The same caveats that apply to ``PyUnstable_Code_New`` also apply to this function. - .. index:: single: PyCode_NewWithPosOnlyArgs (C function) - .. versionadded:: 3.8 as ``PyCode_NewWithPosOnlyArgs`` .. versionchanged:: 3.11 @@ -298,6 +299,9 @@ These functions are part of the unstable C API tier: this functionality is a CPython implementation detail, and the API may change without deprecation warnings. +.. c:function:: Py_ssize_t _PyEval_RequestCodeExtraIndex(freefunc free) + :no-typesetting: + .. c:function:: Py_ssize_t PyUnstable_Eval_RequestCodeExtraIndex(freefunc free) Return a new opaque index value used to adding data to code objects. @@ -310,8 +314,6 @@ may change without deprecation warnings. *free* will be called on non-``NULL`` data stored under the new index. Use :c:func:`Py_DecRef` when storing :c:type:`PyObject`. - .. index:: single: _PyEval_RequestCodeExtraIndex (C function) - .. versionadded:: 3.6 as ``_PyEval_RequestCodeExtraIndex`` .. versionchanged:: 3.12 @@ -320,6 +322,9 @@ may change without deprecation warnings. The old private name is deprecated, but will be available until the API changes. +.. c:function:: int _PyCode_GetExtra(PyObject *code, Py_ssize_t index, void **extra) + :no-typesetting: + .. c:function:: int PyUnstable_Code_GetExtra(PyObject *code, Py_ssize_t index, void **extra) Set *extra* to the extra data stored under the given index. @@ -328,8 +333,6 @@ may change without deprecation warnings. If no data was set under the index, set *extra* to ``NULL`` and return 0 without setting an exception. - .. index:: single: _PyCode_GetExtra (C function) - .. versionadded:: 3.6 as ``_PyCode_GetExtra`` .. versionchanged:: 3.12 @@ -338,13 +341,14 @@ may change without deprecation warnings. The old private name is deprecated, but will be available until the API changes. +.. c:function:: int _PyCode_SetExtra(PyObject *code, Py_ssize_t index, void *extra) + :no-typesetting: + .. c:function:: int PyUnstable_Code_SetExtra(PyObject *code, Py_ssize_t index, void *extra) Set the extra data stored under the given index to *extra*. Return 0 on success. Set an exception and return -1 on failure. - .. index:: single: _PyCode_SetExtra (C function) - .. versionadded:: 3.6 as ``_PyCode_SetExtra`` .. versionchanged:: 3.12 diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index efac86078f9af5..a33da367e6071f 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -1373,6 +1373,9 @@ and :c:data:`PyType_Type` effectively act as defaults.) type structure. + .. c:macro:: _Py_TPFLAGS_HAVE_VECTORCALL + :no-typesetting: + .. c:macro:: Py_TPFLAGS_HAVE_VECTORCALL This bit is set when the class implements @@ -1384,7 +1387,12 @@ and :c:data:`PyType_Type` effectively act as defaults.) This bit is inherited if :c:member:`~PyTypeObject.tp_call` is also inherited. - .. versionadded:: 3.9 + .. versionadded:: 3.8 as ``_Py_TPFLAGS_HAVE_VECTORCALL`` + + .. versionchanged:: 3.9 + + Renamed to the current name, without the leading underscore. + The old provisional name is :term:`soft deprecated`. .. versionchanged:: 3.12 From 94dbce13979ea1b302ba12be8769175c50639b30 Mon Sep 17 00:00:00 2001 From: Hai Zhu <35182391+cocolato@users.noreply.github.com> Date: Wed, 14 Jan 2026 18:27:33 +0800 Subject: [PATCH 2/2] gh-138050: Use cold flag instead of warm flag in `MAKE_WARM` (GH-143827) --- Include/internal/pycore_optimizer.h | 2 +- Python/bytecodes.c | 2 +- Python/executor_cases.c.h | 8 ++++---- Python/optimizer.c | 12 ++++++------ Python/pystate.c | 4 ++-- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Include/internal/pycore_optimizer.h b/Include/internal/pycore_optimizer.h index a2d9d2d4dfc86f..80a22e6bd12c64 100644 --- a/Include/internal/pycore_optimizer.h +++ b/Include/internal/pycore_optimizer.h @@ -27,7 +27,7 @@ typedef struct { uint8_t oparg; uint8_t valid; uint8_t chain_depth; // Must be big enough for MAX_CHAIN_DEPTH - 1. - bool warm; + bool cold; uint8_t pending_deletion; int32_t index; // Index of ENTER_EXECUTOR (if code isn't NULL, below). _PyBloomFilter bloom; diff --git a/Python/bytecodes.c b/Python/bytecodes.c index fda97dc07932fb..273865bd366935 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -5474,7 +5474,7 @@ dummy_func( } tier2 op(_MAKE_WARM, (--)) { - current_executor->vm_data.warm = true; + current_executor->vm_data.cold = false; } tier2 op(_FATAL_ERROR, (--)) { diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 26385e3a32f472..42cca042022fc1 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -18511,7 +18511,7 @@ case _MAKE_WARM_r00: { CHECK_CURRENT_CACHED_VALUES(0); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); - current_executor->vm_data.warm = true; + current_executor->vm_data.cold = false; SET_CURRENT_CACHED_VALUES(0); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; @@ -18521,7 +18521,7 @@ CHECK_CURRENT_CACHED_VALUES(1); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef _stack_item_0 = _tos_cache0; - current_executor->vm_data.warm = true; + current_executor->vm_data.cold = false; _tos_cache0 = _stack_item_0; SET_CURRENT_CACHED_VALUES(1); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); @@ -18533,7 +18533,7 @@ assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef _stack_item_0 = _tos_cache0; _PyStackRef _stack_item_1 = _tos_cache1; - current_executor->vm_data.warm = true; + current_executor->vm_data.cold = false; _tos_cache1 = _stack_item_1; _tos_cache0 = _stack_item_0; SET_CURRENT_CACHED_VALUES(2); @@ -18547,7 +18547,7 @@ _PyStackRef _stack_item_0 = _tos_cache0; _PyStackRef _stack_item_1 = _tos_cache1; _PyStackRef _stack_item_2 = _tos_cache2; - current_executor->vm_data.warm = true; + current_executor->vm_data.cold = false; _tos_cache2 = _stack_item_2; _tos_cache1 = _stack_item_1; _tos_cache0 = _stack_item_0; diff --git a/Python/optimizer.c b/Python/optimizer.c index 79ac179d0b710a..5ef4a5c4fa513c 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -1408,9 +1408,9 @@ make_executor_from_uops(_PyThreadStateImpl *tstate, _PyUOpInstruction *buffer, i #ifdef _Py_JIT executor->jit_code = NULL; executor->jit_size = 0; - // This is initialized to true so we can prevent the executor + // This is initialized to false so we can prevent the executor // from being immediately detected as cold and invalidated. - executor->vm_data.warm = true; + executor->vm_data.cold = false; if (_PyJIT_Compile(executor, executor->trace, length)) { Py_DECREF(executor); return NULL; @@ -1698,9 +1698,9 @@ make_cold_executor(uint16_t opcode) Py_FatalError("Cannot allocate core JIT code"); } ((_PyUOpInstruction *)cold->trace)->opcode = opcode; - // This is initialized to true so we can prevent the executor + // This is initialized to false so we can prevent the executor // from being immediately detected as cold and invalidated. - cold->vm_data.warm = true; + cold->vm_data.cold = false; #ifdef _Py_JIT cold->jit_code = NULL; cold->jit_size = 0; @@ -1895,11 +1895,11 @@ _Py_Executors_InvalidateCold(PyInterpreterState *interp) assert(exec->vm_data.valid); _PyExecutorObject *next = exec->vm_data.links.next; - if (!exec->vm_data.warm && PyList_Append(invalidate, (PyObject *)exec) < 0) { + if (exec->vm_data.cold && PyList_Append(invalidate, (PyObject *)exec) < 0) { goto error; } else { - exec->vm_data.warm = false; + exec->vm_data.cold = true; } exec = next; diff --git a/Python/pystate.c b/Python/pystate.c index b3d375a7feabb0..ebe56b8f32c06b 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -820,7 +820,7 @@ interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate) if (cold != NULL) { interp->cold_executor = NULL; assert(cold->vm_data.valid); - assert(cold->vm_data.warm); + assert(!cold->vm_data.cold); _PyExecutor_Free(cold); } @@ -828,7 +828,7 @@ interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate) if (cold_dynamic != NULL) { interp->cold_dynamic_executor = NULL; assert(cold_dynamic->vm_data.valid); - assert(cold_dynamic->vm_data.warm); + assert(!cold_dynamic->vm_data.cold); _PyExecutor_Free(cold_dynamic); } /* We don't clear sysdict and builtins until the end of this function.