mirror of https://github.com/python/cpython
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.
This commit is contained in:
parent
9c468e2c5d
commit
7d83f7bcc4
|
@ -888,7 +888,7 @@ Experimental JIT Compiler
|
||||||
=========================
|
=========================
|
||||||
|
|
||||||
When CPython is configured using the ``--enable-experimental-jit`` option,
|
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.
|
The internal architecture is roughly as follows.
|
||||||
|
|
||||||
|
@ -905,19 +905,35 @@ The internal architecture is roughly as follows.
|
||||||
before it is interpreted or translated to machine code.
|
before it is interpreted or translated to machine code.
|
||||||
|
|
||||||
* There is a Tier 2 interpreter, but it is mostly intended for debugging
|
* 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
|
the earlier stages of the optimization pipeline.
|
||||||
enabled, the Tier 2 interpreter can be invoked by passing Python the
|
The Tier 2 interpreter can be enabled by configuring Python
|
||||||
``-X uops`` option or by setting the ``PYTHON_UOPS`` environment
|
with ``--enable-experimental-jit=interpreter``.
|
||||||
variable to ``1``.
|
|
||||||
|
|
||||||
* 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.
|
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
|
* The machine code translation process uses an architecture called
|
||||||
*copy-and-patch*. It has no runtime dependencies, but there is a new
|
*copy-and-patch*. It has no runtime dependencies, but there is a new
|
||||||
build-time dependency on LLVM.
|
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-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.
|
||||||
|
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.
|
See :pep:`744` for more details.
|
||||||
|
|
||||||
(JIT by Brandt Bucher, inspired by a paper by Haoran Xu and Fredrik Kjolstad.
|
(JIT by Brandt Bucher, inspired by a paper by Haoran Xu and Fredrik Kjolstad.
|
||||||
|
|
|
@ -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_SLICE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG },
|
||||||
[BUILD_STRING] = { 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 },
|
[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] = { 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_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 },
|
[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 },
|
[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 },
|
[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 },
|
[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] = { 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 },
|
[RESUME_CHECK] = { true, INSTR_FMT_IX, HAS_DEOPT_FLAG },
|
||||||
[RETURN_CONST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_CONST_FLAG },
|
[RETURN_CONST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_CONST_FLAG },
|
||||||
|
|
|
@ -249,7 +249,7 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = {
|
||||||
[_COLD_EXIT] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG,
|
[_COLD_EXIT] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG,
|
||||||
[_DYNAMIC_EXIT] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG,
|
[_DYNAMIC_EXIT] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG,
|
||||||
[_START_EXECUTOR] = HAS_DEOPT_FLAG,
|
[_START_EXECUTOR] = HAS_DEOPT_FLAG,
|
||||||
[_FATAL_ERROR] = HAS_ESCAPES_FLAG,
|
[_FATAL_ERROR] = 0,
|
||||||
[_CHECK_VALIDITY_AND_SET_IP] = HAS_DEOPT_FLAG,
|
[_CHECK_VALIDITY_AND_SET_IP] = HAS_DEOPT_FLAG,
|
||||||
[_DEOPT] = 0,
|
[_DEOPT] = 0,
|
||||||
[_SIDE_EXIT] = 0,
|
[_SIDE_EXIT] = 0,
|
||||||
|
|
|
@ -216,7 +216,7 @@ def _get_code_array(co, adaptive):
|
||||||
if op == ENTER_EXECUTOR:
|
if op == ENTER_EXECUTOR:
|
||||||
try:
|
try:
|
||||||
ex = get_executor(co, i)
|
ex = get_executor(co, i)
|
||||||
except ValueError:
|
except (ValueError, RuntimeError):
|
||||||
ex = None
|
ex = None
|
||||||
|
|
||||||
if ex:
|
if ex:
|
||||||
|
|
|
@ -2539,17 +2539,17 @@ Py_TRACE_REFS = hasattr(sys, 'getobjects')
|
||||||
# Decorator to disable optimizer while a function run
|
# Decorator to disable optimizer while a function run
|
||||||
def without_optimizer(func):
|
def without_optimizer(func):
|
||||||
try:
|
try:
|
||||||
import _testinternalcapi
|
from _testinternalcapi import get_optimizer, set_optimizer
|
||||||
except ImportError:
|
except ImportError:
|
||||||
return func
|
return func
|
||||||
@functools.wraps(func)
|
@functools.wraps(func)
|
||||||
def wrapper(*args, **kwargs):
|
def wrapper(*args, **kwargs):
|
||||||
save_opt = _testinternalcapi.get_optimizer()
|
save_opt = get_optimizer()
|
||||||
try:
|
try:
|
||||||
_testinternalcapi.set_optimizer(None)
|
set_optimizer(None)
|
||||||
return func(*args, **kwargs)
|
return func(*args, **kwargs)
|
||||||
finally:
|
finally:
|
||||||
_testinternalcapi.set_optimizer(save_opt)
|
set_optimizer(save_opt)
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,8 @@ def clear_executors(func):
|
||||||
|
|
||||||
|
|
||||||
@requires_specialization
|
@requires_specialization
|
||||||
|
@unittest.skipUnless(hasattr(_testinternalcapi, "get_optimizer"),
|
||||||
|
"Requires optimizer infrastructure")
|
||||||
class TestOptimizerAPI(unittest.TestCase):
|
class TestOptimizerAPI(unittest.TestCase):
|
||||||
|
|
||||||
def test_new_counter_optimizer_dealloc(self):
|
def test_new_counter_optimizer_dealloc(self):
|
||||||
|
@ -136,6 +138,8 @@ def get_opnames(ex):
|
||||||
|
|
||||||
|
|
||||||
@requires_specialization
|
@requires_specialization
|
||||||
|
@unittest.skipUnless(hasattr(_testinternalcapi, "get_optimizer"),
|
||||||
|
"Requires optimizer infrastructure")
|
||||||
class TestExecutorInvalidation(unittest.TestCase):
|
class TestExecutorInvalidation(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
@ -215,6 +219,8 @@ class TestExecutorInvalidation(unittest.TestCase):
|
||||||
|
|
||||||
|
|
||||||
@requires_specialization
|
@requires_specialization
|
||||||
|
@unittest.skipUnless(hasattr(_testinternalcapi, "get_optimizer"),
|
||||||
|
"Requires optimizer infrastructure")
|
||||||
@unittest.skipIf(os.getenv("PYTHON_UOPS_OPTIMIZE") == "0", "Needs uop optimizer to run.")
|
@unittest.skipIf(os.getenv("PYTHON_UOPS_OPTIMIZE") == "0", "Needs uop optimizer to run.")
|
||||||
class TestUops(unittest.TestCase):
|
class TestUops(unittest.TestCase):
|
||||||
|
|
||||||
|
@ -579,6 +585,8 @@ class TestUops(unittest.TestCase):
|
||||||
|
|
||||||
|
|
||||||
@requires_specialization
|
@requires_specialization
|
||||||
|
@unittest.skipUnless(hasattr(_testinternalcapi, "get_optimizer"),
|
||||||
|
"Requires optimizer infrastructure")
|
||||||
@unittest.skipIf(os.getenv("PYTHON_UOPS_OPTIMIZE") == "0", "Needs uop optimizer to run.")
|
@unittest.skipIf(os.getenv("PYTHON_UOPS_OPTIMIZE") == "0", "Needs uop optimizer to run.")
|
||||||
class TestUopsOptimization(unittest.TestCase):
|
class TestUopsOptimization(unittest.TestCase):
|
||||||
|
|
||||||
|
|
|
@ -1831,6 +1831,7 @@ class TestOptimizer(MonitoringTestBase, unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
_testinternalcapi = import_module("_testinternalcapi")
|
_testinternalcapi = import_module("_testinternalcapi")
|
||||||
|
if hasattr(_testinternalcapi, "get_optimizer"):
|
||||||
self.old_opt = _testinternalcapi.get_optimizer()
|
self.old_opt = _testinternalcapi.get_optimizer()
|
||||||
opt = _testinternalcapi.new_counter_optimizer()
|
opt = _testinternalcapi.new_counter_optimizer()
|
||||||
_testinternalcapi.set_optimizer(opt)
|
_testinternalcapi.set_optimizer(opt)
|
||||||
|
@ -1839,6 +1840,7 @@ class TestOptimizer(MonitoringTestBase, unittest.TestCase):
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
super(TestOptimizer, self).tearDown()
|
super(TestOptimizer, self).tearDown()
|
||||||
import _testinternalcapi
|
import _testinternalcapi
|
||||||
|
if hasattr(_testinternalcapi, "get_optimizer"):
|
||||||
_testinternalcapi.set_optimizer(self.old_opt)
|
_testinternalcapi.set_optimizer(self.old_opt)
|
||||||
|
|
||||||
def test_for_loop(self):
|
def test_for_loop(self):
|
||||||
|
|
|
@ -16,6 +16,8 @@ _testinternalcapi = import_module("_testinternalcapi")
|
||||||
|
|
||||||
def disabling_optimizer(func):
|
def disabling_optimizer(func):
|
||||||
def wrapper(*args, **kwargs):
|
def wrapper(*args, **kwargs):
|
||||||
|
if not hasattr(_testinternalcapi, "get_optimizer"):
|
||||||
|
return func(*args, **kwargs)
|
||||||
old_opt = _testinternalcapi.get_optimizer()
|
old_opt = _testinternalcapi.get_optimizer()
|
||||||
_testinternalcapi.set_optimizer(None)
|
_testinternalcapi.set_optimizer(None)
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -80,6 +80,8 @@ class TestRareEventCounters(unittest.TestCase):
|
||||||
|
|
||||||
class TestOptimizerSymbols(unittest.TestCase):
|
class TestOptimizerSymbols(unittest.TestCase):
|
||||||
|
|
||||||
|
@unittest.skipUnless(hasattr(_testinternalcapi, "uop_symbols_test"),
|
||||||
|
"requires _testinternalcapi.uop_symbols_test")
|
||||||
def test_optimizer_symbols(self):
|
def test_optimizer_symbols(self):
|
||||||
_testinternalcapi.uop_symbols_test()
|
_testinternalcapi.uop_symbols_test()
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ from test.support import script_helper, ALWAYS_EQ, suppress_immortalization
|
||||||
from test.support import gc_collect
|
from test.support import gc_collect
|
||||||
from test.support import import_helper
|
from test.support import import_helper
|
||||||
from test.support import threading_helper
|
from test.support import threading_helper
|
||||||
|
from test.support import is_wasi, Py_DEBUG
|
||||||
|
|
||||||
# Used in ReferencesTestCase.test_ref_created_during_del() .
|
# Used in ReferencesTestCase.test_ref_created_during_del() .
|
||||||
ref_from_del = None
|
ref_from_del = None
|
||||||
|
@ -960,6 +961,7 @@ class ReferencesTestCase(TestBase):
|
||||||
self.assertEqual(hash(a), hash(42))
|
self.assertEqual(hash(a), hash(42))
|
||||||
self.assertRaises(TypeError, hash, b)
|
self.assertRaises(TypeError, hash, b)
|
||||||
|
|
||||||
|
@unittest.skipIf(is_wasi and Py_DEBUG, "requires deep stack")
|
||||||
def test_trashcan_16602(self):
|
def test_trashcan_16602(self):
|
||||||
# Issue #16602: when a weakref's target was part of a long
|
# Issue #16602: when a weakref's target was part of a long
|
||||||
# deallocation chain, the trashcan mechanism could delay clearing
|
# deallocation chain, the trashcan mechanism could delay clearing
|
||||||
|
|
|
@ -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-jit=interpreter``.
|
|
@ -367,7 +367,13 @@ _opcode_get_executor_impl(PyObject *module, PyObject *code, int offset)
|
||||||
Py_TYPE(code)->tp_name);
|
Py_TYPE(code)->tp_name);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
#ifdef _Py_TIER2
|
||||||
return (PyObject *)PyUnstable_GetExecutor((PyCodeObject *)code, offset);
|
return (PyObject *)PyUnstable_GetExecutor((PyCodeObject *)code, offset);
|
||||||
|
#else
|
||||||
|
PyErr_Format(PyExc_RuntimeError,
|
||||||
|
"Executors are not available in this build");
|
||||||
|
return NULL;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyMethodDef
|
static PyMethodDef
|
||||||
|
|
|
@ -985,6 +985,8 @@ get_co_framesize(PyObject *self, PyObject *arg)
|
||||||
return PyLong_FromLong(code->co_framesize);
|
return PyLong_FromLong(code->co_framesize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _Py_TIER2
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
new_counter_optimizer(PyObject *self, PyObject *arg)
|
new_counter_optimizer(PyObject *self, PyObject *arg)
|
||||||
{
|
{
|
||||||
|
@ -1012,7 +1014,10 @@ set_optimizer(PyObject *self, PyObject *opt)
|
||||||
static PyObject *
|
static PyObject *
|
||||||
get_optimizer(PyObject *self, PyObject *Py_UNUSED(ignored))
|
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) {
|
if (opt == NULL) {
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
@ -1045,6 +1050,8 @@ invalidate_executors(PyObject *self, PyObject *obj)
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
static int _pending_callback(void *arg)
|
static int _pending_callback(void *arg)
|
||||||
{
|
{
|
||||||
/* we assume the argument is callable object to which we own a reference */
|
/* we assume the argument is callable object to which we own a reference */
|
||||||
|
@ -2020,12 +2027,14 @@ static PyMethodDef module_functions[] = {
|
||||||
{"iframe_getline", iframe_getline, METH_O, NULL},
|
{"iframe_getline", iframe_getline, METH_O, NULL},
|
||||||
{"iframe_getlasti", iframe_getlasti, METH_O, NULL},
|
{"iframe_getlasti", iframe_getlasti, METH_O, NULL},
|
||||||
{"get_co_framesize", get_co_framesize, METH_O, NULL},
|
{"get_co_framesize", get_co_framesize, METH_O, NULL},
|
||||||
|
#ifdef _Py_TIER2
|
||||||
{"get_optimizer", get_optimizer, METH_NOARGS, NULL},
|
{"get_optimizer", get_optimizer, METH_NOARGS, NULL},
|
||||||
{"set_optimizer", set_optimizer, METH_O, NULL},
|
{"set_optimizer", set_optimizer, METH_O, NULL},
|
||||||
{"new_counter_optimizer", new_counter_optimizer, METH_NOARGS, NULL},
|
{"new_counter_optimizer", new_counter_optimizer, METH_NOARGS, NULL},
|
||||||
{"new_uop_optimizer", new_uop_optimizer, METH_NOARGS, NULL},
|
{"new_uop_optimizer", new_uop_optimizer, METH_NOARGS, NULL},
|
||||||
{"add_executor_dependency", add_executor_dependency, METH_VARARGS, NULL},
|
{"add_executor_dependency", add_executor_dependency, METH_VARARGS, NULL},
|
||||||
{"invalidate_executors", invalidate_executors, METH_O, NULL},
|
{"invalidate_executors", invalidate_executors, METH_O, NULL},
|
||||||
|
#endif
|
||||||
{"pending_threadfunc", _PyCFunction_CAST(pending_threadfunc),
|
{"pending_threadfunc", _PyCFunction_CAST(pending_threadfunc),
|
||||||
METH_VARARGS | METH_KEYWORDS},
|
METH_VARARGS | METH_KEYWORDS},
|
||||||
{"pending_identify", pending_identify, METH_VARARGS, NULL},
|
{"pending_identify", pending_identify, METH_VARARGS, NULL},
|
||||||
|
@ -2072,7 +2081,9 @@ static PyMethodDef module_functions[] = {
|
||||||
{"py_thread_id", get_py_thread_id, METH_NOARGS},
|
{"py_thread_id", get_py_thread_id, METH_NOARGS},
|
||||||
#endif
|
#endif
|
||||||
{"set_immortalize_deferred", set_immortalize_deferred, METH_VARARGS},
|
{"set_immortalize_deferred", set_immortalize_deferred, METH_VARARGS},
|
||||||
|
#ifdef _Py_TIER2
|
||||||
{"uop_symbols_test", _Py_uop_symbols_test, METH_NOARGS},
|
{"uop_symbols_test", _Py_uop_symbols_test, METH_NOARGS},
|
||||||
|
#endif
|
||||||
{NULL, NULL} /* sentinel */
|
{NULL, NULL} /* sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1496,6 +1496,8 @@ PyCode_GetFreevars(PyCodeObject *code)
|
||||||
return _PyCode_GetFreevars(code);
|
return _PyCode_GetFreevars(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _Py_TIER2
|
||||||
|
|
||||||
static void
|
static void
|
||||||
clear_executors(PyCodeObject *co)
|
clear_executors(PyCodeObject *co)
|
||||||
{
|
{
|
||||||
|
@ -1515,6 +1517,8 @@ _PyCode_Clear_Executors(PyCodeObject *code)
|
||||||
clear_executors(code);
|
clear_executors(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
static void
|
static void
|
||||||
deopt_code(PyCodeObject *code, _Py_CODEUNIT *instructions)
|
deopt_code(PyCodeObject *code, _Py_CODEUNIT *instructions)
|
||||||
{
|
{
|
||||||
|
@ -1739,9 +1743,11 @@ code_dealloc(PyCodeObject *co)
|
||||||
|
|
||||||
PyMem_Free(co_extra);
|
PyMem_Free(co_extra);
|
||||||
}
|
}
|
||||||
|
#ifdef _Py_TIER2
|
||||||
if (co->co_executors != NULL) {
|
if (co->co_executors != NULL) {
|
||||||
clear_executors(co);
|
clear_executors(co);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
Py_XDECREF(co->co_consts);
|
Py_XDECREF(co->co_consts);
|
||||||
Py_XDECREF(co->co_names);
|
Py_XDECREF(co->co_names);
|
||||||
|
|
|
@ -2281,9 +2281,11 @@ static PyTypeObject* static_types[] = {
|
||||||
&_PyBufferWrapper_Type,
|
&_PyBufferWrapper_Type,
|
||||||
&_PyContextTokenMissing_Type,
|
&_PyContextTokenMissing_Type,
|
||||||
&_PyCoroWrapper_Type,
|
&_PyCoroWrapper_Type,
|
||||||
|
#ifdef _Py_TIER2
|
||||||
&_PyCounterExecutor_Type,
|
&_PyCounterExecutor_Type,
|
||||||
&_PyCounterOptimizer_Type,
|
&_PyCounterOptimizer_Type,
|
||||||
&_PyDefaultOptimizer_Type,
|
&_PyDefaultOptimizer_Type,
|
||||||
|
#endif
|
||||||
&_Py_GenericAliasIterType,
|
&_Py_GenericAliasIterType,
|
||||||
&_PyHamtItems_Type,
|
&_PyHamtItems_Type,
|
||||||
&_PyHamtKeys_Type,
|
&_PyHamtKeys_Type,
|
||||||
|
@ -2304,8 +2306,10 @@ static PyTypeObject* static_types[] = {
|
||||||
&_PyPositionsIterator,
|
&_PyPositionsIterator,
|
||||||
&_PyUnicodeASCIIIter_Type,
|
&_PyUnicodeASCIIIter_Type,
|
||||||
&_PyUnion_Type,
|
&_PyUnion_Type,
|
||||||
|
#ifdef _Py_TIER2
|
||||||
&_PyUOpExecutor_Type,
|
&_PyUOpExecutor_Type,
|
||||||
&_PyUOpOptimizer_Type,
|
&_PyUOpOptimizer_Type,
|
||||||
|
#endif
|
||||||
&_PyWeakref_CallableProxyType,
|
&_PyWeakref_CallableProxyType,
|
||||||
&_PyWeakref_ProxyType,
|
&_PyWeakref_ProxyType,
|
||||||
&_PyWeakref_RefType,
|
&_PyWeakref_RefType,
|
||||||
|
|
|
@ -108,6 +108,12 @@
|
||||||
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
|
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemDefinitionGroup>
|
||||||
|
<ClCompile>
|
||||||
|
<PreprocessorDefinitions Condition="'$(UseJIT)' == 'true'">_Py_JIT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<PreprocessorDefinitions Condition="'$(UseTIER2)' != '0'">_Py_TIER2=$(UseTIER2);%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets">
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
|
|
|
@ -37,6 +37,8 @@ echo. --disable-gil Enable experimental support for running without the GIL.
|
||||||
echo. --test-marker Enable the test marker within the build.
|
echo. --test-marker Enable the test marker within the build.
|
||||||
echo. --regen Regenerate all opcodes, grammar and tokens.
|
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.
|
||||||
echo.Available flags to avoid building certain modules.
|
echo.Available flags to avoid building certain modules.
|
||||||
echo.These flags have no effect if '-e' is not given:
|
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 kill=
|
||||||
set do_pgo=
|
set do_pgo=
|
||||||
set pgo_job=-m test --pgo
|
set pgo_job=-m test --pgo
|
||||||
|
set UseTIER2=0
|
||||||
|
|
||||||
:CheckOpts
|
:CheckOpts
|
||||||
if "%~1"=="-h" goto Usage
|
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"=="--test-marker" (set UseTestMarker=true) & shift & goto CheckOpts
|
||||||
if "%~1"=="-V" shift & goto Version
|
if "%~1"=="-V" shift & goto Version
|
||||||
if "%~1"=="--regen" (set Regen=true) & shift & goto CheckOpts
|
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 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 them in through the environment, but we specify them on the command line
|
||||||
rem anyway for visibility so set defaults after this
|
rem anyway for visibility so set defaults after this
|
||||||
|
@ -179,6 +185,7 @@ echo on
|
||||||
/p:DisableGil=%UseDisableGil%^
|
/p:DisableGil=%UseDisableGil%^
|
||||||
/p:UseTestMarker=%UseTestMarker% %GITProperty%^
|
/p:UseTestMarker=%UseTestMarker% %GITProperty%^
|
||||||
/p:UseJIT=%UseJIT%^
|
/p:UseJIT=%UseJIT%^
|
||||||
|
/p:UseTIER2=%UseTIER2%^
|
||||||
%1 %2 %3 %4 %5 %6 %7 %8 %9
|
%1 %2 %3 %4 %5 %6 %7 %8 %9
|
||||||
|
|
||||||
@echo off
|
@echo off
|
||||||
|
|
|
@ -105,6 +105,7 @@
|
||||||
<PreprocessorDefinitions>_USRDLL;Py_BUILD_CORE;Py_BUILD_CORE_BUILTIN;Py_ENABLE_SHARED;MS_DLL_ID="$(SysWinVer)";%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>_USRDLL;Py_BUILD_CORE;Py_BUILD_CORE_BUILTIN;Py_ENABLE_SHARED;MS_DLL_ID="$(SysWinVer)";%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<PreprocessorDefinitions Condition="$(IncludeExternals)">_Py_HAVE_ZLIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions Condition="$(IncludeExternals)">_Py_HAVE_ZLIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<PreprocessorDefinitions Condition="'$(UseJIT)' == 'true'">_Py_JIT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions Condition="'$(UseJIT)' == 'true'">_Py_JIT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<PreprocessorDefinitions Condition="'$(UseTIER2)' != '0'">_Py_TIER2=$(UseTIER2);%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<AdditionalDependencies>version.lib;ws2_32.lib;pathcch.lib;bcrypt.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
<AdditionalDependencies>version.lib;ws2_32.lib;pathcch.lib;bcrypt.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
|
|
@ -2363,6 +2363,7 @@ dummy_func(
|
||||||
CHECK_EVAL_BREAKER();
|
CHECK_EVAL_BREAKER();
|
||||||
assert(oparg <= INSTR_OFFSET());
|
assert(oparg <= INSTR_OFFSET());
|
||||||
JUMPBY(-oparg);
|
JUMPBY(-oparg);
|
||||||
|
#ifdef _Py_TIER2
|
||||||
#if ENABLE_SPECIALIZATION
|
#if ENABLE_SPECIALIZATION
|
||||||
_Py_BackoffCounter counter = this_instr[1].counter;
|
_Py_BackoffCounter counter = this_instr[1].counter;
|
||||||
if (backoff_counter_triggers(counter) && this_instr->op.code == JUMP_BACKWARD) {
|
if (backoff_counter_triggers(counter) && this_instr->op.code == JUMP_BACKWARD) {
|
||||||
|
@ -2388,6 +2389,7 @@ dummy_func(
|
||||||
ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter);
|
ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter);
|
||||||
}
|
}
|
||||||
#endif /* ENABLE_SPECIALIZATION */
|
#endif /* ENABLE_SPECIALIZATION */
|
||||||
|
#endif /* _Py_TIER2 */
|
||||||
}
|
}
|
||||||
|
|
||||||
pseudo(JUMP) = {
|
pseudo(JUMP) = {
|
||||||
|
@ -2401,6 +2403,7 @@ dummy_func(
|
||||||
};
|
};
|
||||||
|
|
||||||
tier1 inst(ENTER_EXECUTOR, (--)) {
|
tier1 inst(ENTER_EXECUTOR, (--)) {
|
||||||
|
#ifdef _Py_TIER2
|
||||||
int prevoparg = oparg;
|
int prevoparg = oparg;
|
||||||
CHECK_EVAL_BREAKER();
|
CHECK_EVAL_BREAKER();
|
||||||
if (this_instr->op.code != ENTER_EXECUTOR ||
|
if (this_instr->op.code != ENTER_EXECUTOR ||
|
||||||
|
@ -2418,6 +2421,9 @@ dummy_func(
|
||||||
tstate->previous_executor = Py_None;
|
tstate->previous_executor = Py_None;
|
||||||
Py_INCREF(executor);
|
Py_INCREF(executor);
|
||||||
GOTO_TIER_TWO(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 -- )) {
|
replaced op(_POP_JUMP_IF_FALSE, (cond -- )) {
|
||||||
|
|
|
@ -755,7 +755,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
|
||||||
_Py_CODEUNIT *next_instr;
|
_Py_CODEUNIT *next_instr;
|
||||||
PyObject **stack_pointer;
|
PyObject **stack_pointer;
|
||||||
|
|
||||||
#ifndef _Py_JIT
|
#if defined(_Py_TIER2) && !defined(_Py_JIT)
|
||||||
/* Tier 2 interpreter state */
|
/* Tier 2 interpreter state */
|
||||||
_PyExecutorObject *current_executor = NULL;
|
_PyExecutorObject *current_executor = NULL;
|
||||||
const _PyUOpInstruction *next_uop = NULL;
|
const _PyUOpInstruction *next_uop = NULL;
|
||||||
|
@ -959,6 +959,7 @@ resume_with_error:
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef _Py_TIER2
|
||||||
|
|
||||||
// Tier 2 is also here!
|
// Tier 2 is also here!
|
||||||
enter_tier_two:
|
enter_tier_two:
|
||||||
|
@ -1113,6 +1114,8 @@ exit_to_trace:
|
||||||
|
|
||||||
#endif // _Py_JIT
|
#endif // _Py_JIT
|
||||||
|
|
||||||
|
#endif // _Py_TIER2
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__GNUC__)
|
#if defined(__GNUC__)
|
||||||
|
|
|
@ -2492,6 +2492,7 @@
|
||||||
(void)this_instr;
|
(void)this_instr;
|
||||||
next_instr += 1;
|
next_instr += 1;
|
||||||
INSTRUCTION_STATS(ENTER_EXECUTOR);
|
INSTRUCTION_STATS(ENTER_EXECUTOR);
|
||||||
|
#ifdef _Py_TIER2
|
||||||
int prevoparg = oparg;
|
int prevoparg = oparg;
|
||||||
CHECK_EVAL_BREAKER();
|
CHECK_EVAL_BREAKER();
|
||||||
if (this_instr->op.code != ENTER_EXECUTOR ||
|
if (this_instr->op.code != ENTER_EXECUTOR ||
|
||||||
|
@ -2508,6 +2509,9 @@
|
||||||
tstate->previous_executor = Py_None;
|
tstate->previous_executor = Py_None;
|
||||||
Py_INCREF(executor);
|
Py_INCREF(executor);
|
||||||
GOTO_TIER_TWO(executor);
|
GOTO_TIER_TWO(executor);
|
||||||
|
#else
|
||||||
|
Py_FatalError("ENTER_EXECUTOR is not supported in this build");
|
||||||
|
#endif /* _Py_TIER2 */
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3432,6 +3436,7 @@
|
||||||
CHECK_EVAL_BREAKER();
|
CHECK_EVAL_BREAKER();
|
||||||
assert(oparg <= INSTR_OFFSET());
|
assert(oparg <= INSTR_OFFSET());
|
||||||
JUMPBY(-oparg);
|
JUMPBY(-oparg);
|
||||||
|
#ifdef _Py_TIER2
|
||||||
#if ENABLE_SPECIALIZATION
|
#if ENABLE_SPECIALIZATION
|
||||||
_Py_BackoffCounter counter = this_instr[1].counter;
|
_Py_BackoffCounter counter = this_instr[1].counter;
|
||||||
if (backoff_counter_triggers(counter) && this_instr->op.code == JUMP_BACKWARD) {
|
if (backoff_counter_triggers(counter) && this_instr->op.code == JUMP_BACKWARD) {
|
||||||
|
@ -3457,6 +3462,7 @@
|
||||||
ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter);
|
ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter);
|
||||||
}
|
}
|
||||||
#endif /* ENABLE_SPECIALIZATION */
|
#endif /* ENABLE_SPECIALIZATION */
|
||||||
|
#endif /* _Py_TIER2 */
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1705,10 +1705,12 @@ instrument_lock_held(PyCodeObject *code, PyInterpreterState *interp)
|
||||||
);
|
);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#ifdef _Py_TIER2
|
||||||
if (code->co_executors != NULL) {
|
if (code->co_executors != NULL) {
|
||||||
_PyCode_Clear_Executors(code);
|
_PyCode_Clear_Executors(code);
|
||||||
}
|
}
|
||||||
_Py_Executors_InvalidateDependency(interp, code, 1);
|
_Py_Executors_InvalidateDependency(interp, code, 1);
|
||||||
|
#endif
|
||||||
int code_len = (int)Py_SIZE(code);
|
int code_len = (int)Py_SIZE(code);
|
||||||
/* Exit early to avoid creating instrumentation
|
/* Exit early to avoid creating instrumentation
|
||||||
* data for potential statically allocated code
|
* data for potential statically allocated code
|
||||||
|
@ -1946,7 +1948,9 @@ _PyMonitoring_SetEvents(int tool_id, _PyMonitoringEventSet events)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
set_global_version(tstate, new_version);
|
set_global_version(tstate, new_version);
|
||||||
|
#ifdef _Py_TIER2
|
||||||
_Py_Executors_InvalidateAll(interp, 1);
|
_Py_Executors_InvalidateAll(interp, 1);
|
||||||
|
#endif
|
||||||
res = instrument_all_executing_code_objects(interp);
|
res = instrument_all_executing_code_objects(interp);
|
||||||
done:
|
done:
|
||||||
_PyEval_StartTheWorld(interp);
|
_PyEval_StartTheWorld(interp);
|
||||||
|
@ -1986,7 +1990,9 @@ _PyMonitoring_SetLocalEvents(PyCodeObject *code, int tool_id, _PyMonitoringEvent
|
||||||
code->_co_instrumentation_version -= MONITORING_VERSION_INCREMENT;
|
code->_co_instrumentation_version -= MONITORING_VERSION_INCREMENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _Py_TIER2
|
||||||
_Py_Executors_InvalidateDependency(interp, code, 1);
|
_Py_Executors_InvalidateDependency(interp, code, 1);
|
||||||
|
#endif
|
||||||
|
|
||||||
res = instrument_lock_held(code, interp);
|
res = instrument_lock_held(code, interp);
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#ifdef _Py_TIER2
|
||||||
|
|
||||||
#include "Python.h"
|
#include "Python.h"
|
||||||
#include "opcode.h"
|
#include "opcode.h"
|
||||||
#include "pycore_interp.h"
|
#include "pycore_interp.h"
|
||||||
|
@ -1622,3 +1624,5 @@ _Py_Executors_InvalidateAll(PyInterpreterState *interp, int is_invalidation)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif /* _Py_TIER2 */
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#ifdef _Py_TIER2
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This file contains the support code for CPython's uops optimizer.
|
* This file contains the support code for CPython's uops optimizer.
|
||||||
* It also performs some simple optimizations.
|
* It also performs some simple optimizations.
|
||||||
|
@ -603,3 +605,5 @@ _Py_uop_analyze_and_optimize(
|
||||||
OPT_STAT_INC(optimizer_successes);
|
OPT_STAT_INC(optimizer_successes);
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif /* _Py_TIER2 */
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#ifdef _Py_TIER2
|
||||||
|
|
||||||
#include "Python.h"
|
#include "Python.h"
|
||||||
|
|
||||||
|
@ -506,3 +507,5 @@ fail:
|
||||||
Py_XDECREF(val_43);
|
Py_XDECREF(val_43);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif /* _Py_TIER2 */
|
||||||
|
|
|
@ -624,9 +624,11 @@ static int
|
||||||
builtins_dict_watcher(PyDict_WatchEvent event, PyObject *dict, PyObject *key, PyObject *new_value)
|
builtins_dict_watcher(PyDict_WatchEvent event, PyObject *dict, PyObject *key, PyObject *new_value)
|
||||||
{
|
{
|
||||||
PyInterpreterState *interp = _PyInterpreterState_GET();
|
PyInterpreterState *interp = _PyInterpreterState_GET();
|
||||||
|
#ifdef _Py_TIER2
|
||||||
if (interp->rare_events.builtin_dict < _Py_MAX_ALLOWED_BUILTINS_MODIFICATIONS) {
|
if (interp->rare_events.builtin_dict < _Py_MAX_ALLOWED_BUILTINS_MODIFICATIONS) {
|
||||||
_Py_Executors_InvalidateAll(interp, 1);
|
_Py_Executors_InvalidateAll(interp, 1);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
RARE_EVENT_INTERP_INC(interp, builtin_dict);
|
RARE_EVENT_INTERP_INC(interp, builtin_dict);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1272,30 +1274,30 @@ init_interp_main(PyThreadState *tstate)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Turn on experimental tier 2 (uops-based) optimizer
|
// Turn on experimental tier 2 (uops-based) optimizer
|
||||||
|
// This is also needed when the JIT is enabled
|
||||||
|
#ifdef _Py_TIER2
|
||||||
if (is_main_interp) {
|
if (is_main_interp) {
|
||||||
#ifndef _Py_JIT
|
int enabled = 1;
|
||||||
// No JIT, maybe use the tier two interpreter:
|
#if _Py_TIER2 & 2
|
||||||
char *envvar = Py_GETENV("PYTHON_UOPS");
|
enabled = 0;
|
||||||
int enabled = envvar != NULL && *envvar > '0';
|
#endif
|
||||||
if (_Py_get_xoption(&config->xoptions, L"uops") != NULL) {
|
char *env = Py_GETENV("PYTHON_JIT");
|
||||||
enabled = 1;
|
if (env && *env != '\0') {
|
||||||
|
// PYTHON_JIT=0|1 overrides the default
|
||||||
|
enabled = *env != '0';
|
||||||
}
|
}
|
||||||
if (enabled) {
|
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();
|
PyObject *opt = PyUnstable_Optimizer_NewUOpOptimizer();
|
||||||
if (opt == NULL) {
|
if (opt == NULL) {
|
||||||
return _PyStatus_ERR("can't initialize optimizer");
|
return _PyStatus_ERR("can't initialize optimizer");
|
||||||
}
|
}
|
||||||
if (PyUnstable_SetOptimizer((_PyOptimizerObject *)opt)) {
|
if (PyUnstable_SetOptimizer((_PyOptimizerObject *)opt)) {
|
||||||
return _PyStatus_ERR("can't initialize optimizer");
|
return _PyStatus_ERR("can't install optimizer");
|
||||||
}
|
}
|
||||||
Py_DECREF(opt);
|
Py_DECREF(opt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!is_main_interp) {
|
if (!is_main_interp) {
|
||||||
// The main interpreter is handled in Py_Main(), for now.
|
// The main interpreter is handled in Py_Main(), for now.
|
||||||
|
@ -1655,10 +1657,12 @@ finalize_modules(PyThreadState *tstate)
|
||||||
{
|
{
|
||||||
PyInterpreterState *interp = tstate->interp;
|
PyInterpreterState *interp = tstate->interp;
|
||||||
|
|
||||||
|
#ifdef _Py_TIER2
|
||||||
// Invalidate all executors and turn off tier 2 optimizer
|
// Invalidate all executors and turn off tier 2 optimizer
|
||||||
_Py_Executors_InvalidateAll(interp, 0);
|
_Py_Executors_InvalidateAll(interp, 0);
|
||||||
_PyOptimizerObject *old = _Py_SetOptimizer(interp, NULL);
|
_PyOptimizerObject *old = _Py_SetOptimizer(interp, NULL);
|
||||||
Py_XDECREF(old);
|
Py_XDECREF(old);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Stop watching __builtin__ modifications
|
// Stop watching __builtin__ modifications
|
||||||
PyDict_Unwatch(0, interp->builtins);
|
PyDict_Unwatch(0, interp->builtins);
|
||||||
|
|
|
@ -653,8 +653,10 @@ init_interpreter(PyInterpreterState *interp,
|
||||||
}
|
}
|
||||||
interp->sys_profile_initialized = false;
|
interp->sys_profile_initialized = false;
|
||||||
interp->sys_trace_initialized = false;
|
interp->sys_trace_initialized = false;
|
||||||
|
#ifdef _Py_TIER2
|
||||||
(void)_Py_SetOptimizer(interp, NULL);
|
(void)_Py_SetOptimizer(interp, NULL);
|
||||||
interp->executor_list_head = NULL;
|
interp->executor_list_head = NULL;
|
||||||
|
#endif
|
||||||
if (interp != &runtime->_main_interpreter) {
|
if (interp != &runtime->_main_interpreter) {
|
||||||
/* Fix the self-referential, statically initialized fields. */
|
/* Fix the self-referential, statically initialized fields. */
|
||||||
interp->dtoa = (struct _dtoa_state)_dtoa_state_INIT(interp);
|
interp->dtoa = (struct _dtoa_state)_dtoa_state_INIT(interp);
|
||||||
|
@ -806,9 +808,11 @@ interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate)
|
||||||
tstate->_status.cleared = 0;
|
tstate->_status.cleared = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _Py_TIER2
|
||||||
_PyOptimizerObject *old = _Py_SetOptimizer(interp, NULL);
|
_PyOptimizerObject *old = _Py_SetOptimizer(interp, NULL);
|
||||||
assert(old != NULL);
|
assert(old != NULL);
|
||||||
Py_DECREF(old);
|
Py_DECREF(old);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* It is possible that any of the objects below have a finalizer
|
/* It is possible that any of the objects below have a finalizer
|
||||||
that runs Python code or otherwise relies on a thread state
|
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) {
|
if (eval_frame == interp->eval_frame) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
#ifdef _Py_TIER2
|
||||||
if (eval_frame != NULL) {
|
if (eval_frame != NULL) {
|
||||||
_Py_Executors_InvalidateAll(interp, 1);
|
_Py_Executors_InvalidateAll(interp, 1);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
RARE_EVENT_INC(set_eval_frame_func);
|
RARE_EVENT_INC(set_eval_frame_func);
|
||||||
interp->eval_frame = eval_frame;
|
interp->eval_frame = eval_frame;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2165,8 +2165,10 @@ static PyObject *
|
||||||
sys__clear_internal_caches_impl(PyObject *module)
|
sys__clear_internal_caches_impl(PyObject *module)
|
||||||
/*[clinic end generated code: output=0ee128670a4966d6 input=253e741ca744f6e8]*/
|
/*[clinic end generated code: output=0ee128670a4966d6 input=253e741ca744f6e8]*/
|
||||||
{
|
{
|
||||||
|
#ifdef _Py_TIER2
|
||||||
PyInterpreterState *interp = _PyInterpreterState_GET();
|
PyInterpreterState *interp = _PyInterpreterState_GET();
|
||||||
_Py_Executors_InvalidateAll(interp, 0);
|
_Py_Executors_InvalidateAll(interp, 0);
|
||||||
|
#endif
|
||||||
PyType_ClearCache();
|
PyType_ClearCache();
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -411,6 +411,7 @@ NON_ESCAPING_FUNCTIONS = (
|
||||||
"PyCell_New",
|
"PyCell_New",
|
||||||
"PyFloat_AS_DOUBLE",
|
"PyFloat_AS_DOUBLE",
|
||||||
"_PyFrame_PushUnchecked",
|
"_PyFrame_PushUnchecked",
|
||||||
|
"Py_FatalError",
|
||||||
)
|
)
|
||||||
|
|
||||||
ESCAPING_FUNCTIONS = (
|
ESCAPING_FUNCTIONS = (
|
||||||
|
|
|
@ -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).
|
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:
|
It's easy to install all of the required tools:
|
||||||
|
|
||||||
### Linux
|
### Linux
|
||||||
|
|
||||||
Install LLVM 16 on Ubuntu/Debian:
|
Install LLVM 18 on Ubuntu/Debian:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
wget https://apt.llvm.org/llvm.sh
|
wget https://apt.llvm.org/llvm.sh
|
||||||
chmod +x llvm.sh
|
chmod +x llvm.sh
|
||||||
sudo ./llvm.sh 16
|
sudo ./llvm.sh 18
|
||||||
```
|
```
|
||||||
|
|
||||||
### macOS
|
### macOS
|
||||||
|
|
|
@ -1818,7 +1818,7 @@ Optional Features:
|
||||||
--disable-gil enable experimental support for running without the
|
--disable-gil enable experimental support for running without the
|
||||||
GIL (default is no)
|
GIL (default is no)
|
||||||
--enable-pystats enable internal statistics gathering (default is no)
|
--enable-pystats enable internal statistics gathering (default is no)
|
||||||
--enable-experimental-jit
|
--enable-experimental-jit[=no|yes|yes-off|interpreter]
|
||||||
build the experimental just-in-time compiler
|
build the experimental just-in-time compiler
|
||||||
(default is no)
|
(default is no)
|
||||||
--enable-optimizations enable expensive, stable optimizations (PGO, etc.)
|
--enable-optimizations enable expensive, stable optimizations (PGO, etc.)
|
||||||
|
@ -8229,11 +8229,19 @@ else $as_nop
|
||||||
enable_experimental_jit=no
|
enable_experimental_jit=no
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
case $enable_experimental_jit in
|
||||||
|
no) enable_experimental_jit=no ;;
|
||||||
|
yes) enable_experimental_jit="-D_Py_JIT -D_Py_TIER2=1" ;;
|
||||||
|
yes-off) enable_experimental_jit="-D_Py_JIT -D_Py_TIER2=3" ;;
|
||||||
|
interpreter) enable_experimental_jit="-D_Py_TIER2=4" ;;
|
||||||
|
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
|
if test "x$enable_experimental_jit" = xno
|
||||||
then :
|
then :
|
||||||
|
|
||||||
else $as_nop
|
else $as_nop
|
||||||
as_fn_append CFLAGS_NODIST " -D_Py_JIT"
|
as_fn_append CFLAGS_NODIST " $enable_experimental_jit"
|
||||||
REGEN_JIT_COMMAND="\$(PYTHON_FOR_REGEN) \$(srcdir)/Tools/jit/build.py $host"
|
REGEN_JIT_COMMAND="\$(PYTHON_FOR_REGEN) \$(srcdir)/Tools/jit/build.py $host"
|
||||||
JIT_STENCILS_H="jit_stencils.h"
|
JIT_STENCILS_H="jit_stencils.h"
|
||||||
if test "x$Py_DEBUG" = xtrue
|
if test "x$Py_DEBUG" = xtrue
|
||||||
|
|
13
configure.ac
13
configure.ac
|
@ -1768,14 +1768,23 @@ fi
|
||||||
# Check for --enable-experimental-jit:
|
# Check for --enable-experimental-jit:
|
||||||
AC_MSG_CHECKING([for --enable-experimental-jit])
|
AC_MSG_CHECKING([for --enable-experimental-jit])
|
||||||
AC_ARG_ENABLE([experimental-jit],
|
AC_ARG_ENABLE([experimental-jit],
|
||||||
[AS_HELP_STRING([--enable-experimental-jit],
|
[AS_HELP_STRING([--enable-experimental-jit@<:@=no|yes|yes-off|interpreter@:>@],
|
||||||
[build the experimental just-in-time compiler (default is no)])],
|
[build the experimental just-in-time compiler (default is no)])],
|
||||||
[],
|
[],
|
||||||
[enable_experimental_jit=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-off) enable_experimental_jit="-D_Py_JIT -D_Py_TIER2=3" ;;
|
||||||
|
interpreter) enable_experimental_jit="-D_Py_TIER2=4" ;;
|
||||||
|
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-off|interpreter]) ;;
|
||||||
|
esac
|
||||||
AS_VAR_IF([enable_experimental_jit],
|
AS_VAR_IF([enable_experimental_jit],
|
||||||
[no],
|
[no],
|
||||||
[],
|
[],
|
||||||
[AS_VAR_APPEND([CFLAGS_NODIST], [" -D_Py_JIT"])
|
[AS_VAR_APPEND([CFLAGS_NODIST], [" $enable_experimental_jit"])
|
||||||
AS_VAR_SET([REGEN_JIT_COMMAND],
|
AS_VAR_SET([REGEN_JIT_COMMAND],
|
||||||
["\$(PYTHON_FOR_REGEN) \$(srcdir)/Tools/jit/build.py $host"])
|
["\$(PYTHON_FOR_REGEN) \$(srcdir)/Tools/jit/build.py $host"])
|
||||||
AS_VAR_SET([JIT_STENCILS_H], ["jit_stencils.h"])
|
AS_VAR_SET([JIT_STENCILS_H], ["jit_stencils.h"])
|
||||||
|
|
Loading…
Reference in New Issue