Merge remote-tracking branch 'origin/main' into HEAD

This commit is contained in:
Dino Viehland 2025-11-03 10:10:28 -08:00
commit 8d57aca95a
1284 changed files with 27792 additions and 11927 deletions

4
Python/Python-ast.c generated
View file

@ -5328,7 +5328,7 @@ ast_type_init(PyObject *self, PyObject *args, PyObject *kw)
else {
if (PyErr_WarnFormat(
PyExc_DeprecationWarning, 1,
"Field '%U' is missing from %.400s._field_types. "
"Field %R is missing from %.400s._field_types. "
"This will become an error in Python 3.15.",
name, Py_TYPE(self)->tp_name
) < 0) {
@ -5363,7 +5363,7 @@ ast_type_init(PyObject *self, PyObject *args, PyObject *kw)
// simple field (e.g., identifier)
if (PyErr_WarnFormat(
PyExc_DeprecationWarning, 1,
"%.400s.__init__ missing 1 required positional argument: '%U'. "
"%.400s.__init__ missing 1 required positional argument: %R. "
"This will become an error in Python 3.15.",
Py_TYPE(self)->tp_name, name
) < 0) {

View file

@ -171,7 +171,7 @@ _PyWarnings_InitState(PyInterpreterState *interp)
/*************************************************************************/
static int
check_matched(PyInterpreterState *interp, PyObject *obj, PyObject *arg)
check_matched(PyInterpreterState *interp, PyObject *obj, PyObject *arg, PyObject *arg2)
{
PyObject *result;
int rc;
@ -182,6 +182,9 @@ check_matched(PyInterpreterState *interp, PyObject *obj, PyObject *arg)
/* An internal plain text default filter must match exactly */
if (PyUnicode_CheckExact(obj)) {
if (arg == NULL) {
return 0;
}
int cmp_result = PyUnicode_Compare(obj, arg);
if (cmp_result == -1 && PyErr_Occurred()) {
return -1;
@ -190,10 +193,19 @@ check_matched(PyInterpreterState *interp, PyObject *obj, PyObject *arg)
}
/* Otherwise assume a regex filter and call its match() method */
result = PyObject_CallMethodOneArg(obj, &_Py_ID(match), arg);
if (arg != NULL) {
result = PyObject_CallMethodOneArg(obj, &_Py_ID(match), arg);
}
else {
PyObject *match = PyImport_ImportModuleAttrString("_py_warnings", "_match_filename");
if (match == NULL) {
return -1;
}
result = PyObject_CallFunctionObjArgs(match, obj, arg2, NULL);
Py_DECREF(match);
}
if (result == NULL)
return -1;
rc = PyObject_IsTrue(result);
Py_DECREF(result);
return rc;
@ -423,7 +435,7 @@ get_default_action(PyInterpreterState *interp)
static bool
filter_search(PyInterpreterState *interp, PyObject *category,
PyObject *text, Py_ssize_t lineno,
PyObject *module, char *list_name, PyObject *filters,
PyObject *module, PyObject *filename, char *list_name, PyObject *filters,
PyObject **item, PyObject **matched_action) {
bool result = true;
*matched_action = NULL;
@ -459,14 +471,14 @@ filter_search(PyInterpreterState *interp, PyObject *category,
break;
}
good_msg = check_matched(interp, msg, text);
good_msg = check_matched(interp, msg, text, NULL);
if (good_msg == -1) {
Py_DECREF(tmp_item);
result = false;
break;
}
good_mod = check_matched(interp, mod, module);
good_mod = check_matched(interp, mod, module, filename);
if (good_mod == -1) {
Py_DECREF(tmp_item);
result = false;
@ -504,7 +516,7 @@ filter_search(PyInterpreterState *interp, PyObject *category,
static PyObject*
get_filter(PyInterpreterState *interp, PyObject *category,
PyObject *text, Py_ssize_t lineno,
PyObject *module, PyObject **item)
PyObject *module, PyObject *filename, PyObject **item)
{
#ifdef Py_DEBUG
WarningsState *st = warnings_get_state(interp);
@ -522,7 +534,7 @@ get_filter(PyInterpreterState *interp, PyObject *category,
use_global_filters = true;
} else {
PyObject *context_action = NULL;
if (!filter_search(interp, category, text, lineno, module, "_warnings_context _filters",
if (!filter_search(interp, category, text, lineno, module, filename, "_warnings_context _filters",
context_filters, item, &context_action)) {
Py_DECREF(context_filters);
return NULL;
@ -541,7 +553,7 @@ get_filter(PyInterpreterState *interp, PyObject *category,
if (filters == NULL) {
return NULL;
}
if (!filter_search(interp, category, text, lineno, module, "filters",
if (!filter_search(interp, category, text, lineno, module, filename, "filters",
filters, item, &action)) {
return NULL;
}
@ -612,39 +624,6 @@ already_warned(PyInterpreterState *interp, PyObject *registry, PyObject *key,
return 0;
}
/* New reference. */
static PyObject *
normalize_module(PyObject *filename)
{
PyObject *module;
int kind;
const void *data;
Py_ssize_t len;
len = PyUnicode_GetLength(filename);
if (len < 0)
return NULL;
if (len == 0)
return PyUnicode_FromString("<unknown>");
kind = PyUnicode_KIND(filename);
data = PyUnicode_DATA(filename);
/* if filename.endswith(".py"): */
if (len >= 3 &&
PyUnicode_READ(kind, data, len-3) == '.' &&
PyUnicode_READ(kind, data, len-2) == 'p' &&
PyUnicode_READ(kind, data, len-1) == 'y')
{
module = PyUnicode_Substring(filename, 0, len-3);
}
else {
module = Py_NewRef(filename);
}
return module;
}
static int
update_registry(PyInterpreterState *interp, PyObject *registry, PyObject *text,
PyObject *category, int add_zero)
@ -812,15 +791,6 @@ warn_explicit(PyThreadState *tstate, PyObject *category, PyObject *message,
return NULL;
}
/* Normalize module. */
if (module == NULL) {
module = normalize_module(filename);
if (module == NULL)
return NULL;
}
else
Py_INCREF(module);
/* Normalize message. */
Py_INCREF(message); /* DECREF'ed in cleanup. */
if (PyObject_TypeCheck(message, (PyTypeObject *)PyExc_Warning)) {
@ -858,7 +828,7 @@ warn_explicit(PyThreadState *tstate, PyObject *category, PyObject *message,
/* Else this warning hasn't been generated before. */
}
action = get_filter(interp, category, text, lineno, module, &item);
action = get_filter(interp, category, text, lineno, module, filename, &item);
if (action == NULL)
goto cleanup;
@ -921,7 +891,6 @@ warn_explicit(PyThreadState *tstate, PyObject *category, PyObject *message,
Py_XDECREF(key);
Py_XDECREF(text);
Py_XDECREF(lineno_obj);
Py_DECREF(module);
Py_XDECREF(message);
return result; /* Py_None or NULL. */
}
@ -1473,28 +1442,6 @@ PyErr_WarnExplicitObject(PyObject *category, PyObject *message,
return 0;
}
/* Like PyErr_WarnExplicitObject, but automatically sets up context */
int
_PyErr_WarnExplicitObjectWithContext(PyObject *category, PyObject *message,
PyObject *filename, int lineno)
{
PyObject *unused_filename, *module, *registry;
int unused_lineno;
int stack_level = 1;
if (!setup_context(stack_level, NULL, &unused_filename, &unused_lineno,
&module, &registry)) {
return -1;
}
int rc = PyErr_WarnExplicitObject(category, message, filename, lineno,
module, registry);
Py_DECREF(unused_filename);
Py_DECREF(registry);
Py_DECREF(module);
return rc;
}
int
PyErr_WarnExplicit(PyObject *category, const char *text,
const char *filename_str, int lineno,

View file

@ -19,6 +19,7 @@ typedef struct {
int optimize;
int ff_features;
int syntax_check_only;
int enable_warnings;
_Py_c_array_t cf_finally; /* context for PEP 765 check */
int cf_finally_used;
@ -78,7 +79,7 @@ control_flow_in_finally_warning(const char *kw, stmt_ty n, _PyASTPreprocessState
static int
before_return(_PyASTPreprocessState *state, stmt_ty node_)
{
if (state->cf_finally_used > 0) {
if (state->enable_warnings && state->cf_finally_used > 0) {
ControlFlowInFinallyContext *ctx = get_cf_finally_top(state);
if (ctx->in_finally && ! ctx->in_funcdef) {
if (!control_flow_in_finally_warning("return", node_, state)) {
@ -92,7 +93,7 @@ before_return(_PyASTPreprocessState *state, stmt_ty node_)
static int
before_loop_exit(_PyASTPreprocessState *state, stmt_ty node_, const char *kw)
{
if (state->cf_finally_used > 0) {
if (state->enable_warnings && state->cf_finally_used > 0) {
ControlFlowInFinallyContext *ctx = get_cf_finally_top(state);
if (ctx->in_finally && ! ctx->in_loop) {
if (!control_flow_in_finally_warning(kw, node_, state)) {
@ -968,7 +969,7 @@ astfold_type_param(type_param_ty node_, PyArena *ctx_, _PyASTPreprocessState *st
int
_PyAST_Preprocess(mod_ty mod, PyArena *arena, PyObject *filename, int optimize,
int ff_features, int syntax_check_only)
int ff_features, int syntax_check_only, int enable_warnings)
{
_PyASTPreprocessState state;
memset(&state, 0, sizeof(_PyASTPreprocessState));
@ -976,6 +977,7 @@ _PyAST_Preprocess(mod_ty mod, PyArena *arena, PyObject *filename, int optimize,
state.optimize = optimize;
state.ff_features = ff_features;
state.syntax_check_only = syntax_check_only;
state.enable_warnings = enable_warnings;
if (_Py_CArray_Init(&state.cf_finally, sizeof(ControlFlowInFinallyContext), 20) < 0) {
return -1;
}

View file

@ -3,6 +3,7 @@
#include "Python.h"
#include "pycore_ast.h" // _PyAST_Validate()
#include "pycore_call.h" // _PyObject_CallNoArgs()
#include "pycore_cell.h" // PyCell_GetRef()
#include "pycore_ceval.h" // _PyEval_Vector()
#include "pycore_compile.h" // _PyAST_Compile()
#include "pycore_fileutils.h" // _PyFile_Flush
@ -15,8 +16,7 @@
#include "pycore_pyerrors.h" // _PyErr_NoMemory()
#include "pycore_pystate.h" // _PyThreadState_GET()
#include "pycore_pythonrun.h" // _Py_SourceAsString()
#include "pycore_tuple.h" // _PyTuple_FromArray()
#include "pycore_cell.h" // PyCell_GetRef()
#include "pycore_tuple.h" // _PyTuple_Recycle()
#include "clinic/bltinmodule.c.h"
@ -124,7 +124,7 @@ builtin___build_class__(PyObject *self, PyObject *const *args, Py_ssize_t nargs,
"__build_class__: name is not a string");
return NULL;
}
orig_bases = _PyTuple_FromArray(args + 2, nargs - 2);
orig_bases = PyTuple_FromArray(args + 2, nargs - 2);
if (orig_bases == NULL)
return NULL;
@ -796,7 +796,7 @@ builtin_chr(PyObject *module, PyObject *i)
compile as builtin_compile
source: object
filename: object(converter="PyUnicode_FSDecoder")
filename: unicode_fs_decoded
mode: str
flags: int = 0
dont_inherit: bool = False
@ -822,7 +822,7 @@ static PyObject *
builtin_compile_impl(PyObject *module, PyObject *source, PyObject *filename,
const char *mode, int flags, int dont_inherit,
int optimize, int feature_version)
/*[clinic end generated code: output=b0c09c84f116d3d7 input=cc78e20e7c7682ba]*/
/*[clinic end generated code: output=b0c09c84f116d3d7 input=8f0069edbdac381b]*/
{
PyObject *source_copy;
const char *str;
@ -940,7 +940,6 @@ builtin_compile_impl(PyObject *module, PyObject *source, PyObject *filename,
error:
result = NULL;
finally:
Py_DECREF(filename);
return result;
}
@ -1553,34 +1552,27 @@ map_next(PyObject *self)
}
Py_ssize_t nargs = 0;
for (i=0; i < niters; i++) {
for (i = 0; i < niters; i++) {
PyObject *it = PyTuple_GET_ITEM(lz->iters, i);
PyObject *val = Py_TYPE(it)->tp_iternext(it);
if (val == NULL) {
if (lz->strict) {
goto check;
}
goto exit;
goto exit_no_result;
}
stack[i] = val;
nargs++;
}
result = _PyObject_VectorcallTstate(tstate, lz->func, stack, nargs, NULL);
goto exit;
exit:
for (i=0; i < nargs; i++) {
Py_DECREF(stack[i]);
}
if (stack != small_stack) {
PyMem_Free(stack);
}
return result;
check:
if (PyErr_Occurred()) {
if (!PyErr_ExceptionMatches(PyExc_StopIteration)) {
// next() on argument i raised an exception (not StopIteration)
return NULL;
goto exit_no_result;
}
PyErr_Clear();
}
@ -1588,9 +1580,10 @@ map_next(PyObject *self)
// ValueError: map() argument 2 is shorter than argument 1
// ValueError: map() argument 3 is shorter than arguments 1-2
const char* plural = i == 1 ? " " : "s 1-";
return PyErr_Format(PyExc_ValueError,
"map() argument %d is shorter than argument%s%d",
i + 1, plural, i);
PyErr_Format(PyExc_ValueError,
"map() argument %d is shorter than argument%s%d",
i + 1, plural, i);
goto exit_no_result;
}
for (i = 1; i < niters; i++) {
PyObject *it = PyTuple_GET_ITEM(lz->iters, i);
@ -1598,21 +1591,33 @@ map_next(PyObject *self)
if (val) {
Py_DECREF(val);
const char* plural = i == 1 ? " " : "s 1-";
return PyErr_Format(PyExc_ValueError,
"map() argument %d is longer than argument%s%d",
i + 1, plural, i);
PyErr_Format(PyExc_ValueError,
"map() argument %d is longer than argument%s%d",
i + 1, plural, i);
goto exit_no_result;
}
if (PyErr_Occurred()) {
if (!PyErr_ExceptionMatches(PyExc_StopIteration)) {
// next() on argument i raised an exception (not StopIteration)
return NULL;
goto exit_no_result;
}
PyErr_Clear();
}
// Argument i is exhausted. So far so good...
}
// All arguments are exhausted. Success!
goto exit;
exit_no_result:
assert(result == NULL);
exit:
for (i = 0; i < nargs; i++) {
Py_DECREF(stack[i]);
}
if (stack != small_stack) {
PyMem_Free(stack);
}
return result;
}
static PyObject *

View file

@ -11,7 +11,6 @@
#include "pycore_audit.h" // _PySys_Audit()
#include "pycore_backoff.h"
#include "pycore_cell.h" // PyCell_GetRef()
#include "pycore_ceval.h"
#include "pycore_code.h"
#include "pycore_emscripten_signal.h" // _Py_CHECK_EMSCRIPTEN_SIGNALS
#include "pycore_function.h"
@ -5415,10 +5414,6 @@ dummy_func(
tier2 op(_MAKE_WARM, (--)) {
current_executor->vm_data.warm = true;
// It's okay if this ends up going negative.
if (--tstate->interp->trace_run_counter == 0) {
_Py_set_eval_breaker_bit(tstate, _PY_EVAL_JIT_INVALIDATE_COLD_BIT);
}
}
tier2 op(_FATAL_ERROR, (--)) {

View file

@ -161,6 +161,10 @@ dump_item(_PyStackRef item)
printf("<NULL>");
return;
}
if (PyStackRef_IsMalformed(item)) {
printf("<INVALID>");
return;
}
if (PyStackRef_IsTaggedInt(item)) {
printf("%" PRId64, (int64_t)PyStackRef_UntagInt(item));
return;
@ -439,31 +443,26 @@ int pthread_attr_destroy(pthread_attr_t *a)
#endif
void
_Py_InitializeRecursionLimits(PyThreadState *tstate)
static void
hardware_stack_limits(uintptr_t *top, uintptr_t *base)
{
_PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate;
#ifdef WIN32
ULONG_PTR low, high;
GetCurrentThreadStackLimits(&low, &high);
_tstate->c_stack_top = (uintptr_t)high;
*top = (uintptr_t)high;
ULONG guarantee = 0;
SetThreadStackGuarantee(&guarantee);
_tstate->c_stack_hard_limit = ((uintptr_t)low) + guarantee + _PyOS_STACK_MARGIN_BYTES;
_tstate->c_stack_soft_limit = _tstate->c_stack_hard_limit + _PyOS_STACK_MARGIN_BYTES;
*base = (uintptr_t)low + guarantee;
#elif defined(__APPLE__)
pthread_t this_thread = pthread_self();
void *stack_addr = pthread_get_stackaddr_np(this_thread); // top of the stack
size_t stack_size = pthread_get_stacksize_np(this_thread);
_tstate->c_stack_top = (uintptr_t)stack_addr;
_tstate->c_stack_hard_limit = _tstate->c_stack_top - stack_size;
_tstate->c_stack_soft_limit = _tstate->c_stack_hard_limit + _PyOS_STACK_MARGIN_BYTES;
*top = (uintptr_t)stack_addr;
*base = ((uintptr_t)stack_addr) - stack_size;
#else
uintptr_t here_addr = _Py_get_machine_stack_pointer();
/// XXX musl supports HAVE_PTHRED_GETATTR_NP, but the resulting stack size
/// (on alpine at least) is much smaller than expected and imposes undue limits
/// compared to the old stack size estimation. (We assume musl is not glibc.)
/// XXX musl supports HAVE_PTHRED_GETATTR_NP, but the resulting stack size
/// (on alpine at least) is much smaller than expected and imposes undue limits
/// compared to the old stack size estimation. (We assume musl is not glibc.)
# if defined(HAVE_PTHREAD_GETATTR_NP) && !defined(_AIX) && \
!defined(__NetBSD__) && (defined(__GLIBC__) || !defined(__linux__))
size_t stack_size, guard_size;
@ -476,26 +475,35 @@ _Py_InitializeRecursionLimits(PyThreadState *tstate)
err |= pthread_attr_destroy(&attr);
}
if (err == 0) {
uintptr_t base = ((uintptr_t)stack_addr) + guard_size;
_tstate->c_stack_top = base + stack_size;
#ifdef _Py_THREAD_SANITIZER
// Thread sanitizer crashes if we use a bit more than half the stack.
_tstate->c_stack_soft_limit = base + (stack_size / 2);
#else
_tstate->c_stack_soft_limit = base + _PyOS_STACK_MARGIN_BYTES * 2;
#endif
_tstate->c_stack_hard_limit = base + _PyOS_STACK_MARGIN_BYTES;
assert(_tstate->c_stack_soft_limit < here_addr);
assert(here_addr < _tstate->c_stack_top);
*base = ((uintptr_t)stack_addr) + guard_size;
*top = (uintptr_t)stack_addr + stack_size;
return;
}
# endif
_tstate->c_stack_top = _Py_SIZE_ROUND_UP(here_addr, 4096);
_tstate->c_stack_soft_limit = _tstate->c_stack_top - Py_C_STACK_SIZE;
_tstate->c_stack_hard_limit = _tstate->c_stack_top - (Py_C_STACK_SIZE + _PyOS_STACK_MARGIN_BYTES);
uintptr_t here_addr = _Py_get_machine_stack_pointer();
uintptr_t top_addr = _Py_SIZE_ROUND_UP(here_addr, 4096);
*top = top_addr;
*base = top_addr - Py_C_STACK_SIZE;
#endif
}
void
_Py_InitializeRecursionLimits(PyThreadState *tstate)
{
uintptr_t top;
uintptr_t base;
hardware_stack_limits(&top, &base);
#ifdef _Py_THREAD_SANITIZER
// Thread sanitizer crashes if we use more than half the stack.
uintptr_t stacksize = top - base;
base += stacksize/2;
#endif
_PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate;
_tstate->c_stack_top = top;
_tstate->c_stack_hard_limit = base + _PyOS_STACK_MARGIN_BYTES;
_tstate->c_stack_soft_limit = base + _PyOS_STACK_MARGIN_BYTES * 2;
}
/* The function _Py_EnterRecursiveCallTstate() only calls _Py_CheckRecursiveCall()
if the recursion_depth reaches recursion_limit. */
int
@ -2008,7 +2016,7 @@ PyEval_EvalCodeEx(PyObject *_co, PyObject *globals, PyObject *locals,
{
PyThreadState *tstate = _PyThreadState_GET();
PyObject *res = NULL;
PyObject *defaults = _PyTuple_FromArray(defs, defcount);
PyObject *defaults = PyTuple_FromArray(defs, defcount);
if (defaults == NULL) {
return NULL;
}
@ -2459,6 +2467,10 @@ monitor_unwind(PyThreadState *tstate,
do_monitor_exc(tstate, frame, instr, PY_MONITORING_EVENT_PY_UNWIND);
}
bool
_PyEval_NoToolsForUnwind(PyThreadState *tstate) {
return no_tools_for_global_event(tstate, PY_MONITORING_EVENT_PY_UNWIND);
}
static int
monitor_handled(PyThreadState *tstate,
@ -3412,17 +3424,9 @@ int
_Py_Check_ArgsIterable(PyThreadState *tstate, PyObject *func, PyObject *args)
{
if (Py_TYPE(args)->tp_iter == NULL && !PySequence_Check(args)) {
/* _Py_Check_ArgsIterable() may be called with a live exception:
* clear it to prevent calling _PyObject_FunctionStr() with an
* exception set. */
_PyErr_Clear(tstate);
PyObject *funcstr = _PyObject_FunctionStr(func);
if (funcstr != NULL) {
_PyErr_Format(tstate, PyExc_TypeError,
"%U argument after * must be an iterable, not %.200s",
funcstr, Py_TYPE(args)->tp_name);
Py_DECREF(funcstr);
}
_PyErr_Format(tstate, PyExc_TypeError,
"Value after * must be an iterable, not %.200s",
Py_TYPE(args)->tp_name);
return -1;
}
return 0;
@ -3438,15 +3442,10 @@ _PyEval_FormatKwargsError(PyThreadState *tstate, PyObject *func, PyObject *kwarg
* is not a mapping.
*/
if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) {
_PyErr_Clear(tstate);
PyObject *funcstr = _PyObject_FunctionStr(func);
if (funcstr != NULL) {
_PyErr_Format(
tstate, PyExc_TypeError,
"%U argument after ** must be a mapping, not %.200s",
funcstr, Py_TYPE(kwargs)->tp_name);
Py_DECREF(funcstr);
}
_PyErr_Format(
tstate, PyExc_TypeError,
"Value after ** must be a mapping, not %.200s",
Py_TYPE(kwargs)->tp_name);
}
else if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) {
PyObject *exc = _PyErr_GetRaisedException(tstate);

View file

@ -1398,7 +1398,7 @@ _Py_HandlePending(PyThreadState *tstate)
if ((breaker & _PY_EVAL_JIT_INVALIDATE_COLD_BIT) != 0) {
_Py_unset_eval_breaker_bit(tstate, _PY_EVAL_JIT_INVALIDATE_COLD_BIT);
_Py_Executors_InvalidateCold(tstate->interp);
tstate->interp->trace_run_counter = JIT_CLEANUP_THRESHOLD;
tstate->interp->executor_creation_counter = JIT_CLEANUP_THRESHOLD;
}
/* GIL drop request */

View file

@ -79,6 +79,14 @@
#endif
#if _Py_TAIL_CALL_INTERP
# if defined(__clang__) || defined(__GNUC__)
# if !_Py__has_attribute(preserve_none) || !_Py__has_attribute(musttail)
# error "This compiler does not have support for efficient tail calling."
# endif
# elif defined(_MSC_VER) && (_MSC_VER < 1950)
# error "You need at least VS 2026 / PlatformToolset v145 for tail calling."
# endif
// Note: [[clang::musttail]] works for GCC 15, but not __attribute__((musttail)) at the moment.
# define Py_MUSTTAIL [[clang::musttail]]
# define Py_PRESERVE_NONE_CC __attribute__((preserve_none))
@ -358,7 +366,9 @@ do { \
frame = tstate->current_frame; \
stack_pointer = _PyFrame_GetStackPointer(frame); \
if (next_instr == NULL) { \
next_instr = frame->instr_ptr; \
/* gh-140104: The exception handler expects frame->instr_ptr
to after this_instr, not this_instr! */ \
next_instr = frame->instr_ptr + 1; \
JUMP_TO_LABEL(error); \
} \
DISPATCH(); \

View file

@ -391,7 +391,7 @@ builtin_compile(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObj
PyObject *argsbuf[7];
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 3;
PyObject *source;
PyObject *filename;
PyObject *filename = NULL;
const char *mode;
int flags = 0;
int dont_inherit = 0;
@ -462,6 +462,9 @@ skip_optional_kwonly:
return_value = builtin_compile_impl(module, source, filename, mode, flags, dont_inherit, optimize, feature_version);
exit:
/* Cleanup for filename */
Py_XDECREF(filename);
return return_value;
}

View file

@ -7,7 +7,6 @@ preserve
# include "pycore_runtime.h" // _Py_ID()
#endif
#include "pycore_modsupport.h" // _PyArg_UnpackKeywords()
#include "pycore_tuple.h" // _PyTuple_FromArray()
PyDoc_STRVAR(sys_addaudithook__doc__,
"addaudithook($module, /, hook)\n"
@ -102,7 +101,7 @@ sys_audit(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
PyErr_SetString(PyExc_ValueError, "embedded null character");
goto exit;
}
__clinic_args = _PyTuple_FromArray(args + 1, nargs - 1);
__clinic_args = PyTuple_FromArray(args + 1, nargs - 1);
if (__clinic_args == NULL) {
goto exit;
}

View file

@ -83,8 +83,6 @@ PyCodec_Unregister(PyObject *search_function)
return 0;
}
extern int _Py_normalize_encoding(const char *, char *, size_t);
/* Convert a string to a normalized Python string: all ASCII letters are
converted to lower case, spaces are replaced with hyphens. */

View file

@ -103,6 +103,7 @@ typedef struct _PyCompiler {
bool c_save_nested_seqs; /* if true, construct recursive instruction sequences
* (including instructions for nested code objects)
*/
int c_disable_warning;
} compiler;
static int
@ -135,7 +136,7 @@ compiler_setup(compiler *c, mod_ty mod, PyObject *filename,
c->c_optimize = (optimize == -1) ? _Py_GetConfig()->optimization_level : optimize;
c->c_save_nested_seqs = false;
if (!_PyAST_Preprocess(mod, arena, filename, c->c_optimize, merged, 0)) {
if (!_PyAST_Preprocess(mod, arena, filename, c->c_optimize, merged, 0, 1)) {
return ERROR;
}
c->c_st = _PySymtable_Build(mod, filename, &c->c_future);
@ -765,6 +766,9 @@ _PyCompile_PushFBlock(compiler *c, location loc,
f->fb_loc = loc;
f->fb_exit = exit;
f->fb_datum = datum;
if (t == COMPILE_FBLOCK_FINALLY_END) {
c->c_disable_warning++;
}
return SUCCESS;
}
@ -776,6 +780,9 @@ _PyCompile_PopFBlock(compiler *c, fblocktype t, jump_target_label block_label)
u->u_nfblocks--;
assert(u->u_fblock[u->u_nfblocks].fb_type == t);
assert(SAME_JUMP_TARGET_LABEL(u->u_fblock[u->u_nfblocks].fb_block, block_label));
if (t == COMPILE_FBLOCK_FINALLY_END) {
c->c_disable_warning--;
}
}
fblockinfo *
@ -1223,6 +1230,9 @@ _PyCompile_Error(compiler *c, location loc, const char *format, ...)
int
_PyCompile_Warn(compiler *c, location loc, const char *format, ...)
{
if (c->c_disable_warning) {
return 0;
}
va_list vargs;
va_start(vargs, format);
PyObject *msg = PyUnicode_FromFormatV(format, vargs);
@ -1512,7 +1522,7 @@ _PyCompile_AstPreprocess(mod_ty mod, PyObject *filename, PyCompilerFlags *cf,
if (optimize == -1) {
optimize = _Py_GetConfig()->optimization_level;
}
if (!_PyAST_Preprocess(mod, arena, filename, optimize, flags, no_const_folding)) {
if (!_PyAST_Preprocess(mod, arena, filename, optimize, flags, no_const_folding, 0)) {
return -1;
}
return 0;

View file

@ -1153,8 +1153,8 @@ _release_xid_data(_PyXIData_t *xidata, int rawfree)
{
PyObject *exc = PyErr_GetRaisedException();
int res = rawfree
? _PyXIData_Release(xidata)
: _PyXIData_ReleaseAndRawFree(xidata);
? _PyXIData_ReleaseAndRawFree(xidata)
: _PyXIData_Release(xidata);
if (res < 0) {
/* The owning interpreter is already destroyed. */
_PyXIData_Clear(NULL, xidata);
@ -1805,6 +1805,15 @@ _PyXI_InitFailureUTF8(_PyXI_failure *failure,
int
_PyXI_InitFailure(_PyXI_failure *failure, _PyXI_errcode code, PyObject *obj)
{
*failure = (_PyXI_failure){
.code = code,
.msg = NULL,
.msg_owned = 0,
};
if (obj == NULL) {
return 0;
}
PyObject *msgobj = PyObject_Str(obj);
if (msgobj == NULL) {
return -1;
@ -1813,7 +1822,7 @@ _PyXI_InitFailure(_PyXI_failure *failure, _PyXI_errcode code, PyObject *obj)
// That happens automatically in _capture_current_exception().
const char *msg = _copy_string_obj_raw(msgobj, NULL);
Py_DECREF(msgobj);
if (PyErr_Occurred()) {
if (msg == NULL) {
return -1;
}
*failure = (_PyXI_failure){

View file

@ -1962,8 +1962,8 @@ int
_PyErr_EmitSyntaxWarning(PyObject *msg, PyObject *filename, int lineno, int col_offset,
int end_lineno, int end_col_offset)
{
if (_PyErr_WarnExplicitObjectWithContext(PyExc_SyntaxWarning, msg,
filename, lineno) < 0)
if (PyErr_WarnExplicitObject(PyExc_SyntaxWarning, msg,
filename, lineno, NULL, NULL) < 0)
{
if (PyErr_ExceptionMatches(PyExc_SyntaxWarning)) {
/* Replace the SyntaxWarning exception with a SyntaxError

View file

@ -7464,9 +7464,6 @@
case _MAKE_WARM: {
current_executor->vm_data.warm = true;
if (--tstate->interp->trace_run_counter == 0) {
_Py_set_eval_breaker_bit(tstate, _PY_EVAL_JIT_INVALIDATE_COLD_BIT);
}
break;
}

View file

@ -2,6 +2,7 @@
#include "pycore_fileutils.h" // fileutils definitions
#include "pycore_runtime.h" // _PyRuntime
#include "pycore_pystate.h" // _Py_AssertHoldsTstate()
#include "pycore_unicodeobject.h" // _Py_MAX_UNICODE
#include "osdefs.h" // SEP
#include <stdlib.h> // mbstowcs()
@ -50,9 +51,6 @@ extern int winerror_to_errno(int);
int _Py_open_cloexec_works = -1;
#endif
// The value must be the same in unicodeobject.c.
#define MAX_UNICODE 0x10ffff
// mbstowcs() and mbrtowc() errors
static const size_t DECODE_ERROR = ((size_t)-1);
#ifdef HAVE_MBRTOWC
@ -123,7 +121,7 @@ is_valid_wide_char(wchar_t ch)
{
#ifdef HAVE_NON_UNICODE_WCHAR_T_REPRESENTATION
/* Oracle Solaris doesn't use Unicode code points as wchar_t encoding
for non-Unicode locales, which makes values higher than MAX_UNICODE
for non-Unicode locales, which makes values higher than _Py_MAX_UNICODE
possibly valid. */
return 1;
#endif
@ -132,7 +130,7 @@ is_valid_wide_char(wchar_t ch)
return 0;
}
#if SIZEOF_WCHAR_T > 2
if (ch > MAX_UNICODE) {
if (ch > _Py_MAX_UNICODE) {
// bpo-35883: Reject characters outside [U+0000; U+10ffff] range.
// The glibc mbstowcs() UTF-8 decoder does not respect the RFC 3629,
// it creates characters outside the [U+0000; U+10ffff] range:
@ -180,7 +178,7 @@ _Py_mbrtowc(wchar_t *pwc, const char *str, size_t len, mbstate_t *pmbs)
#define USE_FORCE_ASCII
extern int _Py_normalize_encoding(const char *, char *, size_t);
extern int _Py_normalize_encoding(const char *, char *, size_t, int);
/* Workaround FreeBSD and OpenIndiana locale encoding issue with the C locale
and POSIX locale. nl_langinfo(CODESET) announces an alias of the
@ -231,7 +229,7 @@ check_force_ascii(void)
}
char encoding[20]; /* longest name: "iso_646.irv_1991\0" */
if (!_Py_normalize_encoding(codeset, encoding, sizeof(encoding))) {
if (!_Py_normalize_encoding(codeset, encoding, sizeof(encoding), 1)) {
goto error;
}

File diff suppressed because it is too large Load diff

View file

@ -1639,7 +1639,7 @@ assess_work_to_do(GCState *gcstate)
scale_factor = 2;
}
intptr_t new_objects = gcstate->young.count;
intptr_t max_heap_fraction = new_objects*3/2;
intptr_t max_heap_fraction = new_objects*2;
intptr_t heap_fraction = gcstate->heap_size / SCAN_RATE_DIVISOR / scale_factor;
if (heap_fraction > max_heap_fraction) {
heap_fraction = max_heap_fraction;
@ -1654,6 +1654,9 @@ gc_collect_increment(PyThreadState *tstate, struct gc_collection_stats *stats)
GC_STAT_ADD(1, collections, 1);
GCState *gcstate = &tstate->interp->gc;
gcstate->work_to_do += assess_work_to_do(gcstate);
if (gcstate->work_to_do < 0) {
return;
}
untrack_tuples(&gcstate->young.head);
if (gcstate->phase == GC_PHASE_MARK) {
Py_ssize_t objects_marked = mark_at_start(tstate);
@ -1696,7 +1699,6 @@ gc_collect_increment(PyThreadState *tstate, struct gc_collection_stats *stats)
gc_collect_region(tstate, &increment, &survivors, stats);
gc_list_merge(&survivors, visited);
assert(gc_list_is_empty(&increment));
gcstate->work_to_do += gcstate->heap_size / SCAN_RATE_DIVISOR / scale_factor;
gcstate->work_to_do -= increment_size;
add_stats(gcstate, 1, stats);
@ -2077,8 +2079,10 @@ _PyGC_Collect(PyThreadState *tstate, int generation, _PyGC_Reason reason)
if (reason != _Py_GC_REASON_SHUTDOWN) {
invoke_gc_callback(gcstate, "start", generation, &stats);
}
PyTime_t t1;
if (gcstate->debug & _PyGC_DEBUG_STATS) {
PySys_WriteStderr("gc: collecting generation %d...\n", generation);
(void)PyTime_PerfCounterRaw(&t1);
show_stats_each_generations(gcstate);
}
if (PyDTrace_GC_START_ENABLED()) {
@ -2115,6 +2119,17 @@ _PyGC_Collect(PyThreadState *tstate, int generation, _PyGC_Reason reason)
#endif
validate_spaces(gcstate);
_Py_atomic_store_int(&gcstate->collecting, 0);
if (gcstate->debug & _PyGC_DEBUG_STATS) {
PyTime_t t2;
(void)PyTime_PerfCounterRaw(&t2);
double d = PyTime_AsSecondsDouble(t2 - t1);
PySys_WriteStderr(
"gc: done, %zd unreachable, %zd uncollectable, %.4fs elapsed\n",
stats.collected + stats.uncollectable, stats.uncollectable, d
);
}
return stats.uncollectable + stats.collected;
}
@ -2286,21 +2301,11 @@ _Py_ScheduleGC(PyThreadState *tstate)
}
void
_PyObject_GC_Link(PyObject *op)
_Py_TriggerGC(struct _gc_runtime_state *gcstate)
{
PyGC_Head *gc = AS_GC(op);
// gc must be correctly aligned
_PyObject_ASSERT(op, ((uintptr_t)gc & (sizeof(uintptr_t)-1)) == 0);
PyThreadState *tstate = _PyThreadState_GET();
GCState *gcstate = &tstate->interp->gc;
gc->_gc_next = 0;
gc->_gc_prev = 0;
gcstate->young.count++; /* number of allocated GC objects */
gcstate->heap_size++;
if (gcstate->young.count > gcstate->young.threshold &&
gcstate->enabled &&
gcstate->young.threshold &&
if (gcstate->enabled &&
gcstate->young.threshold != 0 &&
!_Py_atomic_load_int_relaxed(&gcstate->collecting) &&
!_PyErr_Occurred(tstate))
{
@ -2308,6 +2313,17 @@ _PyObject_GC_Link(PyObject *op)
}
}
void
_PyObject_GC_Link(PyObject *op)
{
PyGC_Head *gc = AS_GC(op);
// gc must be correctly aligned
_PyObject_ASSERT(op, ((uintptr_t)gc & (sizeof(uintptr_t)-1)) == 0);
gc->_gc_next = 0;
gc->_gc_prev = 0;
}
void
_Py_RunGC(PyThreadState *tstate)
{
@ -2414,6 +2430,11 @@ PyObject_GC_Del(void *op)
PyGC_Head *g = AS_GC(op);
if (_PyObject_GC_IS_TRACKED(op)) {
gc_list_remove(g);
GCState *gcstate = get_gc_state();
if (gcstate->young.count > 0) {
gcstate->young.count--;
}
gcstate->heap_size--;
#ifdef Py_DEBUG
PyObject *exc = PyErr_GetRaisedException();
if (PyErr_WarnExplicitFormat(PyExc_ResourceWarning, "gc", 0,
@ -2427,11 +2448,6 @@ PyObject_GC_Del(void *op)
PyErr_SetRaisedException(exc);
#endif
}
GCState *gcstate = get_gc_state();
if (gcstate->young.count > 0) {
gcstate->young.count--;
}
gcstate->heap_size--;
PyObject_Free(((char *)op)-presize);
}

View file

@ -797,18 +797,13 @@ _PyImport_ClearModulesByIndex(PyInterpreterState *interp)
substitute this (if the name actually matches).
*/
#ifdef HAVE_THREAD_LOCAL
_Py_thread_local const char *pkgcontext = NULL;
# undef PKGCONTEXT
# define PKGCONTEXT pkgcontext
#endif
const char *
_PyImport_ResolveNameWithPackageContext(const char *name)
{
#ifndef HAVE_THREAD_LOCAL
PyMutex_Lock(&EXTENSIONS.mutex);
#endif
if (PKGCONTEXT != NULL) {
const char *p = strrchr(PKGCONTEXT, '.');
if (p != NULL && strcmp(name, p+1) == 0) {
@ -816,23 +811,14 @@ _PyImport_ResolveNameWithPackageContext(const char *name)
PKGCONTEXT = NULL;
}
}
#ifndef HAVE_THREAD_LOCAL
PyMutex_Unlock(&EXTENSIONS.mutex);
#endif
return name;
}
const char *
_PyImport_SwapPackageContext(const char *newcontext)
{
#ifndef HAVE_THREAD_LOCAL
PyMutex_Lock(&EXTENSIONS.mutex);
#endif
const char *oldcontext = PKGCONTEXT;
PKGCONTEXT = newcontext;
#ifndef HAVE_THREAD_LOCAL
PyMutex_Unlock(&EXTENSIONS.mutex);
#endif
return oldcontext;
}
@ -2373,6 +2359,7 @@ create_builtin(PyThreadState *tstate, PyObject *name, PyObject *spec)
for (struct _inittab *p = INITTAB; p->name != NULL; p++) {
if (_PyUnicode_EqualToASCIIString(info.name, p->name)) {
found = p;
break;
}
}
if (found == NULL) {

View file

@ -9,7 +9,6 @@
#include "pycore_intrinsics.h" // INTRINSIC_PRINT
#include "pycore_pyerrors.h" // _PyErr_SetString()
#include "pycore_runtime.h" // _Py_ID()
#include "pycore_tuple.h" // _PyTuple_FromArray()
#include "pycore_typevarobject.h" // _Py_make_typevar()
#include "pycore_unicodeobject.h" // _PyUnicode_FromASCII()
@ -192,7 +191,7 @@ static PyObject *
list_to_tuple(PyThreadState* unused, PyObject *v)
{
assert(PyList_Check(v));
return _PyTuple_FromArray(((PyListObject *)v)->ob_item, Py_SIZE(v));
return PyTuple_FromArray(((PyListObject *)v)->ob_item, Py_SIZE(v));
}
static PyObject *

View file

@ -157,21 +157,29 @@ set_bits(uint32_t *loc, uint8_t loc_start, uint64_t value, uint8_t value_start,
uint8_t width)
{
assert(loc_start + width <= 32);
uint32_t temp_val;
// Use memcpy to safely read the value, avoiding potential alignment
// issues and strict aliasing violations.
memcpy(&temp_val, loc, sizeof(temp_val));
// Clear the bits we're about to patch:
*loc &= ~(((1ULL << width) - 1) << loc_start);
assert(get_bits(*loc, loc_start, width) == 0);
temp_val &= ~(((1ULL << width) - 1) << loc_start);
assert(get_bits(temp_val, loc_start, width) == 0);
// Patch the bits:
*loc |= get_bits(value, value_start, width) << loc_start;
assert(get_bits(*loc, loc_start, width) == get_bits(value, value_start, width));
temp_val |= get_bits(value, value_start, width) << loc_start;
assert(get_bits(temp_val, loc_start, width) == get_bits(value, value_start, width));
// Safely write the modified value back to memory.
memcpy(loc, &temp_val, sizeof(temp_val));
}
// See https://developer.arm.com/documentation/ddi0602/2023-09/Base-Instructions
// for instruction encodings:
#define IS_AARCH64_ADD_OR_SUB(I) (((I) & 0x11C00000) == 0x11000000)
#define IS_AARCH64_ADRP(I) (((I) & 0x9F000000) == 0x90000000)
#define IS_AARCH64_BRANCH(I) (((I) & 0x7C000000) == 0x14000000)
#define IS_AARCH64_LDR_OR_STR(I) (((I) & 0x3B000000) == 0x39000000)
#define IS_AARCH64_MOV(I) (((I) & 0x9F800000) == 0x92800000)
#define IS_AARCH64_ADD_OR_SUB(I) (((I) & 0x11C00000) == 0x11000000)
#define IS_AARCH64_ADRP(I) (((I) & 0x9F000000) == 0x90000000)
#define IS_AARCH64_BRANCH(I) (((I) & 0x7C000000) == 0x14000000)
#define IS_AARCH64_BRANCH_COND(I) (((I) & 0x7C000000) == 0x54000000)
#define IS_AARCH64_TEST_AND_BRANCH(I) (((I) & 0x7E000000) == 0x36000000)
#define IS_AARCH64_LDR_OR_STR(I) (((I) & 0x3B000000) == 0x39000000)
#define IS_AARCH64_MOV(I) (((I) & 0x9F800000) == 0x92800000)
// LLD is a great reference for performing relocations... just keep in
// mind that Tools/jit/build.py does filtering and preprocessing for us!
@ -202,30 +210,29 @@ set_bits(uint32_t *loc, uint8_t loc_start, uint64_t value, uint8_t value_start,
void
patch_32(unsigned char *location, uint64_t value)
{
uint32_t *loc32 = (uint32_t *)location;
// Check that we're not out of range of 32 unsigned bits:
assert(value < (1ULL << 32));
*loc32 = (uint32_t)value;
uint32_t final_value = (uint32_t)value;
memcpy(location, &final_value, sizeof(final_value));
}
// 32-bit relative address.
void
patch_32r(unsigned char *location, uint64_t value)
{
uint32_t *loc32 = (uint32_t *)location;
value -= (uintptr_t)location;
// Check that we're not out of range of 32 signed bits:
assert((int64_t)value >= -(1LL << 31));
assert((int64_t)value < (1LL << 31));
*loc32 = (uint32_t)value;
uint32_t final_value = (uint32_t)value;
memcpy(location, &final_value, sizeof(final_value));
}
// 64-bit absolute address.
void
patch_64(unsigned char *location, uint64_t value)
{
uint64_t *loc64 = (uint64_t *)location;
*loc64 = value;
memcpy(location, &value, sizeof(value));
}
// 12-bit low part of an absolute address. Pairs nicely with patch_aarch64_21r
@ -332,6 +339,21 @@ patch_aarch64_21rx(unsigned char *location, uint64_t value)
patch_aarch64_21r(location, value);
}
// 21-bit relative branch.
void
patch_aarch64_19r(unsigned char *location, uint64_t value)
{
uint32_t *loc32 = (uint32_t *)location;
assert(IS_AARCH64_BRANCH_COND(*loc32));
value -= (uintptr_t)location;
// Check that we're not out of range of 21 signed bits:
assert((int64_t)value >= -(1 << 20));
assert((int64_t)value < (1 << 20));
// Since instructions are 4-byte aligned, only use 19 bits:
assert(get_bits(value, 0, 2) == 0);
set_bits(loc32, 5, value, 2, 19);
}
// 28-bit relative branch.
void
patch_aarch64_26r(unsigned char *location, uint64_t value)
@ -393,7 +415,10 @@ patch_x86_64_32rx(unsigned char *location, uint64_t value)
{
uint8_t *loc8 = (uint8_t *)location;
// Try to relax the GOT load into an immediate value:
uint64_t relaxed = *(uint64_t *)(value + 4) - 4;
uint64_t relaxed;
memcpy(&relaxed, (void *)(value + 4), sizeof(relaxed));
relaxed -= 4;
if ((int64_t)relaxed - (int64_t)location >= -(1LL << 31) &&
(int64_t)relaxed - (int64_t)location + 1 < (1LL << 31))
{
@ -419,17 +444,42 @@ patch_x86_64_32rx(unsigned char *location, uint64_t value)
}
void patch_aarch64_trampoline(unsigned char *location, int ordinal, jit_state *state);
void patch_x86_64_trampoline(unsigned char *location, int ordinal, jit_state *state);
#include "jit_stencils.h"
#if defined(__aarch64__) || defined(_M_ARM64)
#define TRAMPOLINE_SIZE 16
#define DATA_ALIGN 8
#elif defined(__x86_64__) && defined(__APPLE__)
// LLVM 20 on macOS x86_64 debug builds: GOT entries may exceed ±2GB PC-relative
// range.
#define TRAMPOLINE_SIZE 16 // 14 bytes + 2 bytes padding for alignment
#define DATA_ALIGN 8
#else
#define TRAMPOLINE_SIZE 0
#define DATA_ALIGN 1
#endif
// Get the trampoline memory location for a given symbol ordinal.
static unsigned char *
get_trampoline_slot(int ordinal, jit_state *state)
{
const uint32_t symbol_mask = 1 << (ordinal % 32);
const uint32_t trampoline_mask = state->trampolines.mask[ordinal / 32];
assert(symbol_mask & trampoline_mask);
// Count the number of set bits in the trampoline mask lower than ordinal
int index = _Py_popcount32(trampoline_mask & (symbol_mask - 1));
for (int i = 0; i < ordinal / 32; i++) {
index += _Py_popcount32(state->trampolines.mask[i]);
}
unsigned char *trampoline = state->trampolines.mem + index * TRAMPOLINE_SIZE;
assert((size_t)(index + 1) * TRAMPOLINE_SIZE <= state->trampolines.size);
return trampoline;
}
// Generate and patch AArch64 trampolines. The symbols to jump to are stored
// in the jit_stencils.h in the symbols_map.
void
@ -446,20 +496,8 @@ patch_aarch64_trampoline(unsigned char *location, int ordinal, jit_state *state)
return;
}
// Masking is done modulo 32 as the mask is stored as an array of uint32_t
const uint32_t symbol_mask = 1 << (ordinal % 32);
const uint32_t trampoline_mask = state->trampolines.mask[ordinal / 32];
assert(symbol_mask & trampoline_mask);
// Count the number of set bits in the trampoline mask lower than ordinal,
// this gives the index into the array of trampolines.
int index = _Py_popcount32(trampoline_mask & (symbol_mask - 1));
for (int i = 0; i < ordinal / 32; i++) {
index += _Py_popcount32(state->trampolines.mask[i]);
}
uint32_t *p = (uint32_t*)(state->trampolines.mem + index * TRAMPOLINE_SIZE);
assert((size_t)(index + 1) * TRAMPOLINE_SIZE <= state->trampolines.size);
// Out of range - need a trampoline
uint32_t *p = (uint32_t *)get_trampoline_slot(ordinal, state);
/* Generate the trampoline
@ -476,6 +514,37 @@ patch_aarch64_trampoline(unsigned char *location, int ordinal, jit_state *state)
patch_aarch64_26r(location, (uintptr_t)p);
}
// Generate and patch x86_64 trampolines.
void
patch_x86_64_trampoline(unsigned char *location, int ordinal, jit_state *state)
{
uint64_t value = (uintptr_t)symbols_map[ordinal];
int64_t range = (int64_t)value - 4 - (int64_t)location;
// If we are in range of 32 signed bits, we can patch directly
if (range >= -(1LL << 31) && range < (1LL << 31)) {
patch_32r(location, value - 4);
return;
}
// Out of range - need a trampoline
unsigned char *trampoline = get_trampoline_slot(ordinal, state);
/* Generate the trampoline (14 bytes, padded to 16):
0: ff 25 00 00 00 00 jmp *(%rip)
6: XX XX XX XX XX XX XX XX (64-bit target address)
Reference: https://wiki.osdev.org/X86-64_Instruction_Encoding#FF (JMP r/m64)
*/
trampoline[0] = 0xFF;
trampoline[1] = 0x25;
memset(trampoline + 2, 0, 4);
memcpy(trampoline + 6, &value, 8);
// Patch the call site to call the trampoline instead
patch_32r(location, (uintptr_t)trampoline - 4);
}
static void
combine_symbol_mask(const symbol_mask src, symbol_mask dest)
{

View file

@ -11,6 +11,7 @@
#include "pycore_code.h" // _PyCode_New()
#include "pycore_hashtable.h" // _Py_hashtable_t
#include "pycore_long.h" // _PyLong_IsZero()
#include "pycore_object.h" // _PyObject_IsUniquelyReferenced
#include "pycore_pystate.h" // _PyInterpreterState_GET()
#include "pycore_setobject.h" // _PySet_NextEntryRef()
#include "pycore_unicodeobject.h" // _PyUnicode_InternImmortal()
@ -388,7 +389,7 @@ w_ref(PyObject *v, char *flag, WFILE *p)
* But we use TYPE_REF always for interned string, to PYC file stable
* as possible.
*/
if (Py_REFCNT(v) == 1 &&
if (_PyObject_IsUniquelyReferenced(v) &&
!(PyUnicode_CheckExact(v) && PyUnicode_CHECK_INTERNED(v))) {
return 0;
}

View file

@ -6,6 +6,7 @@
#include "pycore_interp.h"
#include "pycore_backoff.h"
#include "pycore_bitutils.h" // _Py_popcount32()
#include "pycore_ceval.h" // _Py_set_eval_breaker_bit
#include "pycore_code.h" // _Py_GetBaseCodeUnit
#include "pycore_function.h" // _PyFunction_LookupByVersion()
#include "pycore_interpframe.h"
@ -14,7 +15,7 @@
#include "pycore_opcode_utils.h" // MAX_REAL_OPCODE
#include "pycore_optimizer.h" // _Py_uop_analyze_and_optimize()
#include "pycore_pystate.h" // _PyInterpreterState_GET()
#include "pycore_tuple.h" // _PyTuple_FromArraySteal
#include "pycore_tuple.h" // _PyTuple_FromArraySteal
#include "pycore_unicodeobject.h" // _PyUnicode_FromASCII
#include "pycore_uop_ids.h"
#include "pycore_jit.h"
@ -362,7 +363,7 @@ uop_item(PyObject *op, Py_ssize_t index)
return NULL;
}
PyObject *target = PyLong_FromUnsignedLong(self->trace[index].target);
if (oparg == NULL) {
if (target == NULL) {
Py_DECREF(oparg);
Py_DECREF(oname);
return NULL;
@ -1343,6 +1344,14 @@ uop_optimize(
return -1;
}
assert(length <= UOP_MAX_TRACE_LENGTH);
// Check executor coldness
PyThreadState *tstate = PyThreadState_Get();
// It's okay if this ends up going negative.
if (--tstate->interp->executor_creation_counter == 0) {
_Py_set_eval_breaker_bit(tstate, _PY_EVAL_JIT_INVALIDATE_COLD_BIT);
}
*exec_ptr = executor;
return 1;
}

View file

@ -7,7 +7,6 @@
#include "pycore_long.h"
#include "pycore_optimizer.h"
#include "pycore_stats.h"
#include "pycore_tuple.h" // _PyTuple_FromArray()
#include <stdbool.h>
#include <stdint.h>
@ -1044,7 +1043,7 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored))
"tuple item does not match value used to create tuple"
);
PyObject *pair[2] = { val_42, val_43 };
tuple = _PyTuple_FromArray(pair, 2);
tuple = PyTuple_FromArray(pair, 2);
ref = _Py_uop_sym_new_const(ctx, tuple);
TEST_PREDICATE(
_Py_uop_sym_get_const(ctx, _Py_uop_sym_tuple_getitem(ctx, ref, 1)) == val_43,

View file

@ -506,6 +506,7 @@ pycore_init_runtime(_PyRuntimeState *runtime,
_PyRuntimeState_SetFinalizing(runtime, NULL);
_Py_InitVersion();
_Py_DumpTraceback_Init();
status = _Py_HashRandomization_Init(config);
if (_PyStatus_EXCEPTION(status)) {
@ -836,6 +837,10 @@ pycore_init_builtins(PyThreadState *tstate)
}
interp->callable_cache.object__getattribute__ = object__getattribute__;
if (_PyType_InitSlotDefs(interp) < 0) {
return _PyStatus_ERR("failed to init slotdefs");
}
if (_PyBuiltins_AddExceptions(bimod) < 0) {
return _PyStatus_ERR("failed to add exceptions to builtins");
}

View file

@ -68,47 +68,37 @@ to avoid the expense of doing their own locking).
*/
#ifdef HAVE_THREAD_LOCAL
/* The attached thread state for the current thread. */
_Py_thread_local PyThreadState *_Py_tss_tstate = NULL;
/* The "bound" thread state used by PyGILState_Ensure(),
also known as a "gilstate." */
_Py_thread_local PyThreadState *_Py_tss_gilstate = NULL;
#endif
/* The interpreter of the attached thread state,
and is same as tstate->interp. */
_Py_thread_local PyInterpreterState *_Py_tss_interp = NULL;
static inline PyThreadState *
current_fast_get(void)
{
#ifdef HAVE_THREAD_LOCAL
return _Py_tss_tstate;
#else
// XXX Fall back to the PyThread_tss_*() API.
# error "no supported thread-local variable storage classifier"
#endif
}
static inline void
current_fast_set(_PyRuntimeState *Py_UNUSED(runtime), PyThreadState *tstate)
{
assert(tstate != NULL);
#ifdef HAVE_THREAD_LOCAL
_Py_tss_tstate = tstate;
#else
// XXX Fall back to the PyThread_tss_*() API.
# error "no supported thread-local variable storage classifier"
#endif
assert(tstate->interp != NULL);
_Py_tss_interp = tstate->interp;
}
static inline void
current_fast_clear(_PyRuntimeState *Py_UNUSED(runtime))
{
#ifdef HAVE_THREAD_LOCAL
_Py_tss_tstate = NULL;
#else
// XXX Fall back to the PyThread_tss_*() API.
# error "no supported thread-local variable storage classifier"
#endif
_Py_tss_interp = NULL;
}
#define tstate_verify_not_active(tstate) \
@ -457,16 +447,19 @@ _PyInterpreterState_Enable(_PyRuntimeState *runtime)
static PyInterpreterState *
alloc_interpreter(void)
{
// Aligned allocation for PyInterpreterState.
// the first word of the memory block is used to store
// the original pointer to be used later to free the memory.
size_t alignment = _Alignof(PyInterpreterState);
size_t allocsize = sizeof(PyInterpreterState) + alignment - 1;
size_t allocsize = sizeof(PyInterpreterState) + sizeof(void *) + alignment - 1;
void *mem = PyMem_RawCalloc(1, allocsize);
if (mem == NULL) {
return NULL;
}
PyInterpreterState *interp = _Py_ALIGN_UP(mem, alignment);
assert(_Py_IS_ALIGNED(interp, alignment));
interp->_malloced = mem;
return interp;
void *ptr = _Py_ALIGN_UP((char *)mem + sizeof(void *), alignment);
((void **)ptr)[-1] = mem;
assert(_Py_IS_ALIGNED(ptr, alignment));
return ptr;
}
static void
@ -481,7 +474,7 @@ free_interpreter(PyInterpreterState *interp)
interp->obmalloc = NULL;
}
assert(_Py_IS_ALIGNED(interp, _Alignof(PyInterpreterState)));
PyMem_RawFree(interp->_malloced);
PyMem_RawFree(((void **)interp)[-1]);
}
}
@ -575,7 +568,7 @@ init_interpreter(PyInterpreterState *interp,
interp->executor_list_head = NULL;
interp->executor_deletion_list_head = NULL;
interp->executor_deletion_list_remaining_capacity = 0;
interp->trace_run_counter = JIT_CLEANUP_THRESHOLD;
interp->executor_creation_counter = JIT_CLEANUP_THRESHOLD;
if (interp != &runtime->_main_interpreter) {
/* Fix the self-referential, statically initialized fields. */
interp->dtoa = (struct _dtoa_state)_dtoa_state_INIT(interp);
@ -763,10 +756,11 @@ interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate)
Py_CLEAR(interp->audit_hooks);
// At this time, all the threads should be cleared so we don't need atomic
// operations for instrumentation_version or eval_breaker.
// gh-140257: Threads have already been cleared, but daemon threads may
// still access eval_breaker atomically via take_gil() right before they
// hang. Use an atomic store to prevent data races during finalization.
interp->ceval.instrumentation_version = 0;
tstate->eval_breaker = 0;
_Py_atomic_store_uintptr(&tstate->eval_breaker, 0);
for (int i = 0; i < _PY_MONITORING_UNGROUPED_EVENTS; i++) {
interp->monitors.tools[i] = 0;
@ -959,6 +953,8 @@ PyInterpreterState_Delete(PyInterpreterState *interp)
_PyObject_FiniState(interp);
PyConfig_Clear(&interp->config);
free_interpreter(interp);
}
@ -1289,9 +1285,8 @@ _PyInterpreterState_RequireIDRef(PyInterpreterState *interp, int required)
PyInterpreterState*
PyInterpreterState_Get(void)
{
PyThreadState *tstate = current_fast_get();
_Py_EnsureTstateNotNULL(tstate);
PyInterpreterState *interp = tstate->interp;
_Py_AssertHoldsTstate();
PyInterpreterState *interp = _Py_tss_interp;
if (interp == NULL) {
Py_FatalError("no current interpreter");
}
@ -2488,14 +2483,10 @@ _PyThreadState_Bind(PyThreadState *tstate)
uintptr_t
_Py_GetThreadLocal_Addr(void)
{
#ifdef HAVE_THREAD_LOCAL
// gh-112535: Use the address of the thread-local PyThreadState variable as
// a unique identifier for the current thread. Each thread has a unique
// _Py_tss_tstate variable with a unique address.
return (uintptr_t)&_Py_tss_tstate;
#else
# error "no supported thread-local variable storage classifier"
#endif
}
#endif

View file

@ -632,6 +632,7 @@ _PyCode_Quicken(_Py_CODEUNIT *instructions, Py_ssize_t size, int enable_counters
#define SPEC_FAIL_CALL_INIT_NOT_PYTHON 21
#define SPEC_FAIL_CALL_PEP_523 22
#define SPEC_FAIL_CALL_BOUND_METHOD 23
#define SPEC_FAIL_CALL_VECTORCALL 24
#define SPEC_FAIL_CALL_CLASS_MUTABLE 26
#define SPEC_FAIL_CALL_METHOD_WRAPPER 28
#define SPEC_FAIL_CALL_OPERATOR_WRAPPER 29
@ -2092,6 +2093,10 @@ specialize_py_call(PyFunctionObject *func, _Py_CODEUNIT *instr, int nargs,
SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_PEP_523);
return -1;
}
if (func->vectorcall != _PyFunction_Vectorcall) {
SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_VECTORCALL);
return -1;
}
int argcount = -1;
if (kind == SPEC_FAIL_CODE_NOT_OPTIMIZED) {
SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CODE_NOT_OPTIMIZED);
@ -2131,6 +2136,10 @@ specialize_py_call_kw(PyFunctionObject *func, _Py_CODEUNIT *instr, int nargs,
SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_PEP_523);
return -1;
}
if (func->vectorcall != _PyFunction_Vectorcall) {
SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_VECTORCALL);
return -1;
}
if (kind == SPEC_FAIL_CODE_NOT_OPTIMIZED) {
SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CODE_NOT_OPTIMIZED);
return -1;

View file

@ -109,18 +109,19 @@ _Py_stackref_close(_PyStackRef ref, const char *filename, int linenumber)
}
_PyStackRef
_Py_stackref_create(PyObject *obj, const char *filename, int linenumber)
_Py_stackref_create(PyObject *obj, uint16_t flags, const char *filename, int linenumber)
{
if (obj == NULL) {
Py_FatalError("Cannot create a stackref for NULL");
}
PyInterpreterState *interp = PyInterpreterState_Get();
uint64_t new_id = interp->next_stackref;
interp->next_stackref = new_id + 2;
interp->next_stackref = new_id + (1 << Py_TAGGED_SHIFT);
TableEntry *entry = make_table_entry(obj, filename, linenumber);
if (entry == NULL) {
Py_FatalError("No memory left for stackref debug table");
}
new_id |= flags;
if (_Py_hashtable_set(interp->open_stackrefs_table, (void *)new_id, entry) < 0) {
Py_FatalError("No memory left for stackref debug table");
}
@ -194,16 +195,10 @@ _Py_stackref_report_leaks(PyInterpreterState *interp)
}
}
void
_PyStackRef_CLOSE_SPECIALIZED(_PyStackRef ref, destructor destruct, const char *filename, int linenumber)
{
PyObject *obj = _Py_stackref_close(ref, filename, linenumber);
_Py_DECREF_SPECIALIZED(obj, destruct);
}
_PyStackRef PyStackRef_TagInt(intptr_t i)
{
return (_PyStackRef){ .index = (i << 1) + 1 };
assert(Py_ARITHMETIC_RIGHT_SHIFT(intptr_t, (i << Py_TAGGED_SHIFT), Py_TAGGED_SHIFT) == i);
return (_PyStackRef){ .index = (i << Py_TAGGED_SHIFT) | Py_INT_TAG };
}
intptr_t
@ -211,7 +206,7 @@ PyStackRef_UntagInt(_PyStackRef i)
{
assert(PyStackRef_IsTaggedInt(i));
intptr_t val = (intptr_t)i.index;
return Py_ARITHMETIC_RIGHT_SHIFT(intptr_t, val, 1);
return Py_ARITHMETIC_RIGHT_SHIFT(intptr_t, val, Py_TAGGED_SHIFT);
}
bool
@ -223,8 +218,9 @@ PyStackRef_IsNullOrInt(_PyStackRef ref)
_PyStackRef
PyStackRef_IncrementTaggedIntNoOverflow(_PyStackRef ref)
{
assert(ref.index <= INT_MAX - 2); // No overflow
return (_PyStackRef){ .index = ref.index + 2 };
assert(PyStackRef_IsTaggedInt(ref));
assert((ref.index & (~Py_TAG_BITS)) != (INTPTR_MAX & (~Py_TAG_BITS))); // Isn't about to overflow
return (_PyStackRef){ .index = ref.index + (1 << Py_TAGGED_SHIFT) };
}

View file

@ -51,6 +51,7 @@ static const char* _Py_stdlib_module_names[] = {
"_lsprof",
"_lzma",
"_markupbase",
"_math_integer",
"_md5",
"_multibytecodec",
"_multiprocessing",

View file

@ -69,6 +69,13 @@ class traceback "PyTracebackObject *" "&PyTraceback_Type"
#include "clinic/traceback.c.h"
#ifdef MS_WINDOWS
typedef HRESULT (WINAPI *PF_GET_THREAD_DESCRIPTION)(HANDLE, PCWSTR*);
static PF_GET_THREAD_DESCRIPTION pGetThreadDescription = NULL;
#endif
static PyObject *
tb_create_raw(PyTracebackObject *next, PyFrameObject *frame, int lasti,
int lineno)
@ -973,6 +980,52 @@ _Py_DumpASCII(int fd, PyObject *text)
}
}
#ifdef MS_WINDOWS
static void
_Py_DumpWideString(int fd, wchar_t *str)
{
Py_ssize_t size = wcslen(str);
int truncated;
if (MAX_STRING_LENGTH < size) {
size = MAX_STRING_LENGTH;
truncated = 1;
}
else {
truncated = 0;
}
for (Py_ssize_t i=0; i < size; i++) {
Py_UCS4 ch = str[i];
if (' ' <= ch && ch <= 126) {
/* printable ASCII character */
dump_char(fd, (char)ch);
}
else if (ch <= 0xff) {
PUTS(fd, "\\x");
_Py_DumpHexadecimal(fd, ch, 2);
}
else if (Py_UNICODE_IS_HIGH_SURROGATE(ch)
&& Py_UNICODE_IS_LOW_SURROGATE(str[i+1])) {
ch = Py_UNICODE_JOIN_SURROGATES(ch, str[i+1]);
i++; // Skip the low surrogate character
PUTS(fd, "\\U");
_Py_DumpHexadecimal(fd, ch, 8);
}
else {
Py_BUILD_ASSERT(sizeof(wchar_t) == 2);
PUTS(fd, "\\u");
_Py_DumpHexadecimal(fd, ch, 4);
}
}
if (truncated) {
PUTS(fd, "...");
}
}
#endif
/* Write a frame into the file fd: "File "xxx", line xxx in xxx".
This function is signal safe. */
@ -1107,23 +1160,12 @@ _Py_DumpTraceback(int fd, PyThreadState *tstate)
# endif
#endif
/* Write the thread identifier into the file 'fd': "Current thread 0xHHHH:\" if
is_current is true, "Thread 0xHHHH:\n" otherwise.
This function is signal safe. */
// Write the thread name
static void
write_thread_id(int fd, PyThreadState *tstate, int is_current)
write_thread_name(int fd, PyThreadState *tstate)
{
if (is_current)
PUTS(fd, "Current thread 0x");
else
PUTS(fd, "Thread 0x");
_Py_DumpHexadecimal(fd,
tstate->thread_id,
sizeof(unsigned long) * 2);
// Write the thread name
#ifndef MS_WINDOWS
#if defined(HAVE_PTHREAD_GETNAME_NP) || defined(HAVE_PTHREAD_GET_NAME_NP)
char name[100];
pthread_t thread = (pthread_t)tstate->thread_id;
@ -1142,6 +1184,49 @@ write_thread_id(int fd, PyThreadState *tstate, int is_current)
}
}
#endif
#else
// Windows implementation
if (pGetThreadDescription == NULL) {
return;
}
HANDLE thread = OpenThread(THREAD_QUERY_LIMITED_INFORMATION, FALSE, tstate->thread_id);
if (thread == NULL) {
return;
}
wchar_t *name;
HRESULT hr = pGetThreadDescription(thread, &name);
if (!FAILED(hr)) {
if (name[0] != 0) {
PUTS(fd, " [");
_Py_DumpWideString(fd, name);
PUTS(fd, "]");
}
LocalFree(name);
}
CloseHandle(thread);
#endif
}
/* Write the thread identifier into the file 'fd': "Current thread 0xHHHH:\" if
is_current is true, "Thread 0xHHHH:\n" otherwise.
This function is signal safe (except on Windows). */
static void
write_thread_id(int fd, PyThreadState *tstate, int is_current)
{
if (is_current)
PUTS(fd, "Current thread 0x");
else
PUTS(fd, "Thread 0x");
_Py_DumpHexadecimal(fd,
tstate->thread_id,
sizeof(unsigned long) * 2);
write_thread_name(fd, tstate);
PUTS(fd, " (most recent call first):\n");
}
@ -1336,3 +1421,20 @@ _Py_InitDumpStack(void)
(void)backtrace(callstack, 1);
#endif
}
void
_Py_DumpTraceback_Init(void)
{
#ifdef MS_WINDOWS
if (pGetThreadDescription != NULL) {
return;
}
HMODULE kernelbase = GetModuleHandleW(L"kernelbase.dll");
if (kernelbase != NULL) {
pGetThreadDescription = (PF_GET_THREAD_DESCRIPTION)GetProcAddress(
kernelbase, "GetThreadDescription");
}
#endif
}