aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Python
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>2024-04-30 18:26:34 -0700
committerGitHub <noreply@github.com>2024-04-30 18:26:34 -0700
commit7d83f7bcc484145596bae1ff015fed0762da345d (patch)
treef2f3cbb0cefaa920b319c77da00606fef1db48aa /Python
parent9c468e2c5dffb6fa9811fd16e70fa0463bdfce5f (diff)
downloadcpython-7d83f7bcc484145596bae1ff015fed0762da345d.tar.gz
cpython-7d83f7bcc484145596bae1ff015fed0762da345d.zip
gh-118335: Configure Tier 2 interpreter at build time (#118339)
The code for Tier 2 is now only compiled when configured with `--enable-experimental-jit[=yes|interpreter]`. We drop support for `PYTHON_UOPS` and -`Xuops`, but you can disable the interpreter or JIT at runtime by setting `PYTHON_JIT=0`. You can also build it without enabling it by default using `--enable-experimental-jit=yes-off`; enable with `PYTHON_JIT=1`. On Windows, the `build.bat` script supports `--experimental-jit`, `--experimental-jit-off`, `--experimental-interpreter`. In the C code, `_Py_JIT` is defined as before when the JIT is enabled; the new variable `_Py_TIER2` is defined when the JIT *or* the interpreter is enabled. It is actually a bitmask: 1: JIT; 2: default-off; 4: interpreter.
Diffstat (limited to 'Python')
-rw-r--r--Python/bytecodes.c6
-rw-r--r--Python/ceval.c5
-rw-r--r--Python/generated_cases.c.h6
-rw-r--r--Python/instrumentation.c6
-rw-r--r--Python/optimizer.c4
-rw-r--r--Python/optimizer_analysis.c4
-rw-r--r--Python/optimizer_symbols.c3
-rw-r--r--Python/pylifecycle.c28
-rw-r--r--Python/pystate.c6
-rw-r--r--Python/sysmodule.c2
10 files changed, 57 insertions, 13 deletions
diff --git a/Python/bytecodes.c b/Python/bytecodes.c
index 18837aef74d..28766d6d97c 100644
--- a/Python/bytecodes.c
+++ b/Python/bytecodes.c
@@ -2363,6 +2363,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) {
@@ -2388,6 +2389,7 @@ dummy_func(
ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter);
}
#endif /* ENABLE_SPECIALIZATION */
+ #endif /* _Py_TIER2 */
}
pseudo(JUMP) = {
@@ -2401,6 +2403,7 @@ dummy_func(
};
tier1 inst(ENTER_EXECUTOR, (--)) {
+ #ifdef _Py_TIER2
int prevoparg = oparg;
CHECK_EVAL_BREAKER();
if (this_instr->op.code != ENTER_EXECUTOR ||
@@ -2418,6 +2421,9 @@ dummy_func(
tstate->previous_executor = Py_None;
Py_INCREF(executor);
GOTO_TIER_TWO(executor);
+ #else
+ Py_FatalError("ENTER_EXECUTOR is not supported in this build");
+ #endif /* _Py_TIER2 */
}
replaced op(_POP_JUMP_IF_FALSE, (cond -- )) {
diff --git a/Python/ceval.c b/Python/ceval.c
index 8b23bc6bcbe..59498bc826e 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 @@ resume_with_error:
goto error;
+#ifdef _Py_TIER2
// Tier 2 is also here!
enter_tier_two:
@@ -1113,6 +1114,8 @@ exit_to_trace:
#endif // _Py_JIT
+#endif // _Py_TIER2
+
}
#if defined(__GNUC__)
diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h
index 1444f5cdebb..602cce4beb1 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
+ Py_FatalError("ENTER_EXECUTOR is not supported in this build");
+ #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 ce97c3add7d..5614f4867a3 100644
--- a/Python/instrumentation.c
+++ b/Python/instrumentation.c
@@ -1705,10 +1705,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
@@ -1946,7 +1948,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);
@@ -1986,7 +1990,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 a9a35fc9020..a5e7430c464 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"
@@ -1622,3 +1624,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 9315d7228b5..842b2e48923 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.
@@ -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 204599b0876..d52f490853c 100644
--- a/Python/optimizer_symbols.c
+++ b/Python/optimizer_symbols.c
@@ -1,3 +1,4 @@
+#ifdef _Py_TIER2
#include "Python.h"
@@ -506,3 +507,5 @@ fail:
Py_XDECREF(val_43);
return NULL;
}
+
+#endif /* _Py_TIER2 */
diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c
index 790398e944f..7726ccc979d 100644
--- a/Python/pylifecycle.c
+++ b/Python/pylifecycle.c
@@ -624,9 +624,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;
}
@@ -1272,30 +1274,30 @@ 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
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;
+ 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) {
-#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.
@@ -1655,10 +1657,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 9d7b73b3a07..3d6e76e88bd 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
@@ -2821,9 +2825,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 7af363678e8..726051521cf 100644
--- a/Python/sysmodule.c
+++ b/Python/sysmodule.c
@@ -2165,8 +2165,10 @@ static PyObject *
sys__clear_internal_caches_impl(PyObject *module)
/*[clinic end generated code: output=0ee128670a4966d6 input=253e741ca744f6e8]*/
{
+#ifdef _Py_TIER2
PyInterpreterState *interp = _PyInterpreterState_GET();
_Py_Executors_InvalidateAll(interp, 0);
+#endif
PyType_ClearCache();
Py_RETURN_NONE;
}