From 1eb8feaae2f585f3fd73e3a158424e6400b4698b Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Fri, 26 Apr 2024 14:11:59 -0700 Subject: [PATCH 01/40] Step 1: replace 'python -Xuops' with 'configure --enable-experimental-tier2' --- Doc/whatsnew/3.13.rst | 5 ++-- ...-04-26-14-06-18.gh-issue-118335.SRFsxO.rst | 4 ++++ Python/pylifecycle.c | 19 ++++----------- configure | 24 +++++++++++++++++++ configure.ac | 13 ++++++++++ 5 files changed, 47 insertions(+), 18 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-04-26-14-06-18.gh-issue-118335.SRFsxO.rst diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index ad107aad5db3bd..9a6d5727316bea 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -901,9 +901,8 @@ The internal architecture is roughly as follows. * There is a Tier 2 interpreter, but it is mostly intended for debugging the earlier stages of the optimization pipeline. If the JIT is not - enabled, the Tier 2 interpreter can be invoked by passing Python the - ``-X uops`` option or by setting the ``PYTHON_UOPS`` environment - variable to ``1``. + enabled, the Tier 2 interpreter can be enabled by configuring Python + with the ``--enable-experimental-tier2`` option. * When the ``--enable-experimental-jit`` option is used, the optimized Tier 2 IR is translated to machine code, which is then executed. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-04-26-14-06-18.gh-issue-118335.SRFsxO.rst b/Misc/NEWS.d/next/Core and Builtins/2024-04-26-14-06-18.gh-issue-118335.SRFsxO.rst new file mode 100644 index 00000000000000..1388e2356eeb00 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2024-04-26-14-06-18.gh-issue-118335.SRFsxO.rst @@ -0,0 +1,4 @@ +Change how to use the tier 2 interpreter. Instead of running Python with +``-X uops`` or setting the environment variable ``PYTHON_UOPS=1``, this +choice is now made at build time by configuring with +``--enable-experimental-tier2``. diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 0f3ca4a6687514..bfc8cdfe3e759d 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1262,30 +1262,19 @@ init_interp_main(PyThreadState *tstate) } // Turn on experimental tier 2 (uops-based) optimizer + // This is also needed when the JIT is enabled +#if defined(_Py_JIT) || defined(_Py_TIER2) if (is_main_interp) { -#ifndef _Py_JIT - // No JIT, maybe use the tier two interpreter: - char *envvar = Py_GETENV("PYTHON_UOPS"); - int enabled = envvar != NULL && *envvar > '0'; - if (_Py_get_xoption(&config->xoptions, L"uops") != NULL) { - enabled = 1; - } - if (enabled) { -#else - // Always enable tier two for JIT builds (ignoring the environment - // variable and command-line option above): - if (true) { -#endif PyObject *opt = PyUnstable_Optimizer_NewUOpOptimizer(); if (opt == NULL) { return _PyStatus_ERR("can't initialize optimizer"); } if (PyUnstable_SetOptimizer((_PyOptimizerObject *)opt)) { - return _PyStatus_ERR("can't initialize optimizer"); + return _PyStatus_ERR("can't install optimizer"); } Py_DECREF(opt); - } } +#endif if (!is_main_interp) { // The main interpreter is handled in Py_Main(), for now. diff --git a/configure b/configure index 78f86d83077eaa..4817beab6189c8 100755 --- a/configure +++ b/configure @@ -1088,6 +1088,7 @@ with_trace_refs enable_pystats with_assertions enable_experimental_jit +enable_experimental_tier2 enable_optimizations with_lto enable_bolt @@ -1818,6 +1819,9 @@ Optional Features: --enable-experimental-jit build the experimental just-in-time compiler (default is no) + --enable-experimental-tier2 + use the experimental tier 2 interpreter (default is + no) --enable-optimizations enable expensive, stable optimizations (PGO, etc.) (default is no) --enable-bolt enable usage of the llvm-bolt post-link optimizer @@ -8236,6 +8240,26 @@ fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_experimental_jit" >&5 printf "%s\n" "$enable_experimental_jit" >&6; } +# Check for --enable-experimental-tier2: +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --enable-experimental-tier2" >&5 +printf %s "checking for --enable-experimental-tier2... " >&6; } +# Check whether --enable-experimental-tier2 was given. +if test ${enable_experimental_tier2+y} +then : + enableval=$enable_experimental_tier2; +else $as_nop + enable_experimental_tier2=no +fi + +if test "x$enable_experimental_tier2" = xno +then : + +else $as_nop + as_fn_append CFLAGS_NODIST " -D_Py_TIER2" +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_experimental_tier2" >&5 +printf "%s\n" "$enable_experimental_tier2" >&6; } + # Enable optimization flags diff --git a/configure.ac b/configure.ac index 719b8d3a9573b9..e998cc7377a404 100644 --- a/configure.ac +++ b/configure.ac @@ -1784,6 +1784,19 @@ AC_SUBST([REGEN_JIT_COMMAND]) AC_SUBST([JIT_STENCILS_H]) AC_MSG_RESULT([$enable_experimental_jit]) +# Check for --enable-experimental-tier2: +AC_MSG_CHECKING([for --enable-experimental-tier2]) +AC_ARG_ENABLE([experimental-tier2], + [AS_HELP_STRING([--enable-experimental-tier2], + [use the experimental tier 2 interpreter (default is no)])], + [], + [enable_experimental_tier2=no]) +AS_VAR_IF([enable_experimental_tier2], + [no], + [], + [AS_VAR_APPEND([CFLAGS_NODIST], [" -D_Py_TIER2"])]) +AC_MSG_RESULT([$enable_experimental_tier2]) + # Enable optimization flags AC_SUBST([DEF_MAKE_ALL_RULE]) AC_SUBST([DEF_MAKE_RULE]) From 0863c17cfdd11f91ac4009ef34ce08b1aea2d188 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Fri, 26 Apr 2024 15:02:28 -0700 Subject: [PATCH 02/40] Make JIT imply TIER2, for convenience --- Include/Python.h | 5 +++++ Python/pylifecycle.c | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Include/Python.h b/Include/Python.h index bb771fb3aec980..3e9f7d07e8251d 100644 --- a/Include/Python.h +++ b/Include/Python.h @@ -51,6 +51,11 @@ # error "The limited API is not currently supported in the free-threaded build" #endif +// The JIT depends on TIER2 +#ifdef _Py_JIT +#define _Py_TIER2 1 +#endif + // Include Python header files #include "pyport.h" #include "pymacro.h" diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index bfc8cdfe3e759d..06bfd9ccfb4ee2 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1263,7 +1263,7 @@ init_interp_main(PyThreadState *tstate) // Turn on experimental tier 2 (uops-based) optimizer // This is also needed when the JIT is enabled -#if defined(_Py_JIT) || defined(_Py_TIER2) +#ifdef _Py_TIER2 if (is_main_interp) { PyObject *opt = PyUnstable_Optimizer_NewUOpOptimizer(); if (opt == NULL) { From 9e4333175c72624c46ddcccfd659cfffad9712a5 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Fri, 26 Apr 2024 15:29:13 -0700 Subject: [PATCH 03/40] Step 2: Remove all code from optimizer*.c unless TIER2; fix deps except _testinternalcapi --- Modules/_opcode.c | 5 +++++ Objects/codeobject.c | 6 ++++++ Objects/object.c | 4 ++++ Python/bytecodes.c | 6 ++++++ Python/ceval.c | 5 ++++- Python/generated_cases.c.h | 6 ++++++ Python/instrumentation.c | 6 ++++++ Python/optimizer.c | 4 ++++ Python/optimizer_analysis.c | 4 ++++ Python/optimizer_symbols.c | 4 ++++ Python/pylifecycle.c | 4 ++++ Python/pystate.c | 6 ++++++ Python/sysmodule.c | 2 ++ 13 files changed, 61 insertions(+), 1 deletion(-) diff --git a/Modules/_opcode.c b/Modules/_opcode.c index 5350adb456b859..4c262183fa2d31 100644 --- a/Modules/_opcode.c +++ b/Modules/_opcode.c @@ -367,7 +367,12 @@ _opcode_get_executor_impl(PyObject *module, PyObject *code, int offset) Py_TYPE(code)->tp_name); return NULL; } +#ifdef _Py_TIER2 return (PyObject *)PyUnstable_GetExecutor((PyCodeObject *)code, offset); +#else + PyErr_Format(PyExc_RuntimeError, + "Executors is not available in this build"); +#endif } static PyMethodDef diff --git a/Objects/codeobject.c b/Objects/codeobject.c index 014632962bfcf3..605167c5c0bd3a 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -1496,6 +1496,8 @@ PyCode_GetFreevars(PyCodeObject *code) return _PyCode_GetFreevars(code); } +#ifdef _Py_TIER2 + static void clear_executors(PyCodeObject *co) { @@ -1515,6 +1517,8 @@ _PyCode_Clear_Executors(PyCodeObject *code) clear_executors(code); } +#endif + static void deopt_code(PyCodeObject *code, _Py_CODEUNIT *instructions) { @@ -1739,9 +1743,11 @@ code_dealloc(PyCodeObject *co) PyMem_Free(co_extra); } +#ifdef _Py_TIER2 if (co->co_executors != NULL) { clear_executors(co); } +#endif Py_XDECREF(co->co_consts); Py_XDECREF(co->co_names); diff --git a/Objects/object.c b/Objects/object.c index 91bb0114cbfc32..353a80c11dbed7 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -2281,9 +2281,11 @@ static PyTypeObject* static_types[] = { &_PyBufferWrapper_Type, &_PyContextTokenMissing_Type, &_PyCoroWrapper_Type, +#ifdef _Py_TIER2 &_PyCounterExecutor_Type, &_PyCounterOptimizer_Type, &_PyDefaultOptimizer_Type, +#endif &_Py_GenericAliasIterType, &_PyHamtItems_Type, &_PyHamtKeys_Type, @@ -2304,8 +2306,10 @@ static PyTypeObject* static_types[] = { &_PyPositionsIterator, &_PyUnicodeASCIIIter_Type, &_PyUnion_Type, +#ifdef _Py_TIER2 &_PyUOpExecutor_Type, &_PyUOpOptimizer_Type, +#endif &_PyWeakref_CallableProxyType, &_PyWeakref_ProxyType, &_PyWeakref_RefType, diff --git a/Python/bytecodes.c b/Python/bytecodes.c index fe3d61362e6b02..d6eb1062db7a07 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2355,6 +2355,7 @@ dummy_func( CHECK_EVAL_BREAKER(); assert(oparg <= INSTR_OFFSET()); JUMPBY(-oparg); + #ifdef _Py_TIER2 #if ENABLE_SPECIALIZATION _Py_BackoffCounter counter = this_instr[1].counter; if (backoff_counter_triggers(counter) && this_instr->op.code == JUMP_BACKWARD) { @@ -2380,6 +2381,7 @@ dummy_func( ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); } #endif /* ENABLE_SPECIALIZATION */ + #endif /* _Py_TIER2 */ } pseudo(JUMP) = { @@ -2393,6 +2395,7 @@ dummy_func( }; tier1 inst(ENTER_EXECUTOR, (--)) { + #ifdef _Py_TIER2 int prevoparg = oparg; CHECK_EVAL_BREAKER(); if (this_instr->op.code != ENTER_EXECUTOR || @@ -2410,6 +2413,9 @@ dummy_func( tstate->previous_executor = Py_None; Py_INCREF(executor); GOTO_TIER_TWO(executor); + #else + assert(0); + #endif /* _Py_TIER2 */ } replaced op(_POP_JUMP_IF_FALSE, (cond -- )) { diff --git a/Python/ceval.c b/Python/ceval.c index d130c734a67144..0e2e4ac7a0b64a 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -755,7 +755,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int _Py_CODEUNIT *next_instr; PyObject **stack_pointer; -#ifndef _Py_JIT +#if defined(_Py_TIER2) && !defined(_Py_JIT) /* Tier 2 interpreter state */ _PyExecutorObject *current_executor = NULL; const _PyUOpInstruction *next_uop = NULL; @@ -959,6 +959,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int goto error; +#ifdef _Py_TIER2 // Tier 2 is also here! enter_tier_two: @@ -1113,6 +1114,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int #endif // _Py_JIT +#endif // _Py_TIER2 + } #if defined(__GNUC__) diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index c27505fde3d9fa..b6386f5189be3f 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2492,6 +2492,7 @@ (void)this_instr; next_instr += 1; INSTRUCTION_STATS(ENTER_EXECUTOR); + #ifdef _Py_TIER2 int prevoparg = oparg; CHECK_EVAL_BREAKER(); if (this_instr->op.code != ENTER_EXECUTOR || @@ -2508,6 +2509,9 @@ tstate->previous_executor = Py_None; Py_INCREF(executor); GOTO_TIER_TWO(executor); + #else + assert(0); + #endif /* _Py_TIER2 */ DISPATCH(); } @@ -3432,6 +3436,7 @@ CHECK_EVAL_BREAKER(); assert(oparg <= INSTR_OFFSET()); JUMPBY(-oparg); + #ifdef _Py_TIER2 #if ENABLE_SPECIALIZATION _Py_BackoffCounter counter = this_instr[1].counter; if (backoff_counter_triggers(counter) && this_instr->op.code == JUMP_BACKWARD) { @@ -3457,6 +3462,7 @@ ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); } #endif /* ENABLE_SPECIALIZATION */ + #endif /* _Py_TIER2 */ DISPATCH(); } diff --git a/Python/instrumentation.c b/Python/instrumentation.c index 71efeff077633d..6446701cea8954 100644 --- a/Python/instrumentation.c +++ b/Python/instrumentation.c @@ -1670,10 +1670,12 @@ instrument_lock_held(PyCodeObject *code, PyInterpreterState *interp) ); return 0; } +#ifdef _Py_TIER2 if (code->co_executors != NULL) { _PyCode_Clear_Executors(code); } _Py_Executors_InvalidateDependency(interp, code, 1); +#endif int code_len = (int)Py_SIZE(code); /* Exit early to avoid creating instrumentation * data for potential statically allocated code @@ -1911,7 +1913,9 @@ _PyMonitoring_SetEvents(int tool_id, _PyMonitoringEventSet events) goto done; } set_global_version(tstate, new_version); +#ifdef _Py_TIER2 _Py_Executors_InvalidateAll(interp, 1); +#endif res = instrument_all_executing_code_objects(interp); done: _PyEval_StartTheWorld(interp); @@ -1951,7 +1955,9 @@ _PyMonitoring_SetLocalEvents(PyCodeObject *code, int tool_id, _PyMonitoringEvent code->_co_instrumentation_version -= MONITORING_VERSION_INCREMENT; } +#ifdef _Py_TIER2 _Py_Executors_InvalidateDependency(interp, code, 1); +#endif res = instrument_lock_held(code, interp); diff --git a/Python/optimizer.c b/Python/optimizer.c index 02c9b395027791..5eb13e06c3eeb3 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -15,6 +15,8 @@ #include #include +#ifdef _Py_TIER2 + #define NEED_OPCODE_METADATA #include "pycore_uop_metadata.h" // Uop tables #undef NEED_OPCODE_METADATA @@ -1604,3 +1606,5 @@ _Py_Executors_InvalidateAll(PyInterpreterState *interp, int is_invalidation) } } } + +#endif /* _Py_TIER2 */ diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 9315d7228b5732..326d6a5f630e45 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -33,6 +33,8 @@ #include #include +#ifdef _Py_TIER2 + #ifdef Py_DEBUG extern const char *_PyUOpName(int index); extern void _PyUOpPrint(const _PyUOpInstruction *uop); @@ -603,3 +605,5 @@ _Py_uop_analyze_and_optimize( OPT_STAT_INC(optimizer_successes); return length; } + +#endif /* _Py_TIER2 */ diff --git a/Python/optimizer_symbols.c b/Python/optimizer_symbols.c index 204599b08766c3..07d7598988aa5c 100644 --- a/Python/optimizer_symbols.c +++ b/Python/optimizer_symbols.c @@ -11,6 +11,8 @@ #include #include +#ifdef _Py_TIER2 + /* Symbols ======= @@ -506,3 +508,5 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored)) Py_XDECREF(val_43); return NULL; } + +#endif /* _Py_TIER2 */ diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 06bfd9ccfb4ee2..7c7d1c244c8579 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -621,9 +621,11 @@ static int builtins_dict_watcher(PyDict_WatchEvent event, PyObject *dict, PyObject *key, PyObject *new_value) { PyInterpreterState *interp = _PyInterpreterState_GET(); +#ifdef _Py_TIER2 if (interp->rare_events.builtin_dict < _Py_MAX_ALLOWED_BUILTINS_MODIFICATIONS) { _Py_Executors_InvalidateAll(interp, 1); } +#endif RARE_EVENT_INTERP_INC(interp, builtin_dict); return 0; } @@ -1634,10 +1636,12 @@ finalize_modules(PyThreadState *tstate) { PyInterpreterState *interp = tstate->interp; +#ifdef _Py_TIER2 // Invalidate all executors and turn off tier 2 optimizer _Py_Executors_InvalidateAll(interp, 0); _PyOptimizerObject *old = _Py_SetOptimizer(interp, NULL); Py_XDECREF(old); +#endif // Stop watching __builtin__ modifications PyDict_Unwatch(0, interp->builtins); diff --git a/Python/pystate.c b/Python/pystate.c index bca28cebcc9059..16f1e105494a3e 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -653,8 +653,10 @@ init_interpreter(PyInterpreterState *interp, } interp->sys_profile_initialized = false; interp->sys_trace_initialized = false; +#ifdef _Py_TIER2 (void)_Py_SetOptimizer(interp, NULL); interp->executor_list_head = NULL; +#endif if (interp != &runtime->_main_interpreter) { /* Fix the self-referential, statically initialized fields. */ interp->dtoa = (struct _dtoa_state)_dtoa_state_INIT(interp); @@ -806,9 +808,11 @@ interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate) tstate->_status.cleared = 0; } +#ifdef _Py_TIER2 _PyOptimizerObject *old = _Py_SetOptimizer(interp, NULL); assert(old != NULL); Py_DECREF(old); +#endif /* It is possible that any of the objects below have a finalizer that runs Python code or otherwise relies on a thread state @@ -2809,9 +2813,11 @@ _PyInterpreterState_SetEvalFrameFunc(PyInterpreterState *interp, if (eval_frame == interp->eval_frame) { return; } +#ifdef _Py_TIER2 if (eval_frame != NULL) { _Py_Executors_InvalidateAll(interp, 1); } +#endif RARE_EVENT_INC(set_eval_frame_func); interp->eval_frame = eval_frame; } diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 7af363678e8e86..38a74a1e0b8fb5 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -2166,7 +2166,9 @@ sys__clear_internal_caches_impl(PyObject *module) /*[clinic end generated code: output=0ee128670a4966d6 input=253e741ca744f6e8]*/ { PyInterpreterState *interp = _PyInterpreterState_GET(); +#ifdef _Py_TIER2 _Py_Executors_InvalidateAll(interp, 0); +#endif PyType_ClearCache(); Py_RETURN_NONE; } From 064de58e325044b4923b2e3d463c34179f9ef6d5 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Fri, 26 Apr 2024 15:33:47 -0700 Subject: [PATCH 04/40] Remove TIER2 stuff from _testinternalcapi --- Modules/_testinternalcapi.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index b0bba3422a50a0..c63c12435eba98 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -985,6 +985,8 @@ get_co_framesize(PyObject *self, PyObject *arg) return PyLong_FromLong(code->co_framesize); } +#ifdef _Py_TIER2 + static PyObject * new_counter_optimizer(PyObject *self, PyObject *arg) { @@ -1012,7 +1014,10 @@ set_optimizer(PyObject *self, PyObject *opt) static PyObject * get_optimizer(PyObject *self, PyObject *Py_UNUSED(ignored)) { - PyObject *opt = (PyObject *)PyUnstable_GetOptimizer(); + PyObject *opt = NULL; +#ifdef _Py_TIER2 + opt = (PyObject *)PyUnstable_GetOptimizer(); +#endif if (opt == NULL) { Py_RETURN_NONE; } @@ -1045,6 +1050,8 @@ invalidate_executors(PyObject *self, PyObject *obj) Py_RETURN_NONE; } +#endif + static int _pending_callback(void *arg) { /* we assume the argument is callable object to which we own a reference */ @@ -1999,12 +2006,14 @@ static PyMethodDef module_functions[] = { {"iframe_getline", iframe_getline, METH_O, NULL}, {"iframe_getlasti", iframe_getlasti, METH_O, NULL}, {"get_co_framesize", get_co_framesize, METH_O, NULL}, +#ifdef _Py_TIER2 {"get_optimizer", get_optimizer, METH_NOARGS, NULL}, {"set_optimizer", set_optimizer, METH_O, NULL}, {"new_counter_optimizer", new_counter_optimizer, METH_NOARGS, NULL}, {"new_uop_optimizer", new_uop_optimizer, METH_NOARGS, NULL}, {"add_executor_dependency", add_executor_dependency, METH_VARARGS, NULL}, {"invalidate_executors", invalidate_executors, METH_O, NULL}, +#endif {"pending_threadfunc", _PyCFunction_CAST(pending_threadfunc), METH_VARARGS | METH_KEYWORDS}, {"pending_identify", pending_identify, METH_VARARGS, NULL}, @@ -2050,7 +2059,9 @@ static PyMethodDef module_functions[] = { #ifdef Py_GIL_DISABLED {"py_thread_id", get_py_thread_id, METH_NOARGS}, #endif +#ifdef _Py_TIER2 {"uop_symbols_test", _Py_uop_symbols_test, METH_NOARGS}, +#endif {NULL, NULL} /* sentinel */ }; From 13b8ef0cc154955fa357c8e48db1b42011666d4e Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Fri, 26 Apr 2024 16:53:31 -0700 Subject: [PATCH 05/40] Fix test_dis.py: _opcode.get_executor() may raise RuntimeError --- Lib/dis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/dis.py b/Lib/dis.py index 111d624fc259c5..76934eb00e63f0 100644 --- a/Lib/dis.py +++ b/Lib/dis.py @@ -216,7 +216,7 @@ def _get_code_array(co, adaptive): if op == ENTER_EXECUTOR: try: ex = get_executor(co, i) - except ValueError: + except (ValueError, RuntimeError): ex = None if ex: From edbaeef8686ce5d3bdec87a8f7ce65053b9fbbde Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Fri, 26 Apr 2024 16:57:21 -0700 Subject: [PATCH 06/40] Fix test_regrtest (by tweaking without_getoptimizer) --- Lib/test/support/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index ea4945466cac82..c33fe50e2f629c 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -2520,6 +2520,7 @@ def exceeds_recursion_limit(): def without_optimizer(func): try: import _testinternalcapi + from _testinternalcapi import get_optimizer, set_optimizer except ImportError: return func @functools.wraps(func) From 9311198639fe51a3326c825a9ca09b16e85e35fc Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Fri, 26 Apr 2024 16:59:54 -0700 Subject: [PATCH 07/40] Fix test_optimizer.py --- Lib/test/test_optimizer.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Lib/test/test_optimizer.py b/Lib/test/test_optimizer.py index 899a4507317334..fac4d1a4ab44c4 100644 --- a/Lib/test/test_optimizer.py +++ b/Lib/test/test_optimizer.py @@ -80,6 +80,8 @@ def func(x=0): class TestOptimizerSymbols(unittest.TestCase): + @unittest.skipUnless(hasattr(_testinternalcapi, "uop_symbols_test"), + "requires _testinternalcapi.uop_symbols_test") def test_optimizer_symbols(self): _testinternalcapi.uop_symbols_test() From 300ae6dea34fe9993e10992ad70011e9357af1aa Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Fri, 26 Apr 2024 17:01:14 -0700 Subject: [PATCH 08/40] Fix test_opcache --- Lib/test/test_opcache.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Lib/test/test_opcache.py b/Lib/test/test_opcache.py index f4e954fd02148d..92a34113bc0383 100644 --- a/Lib/test/test_opcache.py +++ b/Lib/test/test_opcache.py @@ -16,6 +16,8 @@ def disabling_optimizer(func): def wrapper(*args, **kwargs): + if not hasattr(_testinternalcapi, "get_optimizer"): + return func(*args, **kwargs) old_opt = _testinternalcapi.get_optimizer() _testinternalcapi.set_optimizer(None) try: From db911e4abc228558cf3aaa059e3d601095a216f3 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Fri, 26 Apr 2024 17:04:06 -0700 Subject: [PATCH 09/40] Fix test_monitoring --- Lib/test/test_monitoring.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_monitoring.py b/Lib/test/test_monitoring.py index 11c61bc2e0688d..a9140d4d3dd743 100644 --- a/Lib/test/test_monitoring.py +++ b/Lib/test/test_monitoring.py @@ -1831,15 +1831,17 @@ class TestOptimizer(MonitoringTestBase, unittest.TestCase): def setUp(self): _testinternalcapi = import_module("_testinternalcapi") - self.old_opt = _testinternalcapi.get_optimizer() - opt = _testinternalcapi.new_counter_optimizer() - _testinternalcapi.set_optimizer(opt) + if hasattr(_testinternalcapi, "get_optimizer"): + self.old_opt = _testinternalcapi.get_optimizer() + opt = _testinternalcapi.new_counter_optimizer() + _testinternalcapi.set_optimizer(opt) super(TestOptimizer, self).setUp() def tearDown(self): super(TestOptimizer, self).tearDown() import _testinternalcapi - _testinternalcapi.set_optimizer(self.old_opt) + if hasattr(_testinternalcapi, "get_optimizer"): + _testinternalcapi.set_optimizer(self.old_opt) def test_for_loop(self): def test_func(x): From 8cb71dd614d8abaf367db3341121fec9a1a39949 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Fri, 26 Apr 2024 17:09:45 -0700 Subject: [PATCH 10/40] Fix test_capi.test_opt (by disabling unless get_optimizer exists) --- Lib/test/test_capi/test_opt.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index c798b343626677..6e5b626e93291a 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -34,6 +34,8 @@ def clear_executors(func): @requires_specialization +@unittest.skipUnless(hasattr(_testinternalcapi, "get_optimizer"), + "Requires optimizer infrastructure") class TestOptimizerAPI(unittest.TestCase): def test_new_counter_optimizer_dealloc(self): @@ -136,6 +138,8 @@ def get_opnames(ex): @requires_specialization +@unittest.skipUnless(hasattr(_testinternalcapi, "get_optimizer"), + "Requires optimizer infrastructure") class TestExecutorInvalidation(unittest.TestCase): def setUp(self): @@ -215,6 +219,8 @@ def f(): @requires_specialization +@unittest.skipUnless(hasattr(_testinternalcapi, "get_optimizer"), + "Requires optimizer infrastructure") @unittest.skipIf(os.getenv("PYTHON_UOPS_OPTIMIZE") == "0", "Needs uop optimizer to run.") class TestUops(unittest.TestCase): @@ -579,6 +585,8 @@ def testfunc(n): @requires_specialization +@unittest.skipUnless(hasattr(_testinternalcapi, "get_optimizer"), + "Requires optimizer infrastructure") @unittest.skipIf(os.getenv("PYTHON_UOPS_OPTIMIZE") == "0", "Needs uop optimizer to run.") class TestUopsOptimization(unittest.TestCase): From 7e79509b8d443217ae38a6f58ead7c816a3132e0 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Fri, 26 Apr 2024 20:49:28 -0700 Subject: [PATCH 11/40] Fix _opcode.c --- Modules/_opcode.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Modules/_opcode.c b/Modules/_opcode.c index 4c262183fa2d31..0f28f006d917f7 100644 --- a/Modules/_opcode.c +++ b/Modules/_opcode.c @@ -372,6 +372,7 @@ _opcode_get_executor_impl(PyObject *module, PyObject *code, int offset) #else PyErr_Format(PyExc_RuntimeError, "Executors is not available in this build"); + return NULL; #endif } From 638b7ec0a59172b93825e61e2076d66a0cc1b39c Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Fri, 26 Apr 2024 20:51:44 -0700 Subject: [PATCH 12/40] Fix warning in sysmodule.c --- Python/sysmodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 38a74a1e0b8fb5..726051521cf574 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -2165,8 +2165,8 @@ static PyObject * sys__clear_internal_caches_impl(PyObject *module) /*[clinic end generated code: output=0ee128670a4966d6 input=253e741ca744f6e8]*/ { - PyInterpreterState *interp = _PyInterpreterState_GET(); #ifdef _Py_TIER2 + PyInterpreterState *interp = _PyInterpreterState_GET(); _Py_Executors_InvalidateAll(interp, 0); #endif PyType_ClearCache(); From 8fc905fe25bb3b81e9183759e5f020468cd6ce44 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Mon, 29 Apr 2024 15:49:48 -0700 Subject: [PATCH 13/40] When compiling _testinternalcapi.c, define _Py_JIT --- PCbuild/_testinternalcapi.vcxproj | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/PCbuild/_testinternalcapi.vcxproj b/PCbuild/_testinternalcapi.vcxproj index a825cac9138674..d35278460218e7 100644 --- a/PCbuild/_testinternalcapi.vcxproj +++ b/PCbuild/_testinternalcapi.vcxproj @@ -108,6 +108,11 @@ false + + + _Py_JIT;%(PreprocessorDefinitions) + + From 877a00513f6be76810b75e32ed504f245a8e2358 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Mon, 29 Apr 2024 16:05:27 -0700 Subject: [PATCH 14/40] Try making WASI Debug recursion limit 400 --- Include/cpython/pystate.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h index 0611e299403031..5f3ac0f60a6572 100644 --- a/Include/cpython/pystate.h +++ b/Include/cpython/pystate.h @@ -193,7 +193,12 @@ struct _ts { #ifdef Py_DEBUG // A debug build is likely built with low optimization level which implies // higher stack memory usage than a release build: use a lower limit. +#if defined(__wasi__) +   // On WASI it's even worse. +# define Py_C_RECURSION_LIMIT 400 +#else # define Py_C_RECURSION_LIMIT 500 +#endif #elif defined(__s390x__) # define Py_C_RECURSION_LIMIT 800 #elif defined(_WIN32) && defined(_M_ARM64) From ffd7722fe73c49e32181fe96cb06a9fcf6c4eef8 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Mon, 29 Apr 2024 20:26:00 -0700 Subject: [PATCH 15/40] Revert "Try making WASI Debug recursion limit 400" It doesn't work. I'm giving up. This reverts commit 877a00513f6be76810b75e32ed504f245a8e2358. --- Include/cpython/pystate.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h index 5f3ac0f60a6572..0611e299403031 100644 --- a/Include/cpython/pystate.h +++ b/Include/cpython/pystate.h @@ -193,12 +193,7 @@ struct _ts { #ifdef Py_DEBUG // A debug build is likely built with low optimization level which implies // higher stack memory usage than a release build: use a lower limit. -#if defined(__wasi__) -   // On WASI it's even worse. -# define Py_C_RECURSION_LIMIT 400 -#else # define Py_C_RECURSION_LIMIT 500 -#endif #elif defined(__s390x__) # define Py_C_RECURSION_LIMIT 800 #elif defined(_WIN32) && defined(_M_ARM64) From 6e2777b45f461b2c6b996bd74d98461750e80900 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 30 Apr 2024 07:30:27 -0700 Subject: [PATCH 16/40] Update jit/README.md to require LLVM 18 everywhere --- Tools/jit/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Tools/jit/README.md b/Tools/jit/README.md index 7b33f99d23f75d..0f5aa9ce656bc9 100644 --- a/Tools/jit/README.md +++ b/Tools/jit/README.md @@ -7,18 +7,18 @@ This version of CPython can be built with an experimental just-in-time compiler. The JIT compiler does not require end users to install any third-party dependencies, but part of it must be *built* using LLVM[^why-llvm]. You are *not* required to build the rest of CPython using LLVM, or even the same version of LLVM (in fact, this is uncommon). -LLVM version 16 is required. Both `clang` and `llvm-readobj` need to be installed and discoverable (version suffixes, like `clang-16`, are okay). It's highly recommended that you also have `llvm-objdump` available, since this allows the build script to dump human-readable assembly for the generated code. +LLVM version 18 is required. Both `clang` and `llvm-readobj` need to be installed and discoverable (version suffixes, like `clang-18`, are okay). It's highly recommended that you also have `llvm-objdump` available, since this allows the build script to dump human-readable assembly for the generated code. It's easy to install all of the required tools: ### Linux -Install LLVM 16 on Ubuntu/Debian: +Install LLVM 18 on Ubuntu/Debian: ```sh wget https://apt.llvm.org/llvm.sh chmod +x llvm.sh -sudo ./llvm.sh 16 +sudo ./llvm.sh 18 ``` ### macOS From f228a06dbe965b9f332115c94d305855687a6c80 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Mon, 29 Apr 2024 20:25:10 -0700 Subject: [PATCH 17/40] Rip out --enable-experimental-tier2, in favor of --enable-experimental-jit=XXX There's more to do. --- Include/Python.h | 2 +- configure | 32 ++++++-------------------------- configure.ac | 22 +++++++--------------- 3 files changed, 14 insertions(+), 42 deletions(-) diff --git a/Include/Python.h b/Include/Python.h index 3e9f7d07e8251d..9ece592db92197 100644 --- a/Include/Python.h +++ b/Include/Python.h @@ -53,7 +53,7 @@ // The JIT depends on TIER2 #ifdef _Py_JIT -#define _Py_TIER2 1 +#define _Py_TIER2 _Py_JIT #endif // Include Python header files diff --git a/configure b/configure index 2f3ab35e99652c..caca9e85758bf9 100755 --- a/configure +++ b/configure @@ -1089,7 +1089,6 @@ with_trace_refs enable_pystats with_assertions enable_experimental_jit -enable_experimental_tier2 enable_optimizations with_lto enable_bolt @@ -1819,12 +1818,9 @@ Optional Features: --disable-gil enable experimental support for running without the GIL (default is no) --enable-pystats enable internal statistics gathering (default is no) - --enable-experimental-jit + --enable-experimental-jit[=no|yes|yes-default-off|interpreter] build the experimental just-in-time compiler (default is no) - --enable-experimental-tier2 - use the experimental tier 2 interpreter (default is - no) --enable-optimizations enable expensive, stable optimizations (PGO, etc.) (default is no) --enable-bolt enable usage of the llvm-bolt post-link optimizer @@ -8230,11 +8226,15 @@ else $as_nop enable_experimental_jit=no fi +case $enable_experimental_jit in + no|yes|yes-default-off|interpreter) ;; + *) as_fn_error $? "invalid argument: --enable-experimental-jit=$enable_experimental_jit; expected no|yes|yes-default-off|interpreter" "$LINENO" 5 ;; +esac if test "x$enable_experimental_jit" = xno then : else $as_nop - as_fn_append CFLAGS_NODIST " -D_Py_JIT" + as_fn_append CFLAGS_NODIST " -D_Py_JIT=_PY_JIT_$(echo $enable_experimental_jit | tr a-z- A-Z_)" REGEN_JIT_COMMAND="\$(PYTHON_FOR_REGEN) \$(srcdir)/Tools/jit/build.py $host" JIT_STENCILS_H="jit_stencils.h" if test "x$Py_DEBUG" = xtrue @@ -8247,26 +8247,6 @@ fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_experimental_jit" >&5 printf "%s\n" "$enable_experimental_jit" >&6; } -# Check for --enable-experimental-tier2: -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --enable-experimental-tier2" >&5 -printf %s "checking for --enable-experimental-tier2... " >&6; } -# Check whether --enable-experimental-tier2 was given. -if test ${enable_experimental_tier2+y} -then : - enableval=$enable_experimental_tier2; -else $as_nop - enable_experimental_tier2=no -fi - -if test "x$enable_experimental_tier2" = xno -then : - -else $as_nop - as_fn_append CFLAGS_NODIST " -D_Py_TIER2" -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_experimental_tier2" >&5 -printf "%s\n" "$enable_experimental_tier2" >&6; } - # Enable optimization flags diff --git a/configure.ac b/configure.ac index 835cd14e0a8d7f..c13566d3d617d4 100644 --- a/configure.ac +++ b/configure.ac @@ -1765,14 +1765,19 @@ fi # Check for --enable-experimental-jit: AC_MSG_CHECKING([for --enable-experimental-jit]) AC_ARG_ENABLE([experimental-jit], - [AS_HELP_STRING([--enable-experimental-jit], + [AS_HELP_STRING([--enable-experimental-jit@<:@=no|yes|yes-default-off|interpreter@:>@], [build the experimental just-in-time compiler (default is no)])], [], [enable_experimental_jit=no]) +case $enable_experimental_jit in + no|yes|yes-default-off|interpreter) ;; + *) AC_MSG_ERROR( + [invalid argument: --enable-experimental-jit=$enable_experimental_jit; expected no|yes|yes-default-off|interpreter]) ;; +esac AS_VAR_IF([enable_experimental_jit], [no], [], - [AS_VAR_APPEND([CFLAGS_NODIST], [" -D_Py_JIT"]) + [AS_VAR_APPEND([CFLAGS_NODIST], [" -D_Py_JIT=_PY_JIT_$(echo $enable_experimental_jit | tr a-z- A-Z_)"]) AS_VAR_SET([REGEN_JIT_COMMAND], ["\$(PYTHON_FOR_REGEN) \$(srcdir)/Tools/jit/build.py $host"]) AS_VAR_SET([JIT_STENCILS_H], ["jit_stencils.h"]) @@ -1784,19 +1789,6 @@ AC_SUBST([REGEN_JIT_COMMAND]) AC_SUBST([JIT_STENCILS_H]) AC_MSG_RESULT([$enable_experimental_jit]) -# Check for --enable-experimental-tier2: -AC_MSG_CHECKING([for --enable-experimental-tier2]) -AC_ARG_ENABLE([experimental-tier2], - [AS_HELP_STRING([--enable-experimental-tier2], - [use the experimental tier 2 interpreter (default is no)])], - [], - [enable_experimental_tier2=no]) -AS_VAR_IF([enable_experimental_tier2], - [no], - [], - [AS_VAR_APPEND([CFLAGS_NODIST], [" -D_Py_TIER2"])]) -AC_MSG_RESULT([$enable_experimental_tier2]) - # Enable optimization flags AC_SUBST([DEF_MAKE_ALL_RULE]) AC_SUBST([DEF_MAKE_RULE]) From 70e18a51e383a246ef029301f25170183d56ff1f Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 30 Apr 2024 07:40:51 -0700 Subject: [PATCH 18/40] Rip out _Py_TIER2, replace with _Py_JIT The value is a bitflag: - 0: off - 1: JIT, on by default - 3: JIT, off by default (not yet implemented, requires fiddling pystate.c) - 4: tier 2 interpreter, on by default --- Include/Python.h | 5 ----- Modules/_opcode.c | 2 +- Modules/_testinternalcapi.c | 8 ++++---- Objects/codeobject.c | 4 ++-- Objects/object.c | 4 ++-- Python/bytecodes.c | 8 ++++---- Python/ceval.c | 12 +++--------- Python/generated_cases.c.h | 8 ++++---- Python/instrumentation.c | 6 +++--- Python/optimizer.c | 6 +++--- Python/optimizer_analysis.c | 4 ++-- Python/optimizer_symbols.c | 5 ++--- Python/pylifecycle.c | 6 +++--- Python/pystate.c | 6 +++--- Python/sysmodule.c | 2 +- 15 files changed, 37 insertions(+), 49 deletions(-) diff --git a/Include/Python.h b/Include/Python.h index 9ece592db92197..bb771fb3aec980 100644 --- a/Include/Python.h +++ b/Include/Python.h @@ -51,11 +51,6 @@ # error "The limited API is not currently supported in the free-threaded build" #endif -// The JIT depends on TIER2 -#ifdef _Py_JIT -#define _Py_TIER2 _Py_JIT -#endif - // Include Python header files #include "pyport.h" #include "pymacro.h" diff --git a/Modules/_opcode.c b/Modules/_opcode.c index 0f28f006d917f7..02ad2590c8710b 100644 --- a/Modules/_opcode.c +++ b/Modules/_opcode.c @@ -367,7 +367,7 @@ _opcode_get_executor_impl(PyObject *module, PyObject *code, int offset) Py_TYPE(code)->tp_name); return NULL; } -#ifdef _Py_TIER2 +#ifdef _Py_JIT return (PyObject *)PyUnstable_GetExecutor((PyCodeObject *)code, offset); #else PyErr_Format(PyExc_RuntimeError, diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index f7952a119f0bd9..9c85a4fdd0ed69 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -985,7 +985,7 @@ get_co_framesize(PyObject *self, PyObject *arg) return PyLong_FromLong(code->co_framesize); } -#ifdef _Py_TIER2 +#ifdef _Py_JIT static PyObject * new_counter_optimizer(PyObject *self, PyObject *arg) @@ -1015,7 +1015,7 @@ static PyObject * get_optimizer(PyObject *self, PyObject *Py_UNUSED(ignored)) { PyObject *opt = NULL; -#ifdef _Py_TIER2 +#ifdef _Py_JIT opt = (PyObject *)PyUnstable_GetOptimizer(); #endif if (opt == NULL) { @@ -2027,7 +2027,7 @@ static PyMethodDef module_functions[] = { {"iframe_getline", iframe_getline, METH_O, NULL}, {"iframe_getlasti", iframe_getlasti, METH_O, NULL}, {"get_co_framesize", get_co_framesize, METH_O, NULL}, -#ifdef _Py_TIER2 +#ifdef _Py_JIT {"get_optimizer", get_optimizer, METH_NOARGS, NULL}, {"set_optimizer", set_optimizer, METH_O, NULL}, {"new_counter_optimizer", new_counter_optimizer, METH_NOARGS, NULL}, @@ -2081,7 +2081,7 @@ static PyMethodDef module_functions[] = { {"py_thread_id", get_py_thread_id, METH_NOARGS}, #endif {"set_immortalize_deferred", set_immortalize_deferred, METH_VARARGS}, -#ifdef _Py_TIER2 +#ifdef _Py_JIT {"uop_symbols_test", _Py_uop_symbols_test, METH_NOARGS}, #endif {NULL, NULL} /* sentinel */ diff --git a/Objects/codeobject.c b/Objects/codeobject.c index 605167c5c0bd3a..76eb1a428fea56 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -1496,7 +1496,7 @@ PyCode_GetFreevars(PyCodeObject *code) return _PyCode_GetFreevars(code); } -#ifdef _Py_TIER2 +#ifdef _Py_JIT static void clear_executors(PyCodeObject *co) @@ -1743,7 +1743,7 @@ code_dealloc(PyCodeObject *co) PyMem_Free(co_extra); } -#ifdef _Py_TIER2 +#ifdef _Py_JIT if (co->co_executors != NULL) { clear_executors(co); } diff --git a/Objects/object.c b/Objects/object.c index 45310a6c22d677..d0a8382d003aa5 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -2281,7 +2281,7 @@ static PyTypeObject* static_types[] = { &_PyBufferWrapper_Type, &_PyContextTokenMissing_Type, &_PyCoroWrapper_Type, -#ifdef _Py_TIER2 +#ifdef _Py_JIT &_PyCounterExecutor_Type, &_PyCounterOptimizer_Type, &_PyDefaultOptimizer_Type, @@ -2306,7 +2306,7 @@ static PyTypeObject* static_types[] = { &_PyPositionsIterator, &_PyUnicodeASCIIIter_Type, &_PyUnion_Type, -#ifdef _Py_TIER2 +#ifdef _Py_JIT &_PyUOpExecutor_Type, &_PyUOpOptimizer_Type, #endif diff --git a/Python/bytecodes.c b/Python/bytecodes.c index da717ddbdaee18..8e2027efd11b21 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2355,7 +2355,7 @@ dummy_func( CHECK_EVAL_BREAKER(); assert(oparg <= INSTR_OFFSET()); JUMPBY(-oparg); - #ifdef _Py_TIER2 + #ifdef _Py_JIT #if ENABLE_SPECIALIZATION _Py_BackoffCounter counter = this_instr[1].counter; if (backoff_counter_triggers(counter) && this_instr->op.code == JUMP_BACKWARD) { @@ -2381,7 +2381,7 @@ dummy_func( ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); } #endif /* ENABLE_SPECIALIZATION */ - #endif /* _Py_TIER2 */ + #endif /* _Py_JIT */ } pseudo(JUMP) = { @@ -2395,7 +2395,7 @@ dummy_func( }; tier1 inst(ENTER_EXECUTOR, (--)) { - #ifdef _Py_TIER2 + #ifdef _Py_JIT int prevoparg = oparg; CHECK_EVAL_BREAKER(); if (this_instr->op.code != ENTER_EXECUTOR || @@ -2415,7 +2415,7 @@ dummy_func( GOTO_TIER_TWO(executor); #else assert(0); - #endif /* _Py_TIER2 */ + #endif /* _Py_JIT */ } replaced op(_POP_JUMP_IF_FALSE, (cond -- )) { diff --git a/Python/ceval.c b/Python/ceval.c index 0e2e4ac7a0b64a..070ec88549a9a7 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -755,7 +755,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int _Py_CODEUNIT *next_instr; PyObject **stack_pointer; -#if defined(_Py_TIER2) && !defined(_Py_JIT) +#if _Py_JIT & 4 /* Tier 2 interpreter state */ _PyExecutorObject *current_executor = NULL; const _PyUOpInstruction *next_uop = NULL; @@ -959,15 +959,11 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int goto error; -#ifdef _Py_TIER2 +#if _Py_JIT & 4 /* Tier 2 interpreter */ // Tier 2 is also here! enter_tier_two: -#ifdef _Py_JIT - assert(0); -#else - #undef LOAD_IP #define LOAD_IP(UNUSED) (void)0 @@ -1112,9 +1108,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int tstate->previous_executor = (PyObject *)current_executor; GOTO_TIER_TWO(exit->executor); -#endif // _Py_JIT - -#endif // _Py_TIER2 +#endif /* _Py_JIT & 4 */ } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index b6386f5189be3f..460a6dfeb99302 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2492,7 +2492,7 @@ (void)this_instr; next_instr += 1; INSTRUCTION_STATS(ENTER_EXECUTOR); - #ifdef _Py_TIER2 + #ifdef _Py_JIT int prevoparg = oparg; CHECK_EVAL_BREAKER(); if (this_instr->op.code != ENTER_EXECUTOR || @@ -2511,7 +2511,7 @@ GOTO_TIER_TWO(executor); #else assert(0); - #endif /* _Py_TIER2 */ + #endif /* _Py_JIT */ DISPATCH(); } @@ -3436,7 +3436,7 @@ CHECK_EVAL_BREAKER(); assert(oparg <= INSTR_OFFSET()); JUMPBY(-oparg); - #ifdef _Py_TIER2 + #ifdef _Py_JIT #if ENABLE_SPECIALIZATION _Py_BackoffCounter counter = this_instr[1].counter; if (backoff_counter_triggers(counter) && this_instr->op.code == JUMP_BACKWARD) { @@ -3462,7 +3462,7 @@ ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); } #endif /* ENABLE_SPECIALIZATION */ - #endif /* _Py_TIER2 */ + #endif /* _Py_JIT */ DISPATCH(); } diff --git a/Python/instrumentation.c b/Python/instrumentation.c index 7c66c6498c8eb2..c340718129942b 100644 --- a/Python/instrumentation.c +++ b/Python/instrumentation.c @@ -1702,7 +1702,7 @@ instrument_lock_held(PyCodeObject *code, PyInterpreterState *interp) ); return 0; } -#ifdef _Py_TIER2 +#ifdef _Py_JIT if (code->co_executors != NULL) { _PyCode_Clear_Executors(code); } @@ -1945,7 +1945,7 @@ _PyMonitoring_SetEvents(int tool_id, _PyMonitoringEventSet events) goto done; } set_global_version(tstate, new_version); -#ifdef _Py_TIER2 +#ifdef _Py_JIT _Py_Executors_InvalidateAll(interp, 1); #endif res = instrument_all_executing_code_objects(interp); @@ -1987,7 +1987,7 @@ _PyMonitoring_SetLocalEvents(PyCodeObject *code, int tool_id, _PyMonitoringEvent code->_co_instrumentation_version -= MONITORING_VERSION_INCREMENT; } -#ifdef _Py_TIER2 +#ifdef _Py_JIT _Py_Executors_InvalidateDependency(interp, code, 1); #endif diff --git a/Python/optimizer.c b/Python/optimizer.c index 4ea3207e7eea47..bffc900e805a81 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -1,3 +1,5 @@ +#ifdef _Py_JIT + #include "Python.h" #include "opcode.h" #include "pycore_interp.h" @@ -15,8 +17,6 @@ #include #include -#ifdef _Py_TIER2 - #define NEED_OPCODE_METADATA #include "pycore_uop_metadata.h" // Uop tables #undef NEED_OPCODE_METADATA @@ -1625,4 +1625,4 @@ _Py_Executors_InvalidateAll(PyInterpreterState *interp, int is_invalidation) } } -#endif /* _Py_TIER2 */ +#endif /* _Py_JIT */ diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 326d6a5f630e45..6f0f39c51cd7ae 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -33,7 +33,7 @@ #include #include -#ifdef _Py_TIER2 +#ifdef _Py_JIT #ifdef Py_DEBUG extern const char *_PyUOpName(int index); @@ -606,4 +606,4 @@ _Py_uop_analyze_and_optimize( return length; } -#endif /* _Py_TIER2 */ +#endif /* _Py_JIT */ diff --git a/Python/optimizer_symbols.c b/Python/optimizer_symbols.c index 07d7598988aa5c..044622c2c10097 100644 --- a/Python/optimizer_symbols.c +++ b/Python/optimizer_symbols.c @@ -1,3 +1,4 @@ +#ifdef _Py_JIT #include "Python.h" @@ -11,8 +12,6 @@ #include #include -#ifdef _Py_TIER2 - /* Symbols ======= @@ -509,4 +508,4 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored)) return NULL; } -#endif /* _Py_TIER2 */ +#endif /* _Py_JIT */ diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 7c7d1c244c8579..17708f2e46aaf2 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -621,7 +621,7 @@ static int builtins_dict_watcher(PyDict_WatchEvent event, PyObject *dict, PyObject *key, PyObject *new_value) { PyInterpreterState *interp = _PyInterpreterState_GET(); -#ifdef _Py_TIER2 +#ifdef _Py_JIT if (interp->rare_events.builtin_dict < _Py_MAX_ALLOWED_BUILTINS_MODIFICATIONS) { _Py_Executors_InvalidateAll(interp, 1); } @@ -1265,7 +1265,7 @@ init_interp_main(PyThreadState *tstate) // Turn on experimental tier 2 (uops-based) optimizer // This is also needed when the JIT is enabled -#ifdef _Py_TIER2 +#ifdef _Py_JIT if (is_main_interp) { PyObject *opt = PyUnstable_Optimizer_NewUOpOptimizer(); if (opt == NULL) { @@ -1636,7 +1636,7 @@ finalize_modules(PyThreadState *tstate) { PyInterpreterState *interp = tstate->interp; -#ifdef _Py_TIER2 +#ifdef _Py_JIT // Invalidate all executors and turn off tier 2 optimizer _Py_Executors_InvalidateAll(interp, 0); _PyOptimizerObject *old = _Py_SetOptimizer(interp, NULL); diff --git a/Python/pystate.c b/Python/pystate.c index 173759ac347152..5ecb80f37492cd 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -653,7 +653,7 @@ init_interpreter(PyInterpreterState *interp, } interp->sys_profile_initialized = false; interp->sys_trace_initialized = false; -#ifdef _Py_TIER2 +#ifdef _Py_JIT (void)_Py_SetOptimizer(interp, NULL); interp->executor_list_head = NULL; #endif @@ -808,7 +808,7 @@ interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate) tstate->_status.cleared = 0; } -#ifdef _Py_TIER2 +#ifdef _Py_JIT _PyOptimizerObject *old = _Py_SetOptimizer(interp, NULL); assert(old != NULL); Py_DECREF(old); @@ -2824,7 +2824,7 @@ _PyInterpreterState_SetEvalFrameFunc(PyInterpreterState *interp, if (eval_frame == interp->eval_frame) { return; } -#ifdef _Py_TIER2 +#ifdef _Py_JIT if (eval_frame != NULL) { _Py_Executors_InvalidateAll(interp, 1); } diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 726051521cf574..226e310545065c 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -2165,7 +2165,7 @@ static PyObject * sys__clear_internal_caches_impl(PyObject *module) /*[clinic end generated code: output=0ee128670a4966d6 input=253e741ca744f6e8]*/ { -#ifdef _Py_TIER2 +#ifdef _Py_JIT PyInterpreterState *interp = _PyInterpreterState_GET(); _Py_Executors_InvalidateAll(interp, 0); #endif From 17f16748092be0ff4058434ec39913de37a73748 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 30 Apr 2024 08:52:46 -0700 Subject: [PATCH 19/40] configure: set _Py_JIT={1|3|4} (for now) --- configure | 9 ++++++--- configure.ac | 9 ++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/configure b/configure index caca9e85758bf9..2c2af2d68309f8 100755 --- a/configure +++ b/configure @@ -8227,14 +8227,17 @@ else $as_nop fi case $enable_experimental_jit in - no|yes|yes-default-off|interpreter) ;; + no) enable_experimental_jit=0 ;; + yes) enable_experimental_jit=1 ;; + yes-default-off) enable_experimental_jit=3 ;; + interpreter) enable_experimental_jit=4 ;; *) as_fn_error $? "invalid argument: --enable-experimental-jit=$enable_experimental_jit; expected no|yes|yes-default-off|interpreter" "$LINENO" 5 ;; esac -if test "x$enable_experimental_jit" = xno +if test "x$enable_experimental_jit" = x0 then : else $as_nop - as_fn_append CFLAGS_NODIST " -D_Py_JIT=_PY_JIT_$(echo $enable_experimental_jit | tr a-z- A-Z_)" + as_fn_append CFLAGS_NODIST " -D_Py_JIT=$enable_experimental_jit" REGEN_JIT_COMMAND="\$(PYTHON_FOR_REGEN) \$(srcdir)/Tools/jit/build.py $host" JIT_STENCILS_H="jit_stencils.h" if test "x$Py_DEBUG" = xtrue diff --git a/configure.ac b/configure.ac index c13566d3d617d4..1341a09c147285 100644 --- a/configure.ac +++ b/configure.ac @@ -1770,14 +1770,17 @@ AC_ARG_ENABLE([experimental-jit], [], [enable_experimental_jit=no]) case $enable_experimental_jit in - no|yes|yes-default-off|interpreter) ;; + no) enable_experimental_jit=0 ;; + yes) enable_experimental_jit=1 ;; + yes-default-off) enable_experimental_jit=3 ;; + interpreter) enable_experimental_jit=4 ;; *) AC_MSG_ERROR( [invalid argument: --enable-experimental-jit=$enable_experimental_jit; expected no|yes|yes-default-off|interpreter]) ;; esac AS_VAR_IF([enable_experimental_jit], - [no], + [0], [], - [AS_VAR_APPEND([CFLAGS_NODIST], [" -D_Py_JIT=_PY_JIT_$(echo $enable_experimental_jit | tr a-z- A-Z_)"]) + [AS_VAR_APPEND([CFLAGS_NODIST], [" -D_Py_JIT=$enable_experimental_jit"]) AS_VAR_SET([REGEN_JIT_COMMAND], ["\$(PYTHON_FOR_REGEN) \$(srcdir)/Tools/jit/build.py $host"]) AS_VAR_SET([JIT_STENCILS_H], ["jit_stencils.h"]) From e23c6881f54b8f9cadd79f6115a294ab9674cc04 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Mon, 29 Apr 2024 16:05:27 -0700 Subject: [PATCH 20/40] Try making WASI Debug recursion limit 300 --- Include/cpython/pystate.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h index 0611e299403031..207f2ea8879b11 100644 --- a/Include/cpython/pystate.h +++ b/Include/cpython/pystate.h @@ -193,7 +193,12 @@ struct _ts { #ifdef Py_DEBUG // A debug build is likely built with low optimization level which implies // higher stack memory usage than a release build: use a lower limit. +#if defined(__wasi__) +   // On WASI it's even worse. +# define Py_C_RECURSION_LIMIT 300 +#else # define Py_C_RECURSION_LIMIT 500 +#endif #elif defined(__s390x__) # define Py_C_RECURSION_LIMIT 800 #elif defined(_WIN32) && defined(_M_ARM64) From ebd8025ba9ad7c97af12de52468a84e777b2a786 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 30 Apr 2024 09:39:52 -0700 Subject: [PATCH 21/40] Revert "Rip out _Py_TIER2, replace with _Py_JIT" This reverts commit 70e18a51e383a246ef029301f25170183d56ff1f. --- Include/Python.h | 5 +++++ Modules/_opcode.c | 2 +- Modules/_testinternalcapi.c | 8 ++++---- Objects/codeobject.c | 4 ++-- Objects/object.c | 4 ++-- Python/bytecodes.c | 8 ++++---- Python/ceval.c | 12 +++++++++--- Python/generated_cases.c.h | 8 ++++---- Python/instrumentation.c | 6 +++--- Python/optimizer.c | 6 +++--- Python/optimizer_analysis.c | 4 ++-- Python/optimizer_symbols.c | 5 +++-- Python/pylifecycle.c | 6 +++--- Python/pystate.c | 6 +++--- Python/sysmodule.c | 2 +- 15 files changed, 49 insertions(+), 37 deletions(-) diff --git a/Include/Python.h b/Include/Python.h index bb771fb3aec980..9ece592db92197 100644 --- a/Include/Python.h +++ b/Include/Python.h @@ -51,6 +51,11 @@ # error "The limited API is not currently supported in the free-threaded build" #endif +// The JIT depends on TIER2 +#ifdef _Py_JIT +#define _Py_TIER2 _Py_JIT +#endif + // Include Python header files #include "pyport.h" #include "pymacro.h" diff --git a/Modules/_opcode.c b/Modules/_opcode.c index 02ad2590c8710b..0f28f006d917f7 100644 --- a/Modules/_opcode.c +++ b/Modules/_opcode.c @@ -367,7 +367,7 @@ _opcode_get_executor_impl(PyObject *module, PyObject *code, int offset) Py_TYPE(code)->tp_name); return NULL; } -#ifdef _Py_JIT +#ifdef _Py_TIER2 return (PyObject *)PyUnstable_GetExecutor((PyCodeObject *)code, offset); #else PyErr_Format(PyExc_RuntimeError, diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index 9c85a4fdd0ed69..f7952a119f0bd9 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -985,7 +985,7 @@ get_co_framesize(PyObject *self, PyObject *arg) return PyLong_FromLong(code->co_framesize); } -#ifdef _Py_JIT +#ifdef _Py_TIER2 static PyObject * new_counter_optimizer(PyObject *self, PyObject *arg) @@ -1015,7 +1015,7 @@ static PyObject * get_optimizer(PyObject *self, PyObject *Py_UNUSED(ignored)) { PyObject *opt = NULL; -#ifdef _Py_JIT +#ifdef _Py_TIER2 opt = (PyObject *)PyUnstable_GetOptimizer(); #endif if (opt == NULL) { @@ -2027,7 +2027,7 @@ static PyMethodDef module_functions[] = { {"iframe_getline", iframe_getline, METH_O, NULL}, {"iframe_getlasti", iframe_getlasti, METH_O, NULL}, {"get_co_framesize", get_co_framesize, METH_O, NULL}, -#ifdef _Py_JIT +#ifdef _Py_TIER2 {"get_optimizer", get_optimizer, METH_NOARGS, NULL}, {"set_optimizer", set_optimizer, METH_O, NULL}, {"new_counter_optimizer", new_counter_optimizer, METH_NOARGS, NULL}, @@ -2081,7 +2081,7 @@ static PyMethodDef module_functions[] = { {"py_thread_id", get_py_thread_id, METH_NOARGS}, #endif {"set_immortalize_deferred", set_immortalize_deferred, METH_VARARGS}, -#ifdef _Py_JIT +#ifdef _Py_TIER2 {"uop_symbols_test", _Py_uop_symbols_test, METH_NOARGS}, #endif {NULL, NULL} /* sentinel */ diff --git a/Objects/codeobject.c b/Objects/codeobject.c index 76eb1a428fea56..605167c5c0bd3a 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -1496,7 +1496,7 @@ PyCode_GetFreevars(PyCodeObject *code) return _PyCode_GetFreevars(code); } -#ifdef _Py_JIT +#ifdef _Py_TIER2 static void clear_executors(PyCodeObject *co) @@ -1743,7 +1743,7 @@ code_dealloc(PyCodeObject *co) PyMem_Free(co_extra); } -#ifdef _Py_JIT +#ifdef _Py_TIER2 if (co->co_executors != NULL) { clear_executors(co); } diff --git a/Objects/object.c b/Objects/object.c index d0a8382d003aa5..45310a6c22d677 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -2281,7 +2281,7 @@ static PyTypeObject* static_types[] = { &_PyBufferWrapper_Type, &_PyContextTokenMissing_Type, &_PyCoroWrapper_Type, -#ifdef _Py_JIT +#ifdef _Py_TIER2 &_PyCounterExecutor_Type, &_PyCounterOptimizer_Type, &_PyDefaultOptimizer_Type, @@ -2306,7 +2306,7 @@ static PyTypeObject* static_types[] = { &_PyPositionsIterator, &_PyUnicodeASCIIIter_Type, &_PyUnion_Type, -#ifdef _Py_JIT +#ifdef _Py_TIER2 &_PyUOpExecutor_Type, &_PyUOpOptimizer_Type, #endif diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 8e2027efd11b21..da717ddbdaee18 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2355,7 +2355,7 @@ dummy_func( CHECK_EVAL_BREAKER(); assert(oparg <= INSTR_OFFSET()); JUMPBY(-oparg); - #ifdef _Py_JIT + #ifdef _Py_TIER2 #if ENABLE_SPECIALIZATION _Py_BackoffCounter counter = this_instr[1].counter; if (backoff_counter_triggers(counter) && this_instr->op.code == JUMP_BACKWARD) { @@ -2381,7 +2381,7 @@ dummy_func( ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); } #endif /* ENABLE_SPECIALIZATION */ - #endif /* _Py_JIT */ + #endif /* _Py_TIER2 */ } pseudo(JUMP) = { @@ -2395,7 +2395,7 @@ dummy_func( }; tier1 inst(ENTER_EXECUTOR, (--)) { - #ifdef _Py_JIT + #ifdef _Py_TIER2 int prevoparg = oparg; CHECK_EVAL_BREAKER(); if (this_instr->op.code != ENTER_EXECUTOR || @@ -2415,7 +2415,7 @@ dummy_func( GOTO_TIER_TWO(executor); #else assert(0); - #endif /* _Py_JIT */ + #endif /* _Py_TIER2 */ } replaced op(_POP_JUMP_IF_FALSE, (cond -- )) { diff --git a/Python/ceval.c b/Python/ceval.c index 070ec88549a9a7..0e2e4ac7a0b64a 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -755,7 +755,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int _Py_CODEUNIT *next_instr; PyObject **stack_pointer; -#if _Py_JIT & 4 +#if defined(_Py_TIER2) && !defined(_Py_JIT) /* Tier 2 interpreter state */ _PyExecutorObject *current_executor = NULL; const _PyUOpInstruction *next_uop = NULL; @@ -959,11 +959,15 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int goto error; -#if _Py_JIT & 4 /* Tier 2 interpreter */ +#ifdef _Py_TIER2 // Tier 2 is also here! enter_tier_two: +#ifdef _Py_JIT + assert(0); +#else + #undef LOAD_IP #define LOAD_IP(UNUSED) (void)0 @@ -1108,7 +1112,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int tstate->previous_executor = (PyObject *)current_executor; GOTO_TIER_TWO(exit->executor); -#endif /* _Py_JIT & 4 */ +#endif // _Py_JIT + +#endif // _Py_TIER2 } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 460a6dfeb99302..b6386f5189be3f 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2492,7 +2492,7 @@ (void)this_instr; next_instr += 1; INSTRUCTION_STATS(ENTER_EXECUTOR); - #ifdef _Py_JIT + #ifdef _Py_TIER2 int prevoparg = oparg; CHECK_EVAL_BREAKER(); if (this_instr->op.code != ENTER_EXECUTOR || @@ -2511,7 +2511,7 @@ GOTO_TIER_TWO(executor); #else assert(0); - #endif /* _Py_JIT */ + #endif /* _Py_TIER2 */ DISPATCH(); } @@ -3436,7 +3436,7 @@ CHECK_EVAL_BREAKER(); assert(oparg <= INSTR_OFFSET()); JUMPBY(-oparg); - #ifdef _Py_JIT + #ifdef _Py_TIER2 #if ENABLE_SPECIALIZATION _Py_BackoffCounter counter = this_instr[1].counter; if (backoff_counter_triggers(counter) && this_instr->op.code == JUMP_BACKWARD) { @@ -3462,7 +3462,7 @@ ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); } #endif /* ENABLE_SPECIALIZATION */ - #endif /* _Py_JIT */ + #endif /* _Py_TIER2 */ DISPATCH(); } diff --git a/Python/instrumentation.c b/Python/instrumentation.c index c340718129942b..7c66c6498c8eb2 100644 --- a/Python/instrumentation.c +++ b/Python/instrumentation.c @@ -1702,7 +1702,7 @@ instrument_lock_held(PyCodeObject *code, PyInterpreterState *interp) ); return 0; } -#ifdef _Py_JIT +#ifdef _Py_TIER2 if (code->co_executors != NULL) { _PyCode_Clear_Executors(code); } @@ -1945,7 +1945,7 @@ _PyMonitoring_SetEvents(int tool_id, _PyMonitoringEventSet events) goto done; } set_global_version(tstate, new_version); -#ifdef _Py_JIT +#ifdef _Py_TIER2 _Py_Executors_InvalidateAll(interp, 1); #endif res = instrument_all_executing_code_objects(interp); @@ -1987,7 +1987,7 @@ _PyMonitoring_SetLocalEvents(PyCodeObject *code, int tool_id, _PyMonitoringEvent code->_co_instrumentation_version -= MONITORING_VERSION_INCREMENT; } -#ifdef _Py_JIT +#ifdef _Py_TIER2 _Py_Executors_InvalidateDependency(interp, code, 1); #endif diff --git a/Python/optimizer.c b/Python/optimizer.c index bffc900e805a81..4ea3207e7eea47 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -1,5 +1,3 @@ -#ifdef _Py_JIT - #include "Python.h" #include "opcode.h" #include "pycore_interp.h" @@ -17,6 +15,8 @@ #include #include +#ifdef _Py_TIER2 + #define NEED_OPCODE_METADATA #include "pycore_uop_metadata.h" // Uop tables #undef NEED_OPCODE_METADATA @@ -1625,4 +1625,4 @@ _Py_Executors_InvalidateAll(PyInterpreterState *interp, int is_invalidation) } } -#endif /* _Py_JIT */ +#endif /* _Py_TIER2 */ diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 6f0f39c51cd7ae..326d6a5f630e45 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -33,7 +33,7 @@ #include #include -#ifdef _Py_JIT +#ifdef _Py_TIER2 #ifdef Py_DEBUG extern const char *_PyUOpName(int index); @@ -606,4 +606,4 @@ _Py_uop_analyze_and_optimize( return length; } -#endif /* _Py_JIT */ +#endif /* _Py_TIER2 */ diff --git a/Python/optimizer_symbols.c b/Python/optimizer_symbols.c index 044622c2c10097..07d7598988aa5c 100644 --- a/Python/optimizer_symbols.c +++ b/Python/optimizer_symbols.c @@ -1,4 +1,3 @@ -#ifdef _Py_JIT #include "Python.h" @@ -12,6 +11,8 @@ #include #include +#ifdef _Py_TIER2 + /* Symbols ======= @@ -508,4 +509,4 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored)) return NULL; } -#endif /* _Py_JIT */ +#endif /* _Py_TIER2 */ diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 17708f2e46aaf2..7c7d1c244c8579 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -621,7 +621,7 @@ static int builtins_dict_watcher(PyDict_WatchEvent event, PyObject *dict, PyObject *key, PyObject *new_value) { PyInterpreterState *interp = _PyInterpreterState_GET(); -#ifdef _Py_JIT +#ifdef _Py_TIER2 if (interp->rare_events.builtin_dict < _Py_MAX_ALLOWED_BUILTINS_MODIFICATIONS) { _Py_Executors_InvalidateAll(interp, 1); } @@ -1265,7 +1265,7 @@ init_interp_main(PyThreadState *tstate) // Turn on experimental tier 2 (uops-based) optimizer // This is also needed when the JIT is enabled -#ifdef _Py_JIT +#ifdef _Py_TIER2 if (is_main_interp) { PyObject *opt = PyUnstable_Optimizer_NewUOpOptimizer(); if (opt == NULL) { @@ -1636,7 +1636,7 @@ finalize_modules(PyThreadState *tstate) { PyInterpreterState *interp = tstate->interp; -#ifdef _Py_JIT +#ifdef _Py_TIER2 // Invalidate all executors and turn off tier 2 optimizer _Py_Executors_InvalidateAll(interp, 0); _PyOptimizerObject *old = _Py_SetOptimizer(interp, NULL); diff --git a/Python/pystate.c b/Python/pystate.c index 5ecb80f37492cd..173759ac347152 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -653,7 +653,7 @@ init_interpreter(PyInterpreterState *interp, } interp->sys_profile_initialized = false; interp->sys_trace_initialized = false; -#ifdef _Py_JIT +#ifdef _Py_TIER2 (void)_Py_SetOptimizer(interp, NULL); interp->executor_list_head = NULL; #endif @@ -808,7 +808,7 @@ interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate) tstate->_status.cleared = 0; } -#ifdef _Py_JIT +#ifdef _Py_TIER2 _PyOptimizerObject *old = _Py_SetOptimizer(interp, NULL); assert(old != NULL); Py_DECREF(old); @@ -2824,7 +2824,7 @@ _PyInterpreterState_SetEvalFrameFunc(PyInterpreterState *interp, if (eval_frame == interp->eval_frame) { return; } -#ifdef _Py_JIT +#ifdef _Py_TIER2 if (eval_frame != NULL) { _Py_Executors_InvalidateAll(interp, 1); } diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 226e310545065c..726051521cf574 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -2165,7 +2165,7 @@ static PyObject * sys__clear_internal_caches_impl(PyObject *module) /*[clinic end generated code: output=0ee128670a4966d6 input=253e741ca744f6e8]*/ { -#ifdef _Py_JIT +#ifdef _Py_TIER2 PyInterpreterState *interp = _PyInterpreterState_GET(); _Py_Executors_InvalidateAll(interp, 0); #endif From e367c2724fd23b127a522272ddc7956f092d653f Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 30 Apr 2024 09:58:52 -0700 Subject: [PATCH 22/40] Make the configure script set both _Py_JIT and _Py_TIER2, as appropriate --- Include/Python.h | 5 ----- Python/optimizer.c | 4 ++-- Python/optimizer_analysis.c | 4 ++-- Python/optimizer_symbols.c | 3 +-- configure | 12 ++++++------ configure.ac | 12 ++++++------ 6 files changed, 17 insertions(+), 23 deletions(-) diff --git a/Include/Python.h b/Include/Python.h index 9ece592db92197..bb771fb3aec980 100644 --- a/Include/Python.h +++ b/Include/Python.h @@ -51,11 +51,6 @@ # error "The limited API is not currently supported in the free-threaded build" #endif -// The JIT depends on TIER2 -#ifdef _Py_JIT -#define _Py_TIER2 _Py_JIT -#endif - // Include Python header files #include "pyport.h" #include "pymacro.h" diff --git a/Python/optimizer.c b/Python/optimizer.c index 4ea3207e7eea47..288513eab81e07 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -1,3 +1,5 @@ +#ifdef _Py_TIER2 + #include "Python.h" #include "opcode.h" #include "pycore_interp.h" @@ -15,8 +17,6 @@ #include #include -#ifdef _Py_TIER2 - #define NEED_OPCODE_METADATA #include "pycore_uop_metadata.h" // Uop tables #undef NEED_OPCODE_METADATA diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 326d6a5f630e45..842b2e489239af 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -1,3 +1,5 @@ +#ifdef _Py_TIER2 + /* * This file contains the support code for CPython's uops optimizer. * It also performs some simple optimizations. @@ -33,8 +35,6 @@ #include #include -#ifdef _Py_TIER2 - #ifdef Py_DEBUG extern const char *_PyUOpName(int index); extern void _PyUOpPrint(const _PyUOpInstruction *uop); diff --git a/Python/optimizer_symbols.c b/Python/optimizer_symbols.c index 07d7598988aa5c..d52f490853c006 100644 --- a/Python/optimizer_symbols.c +++ b/Python/optimizer_symbols.c @@ -1,3 +1,4 @@ +#ifdef _Py_TIER2 #include "Python.h" @@ -11,8 +12,6 @@ #include #include -#ifdef _Py_TIER2 - /* Symbols ======= diff --git a/configure b/configure index 2c2af2d68309f8..6ab17938c48b6c 100755 --- a/configure +++ b/configure @@ -8227,17 +8227,17 @@ else $as_nop fi case $enable_experimental_jit in - no) enable_experimental_jit=0 ;; - yes) enable_experimental_jit=1 ;; - yes-default-off) enable_experimental_jit=3 ;; - interpreter) enable_experimental_jit=4 ;; + no) enable_experimental_jit=no ;; + yes) enable_experimental_jit="-D_Py_JIT=1 -D_Py_TIER2" ;; + yes-default-off) enable_experimental_jit="-D_Py_JIT=3 -D_Py_TIER2" ;; + interpreter) enable_experimental_jit="-D_Py_TIER2" ;; *) as_fn_error $? "invalid argument: --enable-experimental-jit=$enable_experimental_jit; expected no|yes|yes-default-off|interpreter" "$LINENO" 5 ;; esac -if test "x$enable_experimental_jit" = x0 +if test "x$enable_experimental_jit" = xno then : else $as_nop - as_fn_append CFLAGS_NODIST " -D_Py_JIT=$enable_experimental_jit" + as_fn_append CFLAGS_NODIST " $enable_experimental_jit" REGEN_JIT_COMMAND="\$(PYTHON_FOR_REGEN) \$(srcdir)/Tools/jit/build.py $host" JIT_STENCILS_H="jit_stencils.h" if test "x$Py_DEBUG" = xtrue diff --git a/configure.ac b/configure.ac index 1341a09c147285..8950f4d58b7322 100644 --- a/configure.ac +++ b/configure.ac @@ -1770,17 +1770,17 @@ AC_ARG_ENABLE([experimental-jit], [], [enable_experimental_jit=no]) case $enable_experimental_jit in - no) enable_experimental_jit=0 ;; - yes) enable_experimental_jit=1 ;; - yes-default-off) enable_experimental_jit=3 ;; - interpreter) enable_experimental_jit=4 ;; + no) enable_experimental_jit=no ;; + yes) enable_experimental_jit="-D_Py_JIT=1 -D_Py_TIER2" ;; + yes-default-off) enable_experimental_jit="-D_Py_JIT=3 -D_Py_TIER2" ;; + interpreter) enable_experimental_jit="-D_Py_TIER2" ;; *) AC_MSG_ERROR( [invalid argument: --enable-experimental-jit=$enable_experimental_jit; expected no|yes|yes-default-off|interpreter]) ;; esac AS_VAR_IF([enable_experimental_jit], - [0], + [no], [], - [AS_VAR_APPEND([CFLAGS_NODIST], [" -D_Py_JIT=$enable_experimental_jit"]) + [AS_VAR_APPEND([CFLAGS_NODIST], [" $enable_experimental_jit"]) AS_VAR_SET([REGEN_JIT_COMMAND], ["\$(PYTHON_FOR_REGEN) \$(srcdir)/Tools/jit/build.py $host"]) AS_VAR_SET([JIT_STENCILS_H], ["jit_stencils.h"]) From 86818130133adc11d910549f573b213dfe687a39 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 30 Apr 2024 10:09:07 -0700 Subject: [PATCH 23/40] Pass flag bit in _Py_TIER2 instead of _Py_JIT --- configure | 6 +++--- configure.ac | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/configure b/configure index 6ab17938c48b6c..5df7d1960d9e05 100755 --- a/configure +++ b/configure @@ -8228,9 +8228,9 @@ fi case $enable_experimental_jit in no) enable_experimental_jit=no ;; - yes) enable_experimental_jit="-D_Py_JIT=1 -D_Py_TIER2" ;; - yes-default-off) enable_experimental_jit="-D_Py_JIT=3 -D_Py_TIER2" ;; - interpreter) enable_experimental_jit="-D_Py_TIER2" ;; + yes) enable_experimental_jit="-D_Py_JIT -D_Py_TIER2=1" ;; + yes-default-off) enable_experimental_jit="-D_Py_JIT -D_Py_TIER2=3" ;; + interpreter) enable_experimental_jit="-D_Py_TIER2=4" ;; *) as_fn_error $? "invalid argument: --enable-experimental-jit=$enable_experimental_jit; expected no|yes|yes-default-off|interpreter" "$LINENO" 5 ;; esac if test "x$enable_experimental_jit" = xno diff --git a/configure.ac b/configure.ac index 8950f4d58b7322..a4b1c439e9d3e6 100644 --- a/configure.ac +++ b/configure.ac @@ -1771,9 +1771,9 @@ AC_ARG_ENABLE([experimental-jit], [enable_experimental_jit=no]) case $enable_experimental_jit in no) enable_experimental_jit=no ;; - yes) enable_experimental_jit="-D_Py_JIT=1 -D_Py_TIER2" ;; - yes-default-off) enable_experimental_jit="-D_Py_JIT=3 -D_Py_TIER2" ;; - interpreter) enable_experimental_jit="-D_Py_TIER2" ;; + yes) enable_experimental_jit="-D_Py_JIT -D_Py_TIER2=1" ;; + yes-default-off) enable_experimental_jit="-D_Py_JIT -D_Py_TIER2=3" ;; + interpreter) enable_experimental_jit="-D_Py_TIER2=4" ;; *) AC_MSG_ERROR( [invalid argument: --enable-experimental-jit=$enable_experimental_jit; expected no|yes|yes-default-off|interpreter]) ;; esac From 8f89b3bb9e1ff714820eab9711b36068a24bc136 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 30 Apr 2024 10:29:28 -0700 Subject: [PATCH 24/40] Honor default-off and PYTHON_JIT=0|1 --- Python/pylifecycle.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 7c7d1c244c8579..f08b938668df85 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1267,6 +1267,16 @@ init_interp_main(PyThreadState *tstate) // This is also needed when the JIT is enabled #ifdef _Py_TIER2 if (is_main_interp) { + int enabled = 1; +#if _Py_TIER2 & 2 + enabled = 0; +#endif + char *env = Py_GETENV("PYTHON_JIT"); + if (env && *env != '\0') { + // PYTHON_JIT=0|1 overrides the default + enabled = *env != '0'; + } + if (enabled) { PyObject *opt = PyUnstable_Optimizer_NewUOpOptimizer(); if (opt == NULL) { return _PyStatus_ERR("can't initialize optimizer"); @@ -1275,6 +1285,7 @@ init_interp_main(PyThreadState *tstate) return _PyStatus_ERR("can't install optimizer"); } Py_DECREF(opt); + } } #endif From fe94220ccf69356c30efc02c8b0c33631244695b Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 30 Apr 2024 10:30:03 -0700 Subject: [PATCH 25/40] Add interpreter-default-off as secret menu item --- configure | 1 + configure.ac | 1 + 2 files changed, 2 insertions(+) diff --git a/configure b/configure index 5df7d1960d9e05..72aba35ae89ace 100755 --- a/configure +++ b/configure @@ -8231,6 +8231,7 @@ case $enable_experimental_jit in yes) enable_experimental_jit="-D_Py_JIT -D_Py_TIER2=1" ;; yes-default-off) enable_experimental_jit="-D_Py_JIT -D_Py_TIER2=3" ;; interpreter) enable_experimental_jit="-D_Py_TIER2=4" ;; + interpreter-default-off) enable_experimental_jit="-D_Py_TIER2=6" ;; # Secret option *) as_fn_error $? "invalid argument: --enable-experimental-jit=$enable_experimental_jit; expected no|yes|yes-default-off|interpreter" "$LINENO" 5 ;; esac if test "x$enable_experimental_jit" = xno diff --git a/configure.ac b/configure.ac index a4b1c439e9d3e6..a7120fa411e22b 100644 --- a/configure.ac +++ b/configure.ac @@ -1774,6 +1774,7 @@ case $enable_experimental_jit in yes) enable_experimental_jit="-D_Py_JIT -D_Py_TIER2=1" ;; yes-default-off) enable_experimental_jit="-D_Py_JIT -D_Py_TIER2=3" ;; interpreter) enable_experimental_jit="-D_Py_TIER2=4" ;; + interpreter-default-off) enable_experimental_jit="-D_Py_TIER2=6" ;; # Secret option *) AC_MSG_ERROR( [invalid argument: --enable-experimental-jit=$enable_experimental_jit; expected no|yes|yes-default-off|interpreter]) ;; esac From 2963ccbaba9a08ed8132387288f3490f371b129d Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 30 Apr 2024 10:31:38 -0700 Subject: [PATCH 26/40] Revert "Try making WASI Debug recursion limit 300" It seems to make no difference. This reverts commit e23c6881f54b8f9cadd79f6115a294ab9674cc04. --- Include/cpython/pystate.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h index 207f2ea8879b11..0611e299403031 100644 --- a/Include/cpython/pystate.h +++ b/Include/cpython/pystate.h @@ -193,12 +193,7 @@ struct _ts { #ifdef Py_DEBUG // A debug build is likely built with low optimization level which implies // higher stack memory usage than a release build: use a lower limit. -#if defined(__wasi__) -   // On WASI it's even worse. -# define Py_C_RECURSION_LIMIT 300 -#else # define Py_C_RECURSION_LIMIT 500 -#endif #elif defined(__s390x__) # define Py_C_RECURSION_LIMIT 800 #elif defined(_WIN32) && defined(_M_ARM64) From f45f7caabf57cd5e1adf034f147e9ea07bc90d6d Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 30 Apr 2024 10:38:11 -0700 Subject: [PATCH 27/40] Also predefine _Py_TIER2 on Windows if UseJIT is true --- PCbuild/_testinternalcapi.vcxproj | 1 + PCbuild/pythoncore.vcxproj | 1 + 2 files changed, 2 insertions(+) diff --git a/PCbuild/_testinternalcapi.vcxproj b/PCbuild/_testinternalcapi.vcxproj index d35278460218e7..946d1249dc4f30 100644 --- a/PCbuild/_testinternalcapi.vcxproj +++ b/PCbuild/_testinternalcapi.vcxproj @@ -111,6 +111,7 @@ _Py_JIT;%(PreprocessorDefinitions) + _Py_TIER2;%(PreprocessorDefinitions) diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index 25d52945c1c330..e412e0c06cfe41 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -105,6 +105,7 @@ _USRDLL;Py_BUILD_CORE;Py_BUILD_CORE_BUILTIN;Py_ENABLE_SHARED;MS_DLL_ID="$(SysWinVer)";%(PreprocessorDefinitions) _Py_HAVE_ZLIB;%(PreprocessorDefinitions) _Py_JIT;%(PreprocessorDefinitions) + _Py_TIER2;%(PreprocessorDefinitions) version.lib;ws2_32.lib;pathcch.lib;bcrypt.lib;%(AdditionalDependencies) From 391bd46fd0f6a4ee3041ae1e499d104a0e3b685c Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 30 Apr 2024 10:49:43 -0700 Subject: [PATCH 28/40] Trashcan consumes more C stack (experimental, targeting WASI Debug build) --- Include/cpython/object.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Include/cpython/object.h b/Include/cpython/object.h index a6b93b93ab0f7a..4875b2c26ea304 100644 --- a/Include/cpython/object.h +++ b/Include/cpython/object.h @@ -468,8 +468,8 @@ PyAPI_FUNC(void) _PyTrash_thread_destroy_chain(PyThreadState *tstate); /* Python 3.10 private API, invoked by the Py_TRASHCAN_BEGIN(). */ -/* To avoid raising recursion errors during dealloc trigger trashcan before we reach - * recursion limit. To avoid trashing, we don't attempt to empty the trashcan until +/* To avoid raising recursion errors during dealloc, trigger trashcan before we reach + * recursion limit. To avoid thrashing, we don't attempt to empty the trashcan until * we have headroom above the trigger limit */ #define Py_TRASHCAN_HEADROOM 50 @@ -480,10 +480,10 @@ do { \ _PyTrash_thread_deposit_object(tstate, (PyObject *)op); \ break; \ } \ - tstate->c_recursion_remaining--; + tstate->c_recursion_remaining -= 2; /* The body of the deallocator is here. */ #define Py_TRASHCAN_END \ - tstate->c_recursion_remaining++; \ + tstate->c_recursion_remaining += 2; \ if (tstate->delete_later && tstate->c_recursion_remaining > (Py_TRASHCAN_HEADROOM*2)) { \ _PyTrash_thread_destroy_chain(tstate); \ } \ From c5d8c0a64c27cf309906762cfa0c811f3d0ea83d Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 30 Apr 2024 11:36:56 -0700 Subject: [PATCH 29/40] Update what's new for new --enable-experimental-jit options --- Doc/whatsnew/3.13.rst | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index d094e646f8dbcd..470e635708a1b6 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -888,7 +888,7 @@ Experimental JIT Compiler ========================= When CPython is configured using the ``--enable-experimental-jit`` option, -a just-in-time compiler is added which can speed up some Python programs. +a just-in-time compiler is added which may speed up some Python programs. The internal architecture is roughly as follows. @@ -905,18 +905,35 @@ The internal architecture is roughly as follows. before it is interpreted or translated to machine code. * There is a Tier 2 interpreter, but it is mostly intended for debugging - the earlier stages of the optimization pipeline. If the JIT is not - enabled, the Tier 2 interpreter can be enabled by configuring Python - with the ``--enable-experimental-tier2`` option. + the earlier stages of the optimization pipeline. + The Tier 2 interpreter can be enabled by configuring Python + with ``--enable-experimental-jit=interpreter``. -* When the ``--enable-experimental-jit`` option is used, the optimized +* When the JIT is enabled, the optimized Tier 2 IR is translated to machine code, which is then executed. - This does not require additional runtime options. * The machine code translation process uses an architecture called *copy-and-patch*. It has no runtime dependencies, but there is a new build-time dependency on LLVM. +The ``--enable-experimental-jit`` flag has the following optional values: + +* ``no`` (default) -- Disable the entire Tier 2 and JIT pipeline. + +* ``yes`` (default if the flag is present without optional value) + -- Enable the JIT. To disable the JIT at runtime, + pass the environment variable ``PYTHON_JIT=0``. + +* ``yes-default-off`` -- Build the JIT but disable it by default. + To emable the JIT at runtime, pass the environment variable + ``PYTHON_JIT=1``. + +* ``interpreter`` -- Enable the Tier 2 interpreter but disable the JIT. + The interpreter can be disabled by running with + ``PYTHON_JIT=0``. + +(On Windows, use ``PCbuild/build.bat --enable-jit`` to enable the JIT.) + See :pep:`744` for more details. (JIT by Brandt Bucher, inspired by a paper by Haoran Xu and Fredrik Kjolstad. From f45bf67f1f092e997b47eb84a745feef3cde676b Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 30 Apr 2024 11:37:08 -0700 Subject: [PATCH 30/40] Revert "Trashcan consumes more C stack (experimental, targeting WASI Debug build)" This doesn't work either. This reverts commit 391bd46fd0f6a4ee3041ae1e499d104a0e3b685c. --- Include/cpython/object.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Include/cpython/object.h b/Include/cpython/object.h index 4875b2c26ea304..a6b93b93ab0f7a 100644 --- a/Include/cpython/object.h +++ b/Include/cpython/object.h @@ -468,8 +468,8 @@ PyAPI_FUNC(void) _PyTrash_thread_destroy_chain(PyThreadState *tstate); /* Python 3.10 private API, invoked by the Py_TRASHCAN_BEGIN(). */ -/* To avoid raising recursion errors during dealloc, trigger trashcan before we reach - * recursion limit. To avoid thrashing, we don't attempt to empty the trashcan until +/* To avoid raising recursion errors during dealloc trigger trashcan before we reach + * recursion limit. To avoid trashing, we don't attempt to empty the trashcan until * we have headroom above the trigger limit */ #define Py_TRASHCAN_HEADROOM 50 @@ -480,10 +480,10 @@ do { \ _PyTrash_thread_deposit_object(tstate, (PyObject *)op); \ break; \ } \ - tstate->c_recursion_remaining -= 2; + tstate->c_recursion_remaining--; /* The body of the deallocator is here. */ #define Py_TRASHCAN_END \ - tstate->c_recursion_remaining += 2; \ + tstate->c_recursion_remaining++; \ if (tstate->delete_later && tstate->c_recursion_remaining > (Py_TRASHCAN_HEADROOM*2)) { \ _PyTrash_thread_destroy_chain(tstate); \ } \ From a6cc5ee7f900d6f5afd2743aed9accbf826afa09 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 30 Apr 2024 11:40:35 -0700 Subject: [PATCH 31/40] Just disable test_trashcan_16602 on WASI Debug builds --- Lib/test/test_weakref.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_weakref.py b/Lib/test/test_weakref.py index df90647baee31e..c964f33667d5e2 100644 --- a/Lib/test/test_weakref.py +++ b/Lib/test/test_weakref.py @@ -13,7 +13,7 @@ import textwrap from test import support -from test.support import script_helper, ALWAYS_EQ, suppress_immortalization +from test.support import script_helper, ALWAYS_EQ, suppress_immortalization, is_wasi from test.support import gc_collect from test.support import import_helper from test.support import threading_helper @@ -960,6 +960,7 @@ def test_hashing(self): self.assertEqual(hash(a), hash(42)) self.assertRaises(TypeError, hash, b) + @unittest.skipIf(is_wasi and Py_DEBUG, "requires deep stack") def test_trashcan_16602(self): # Issue #16602: when a weakref's target was part of a long # deallocation chain, the trashcan mechanism could delay clearing From 35cb5bd155c8a77a3e7b0ce728e167f6e6ba9c71 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 30 Apr 2024 13:33:06 -0700 Subject: [PATCH 32/40] Fix test_weakref :-( --- Lib/test/test_weakref.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_weakref.py b/Lib/test/test_weakref.py index c964f33667d5e2..16da24d7805b56 100644 --- a/Lib/test/test_weakref.py +++ b/Lib/test/test_weakref.py @@ -13,10 +13,11 @@ import textwrap from test import support -from test.support import script_helper, ALWAYS_EQ, suppress_immortalization, is_wasi +from test.support import script_helper, ALWAYS_EQ, suppress_immortalization from test.support import gc_collect from test.support import import_helper from test.support import threading_helper +from test.support import is_wasi, Py_DEBUG # Used in ReferencesTestCase.test_ref_created_during_del() . ref_from_del = None From 8276a9a6e2a612127e75c8bc98f5358c64bd50d5 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 30 Apr 2024 15:01:53 -0700 Subject: [PATCH 33/40] Shorten to --enable-exerimental-jit=yes-off --- Doc/whatsnew/3.13.rst | 4 ++-- configure | 8 ++++---- configure.ac | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index 470e635708a1b6..74b0bc5a746a2e 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -924,8 +924,8 @@ The ``--enable-experimental-jit`` flag has the following optional values: -- Enable the JIT. To disable the JIT at runtime, pass the environment variable ``PYTHON_JIT=0``. -* ``yes-default-off`` -- Build the JIT but disable it by default. - To emable the JIT at runtime, pass the environment variable +* ``yes-off`` -- Build the JIT but disable it by default. + To enable the JIT at runtime, pass the environment variable ``PYTHON_JIT=1``. * ``interpreter`` -- Enable the Tier 2 interpreter but disable the JIT. diff --git a/configure b/configure index ebd6272f89ba54..01c00d2198548f 100755 --- a/configure +++ b/configure @@ -1818,7 +1818,7 @@ Optional Features: --disable-gil enable experimental support for running without the GIL (default is no) --enable-pystats enable internal statistics gathering (default is no) - --enable-experimental-jit[=no|yes|yes-default-off|interpreter] + --enable-experimental-jit[=no|yes|yes-off|interpreter] build the experimental just-in-time compiler (default is no) --enable-optimizations enable expensive, stable optimizations (PGO, etc.) @@ -8232,10 +8232,10 @@ fi case $enable_experimental_jit in no) enable_experimental_jit=no ;; yes) enable_experimental_jit="-D_Py_JIT -D_Py_TIER2=1" ;; - yes-default-off) enable_experimental_jit="-D_Py_JIT -D_Py_TIER2=3" ;; + yes-off) enable_experimental_jit="-D_Py_JIT -D_Py_TIER2=3" ;; interpreter) enable_experimental_jit="-D_Py_TIER2=4" ;; - interpreter-default-off) enable_experimental_jit="-D_Py_TIER2=6" ;; # Secret option - *) as_fn_error $? "invalid argument: --enable-experimental-jit=$enable_experimental_jit; expected no|yes|yes-default-off|interpreter" "$LINENO" 5 ;; + interpreter-off) enable_experimental_jit="-D_Py_TIER2=6" ;; # Secret option + *) as_fn_error $? "invalid argument: --enable-experimental-jit=$enable_experimental_jit; expected no|yes|yes-off|interpreter" "$LINENO" 5 ;; esac if test "x$enable_experimental_jit" = xno then : diff --git a/configure.ac b/configure.ac index 8188a22029ebba..ae65efeac55366 100644 --- a/configure.ac +++ b/configure.ac @@ -1768,18 +1768,18 @@ fi # Check for --enable-experimental-jit: AC_MSG_CHECKING([for --enable-experimental-jit]) AC_ARG_ENABLE([experimental-jit], - [AS_HELP_STRING([--enable-experimental-jit@<:@=no|yes|yes-default-off|interpreter@:>@], + [AS_HELP_STRING([--enable-experimental-jit@<:@=no|yes|yes-off|interpreter@:>@], [build the experimental just-in-time compiler (default is no)])], [], [enable_experimental_jit=no]) case $enable_experimental_jit in no) enable_experimental_jit=no ;; yes) enable_experimental_jit="-D_Py_JIT -D_Py_TIER2=1" ;; - yes-default-off) enable_experimental_jit="-D_Py_JIT -D_Py_TIER2=3" ;; + yes-off) enable_experimental_jit="-D_Py_JIT -D_Py_TIER2=3" ;; interpreter) enable_experimental_jit="-D_Py_TIER2=4" ;; - interpreter-default-off) enable_experimental_jit="-D_Py_TIER2=6" ;; # Secret option + interpreter-off) enable_experimental_jit="-D_Py_TIER2=6" ;; # Secret option *) AC_MSG_ERROR( - [invalid argument: --enable-experimental-jit=$enable_experimental_jit; expected no|yes|yes-default-off|interpreter]) ;; + [invalid argument: --enable-experimental-jit=$enable_experimental_jit; expected no|yes|yes-off|interpreter]) ;; esac AS_VAR_IF([enable_experimental_jit], [no], From f950e2588f5c217c30547634b873050152673ef4 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 30 Apr 2024 15:04:00 -0700 Subject: [PATCH 34/40] Tweak code in test/support/__init__.py without_optimizer() --- Lib/test/support/__init__.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 29180e8e4a20ab..52573e665a1273 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -2539,18 +2539,17 @@ def exceeds_recursion_limit(): # Decorator to disable optimizer while a function run def without_optimizer(func): try: - import _testinternalcapi from _testinternalcapi import get_optimizer, set_optimizer except ImportError: return func @functools.wraps(func) def wrapper(*args, **kwargs): - save_opt = _testinternalcapi.get_optimizer() + save_opt = get_optimizer() try: - _testinternalcapi.set_optimizer(None) + set_optimizer(None) return func(*args, **kwargs) finally: - _testinternalcapi.set_optimizer(save_opt) + set_optimizer(save_opt) return wrapper From 6be70c001a5bdaf0830f1c4f89a08c0a8238111a Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 30 Apr 2024 15:05:21 -0700 Subject: [PATCH 35/40] Fix news blurb --- .../2024-04-26-14-06-18.gh-issue-118335.SRFsxO.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-04-26-14-06-18.gh-issue-118335.SRFsxO.rst b/Misc/NEWS.d/next/Core and Builtins/2024-04-26-14-06-18.gh-issue-118335.SRFsxO.rst index 1388e2356eeb00..e13edbbbe528eb 100644 --- a/Misc/NEWS.d/next/Core and Builtins/2024-04-26-14-06-18.gh-issue-118335.SRFsxO.rst +++ b/Misc/NEWS.d/next/Core and Builtins/2024-04-26-14-06-18.gh-issue-118335.SRFsxO.rst @@ -1,4 +1,4 @@ Change how to use the tier 2 interpreter. Instead of running Python with ``-X uops`` or setting the environment variable ``PYTHON_UOPS=1``, this choice is now made at build time by configuring with -``--enable-experimental-tier2``. +``--enable-experimental-jit=interpreter``. From fdbe4407275b4b4914704b22db11e18384d5d26c Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 30 Apr 2024 15:32:37 -0700 Subject: [PATCH 36/40] Fix typo in _opcode.c --- Modules/_opcode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_opcode.c b/Modules/_opcode.c index 0f28f006d917f7..85e0ffec900e89 100644 --- a/Modules/_opcode.c +++ b/Modules/_opcode.c @@ -371,7 +371,7 @@ _opcode_get_executor_impl(PyObject *module, PyObject *code, int offset) return (PyObject *)PyUnstable_GetExecutor((PyCodeObject *)code, offset); #else PyErr_Format(PyExc_RuntimeError, - "Executors is not available in this build"); + "Executors are not available in this build"); return NULL; #endif } From 3c919bb2b095b8e5aacad2d1c523066f5302fb0b Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 30 Apr 2024 15:46:42 -0700 Subject: [PATCH 37/40] Shut up annoying warning --- Python/pystate.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Python/pystate.c b/Python/pystate.c index 173759ac347152..1315e22d270e68 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -584,7 +584,9 @@ free_interpreter(PyInterpreterState *interp) } } +#ifdef Py_DEBUG static inline int check_interpreter_whence(long); +#endif /* Get the interpreter state to a minimal consistent state. Further init happens in pylifecycle.c before it can be used. @@ -1123,6 +1125,7 @@ _PyInterpreterState_IsReady(PyInterpreterState *interp) } +#ifdef Py_DEBUG static inline int check_interpreter_whence(long whence) { @@ -1134,6 +1137,7 @@ check_interpreter_whence(long whence) } return 0; } +#endif long _PyInterpreterState_GetWhence(PyInterpreterState *interp) From d5a3ff0c274f8a467dc76cfe464d4630f25c7f11 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 30 Apr 2024 15:47:19 -0700 Subject: [PATCH 38/40] Use Py_FatalError for ENTER_EXECUTOR in non-TIER2 build --- Include/internal/pycore_opcode_metadata.h | 4 ++-- Include/internal/pycore_uop_metadata.h | 2 +- Python/bytecodes.c | 2 +- Python/generated_cases.c.h | 2 +- Tools/cases_generator/analyzer.py | 1 + 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index 2ccc548ca6c5fd..808badea90d8ed 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -981,7 +981,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[268] = { [BUILD_SLICE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG }, [BUILD_STRING] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG }, [BUILD_TUPLE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG }, - [CACHE] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG }, + [CACHE] = { true, INSTR_FMT_IX, 0 }, [CALL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, [CALL_ALLOC_AND_ENTER_INIT] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, [CALL_BOUND_METHOD_EXACT_ARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG }, @@ -1121,7 +1121,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[268] = { [PUSH_NULL] = { true, INSTR_FMT_IX, HAS_PURE_FLAG }, [RAISE_VARARGS] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, [RERAISE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, - [RESERVED] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG }, + [RESERVED] = { true, INSTR_FMT_IX, 0 }, [RESUME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [RESUME_CHECK] = { true, INSTR_FMT_IX, HAS_DEOPT_FLAG }, [RETURN_CONST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_CONST_FLAG }, diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h index a84212c1ec0b69..5697b13d1fc51d 100644 --- a/Include/internal/pycore_uop_metadata.h +++ b/Include/internal/pycore_uop_metadata.h @@ -249,7 +249,7 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_COLD_EXIT] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG, [_DYNAMIC_EXIT] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG, [_START_EXECUTOR] = HAS_DEOPT_FLAG, - [_FATAL_ERROR] = HAS_ESCAPES_FLAG, + [_FATAL_ERROR] = 0, [_CHECK_VALIDITY_AND_SET_IP] = HAS_DEOPT_FLAG, [_DEOPT] = 0, [_SIDE_EXIT] = 0, diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 8e9fff034bf70c..f6db96f8acf7a6 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2420,7 +2420,7 @@ dummy_func( Py_INCREF(executor); GOTO_TIER_TWO(executor); #else - assert(0); + Py_FatalError("ENTER_EXECUTOR is not supported in this build"); #endif /* _Py_TIER2 */ } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 36cf7007fdd13e..1440b64f403c01 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2510,7 +2510,7 @@ Py_INCREF(executor); GOTO_TIER_TWO(executor); #else - assert(0); + Py_FatalError("ENTER_EXECUTOR is not supported in this build"); #endif /* _Py_TIER2 */ DISPATCH(); } diff --git a/Tools/cases_generator/analyzer.py b/Tools/cases_generator/analyzer.py index 18cefa08328804..fdb635486b9531 100644 --- a/Tools/cases_generator/analyzer.py +++ b/Tools/cases_generator/analyzer.py @@ -411,6 +411,7 @@ def has_error_without_pop(op: parser.InstDef) -> bool: "PyCell_New", "PyFloat_AS_DOUBLE", "_PyFrame_PushUnchecked", + "Py_FatalError", ) ESCAPING_FUNCTIONS = ( From 07c485e1192ff457cd142aa8b5b5f590315c3ee5 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 30 Apr 2024 17:02:54 -0700 Subject: [PATCH 39/40] Add --experimental-jit-{off|interpreter} to PCbuild/build.bat --- PCbuild/_testinternalcapi.vcxproj | 2 +- PCbuild/build.bat | 11 +++++++++-- PCbuild/pythoncore.vcxproj | 2 +- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/PCbuild/_testinternalcapi.vcxproj b/PCbuild/_testinternalcapi.vcxproj index 946d1249dc4f30..d4cd8ad1a46f24 100644 --- a/PCbuild/_testinternalcapi.vcxproj +++ b/PCbuild/_testinternalcapi.vcxproj @@ -111,7 +111,7 @@ _Py_JIT;%(PreprocessorDefinitions) - _Py_TIER2;%(PreprocessorDefinitions) + _Py_TIER2=$(UseTIER2);%(PreprocessorDefinitions) diff --git a/PCbuild/build.bat b/PCbuild/build.bat index 83b50db4467033..43a99aa684483f 100644 --- a/PCbuild/build.bat +++ b/PCbuild/build.bat @@ -36,7 +36,9 @@ echo. overrides -c and -d echo. --disable-gil Enable experimental support for running without the GIL. echo. --test-marker Enable the test marker within the build. echo. --regen Regenerate all opcodes, grammar and tokens. -echo. --experimental-jit Enable the experimental just-in-time compiler. +echo. --experimental-jit Enable the experimental just-in-time compiler. +echo. --experimental-jit-off Ditto but off by default (PYTHON_JIT=1 enables). +echo. --experimental-interpreter Enable the experimental Tier 2 interpreter. echo. echo.Available flags to avoid building certain modules. echo.These flags have no effect if '-e' is not given: @@ -66,6 +68,7 @@ set verbose=/nologo /v:m /clp:summary set kill= set do_pgo= set pgo_job=-m test --pgo +set UseTIER2=0 :CheckOpts if "%~1"=="-h" goto Usage @@ -86,7 +89,10 @@ if "%~1"=="--disable-gil" (set UseDisableGil=true) & shift & goto CheckOpts if "%~1"=="--test-marker" (set UseTestMarker=true) & shift & goto CheckOpts if "%~1"=="-V" shift & goto Version if "%~1"=="--regen" (set Regen=true) & shift & goto CheckOpts -if "%~1"=="--experimental-jit" (set UseJIT=true) & shift & goto CheckOpts +if "%~1"=="--experimental-jit" (set UseJIT=true) & (set UseTIER2=1) & shift & goto CheckOpts +if "%~1"=="--experimental-jit-off" (set UseJIT=true) & (set UseTIER2=3) & shift & goto CheckOpts +if "%~1"=="--experimental-interpreter" (set UseTIER2=4) & shift & goto CheckOpts +if "%~1"=="--experimental-interpreter-off" (set UseTIER2=6) & shift & goto CheckOpts rem These use the actual property names used by MSBuild. We could just let rem them in through the environment, but we specify them on the command line rem anyway for visibility so set defaults after this @@ -179,6 +185,7 @@ echo on /p:DisableGil=%UseDisableGil%^ /p:UseTestMarker=%UseTestMarker% %GITProperty%^ /p:UseJIT=%UseJIT%^ + /p:UseTIER2=%UseTIER2%^ %1 %2 %3 %4 %5 %6 %7 %8 %9 @echo off diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index e412e0c06cfe41..b1383187231ff7 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -105,7 +105,7 @@ _USRDLL;Py_BUILD_CORE;Py_BUILD_CORE_BUILTIN;Py_ENABLE_SHARED;MS_DLL_ID="$(SysWinVer)";%(PreprocessorDefinitions) _Py_HAVE_ZLIB;%(PreprocessorDefinitions) _Py_JIT;%(PreprocessorDefinitions) - _Py_TIER2;%(PreprocessorDefinitions) + _Py_TIER2=$(UseTIER2);%(PreprocessorDefinitions) version.lib;ws2_32.lib;pathcch.lib;bcrypt.lib;%(AdditionalDependencies) From a2d4f30d3469ada0cf2a7e2433d40bbc2059b3b2 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 30 Apr 2024 17:03:14 -0700 Subject: [PATCH 40/40] Revert "Shut up annoying warning" Apparently makes the CI fuzzer unhappy. This reverts commit 3c919bb2b095b8e5aacad2d1c523066f5302fb0b. --- Python/pystate.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Python/pystate.c b/Python/pystate.c index 1315e22d270e68..173759ac347152 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -584,9 +584,7 @@ free_interpreter(PyInterpreterState *interp) } } -#ifdef Py_DEBUG static inline int check_interpreter_whence(long); -#endif /* Get the interpreter state to a minimal consistent state. Further init happens in pylifecycle.c before it can be used. @@ -1125,7 +1123,6 @@ _PyInterpreterState_IsReady(PyInterpreterState *interp) } -#ifdef Py_DEBUG static inline int check_interpreter_whence(long whence) { @@ -1137,7 +1134,6 @@ check_interpreter_whence(long whence) } return 0; } -#endif long _PyInterpreterState_GetWhence(PyInterpreterState *interp)