mirror of
https://github.com/python/cpython.git
synced 2025-12-08 06:10:17 +00:00
Merge remote-tracking branch 'origin/main' into HEAD
This commit is contained in:
commit
8d57aca95a
1284 changed files with 27792 additions and 11927 deletions
4
Python/Python-ast.c
generated
4
Python/Python-ast.c
generated
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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, ®istry)) {
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 *
|
||||
|
|
|
|||
|
|
@ -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, (--)) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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(); \
|
||||
|
|
|
|||
5
Python/clinic/bltinmodule.c.h
generated
5
Python/clinic/bltinmodule.c.h
generated
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
3
Python/clinic/sysmodule.c.h
generated
3
Python/clinic/sysmodule.c.h
generated
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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. */
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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){
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
3
Python/executor_cases.c.h
generated
3
Python/executor_cases.c.h
generated
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
56
Python/gc.c
56
Python/gc.c
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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 *
|
||||
|
|
|
|||
129
Python/jit.c
129
Python/jit.c
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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) };
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
1
Python/stdlib_module_names.h
generated
1
Python/stdlib_module_names.h
generated
|
|
@ -51,6 +51,7 @@ static const char* _Py_stdlib_module_names[] = {
|
|||
"_lsprof",
|
||||
"_lzma",
|
||||
"_markupbase",
|
||||
"_math_integer",
|
||||
"_md5",
|
||||
"_multibytecodec",
|
||||
"_multiprocessing",
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue