Skip to content

Commit fc4824b

Browse files
committed
Rework sys._jit.is_active to support the tail-calling interpreter
1 parent db7609f commit fc4824b

File tree

10 files changed

+78
-36
lines changed

10 files changed

+78
-36
lines changed

Include/cpython/pystate.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,10 @@ struct _ts {
206206
*/
207207
PyObject *threading_local_sentinel;
208208
_PyRemoteDebuggerSupport remote_debugger_support;
209+
210+
// Any frame between the topmost frame where the JIT is currently active,
211+
// and the interpreter entry frame below it (used by sys._jit.is_active):
212+
struct _PyInterpreterFrame *jit_entry;
209213
};
210214

211215
/* other API */

Include/internal/pycore_interpframe.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,6 @@ _PyFrame_Initialize(
146146
frame->return_offset = 0;
147147
frame->owner = FRAME_OWNED_BY_THREAD;
148148
frame->visited = 0;
149-
frame->jit_active = false;
150149
#ifdef Py_DEBUG
151150
frame->lltrace = 0;
152151
#endif
@@ -328,7 +327,6 @@ _PyFrame_PushTrampolineUnchecked(PyThreadState *tstate, PyCodeObject *code, int
328327
#endif
329328
frame->owner = FRAME_OWNED_BY_THREAD;
330329
frame->visited = 0;
331-
frame->jit_active = false;
332330
#ifdef Py_DEBUG
333331
frame->lltrace = 0;
334332
#endif

Include/internal/pycore_interpframe_structs.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,11 @@ struct _PyInterpreterFrame {
4343
#endif
4444
uint16_t return_offset; /* Only relevant during a function call */
4545
char owner;
46-
uint8_t visited:1;
47-
// Set on interpreter entry frames when the JIT is active:
48-
uint8_t jit_active:1;
4946
#ifdef Py_DEBUG
50-
uint8_t lltrace:6;
47+
uint8_t visited:1;
48+
uint8_t lltrace:7;
49+
#else
50+
uint8_t visited;
5151
#endif
5252
/* Locals and stack */
5353
_PyStackRef localsplus[1];

Python/bytecodes.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1191,6 +1191,9 @@ dummy_func(
11911191
LOAD_IP(frame->return_offset);
11921192
res = temp;
11931193
LLTRACE_RESUME_FRAME();
1194+
#if TIER_TWO
1195+
tstate->jit_entry = frame;
1196+
#endif
11941197
}
11951198

11961199
tier1 op(_RETURN_VALUE_EVENT, (val -- val)) {
@@ -1377,6 +1380,9 @@ dummy_func(
13771380
LOAD_IP(1 + INLINE_CACHE_ENTRIES_SEND);
13781381
value = PyStackRef_MakeHeapSafe(temp);
13791382
LLTRACE_RESUME_FRAME();
1383+
#if TIER_TWO
1384+
tstate->jit_entry = frame;
1385+
#endif
13801386
}
13811387

13821388
tier1 op(_YIELD_VALUE_EVENT, (val -- val)) {
@@ -4962,6 +4968,9 @@ dummy_func(
49624968
RELOAD_STACK();
49634969
res = PyStackRef_FromPyObjectStealMortal((PyObject *)gen);
49644970
LLTRACE_RESUME_FRAME();
4971+
#if TIER_TWO
4972+
tstate->jit_entry = frame;
4973+
#endif
49654974
}
49664975

49674976
inst(BUILD_SLICE, (args[oparg] -- slice)) {

Python/ceval.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,10 +1035,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
10351035
entry_frame.f_executable = PyStackRef_None;
10361036
entry_frame.instr_ptr = (_Py_CODEUNIT *)_Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS + 1;
10371037
entry_frame.stackpointer = entry_frame.localsplus;
1038-
entry_frame.return_offset = 0;
10391038
entry_frame.owner = FRAME_OWNED_BY_INTERPRETER;
10401039
entry_frame.visited = 0;
1041-
entry_frame.jit_active = false;
1040+
entry_frame.return_offset = 0;
10421041
#ifdef Py_DEBUG
10431042
entry_frame.lltrace = 0;
10441043
#endif

Python/ceval_macros.h

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -355,45 +355,43 @@ _PyFrame_SetStackPointer(frame, stack_pointer)
355355
/* Tier-switching macros. */
356356

357357
#ifdef _Py_JIT
358-
#define GOTO_TIER_TWO(EXECUTOR) \
359-
do { \
360-
OPT_STAT_INC(traces_executed); \
361-
_PyExecutorObject *_executor = (EXECUTOR); \
362-
jit_func jitted = _executor->jit_code; \
363-
/* Keep the shim frame alive via the executor: */ \
364-
Py_INCREF(_executor); \
365-
assert(!entry_frame.jit_active); \
366-
entry_frame.jit_active = true; \
367-
next_instr = jitted(frame, stack_pointer, tstate); \
368-
assert(entry_frame.jit_active); \
369-
entry_frame.jit_active = false; \
370-
Py_DECREF(_executor); \
371-
Py_CLEAR(tstate->previous_executor); \
372-
frame = tstate->current_frame; \
373-
stack_pointer = _PyFrame_GetStackPointer(frame); \
374-
if (next_instr == NULL) { \
375-
next_instr = frame->instr_ptr; \
376-
JUMP_TO_LABEL(error); \
377-
} \
378-
DISPATCH(); \
358+
#define GOTO_TIER_TWO(EXECUTOR) \
359+
do { \
360+
OPT_STAT_INC(traces_executed); \
361+
_PyExecutorObject *_executor = (EXECUTOR); \
362+
jit_func jitted = _executor->jit_code; \
363+
/* Keep the shim frame alive via the executor: */ \
364+
Py_INCREF(_executor); \
365+
_PyInterpreterFrame *jit_entry = tstate->jit_entry; \
366+
tstate->jit_entry = frame; \
367+
next_instr = jitted(frame, stack_pointer, tstate); \
368+
tstate->jit_entry = jit_entry; \
369+
Py_DECREF(_executor); \
370+
Py_CLEAR(tstate->previous_executor); \
371+
frame = tstate->current_frame; \
372+
stack_pointer = _PyFrame_GetStackPointer(frame); \
373+
if (next_instr == NULL) { \
374+
next_instr = frame->instr_ptr; \
375+
JUMP_TO_LABEL(error); \
376+
} \
377+
DISPATCH(); \
379378
} while (0)
380379
#else
381380
#define GOTO_TIER_TWO(EXECUTOR) \
382381
do { \
383382
OPT_STAT_INC(traces_executed); \
384383
next_uop = (EXECUTOR)->trace; \
385384
assert(next_uop->opcode == _START_EXECUTOR); \
386-
assert(!entry_frame.jit_active); \
387-
entry_frame.jit_active = true; \
385+
jit_entry = tstate->jit_entry; \
386+
tstate->jit_entry = frame; \
388387
goto enter_tier_two; \
389388
} while (0)
390389
#endif
391390

392391
#define GOTO_TIER_ONE(TARGET) \
393392
do \
394393
{ \
395-
assert(entry_frame.jit_active); \
396-
entry_frame.jit_active = false; \
394+
tstate->jit_entry = jit_entry; \
397395
next_instr = (TARGET); \
398396
OPT_HIST(trace_uop_execution_counter, trace_run_length_hist); \
399397
_PyFrame_SetStackPointer(frame, stack_pointer); \

Python/executor_cases.c.h

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/generated_cases.c.h

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/pystate.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1582,6 +1582,8 @@ init_threadstate(_PyThreadStateImpl *_tstate,
15821582

15831583
tstate->delete_later = NULL;
15841584

1585+
tstate->jit_entry = NULL;
1586+
15851587
llist_init(&_tstate->mem_free_queue);
15861588
llist_init(&_tstate->asyncio_tasks_head);
15871589
if (interp->stoptheworld.requested || _PyRuntime.stoptheworld.requested) {

Python/sysmodule.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4033,13 +4033,21 @@ _jit_is_active_impl(PyObject *module)
40334033
/*[clinic end generated code: output=7facca06b10064d4 input=a7e31db659d40a0b]*/
40344034
{
40354035
(void)module;
4036-
_PyInterpreterFrame *frame = _PyThreadState_GET()->current_frame;
4036+
PyThreadState *tstate = _PyThreadState_GET();
4037+
_PyInterpreterFrame *frame = tstate->current_frame;
4038+
_PyInterpreterFrame *jit_entry_frame = tstate->jit_entry;
40374039
while (true) {
4038-
frame = frame->previous;
4040+
// If we hit the JIT's "entry" frame first, we're in JIT code:
4041+
if (frame == jit_entry_frame) {
4042+
return true;
4043+
}
4044+
// If we hit the interpreter's "entry" frame first, we're not:
40394045
if (frame->owner == FRAME_OWNED_BY_INTERPRETER) {
4040-
return frame->jit_active;
4046+
return false;
40414047
}
4048+
frame = frame->previous;
40424049
}
4050+
Py_UNREACHABLE();
40434051
}
40444052

40454053
static PyMethodDef _jit_methods[] = {

0 commit comments

Comments
 (0)