GH-87849: Simplify stack effect of SEND and specialize it for generators and coroutines. (GH-101788)

This commit is contained in:
Mark Shannon 2023-02-13 11:24:55 +00:00 committed by GitHub
parent a1f08f5f19
commit 160f2fe2b9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 191 additions and 105 deletions

View file

@ -882,57 +882,69 @@
}
TARGET(SEND) {
PREDICTED(SEND);
PyObject *v = PEEK(1);
PyObject *receiver = PEEK(2);
PyObject *retval;
#if ENABLE_SPECIALIZATION
_PySendCache *cache = (_PySendCache *)next_instr;
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
assert(cframe.use_tracing == 0);
next_instr--;
_Py_Specialize_Send(receiver, next_instr);
DISPATCH_SAME_OPARG();
}
STAT_INC(SEND, deferred);
DECREMENT_ADAPTIVE_COUNTER(cache->counter);
#endif /* ENABLE_SPECIALIZATION */
assert(frame != &entry_frame);
bool jump = false;
PySendResult gen_status;
if (tstate->c_tracefunc == NULL) {
gen_status = PyIter_Send(receiver, v, &retval);
} else {
if (Py_IsNone(v) && PyIter_Check(receiver)) {
retval = Py_TYPE(receiver)->tp_iternext(receiver);
}
else {
retval = PyObject_CallMethodOneArg(receiver, &_Py_ID(send), v);
}
if (retval == NULL) {
if (tstate->c_tracefunc != NULL
&& _PyErr_ExceptionMatches(tstate, PyExc_StopIteration))
call_exc_trace(tstate->c_tracefunc, tstate->c_traceobj, tstate, frame);
if (_PyGen_FetchStopIterationValue(&retval) == 0) {
gen_status = PYGEN_RETURN;
}
else {
gen_status = PYGEN_ERROR;
}
}
else {
gen_status = PYGEN_NEXT;
}
}
if (gen_status == PYGEN_ERROR) {
assert(retval == NULL);
goto error;
}
Py_DECREF(v);
if (gen_status == PYGEN_RETURN) {
assert(retval != NULL);
Py_DECREF(receiver);
JUMPBY(oparg);
jump = true;
if (Py_IsNone(v) && PyIter_Check(receiver)) {
retval = Py_TYPE(receiver)->tp_iternext(receiver);
}
else {
retval = PyObject_CallMethodOneArg(receiver, &_Py_ID(send), v);
}
if (retval == NULL) {
if (tstate->c_tracefunc != NULL
&& _PyErr_ExceptionMatches(tstate, PyExc_StopIteration))
call_exc_trace(tstate->c_tracefunc, tstate->c_traceobj, tstate, frame);
if (_PyGen_FetchStopIterationValue(&retval) == 0) {
assert(retval != NULL);
JUMPBY(oparg);
}
else {
assert(retval == NULL);
goto error;
}
}
else {
assert(gen_status == PYGEN_NEXT);
assert(retval != NULL);
}
STACK_SHRINK(1);
STACK_GROW(((!jump) ? 1 : 0));
POKE(1, retval);
JUMPBY(1);
DISPATCH();
}
TARGET(SEND_GEN) {
PyObject *v = PEEK(1);
PyObject *receiver = PEEK(2);
assert(cframe.use_tracing == 0);
PyGenObject *gen = (PyGenObject *)receiver;
DEOPT_IF(Py_TYPE(gen) != &PyGen_Type &&
Py_TYPE(gen) != &PyCoro_Type, SEND);
DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING, SEND);
STAT_INC(SEND, hit);
_PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe;
frame->yield_offset = oparg;
STACK_SHRINK(1);
_PyFrame_StackPush(gen_frame, v);
gen->gi_frame_state = FRAME_EXECUTING;
gen->gi_exc_state.previous_item = tstate->exc_info;
tstate->exc_info = &gen->gi_exc_state;
JUMPBY(INLINE_CACHE_ENTRIES_SEND + oparg);
DISPATCH_INLINED(gen_frame);
}
TARGET(YIELD_VALUE) {
PyObject *retval = PEEK(1);
// NOTE: It's important that YIELD_VALUE never raises an exception!
@ -1026,6 +1038,7 @@
PyObject *exc_value = PEEK(1);
PyObject *last_sent_val = PEEK(2);
PyObject *sub_iter = PEEK(3);
PyObject *none;
PyObject *value;
assert(throwflag);
assert(exc_value && PyExceptionInstance_Check(exc_value));
@ -1034,13 +1047,15 @@
Py_DECREF(sub_iter);
Py_DECREF(last_sent_val);
Py_DECREF(exc_value);
none = Py_NewRef(Py_None);
}
else {
_PyErr_SetRaisedException(tstate, Py_NewRef(exc_value));
goto exception_unwind;
}
STACK_SHRINK(2);
STACK_SHRINK(1);
POKE(1, value);
POKE(2, none);
DISPATCH();
}