Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Include/internal/pycore_optimizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ PyAPI_FUNC(int) _PyDumpExecutors(FILE *out);
extern void _Py_ClearExecutorDeletionList(PyInterpreterState *interp);
#endif

int _PyJit_translate_single_bytecode_to_trace(PyThreadState *tstate, _PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr, bool stop_tracing);
int _PyJit_translate_single_bytecode_to_trace(PyThreadState *tstate, _PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr, int stop_tracing_opcode);

int
_PyJit_TryInitializeTracing(PyThreadState *tstate, _PyInterpreterFrame *frame,
Expand Down
23 changes: 23 additions & 0 deletions Lib/test/test_capi/test_opt.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,17 @@ def get_first_executor(func):
pass
return None

def get_all_executors(func):
code = func.__code__
co_code = code.co_code
execs = []
for i in range(0, len(co_code), 2):
try:
execs.append(_opcode.get_executor(code, i))
except ValueError:
pass
return execs


def iter_opnames(ex):
for item in ex:
Expand Down Expand Up @@ -2629,6 +2640,18 @@ def gen():
next(g)
""" % _testinternalcapi.SPECIALIZATION_THRESHOLD))

def test_executor_side_exits_create_another_executor(self):
def f():
for x in range(TIER2_THRESHOLD + 3):
for y in range(TIER2_THRESHOLD + 3):
z = x + y

f()
# Inner loop warms up first.
# Outer loop warms up later, linking to the inner one.
# Therefore, at least two executors.
self.assertGreaterEqual(len(get_all_executors(f)), 2)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please explain, why this test checks _DEOPT vs _EXIT_TRACE pair?
On my machine it passes both on this PR and on main branch.
Using option --enable-experimental-jit=interpreter or --enable-experimental-jit=yes also doesn't matter.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm it shouldn't pass on main. Let me strengthen the test.

Copy link
Member

@efimov-mikhail efimov-mikhail Nov 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This version of test fails on main with --enable-experimental-jit=interpreter or with --enable-experimental-jit=yes as expected.



def global_identity(x):
return x
Expand Down
4 changes: 2 additions & 2 deletions Python/bytecodes.c
Original file line number Diff line number Diff line change
Expand Up @@ -5644,7 +5644,7 @@ dummy_func(
bool stop_tracing = (opcode == WITH_EXCEPT_START ||
opcode == RERAISE || opcode == CLEANUP_THROW ||
opcode == PUSH_EXC_INFO || opcode == INTERPRETER_EXIT);
int full = !_PyJit_translate_single_bytecode_to_trace(tstate, frame, next_instr, stop_tracing);
int full = !_PyJit_translate_single_bytecode_to_trace(tstate, frame, next_instr, stop_tracing ? _DEOPT : 0);
if (full) {
LEAVE_TRACING();
int err = stop_tracing_and_jit(tstate, frame);
Expand Down Expand Up @@ -5684,7 +5684,7 @@ dummy_func(
#if _Py_TIER2
assert(IS_JIT_TRACING());
int opcode = next_instr->op.code;
_PyJit_translate_single_bytecode_to_trace(tstate, frame, NULL, true);
_PyJit_translate_single_bytecode_to_trace(tstate, frame, NULL, _EXIT_TRACE);
LEAVE_TRACING();
int err = stop_tracing_and_jit(tstate, frame);
ERROR_IF(err < 0);
Expand Down
4 changes: 2 additions & 2 deletions Python/generated_cases.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions Python/optimizer.c
Original file line number Diff line number Diff line change
Expand Up @@ -574,7 +574,7 @@ _PyJit_translate_single_bytecode_to_trace(
PyThreadState *tstate,
_PyInterpreterFrame *frame,
_Py_CODEUNIT *next_instr,
bool stop_tracing)
int stop_tracing_opocde)
{

#ifdef Py_DEBUG
Expand Down Expand Up @@ -637,8 +637,8 @@ _PyJit_translate_single_bytecode_to_trace(
goto full;
}

if (stop_tracing) {
ADD_TO_TRACE(_DEOPT, 0, 0, target);
if (stop_tracing_opocde != 0) {
ADD_TO_TRACE(stop_tracing_opocde, 0, 0, target);
goto done;
}

Expand Down
Loading