Skip to content

Commit a2c0994

Browse files
committed
Inline creation of coroutines.
1 parent 0721cea commit a2c0994

File tree

1 file changed

+37
-22
lines changed

1 file changed

+37
-22
lines changed

Python/ceval.c

Lines changed: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1541,6 +1541,12 @@ _PyEval_FrameFromPyFunctionAndArgs(PyThreadState *tstate, PyObject* const *args,
15411541
return _PyEvalFramePushAndInit(tstate, con, locals, args, vector_nargs, NULL, 1);
15421542
}
15431543

1544+
static PyObject *
1545+
make_coro(PyThreadState *tstate, PyFrameConstructor *con,
1546+
PyObject *locals,
1547+
PyObject* const* args, size_t argcount,
1548+
PyObject *kwnames);
1549+
15441550
PyObject* _Py_HOT_FUNCTION
15451551
_PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int throwflag)
15461552
{
@@ -4637,39 +4643,48 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
46374643

46384644
// Check if the call can be inlined or not
46394645
PyObject *function = PEEK(oparg + 1);
4640-
int inline_call = 0;
46414646
if (Py_TYPE(function) == &PyFunction_Type) {
46424647
PyCodeObject *code = (PyCodeObject*)PyFunction_GET_CODE(function);
4643-
int is_coro = code->co_flags & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR);
4644-
inline_call = !is_coro;
4648+
STACK_SHRINK(oparg + 1);
4649+
if (code->co_flags & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR)) {
4650+
PyObject *locals = code->co_flags & CO_OPTIMIZED ? NULL : PyFunction_GET_GLOBALS(function);
4651+
res = make_coro(
4652+
tstate, PyFunction_AS_FRAME_CONSTRUCTOR(function), locals, stack_pointer+1, oparg, NULL);
4653+
for (int i = 0; i < oparg+1; i++) {
4654+
Py_DECREF(stack_pointer[i]);
4655+
}
4656+
PUSH(res);
4657+
if (res == NULL) {
4658+
goto error;
4659+
}
4660+
}
4661+
else {
4662+
InterpreterFrame *new_frame = _PyEval_FrameFromPyFunctionAndArgs(tstate, stack_pointer+1, oparg, function);
4663+
if (new_frame == NULL) {
4664+
// When we exit here, we own all variables in the stack (the frame creation has not stolen
4665+
// any variable) so we need to clean the whole stack (done in the "error" label).
4666+
goto error;
4667+
}
4668+
assert(tstate->interp->eval_frame != NULL);
4669+
// The frame has stolen all the arguments from the stack, so there is no need to clean up them
4670+
Py_DECREF(function);
4671+
_PyFrame_SetStackPointer(frame, stack_pointer);
4672+
new_frame->depth = frame->depth + 1;
4673+
tstate->frame = frame = new_frame;
4674+
goto start_frame;
4675+
}
46454676
}
4646-
4647-
if (!inline_call) {
4677+
else {
46484678
PyObject **sp = stack_pointer;
46494679
res = call_function(tstate, &sp, oparg, NULL, cframe.use_tracing);
46504680
stack_pointer = sp;
46514681
PUSH(res);
46524682
if (res == NULL) {
46534683
goto error;
46544684
}
4655-
CHECK_EVAL_BREAKER();
4656-
DISPATCH();
46574685
}
4658-
4659-
InterpreterFrame *new_frame = _PyEval_FrameFromPyFunctionAndArgs(tstate, stack_pointer-oparg, oparg, function);
4660-
if (new_frame == NULL) {
4661-
// When we exit here, we own all variables in the stack (the frame creation has not stolen
4662-
// any variable) so we need to clean the whole stack (done in the "error" label).
4663-
goto error;
4664-
}
4665-
assert(tstate->interp->eval_frame != NULL);
4666-
// The frame has stolen all the arguments from the stack, so there is no need to clean up them
4667-
STACK_SHRINK(oparg + 1);
4668-
Py_DECREF(function);
4669-
_PyFrame_SetStackPointer(frame, stack_pointer);
4670-
new_frame->depth = frame->depth + 1;
4671-
tstate->frame = frame = new_frame;
4672-
goto start_frame;
4686+
CHECK_EVAL_BREAKER();
4687+
DISPATCH();
46734688
}
46744689

46754690
TARGET(CALL_FUNCTION_KW): {

0 commit comments

Comments
 (0)