Skip to content

Commit a5c00e8

Browse files
committed
Split CALL_PY_EXACT_ARGS into uops
This is only the first step for doing `CALL` in Tier 2. The next step involves tracing into the called code object. After that we'll have to do the remaining `CALL` specialization. Finally we'll have to tweak various things like `KW_NAMES`, and possibly move the `NULL` (for method calls) *above* the callable. But those are things for future PRs. Note: this moves setting `frame->return_offset` directly in front of `DISPATCH_INLINED()`, to make it easier to move it into `_PUSH_FRAME`.
1 parent 328d925 commit a5c00e8

File tree

9 files changed

+210
-58
lines changed

9 files changed

+210
-58
lines changed

Include/internal/pycore_opcode_metadata.h

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

Python/bytecodes.c

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -941,13 +941,13 @@ dummy_func(
941941
{
942942
PyGenObject *gen = (PyGenObject *)receiver;
943943
_PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe;
944-
frame->return_offset = oparg;
945944
STACK_SHRINK(1);
946945
_PyFrame_StackPush(gen_frame, v);
947946
gen->gi_frame_state = FRAME_EXECUTING;
948947
gen->gi_exc_state.previous_item = tstate->exc_info;
949948
tstate->exc_info = &gen->gi_exc_state;
950949
SKIP_OVER(INLINE_CACHE_ENTRIES_SEND);
950+
frame->return_offset = oparg;
951951
DISPATCH_INLINED(gen_frame);
952952
}
953953
if (Py_IsNone(v) && PyIter_Check(receiver)) {
@@ -980,13 +980,13 @@ dummy_func(
980980
DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING, SEND);
981981
STAT_INC(SEND, hit);
982982
_PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe;
983-
frame->return_offset = oparg;
984983
STACK_SHRINK(1);
985984
_PyFrame_StackPush(gen_frame, v);
986985
gen->gi_frame_state = FRAME_EXECUTING;
987986
gen->gi_exc_state.previous_item = tstate->exc_info;
988987
tstate->exc_info = &gen->gi_exc_state;
989988
SKIP_OVER(INLINE_CACHE_ENTRIES_SEND);
989+
frame->return_offset = oparg;
990990
DISPATCH_INLINED(gen_frame);
991991
}
992992

@@ -2578,14 +2578,14 @@ dummy_func(
25782578
DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING, FOR_ITER);
25792579
STAT_INC(FOR_ITER, hit);
25802580
_PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe;
2581-
frame->return_offset = oparg;
25822581
_PyFrame_StackPush(gen_frame, Py_None);
25832582
gen->gi_frame_state = FRAME_EXECUTING;
25842583
gen->gi_exc_state.previous_item = tstate->exc_info;
25852584
tstate->exc_info = &gen->gi_exc_state;
25862585
SKIP_OVER(INLINE_CACHE_ENTRIES_FOR_ITER);
25872586
assert(next_instr[oparg].op.code == END_FOR ||
25882587
next_instr[oparg].op.code == INSTRUMENTED_END_FOR);
2588+
frame->return_offset = oparg;
25892589
DISPATCH_INLINED(gen_frame);
25902590
}
25912591

@@ -2939,14 +2939,13 @@ dummy_func(
29392939
GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS);
29402940
}
29412941

2942-
inst(CALL_PY_EXACT_ARGS, (unused/1, func_version/2, method, callable, args[oparg] -- unused)) {
2942+
op(_CHECK_CALL_PY_EXACT_ARGS, (func_version/2, method, callable, unused[oparg] -- method, callable, unused[oparg])) {
29432943
ASSERT_KWNAMES_IS_NULL();
29442944
DEOPT_IF(tstate->interp->eval_frame, CALL);
29452945
int is_meth = method != NULL;
29462946
int argcount = oparg;
29472947
if (is_meth) {
29482948
callable = method;
2949-
args--;
29502949
argcount++;
29512950
}
29522951
DEOPT_IF(!PyFunction_Check(callable), CALL);
@@ -2955,18 +2954,35 @@ dummy_func(
29552954
PyCodeObject *code = (PyCodeObject *)func->func_code;
29562955
DEOPT_IF(code->co_argcount != argcount, CALL);
29572956
DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), CALL);
2957+
}
2958+
2959+
op(_INIT_CALL_PY_EXACT_ARGS, (method, callable, args[oparg] -- new_frame: _PyInterpreterFrame*)) {
2960+
int is_meth = method != NULL;
2961+
int argcount = oparg;
2962+
if (is_meth) {
2963+
callable = method;
2964+
args--;
2965+
argcount++;
2966+
}
29582967
STAT_INC(CALL, hit);
2959-
_PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, func, argcount);
2968+
PyFunctionObject *func = (PyFunctionObject *)callable;
2969+
new_frame = _PyFrame_PushUnchecked(tstate, func, argcount);
29602970
for (int i = 0; i < argcount; i++) {
29612971
new_frame->localsplus[i] = args[i];
29622972
}
2963-
// Manipulate stack directly since we leave using DISPATCH_INLINED().
2964-
STACK_SHRINK(oparg + 2);
2965-
SKIP_OVER(INLINE_CACHE_ENTRIES_CALL);
2973+
}
2974+
2975+
op(_PUSH_FRAME, (new_frame: _PyInterpreterFrame* -- unused)) {
29662976
frame->return_offset = 0;
29672977
DISPATCH_INLINED(new_frame);
29682978
}
29692979

2980+
macro(CALL_PY_EXACT_ARGS) =
2981+
unused/1 + // Skip over the counter
2982+
_CHECK_CALL_PY_EXACT_ARGS +
2983+
_INIT_CALL_PY_EXACT_ARGS +
2984+
_PUSH_FRAME;
2985+
29702986
inst(CALL_PY_WITH_DEFAULTS, (unused/1, func_version/2, method, callable, args[oparg] -- unused)) {
29712987
ASSERT_KWNAMES_IS_NULL();
29722988
DEOPT_IF(tstate->interp->eval_frame, CALL);

Python/executor.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,19 @@
3030
#undef ENABLE_SPECIALIZATION
3131
#define ENABLE_SPECIALIZATION 0
3232

33+
#undef DISPATCH_INLINED
34+
#define DISPATCH_INLINED(NEW_FRAME) \
35+
do { \
36+
assert(tstate->interp->eval_frame == NULL); \
37+
_PyFrame_SetStackPointer(frame, stack_pointer); \
38+
frame->prev_instr -= 1; \
39+
(NEW_FRAME)->previous = frame; \
40+
frame = tstate->cframe->current_frame = (NEW_FRAME); \
41+
CALL_STAT_INC(inlined_py_calls); \
42+
stack_pointer = _PyFrame_GetStackPointer(frame); \
43+
ip_offset = (_Py_CODEUNIT *)_PyFrame_GetCode(frame)->co_code_adaptive; \
44+
} while (0)
45+
3346

3447
_PyInterpreterFrame *
3548
_PyUopExecute(_PyExecutorObject *executor, _PyInterpreterFrame *frame, PyObject **stack_pointer)

Python/executor_cases.c.h

Lines changed: 59 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: 47 additions & 30 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/optimizer.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,10 @@ translate_bytecode_to_trace(
602602
case OPARG_BOTTOM: // Second half of super-instr
603603
oparg = orig_oparg & 0xF;
604604
break;
605+
case OPARG_SAVE_IP: // op==SAVE_IP; oparg=next instr
606+
oparg = INSTR_IP(instr + offset, code);
607+
break;
608+
605609
default:
606610
fprintf(stderr,
607611
"opcode=%d, oparg=%d; nuops=%d, i=%d; size=%d, offset=%d\n",
@@ -611,6 +615,10 @@ translate_bytecode_to_trace(
611615
Py_FatalError("garbled expansion");
612616
}
613617
ADD_TO_TRACE(expansion->uops[i].uop, oparg, operand);
618+
if (expansion->uops[i].uop == _PUSH_FRAME) {
619+
ADD_TO_TRACE(SAVE_IP, 0, 0);
620+
goto done;
621+
}
614622
}
615623
break;
616624
}

0 commit comments

Comments
 (0)