Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
36 changes: 36 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
executors = []
for i in range(0, len(co_code), 2):
try:
executors.append(_opcode.get_executor(code, i))
except ValueError:
pass
return executors


def iter_opnames(ex):
for item in ex:
Expand Down Expand Up @@ -2629,6 +2640,31 @@ 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()
all_executors = get_all_executors(f)
# Inner loop warms up first.
# Outer loop warms up later, linking to the inner one.
# Therefore, we have at least two executors.
self.assertGreaterEqual(len(all_executors), 2)
for executor in all_executors:
opnames = list(get_opnames(executor))
# Assert all executors first terminator ends in
# _EXIT_TRACE or _JUMP_TO_TOP, not _DEOPT
for idx, op in enumerate(opnames):
if op == "_EXIT_TRACE" or op == "_JUMP_TO_TOP":
break
elif op == "_DEOPT":
self.fail(f"_DEOPT encountered first at executor"
f" {executor} at offset {idx} rather"
f" than expected _EXIT_TRACE")



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_opcode)
{

#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_opcode != 0) {
ADD_TO_TRACE(stop_tracing_opcode, 0, 0, target);
goto done;
}

Expand Down
Loading