GH-145667: Merge GET_ITER and GET_YIELD_FROM_ITER (GH-146120)

* Merge GET_ITER and GET_YIELD_FROM_ITER. Modify SEND to make it a bit more like FOR_ITER
This commit is contained in:
Mark Shannon 2026-03-21 10:48:13 +00:00 committed by GitHub
parent b5e4c46be2
commit 879c85f6e4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
30 changed files with 944 additions and 989 deletions

View file

@ -425,13 +425,15 @@ dummy_func(
PyStackRef_CLOSE(iter);
}
pure inst(END_SEND, (receiver, value -- val)) {
pure inst(END_SEND, (receiver, index_or_null, value -- val)) {
val = value;
(void)index_or_null;
DEAD(value);
DEAD(index_or_null);
PyStackRef_CLOSE(receiver);
}
tier1 inst(INSTRUMENTED_END_SEND, (receiver, value -- val)) {
tier1 inst(INSTRUMENTED_END_SEND, (receiver, index_or_null, value -- val)) {
PyObject *receiver_o = PyStackRef_AsPyObjectBorrow(receiver);
if (PyGen_Check(receiver_o) || PyCoro_CheckExact(receiver_o)) {
int err = monitor_stop_iteration(tstate, frame, this_instr, PyStackRef_AsPyObjectBorrow(value));
@ -440,6 +442,8 @@ dummy_func(
}
}
val = value;
(void)index_or_null;
DEAD(index_or_null);
DEAD(value);
PyStackRef_CLOSE(receiver);
}
@ -1410,7 +1414,7 @@ dummy_func(
SEND_GEN,
};
specializing op(_SPECIALIZE_SEND, (counter/1, receiver, unused -- receiver, unused)) {
specializing op(_SPECIALIZE_SEND, (counter/1, receiver, unused, unused -- receiver, unused, unused)) {
#if ENABLE_SPECIALIZATION
if (ADAPTIVE_COUNTER_TRIGGERS(counter)) {
next_instr = this_instr;
@ -1422,7 +1426,7 @@ dummy_func(
#endif /* ENABLE_SPECIALIZATION */
}
op(_SEND, (receiver, v -- receiver, retval)) {
op(_SEND, (receiver, null_or_index, v -- receiver, null_or_index, retval)) {
PyObject *receiver_o = PyStackRef_AsPyObjectBorrow(receiver);
PyObject *retval_o;
assert(frame->owner != FRAME_OWNED_BY_INTERPRETER);
@ -1443,36 +1447,49 @@ dummy_func(
gen_frame->previous = frame;
DISPATCH_INLINED(gen_frame);
}
if (PyStackRef_IsNone(v) && PyIter_Check(receiver_o)) {
retval_o = Py_TYPE(receiver_o)->tp_iternext(receiver_o);
if (!PyStackRef_IsNull(null_or_index)) {
_PyStackRef item = _PyForIter_VirtualIteratorNext(tstate, frame, receiver, &null_or_index);
if (!PyStackRef_IsValid(item)) {
if (PyStackRef_IsError(item)) {
ERROR_NO_POP();
}
JUMPBY(oparg);
DISPATCH();
}
retval = item;
}
else {
retval_o = PyObject_CallMethodOneArg(receiver_o,
&_Py_ID(send),
PyStackRef_AsPyObjectBorrow(v));
}
if (retval_o == NULL) {
int matches = _PyErr_ExceptionMatches(tstate, PyExc_StopIteration);
if (matches) {
_PyEval_MonitorRaise(tstate, frame, this_instr);
}
int err = _PyGen_FetchStopIterationValue(&retval_o);
if (err == 0) {
assert(retval_o != NULL);
JUMPBY(oparg);
if (PyStackRef_IsNone(v) && PyIter_Check(receiver_o)) {
retval_o = Py_TYPE(receiver_o)->tp_iternext(receiver_o);
}
else {
PyStackRef_CLOSE(v);
ERROR_IF(true);
retval_o = PyObject_CallMethodOneArg(receiver_o,
&_Py_ID(send),
PyStackRef_AsPyObjectBorrow(v));
}
if (retval_o == NULL) {
int matches = _PyErr_ExceptionMatches(tstate, PyExc_StopIteration);
if (matches) {
_PyEval_MonitorRaise(tstate, frame, this_instr);
}
int err = _PyGen_FetchStopIterationValue(&retval_o);
if (err == 0) {
assert(retval_o != NULL);
JUMPBY(oparg);
}
else {
PyStackRef_CLOSE(v);
ERROR_IF(true);
}
}
retval = PyStackRef_FromPyObjectSteal(retval_o);
}
PyStackRef_CLOSE(v);
retval = PyStackRef_FromPyObjectSteal(retval_o);
}
macro(SEND) = _SPECIALIZE_SEND + _SEND;
op(_SEND_GEN_FRAME, (receiver, v -- receiver, gen_frame)) {
op(_SEND_GEN_FRAME, (receiver, null, v -- receiver, null, gen_frame)) {
PyGenObject *gen = (PyGenObject *)PyStackRef_AsPyObjectBorrow(receiver);
EXIT_IF(Py_TYPE(gen) != &PyGen_Type && Py_TYPE(gen) != &PyCoro_Type);
EXIT_IF(!gen_try_set_executing((PyGenObject *)gen));
@ -1490,7 +1507,7 @@ dummy_func(
macro(SEND_GEN) =
unused/1 +
_RECORD_NOS_GEN_FUNC +
_RECORD_3OS_GEN_FUNC +
_CHECK_PEP_523 +
_SEND_GEN_FRAME +
_PUSH_FRAME;
@ -1602,17 +1619,17 @@ dummy_func(
macro(END_ASYNC_FOR) = _END_ASYNC_FOR;
tier1 inst(CLEANUP_THROW, (sub_iter, last_sent_val, exc_value_st -- none, value)) {
tier1 inst(CLEANUP_THROW, (sub_iter, null_in, last_sent_val, exc_value_st -- none, null_out, value)) {
PyObject *exc_value = PyStackRef_AsPyObjectBorrow(exc_value_st);
#if !_Py_TAIL_CALL_INTERP
assert(throwflag);
#endif
assert(exc_value && PyExceptionInstance_Check(exc_value));
int matches = PyErr_GivenExceptionMatches(exc_value, PyExc_StopIteration);
if (matches) {
value = PyStackRef_FromPyObjectNew(((PyStopIterationObject *)exc_value)->value);
DECREF_INPUTS();
null_out = null_in;
none = PyStackRef_None;
}
else {
@ -3335,52 +3352,10 @@ dummy_func(
#ifdef Py_STATS
_Py_GatherStats_GetIter(iterable);
#endif
PyTypeObject *tp = PyStackRef_TYPE(iterable);
if (tp == &PyTuple_Type || tp == &PyList_Type) {
/* Leave iterable on stack and pushed tagged 0 */
iter = iterable;
DEAD(iterable);
index_or_null = PyStackRef_TagInt(0);
}
else {
/* Pop iterable, and push iterator then NULL */
PyObject *iter_o = PyObject_GetIter(PyStackRef_AsPyObjectBorrow(iterable));
PyStackRef_CLOSE(iterable);
ERROR_IF(iter_o == NULL);
iter = PyStackRef_FromPyObjectSteal(iter_o);
index_or_null = PyStackRef_NULL;
}
}
inst(GET_YIELD_FROM_ITER, (iterable -- iter)) {
/* before: [obj]; after [getiter(obj)] */
PyObject *iterable_o = PyStackRef_AsPyObjectBorrow(iterable);
if (PyCoro_CheckExact(iterable_o)) {
/* `iterable` is a coroutine */
if (!(_PyFrame_GetCode(frame)->co_flags & (CO_COROUTINE | CO_ITERABLE_COROUTINE))) {
/* and it is used in a 'yield from' expression of a
regular generator. */
_PyErr_SetString(tstate, PyExc_TypeError,
"cannot 'yield from' a coroutine object "
"in a non-coroutine generator");
ERROR_NO_POP();
}
iter = iterable;
DEAD(iterable);
}
else if (PyGen_CheckExact(iterable_o)) {
iter = iterable;
DEAD(iterable);
}
else {
/* `iterable` is not a generator. */
PyObject *iter_o = PyObject_GetIter(iterable_o);
if (iter_o == NULL) {
ERROR_NO_POP();
}
iter = PyStackRef_FromPyObjectSteal(iter_o);
DECREF_INPUTS();
}
_PyStackRef result = _PyEval_GetIter(iterable, &index_or_null, oparg);
DEAD(iterable);
ERROR_IF(PyStackRef_IsError(result));
iter = result;
}
// Most members of this family are "secretly" super-instructions.
@ -5857,6 +5832,17 @@ dummy_func(
}
}
tier2 op(_RECORD_3OS_GEN_FUNC, (gen, nos, tos -- gen, nos, tos)) {
PyObject *obj = PyStackRef_AsPyObjectBorrow(gen);
if (PyGen_Check(obj)) {
PyGenObject *gen_obj = (PyGenObject *)obj;
_PyStackRef func = gen_obj->gi_iframe.f_funcobj;
if (!PyStackRef_IsNull(func)) {
RECORD_VALUE(PyStackRef_AsPyObjectBorrow(func));
}
}
}
tier2 op(_RECORD_4OS, (value, _3os, nos, tos -- value, _3os, nos, tos)) {
RECORD_VALUE(PyStackRef_AsPyObjectBorrow(value));
}

View file

@ -1165,6 +1165,42 @@ stop_tracing_and_jit(PyThreadState *tstate, _PyInterpreterFrame *frame)
#include "generated_cases.c.h"
#endif
_PyStackRef
_PyEval_GetIter(_PyStackRef iterable, _PyStackRef *index_or_null, int yield_from)
{
PyTypeObject *tp = PyStackRef_TYPE(iterable);
if (tp == &PyTuple_Type || tp == &PyList_Type) {
/* Leave iterable on stack and pushed tagged 0 */
*index_or_null = PyStackRef_TagInt(0);
return iterable;
}
*index_or_null = PyStackRef_NULL;
if (tp->tp_iter == PyObject_SelfIter) {
return iterable;
}
if (yield_from && tp == &PyCoro_Type) {
assert(yield_from != GET_ITER_YIELD_FROM);
if (yield_from == GET_ITER_YIELD_FROM_CORO_CHECK) {
/* `iterable` is a coroutine and it is used in a 'yield from'
* expression of a regular generator. */
PyErr_SetString(PyExc_TypeError,
"cannot 'yield from' a coroutine object "
"in a non-coroutine generator");
PyStackRef_CLOSE(iterable);
return PyStackRef_ERROR;
}
return iterable;
}
/* Pop iterable, and push iterator then NULL */
PyObject *iter_o = PyObject_GetIter(PyStackRef_AsPyObjectBorrow(iterable));
PyStackRef_CLOSE(iterable);
if (iter_o == NULL) {
return PyStackRef_ERROR;
}
return PyStackRef_FromPyObjectSteal(iter_o);
}
#if (defined(__GNUC__) && __GNUC__ >= 10 && !defined(__clang__)) && defined(__x86_64__)
/*
* gh-129987: The SLP autovectorizer can cause poor code generation for

View file

@ -606,6 +606,7 @@ codegen_unwind_fblock(compiler *c, location *ploc,
RETURN_IF_ERROR(codegen_call_exit_with_nones(c, *ploc));
if (info->fb_type == COMPILE_FBLOCK_ASYNC_WITH) {
ADDOP_I(c, *ploc, GET_AWAITABLE, 2);
ADDOP(c, *ploc, PUSH_NULL);
ADDOP_LOAD_CONST(c, *ploc, Py_None);
ADD_YIELD_FROM(c, *ploc, 1);
}
@ -2124,7 +2125,7 @@ codegen_for(compiler *c, stmt_ty s)
VISIT(c, expr, s->v.For.iter);
loc = LOC(s->v.For.iter);
ADDOP(c, loc, GET_ITER);
ADDOP_I(c, loc, GET_ITER, 0);
USE_LABEL(c, start);
ADDOP_JUMP(c, loc, FOR_ITER, cleanup);
@ -2175,6 +2176,7 @@ codegen_async_for(compiler *c, stmt_ty s)
/* SETUP_FINALLY to guard the __anext__ call */
ADDOP_JUMP(c, loc, SETUP_FINALLY, except);
ADDOP(c, loc, GET_ANEXT);
ADDOP(c, loc, PUSH_NULL);
ADDOP_LOAD_CONST(c, loc, Py_None);
USE_LABEL(c, send);
ADD_YIELD_FROM(c, loc, 1);
@ -4540,7 +4542,7 @@ codegen_sync_comprehension_generator(compiler *c, location loc,
if (IS_JUMP_TARGET_LABEL(start)) {
if (iter_pos != ITERATOR_ON_STACK) {
ADDOP(c, LOC(gen->iter), GET_ITER);
ADDOP_I(c, LOC(gen->iter), GET_ITER, 0);
depth += 1;
}
USE_LABEL(c, start);
@ -4574,7 +4576,7 @@ codegen_sync_comprehension_generator(compiler *c, location loc,
NEW_JUMP_TARGET_LABEL(c, unpack_start);
NEW_JUMP_TARGET_LABEL(c, unpack_end);
VISIT(c, expr, elt->v.Starred.value);
ADDOP(c, elt_loc, GET_ITER);
ADDOP_I(c, elt_loc, GET_ITER, 0);
USE_LABEL(c, unpack_start);
ADDOP_JUMP(c, elt_loc, FOR_ITER, unpack_end);
ADDOP_YIELD(c, elt_loc);
@ -4686,6 +4688,7 @@ codegen_async_comprehension_generator(compiler *c, location loc,
ADDOP_JUMP(c, loc, SETUP_FINALLY, except);
ADDOP(c, loc, GET_ANEXT);
ADDOP(c, loc, PUSH_NULL);
ADDOP_LOAD_CONST(c, loc, Py_None);
USE_LABEL(c, send);
ADD_YIELD_FROM(c, loc, 1);
@ -4716,7 +4719,7 @@ codegen_async_comprehension_generator(compiler *c, location loc,
NEW_JUMP_TARGET_LABEL(c, unpack_start);
NEW_JUMP_TARGET_LABEL(c, unpack_end);
VISIT(c, expr, elt->v.Starred.value);
ADDOP(c, elt_loc, GET_ITER);
ADDOP_I(c, elt_loc, GET_ITER, 0);
USE_LABEL(c, unpack_start);
ADDOP_JUMP(c, elt_loc, FOR_ITER, unpack_end);
ADDOP_YIELD(c, elt_loc);
@ -5039,6 +5042,7 @@ codegen_comprehension(compiler *c, expr_ty e, int type,
if (is_async_comprehension && type != COMP_GENEXP) {
ADDOP_I(c, loc, GET_AWAITABLE, 0);
ADDOP(c, loc, PUSH_NULL);
ADDOP_LOAD_CONST(c, loc, Py_None);
ADD_YIELD_FROM(c, loc, 1);
}
@ -5178,6 +5182,7 @@ codegen_async_with_inner(compiler *c, stmt_ty s, int pos)
ADDOP_I(c, loc, LOAD_SPECIAL, SPECIAL___AENTER__);
ADDOP_I(c, loc, CALL, 0);
ADDOP_I(c, loc, GET_AWAITABLE, 1);
ADDOP(c, loc, PUSH_NULL);
ADDOP_LOAD_CONST(c, loc, Py_None);
ADD_YIELD_FROM(c, loc, 1);
@ -5214,6 +5219,7 @@ codegen_async_with_inner(compiler *c, stmt_ty s, int pos)
*/
RETURN_IF_ERROR(codegen_call_exit_with_nones(c, loc));
ADDOP_I(c, loc, GET_AWAITABLE, 2);
ADDOP(c, loc, PUSH_NULL);
ADDOP_LOAD_CONST(c, loc, Py_None);
ADD_YIELD_FROM(c, loc, 1);
@ -5228,6 +5234,7 @@ codegen_async_with_inner(compiler *c, stmt_ty s, int pos)
ADDOP(c, loc, PUSH_EXC_INFO);
ADDOP(c, loc, WITH_EXCEPT_START);
ADDOP_I(c, loc, GET_AWAITABLE, 2);
ADDOP(c, loc, PUSH_NULL);
ADDOP_LOAD_CONST(c, loc, Py_None);
ADD_YIELD_FROM(c, loc, 1);
RETURN_IF_ERROR(codegen_with_except_finish(c, cleanup));
@ -5408,13 +5415,14 @@ codegen_visit_expr(compiler *c, expr_ty e)
return _PyCompile_Error(c, loc, "'yield from' inside async function");
}
VISIT(c, expr, e->v.YieldFrom.value);
ADDOP(c, loc, GET_YIELD_FROM_ITER);
ADDOP_I(c, loc, GET_ITER, GET_ITER_YIELD_FROM);
ADDOP_LOAD_CONST(c, loc, Py_None);
ADD_YIELD_FROM(c, loc, 0);
break;
case Await_kind:
VISIT(c, expr, e->v.Await.value);
ADDOP_I(c, loc, GET_AWAITABLE, 0);
ADDOP(c, loc, PUSH_NULL);
ADDOP_LOAD_CONST(c, loc, Py_None);
ADD_YIELD_FROM(c, loc, 1);
break;

View file

@ -2602,17 +2602,21 @@
break;
}
case _END_SEND_r21: {
CHECK_CURRENT_CACHED_VALUES(2);
case _END_SEND_r31: {
CHECK_CURRENT_CACHED_VALUES(3);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
_PyStackRef value;
_PyStackRef index_or_null;
_PyStackRef receiver;
_PyStackRef val;
_PyStackRef _stack_item_0 = _tos_cache0;
_PyStackRef _stack_item_1 = _tos_cache1;
value = _stack_item_1;
_PyStackRef _stack_item_2 = _tos_cache2;
value = _stack_item_2;
index_or_null = _stack_item_1;
receiver = _stack_item_0;
val = value;
(void)index_or_null;
stack_pointer[0] = val;
stack_pointer += 1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
@ -7132,30 +7136,33 @@
/* _SEND is not a viable micro-op for tier 2 because it uses the 'this_instr' variable */
case _SEND_GEN_FRAME_r22: {
CHECK_CURRENT_CACHED_VALUES(2);
case _SEND_GEN_FRAME_r33: {
CHECK_CURRENT_CACHED_VALUES(3);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
_PyStackRef v;
_PyStackRef receiver;
_PyStackRef gen_frame;
_PyStackRef _stack_item_0 = _tos_cache0;
_PyStackRef _stack_item_1 = _tos_cache1;
_PyStackRef _stack_item_2 = _tos_cache2;
oparg = CURRENT_OPARG();
v = _stack_item_1;
v = _stack_item_2;
receiver = _stack_item_0;
PyGenObject *gen = (PyGenObject *)PyStackRef_AsPyObjectBorrow(receiver);
if (Py_TYPE(gen) != &PyGen_Type && Py_TYPE(gen) != &PyCoro_Type) {
UOP_STAT_INC(uopcode, miss);
_tos_cache1 = v;
_tos_cache2 = v;
_tos_cache1 = _stack_item_1;
_tos_cache0 = receiver;
SET_CURRENT_CACHED_VALUES(2);
SET_CURRENT_CACHED_VALUES(3);
JUMP_TO_JUMP_TARGET();
}
if (!gen_try_set_executing((PyGenObject *)gen)) {
UOP_STAT_INC(uopcode, miss);
_tos_cache1 = v;
_tos_cache2 = v;
_tos_cache1 = _stack_item_1;
_tos_cache0 = receiver;
SET_CURRENT_CACHED_VALUES(2);
SET_CURRENT_CACHED_VALUES(3);
JUMP_TO_JUMP_TARGET();
}
STAT_INC(SEND, hit);
@ -7167,10 +7174,10 @@
frame->return_offset = (uint16_t)( 2u + oparg);
pushed_frame->previous = frame;
gen_frame = PyStackRef_Wrap(pushed_frame);
_tos_cache1 = gen_frame;
_tos_cache2 = gen_frame;
_tos_cache1 = _stack_item_1;
_tos_cache0 = receiver;
_tos_cache2 = PyStackRef_ZERO_BITS;
SET_CURRENT_CACHED_VALUES(2);
SET_CURRENT_CACHED_VALUES(3);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
break;
}
@ -11493,98 +11500,30 @@
_PyStackRef iter;
_PyStackRef index_or_null;
_PyStackRef _stack_item_0 = _tos_cache0;
oparg = CURRENT_OPARG();
iterable = _stack_item_0;
#ifdef Py_STATS
_Py_GatherStats_GetIter(iterable);
#endif
stack_pointer[0] = iterable;
stack_pointer += 1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
_PyFrame_SetStackPointer(frame, stack_pointer);
_Py_GatherStats_GetIter(iterable);
_PyStackRef result = _PyEval_GetIter(iterable, &index_or_null, oparg);
stack_pointer = _PyFrame_GetStackPointer(frame);
stack_pointer += -1;
#endif
PyTypeObject *tp = PyStackRef_TYPE(iterable);
if (tp == &PyTuple_Type || tp == &PyList_Type) {
iter = iterable;
index_or_null = PyStackRef_TagInt(0);
}
else {
stack_pointer[0] = iterable;
stack_pointer += 1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
_PyFrame_SetStackPointer(frame, stack_pointer);
PyObject *iter_o = PyObject_GetIter(PyStackRef_AsPyObjectBorrow(iterable));
stack_pointer = _PyFrame_GetStackPointer(frame);
if (PyStackRef_IsError(result)) {
stack_pointer += -1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
_PyFrame_SetStackPointer(frame, stack_pointer);
PyStackRef_CLOSE(iterable);
stack_pointer = _PyFrame_GetStackPointer(frame);
if (iter_o == NULL) {
SET_CURRENT_CACHED_VALUES(0);
JUMP_TO_ERROR();
}
iter = PyStackRef_FromPyObjectSteal(iter_o);
index_or_null = PyStackRef_NULL;
SET_CURRENT_CACHED_VALUES(0);
JUMP_TO_ERROR();
}
iter = result;
_tos_cache1 = index_or_null;
_tos_cache0 = iter;
_tos_cache2 = PyStackRef_ZERO_BITS;
SET_CURRENT_CACHED_VALUES(2);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
break;
}
case _GET_YIELD_FROM_ITER_r11: {
CHECK_CURRENT_CACHED_VALUES(1);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
_PyStackRef iterable;
_PyStackRef iter;
_PyStackRef _stack_item_0 = _tos_cache0;
iterable = _stack_item_0;
PyObject *iterable_o = PyStackRef_AsPyObjectBorrow(iterable);
if (PyCoro_CheckExact(iterable_o)) {
if (!(_PyFrame_GetCode(frame)->co_flags & (CO_COROUTINE | CO_ITERABLE_COROUTINE))) {
stack_pointer[0] = iterable;
stack_pointer += 1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
_PyFrame_SetStackPointer(frame, stack_pointer);
_PyErr_SetString(tstate, PyExc_TypeError,
"cannot 'yield from' a coroutine object "
"in a non-coroutine generator");
stack_pointer = _PyFrame_GetStackPointer(frame);
SET_CURRENT_CACHED_VALUES(0);
JUMP_TO_ERROR();
}
iter = iterable;
}
else if (PyGen_CheckExact(iterable_o)) {
iter = iterable;
}
else {
stack_pointer[0] = iterable;
stack_pointer += 1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
_PyFrame_SetStackPointer(frame, stack_pointer);
PyObject *iter_o = PyObject_GetIter(iterable_o);
stack_pointer = _PyFrame_GetStackPointer(frame);
if (iter_o == NULL) {
SET_CURRENT_CACHED_VALUES(0);
JUMP_TO_ERROR();
}
iter = PyStackRef_FromPyObjectSteal(iter_o);
_PyFrame_SetStackPointer(frame, stack_pointer);
_PyStackRef tmp = iterable;
iterable = iter;
stack_pointer[-1] = iterable;
PyStackRef_CLOSE(tmp);
stack_pointer = _PyFrame_GetStackPointer(frame);
stack_pointer += -1;
}
_tos_cache0 = iter;
_tos_cache1 = PyStackRef_ZERO_BITS;
_tos_cache2 = PyStackRef_ZERO_BITS;
SET_CURRENT_CACHED_VALUES(1);
stack_pointer += -1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
break;
}

View file

@ -2884,7 +2884,6 @@ optimize_load_fast(cfg_builder *g)
case GET_ANEXT:
case GET_ITER:
case GET_LEN:
case GET_YIELD_FROM_ITER:
case IMPORT_FROM:
case MATCH_KEYS:
case MATCH_MAPPING:
@ -2919,7 +2918,16 @@ optimize_load_fast(cfg_builder *g)
break;
}
case END_SEND:
case END_SEND: {
assert(_PyOpcode_num_popped(opcode, oparg) == 3);
assert(_PyOpcode_num_pushed(opcode, oparg) == 1);
ref tos = ref_stack_pop(&refs);
ref_stack_pop(&refs);
ref_stack_pop(&refs);
PUSH_REF(tos.instr, tos.local);
break;
}
case SET_FUNCTION_ATTRIBUTE: {
assert(_PyOpcode_num_popped(opcode, oparg) == 2);
assert(_PyOpcode_num_pushed(opcode, oparg) == 1);

View file

@ -4740,13 +4740,16 @@
next_instr += 1;
INSTRUCTION_STATS(CLEANUP_THROW);
_PyStackRef sub_iter;
_PyStackRef null_in;
_PyStackRef last_sent_val;
_PyStackRef exc_value_st;
_PyStackRef none;
_PyStackRef null_out;
_PyStackRef value;
exc_value_st = stack_pointer[-1];
last_sent_val = stack_pointer[-2];
sub_iter = stack_pointer[-3];
null_in = stack_pointer[-3];
sub_iter = stack_pointer[-4];
PyObject *exc_value = PyStackRef_AsPyObjectBorrow(exc_value_st);
#if !_Py_TAIL_CALL_INTERP
assert(throwflag);
@ -4760,7 +4763,7 @@
_PyFrame_SetStackPointer(frame, stack_pointer);
_PyStackRef tmp = sub_iter;
sub_iter = value;
stack_pointer[-3] = sub_iter;
stack_pointer[-4] = sub_iter;
PyStackRef_CLOSE(tmp);
tmp = exc_value_st;
exc_value_st = PyStackRef_NULL;
@ -4770,9 +4773,14 @@
last_sent_val = PyStackRef_NULL;
stack_pointer[-2] = last_sent_val;
PyStackRef_CLOSE(tmp);
tmp = null_in;
null_in = PyStackRef_NULL;
stack_pointer[-3] = null_in;
PyStackRef_XCLOSE(tmp);
stack_pointer = _PyFrame_GetStackPointer(frame);
stack_pointer += -3;
stack_pointer += -4;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
null_out = null_in;
none = PyStackRef_None;
}
else {
@ -4782,8 +4790,9 @@
JUMP_TO_LABEL(exception_unwind);
}
stack_pointer[0] = none;
stack_pointer[1] = value;
stack_pointer += 2;
stack_pointer[1] = null_out;
stack_pointer[2] = value;
stack_pointer += 3;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
DISPATCH();
}
@ -5668,13 +5677,16 @@
next_instr += 1;
INSTRUCTION_STATS(END_SEND);
_PyStackRef receiver;
_PyStackRef index_or_null;
_PyStackRef value;
_PyStackRef val;
value = stack_pointer[-1];
receiver = stack_pointer[-2];
index_or_null = stack_pointer[-2];
receiver = stack_pointer[-3];
val = value;
stack_pointer[-2] = val;
stack_pointer += -1;
(void)index_or_null;
stack_pointer[-3] = val;
stack_pointer += -2;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
_PyFrame_SetStackPointer(frame, stack_pointer);
PyStackRef_CLOSE(receiver);
@ -6294,31 +6306,15 @@
_PyStackRef index_or_null;
iterable = stack_pointer[-1];
#ifdef Py_STATS
_PyFrame_SetStackPointer(frame, stack_pointer);
_Py_GatherStats_GetIter(iterable);
stack_pointer = _PyFrame_GetStackPointer(frame);
#endif
PyTypeObject *tp = PyStackRef_TYPE(iterable);
if (tp == &PyTuple_Type || tp == &PyList_Type) {
iter = iterable;
index_or_null = PyStackRef_TagInt(0);
}
else {
_PyFrame_SetStackPointer(frame, stack_pointer);
PyObject *iter_o = PyObject_GetIter(PyStackRef_AsPyObjectBorrow(iterable));
stack_pointer = _PyFrame_GetStackPointer(frame);
stack_pointer += -1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
_PyFrame_SetStackPointer(frame, stack_pointer);
PyStackRef_CLOSE(iterable);
stack_pointer = _PyFrame_GetStackPointer(frame);
if (iter_o == NULL) {
JUMP_TO_LABEL(error);
}
iter = PyStackRef_FromPyObjectSteal(iter_o);
index_or_null = PyStackRef_NULL;
stack_pointer += 1;
_PyFrame_SetStackPointer(frame, stack_pointer);
_PyStackRef result = _PyEval_GetIter(iterable, &index_or_null, oparg);
stack_pointer = _PyFrame_GetStackPointer(frame);
if (PyStackRef_IsError(result)) {
JUMP_TO_LABEL(pop_1_error);
}
iter = result;
stack_pointer[-1] = iter;
stack_pointer[0] = index_or_null;
stack_pointer += 1;
@ -6354,51 +6350,6 @@
DISPATCH();
}
TARGET(GET_YIELD_FROM_ITER) {
#if _Py_TAIL_CALL_INTERP
int opcode = GET_YIELD_FROM_ITER;
(void)(opcode);
#endif
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(GET_YIELD_FROM_ITER);
_PyStackRef iterable;
_PyStackRef iter;
iterable = stack_pointer[-1];
PyObject *iterable_o = PyStackRef_AsPyObjectBorrow(iterable);
if (PyCoro_CheckExact(iterable_o)) {
if (!(_PyFrame_GetCode(frame)->co_flags & (CO_COROUTINE | CO_ITERABLE_COROUTINE))) {
_PyFrame_SetStackPointer(frame, stack_pointer);
_PyErr_SetString(tstate, PyExc_TypeError,
"cannot 'yield from' a coroutine object "
"in a non-coroutine generator");
stack_pointer = _PyFrame_GetStackPointer(frame);
JUMP_TO_LABEL(error);
}
iter = iterable;
}
else if (PyGen_CheckExact(iterable_o)) {
iter = iterable;
}
else {
_PyFrame_SetStackPointer(frame, stack_pointer);
PyObject *iter_o = PyObject_GetIter(iterable_o);
stack_pointer = _PyFrame_GetStackPointer(frame);
if (iter_o == NULL) {
JUMP_TO_LABEL(error);
}
iter = PyStackRef_FromPyObjectSteal(iter_o);
_PyFrame_SetStackPointer(frame, stack_pointer);
_PyStackRef tmp = iterable;
iterable = iter;
stack_pointer[-1] = iterable;
PyStackRef_CLOSE(tmp);
stack_pointer = _PyFrame_GetStackPointer(frame);
}
stack_pointer[-1] = iter;
DISPATCH();
}
TARGET(IMPORT_FROM) {
#if _Py_TAIL_CALL_INTERP
int opcode = IMPORT_FROM;
@ -7002,10 +6953,12 @@
next_instr += 1;
INSTRUCTION_STATS(INSTRUMENTED_END_SEND);
_PyStackRef receiver;
_PyStackRef index_or_null;
_PyStackRef value;
_PyStackRef val;
value = stack_pointer[-1];
receiver = stack_pointer[-2];
index_or_null = stack_pointer[-2];
receiver = stack_pointer[-3];
PyObject *receiver_o = PyStackRef_AsPyObjectBorrow(receiver);
if (PyGen_Check(receiver_o) || PyCoro_CheckExact(receiver_o)) {
_PyFrame_SetStackPointer(frame, stack_pointer);
@ -7016,8 +6969,9 @@
}
}
val = value;
stack_pointer[-2] = val;
stack_pointer += -1;
(void)index_or_null;
stack_pointer[-3] = val;
stack_pointer += -2;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
_PyFrame_SetStackPointer(frame, stack_pointer);
PyStackRef_CLOSE(receiver);
@ -10733,11 +10687,12 @@
_Py_CODEUNIT* const this_instr = next_instr - 2;
(void)this_instr;
_PyStackRef receiver;
_PyStackRef null_or_index;
_PyStackRef v;
_PyStackRef retval;
// _SPECIALIZE_SEND
{
receiver = stack_pointer[-2];
receiver = stack_pointer[-3];
uint16_t counter = read_u16(&this_instr[1].cache);
(void)counter;
#if ENABLE_SPECIALIZATION
@ -10755,6 +10710,7 @@
// _SEND
{
v = stack_pointer[-1];
null_or_index = stack_pointer[-2];
PyObject *receiver_o = PyStackRef_AsPyObjectBorrow(receiver);
PyObject *retval_o;
assert(frame->owner != FRAME_OWNED_BY_INTERPRETER);
@ -10775,53 +10731,66 @@
gen_frame->previous = frame;
DISPATCH_INLINED(gen_frame);
}
if (PyStackRef_IsNone(v) && PyIter_Check(receiver_o)) {
if (!PyStackRef_IsNull(null_or_index)) {
_PyFrame_SetStackPointer(frame, stack_pointer);
retval_o = Py_TYPE(receiver_o)->tp_iternext(receiver_o);
_PyStackRef item = _PyForIter_VirtualIteratorNext(tstate, frame, receiver, &null_or_index);
stack_pointer = _PyFrame_GetStackPointer(frame);
if (!PyStackRef_IsValid(item)) {
if (PyStackRef_IsError(item)) {
JUMP_TO_LABEL(error);
}
JUMPBY(oparg);
stack_pointer[-2] = null_or_index;
DISPATCH();
}
retval = item;
}
else {
_PyFrame_SetStackPointer(frame, stack_pointer);
retval_o = PyObject_CallMethodOneArg(receiver_o,
&_Py_ID(send),
PyStackRef_AsPyObjectBorrow(v));
stack_pointer = _PyFrame_GetStackPointer(frame);
}
if (retval_o == NULL) {
_PyFrame_SetStackPointer(frame, stack_pointer);
int matches = _PyErr_ExceptionMatches(tstate, PyExc_StopIteration);
stack_pointer = _PyFrame_GetStackPointer(frame);
if (matches) {
if (PyStackRef_IsNone(v) && PyIter_Check(receiver_o)) {
_PyFrame_SetStackPointer(frame, stack_pointer);
_PyEval_MonitorRaise(tstate, frame, this_instr);
retval_o = Py_TYPE(receiver_o)->tp_iternext(receiver_o);
stack_pointer = _PyFrame_GetStackPointer(frame);
}
_PyFrame_SetStackPointer(frame, stack_pointer);
int err = _PyGen_FetchStopIterationValue(&retval_o);
stack_pointer = _PyFrame_GetStackPointer(frame);
if (err == 0) {
assert(retval_o != NULL);
JUMPBY(oparg);
}
else {
stack_pointer += -1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
_PyFrame_SetStackPointer(frame, stack_pointer);
PyStackRef_CLOSE(v);
retval_o = PyObject_CallMethodOneArg(receiver_o,
&_Py_ID(send),
PyStackRef_AsPyObjectBorrow(v));
stack_pointer = _PyFrame_GetStackPointer(frame);
JUMP_TO_LABEL(error);
}
if (retval_o == NULL) {
_PyFrame_SetStackPointer(frame, stack_pointer);
int matches = _PyErr_ExceptionMatches(tstate, PyExc_StopIteration);
stack_pointer = _PyFrame_GetStackPointer(frame);
if (matches) {
_PyFrame_SetStackPointer(frame, stack_pointer);
_PyEval_MonitorRaise(tstate, frame, this_instr);
stack_pointer = _PyFrame_GetStackPointer(frame);
}
_PyFrame_SetStackPointer(frame, stack_pointer);
int err = _PyGen_FetchStopIterationValue(&retval_o);
stack_pointer = _PyFrame_GetStackPointer(frame);
if (err == 0) {
assert(retval_o != NULL);
JUMPBY(oparg);
}
else {
stack_pointer += -1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
_PyFrame_SetStackPointer(frame, stack_pointer);
PyStackRef_CLOSE(v);
stack_pointer = _PyFrame_GetStackPointer(frame);
JUMP_TO_LABEL(error);
}
}
retval = PyStackRef_FromPyObjectSteal(retval_o);
}
stack_pointer += -1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
stack_pointer[-2] = null_or_index;
stack_pointer[-1] = retval;
_PyFrame_SetStackPointer(frame, stack_pointer);
PyStackRef_CLOSE(v);
stack_pointer = _PyFrame_GetStackPointer(frame);
retval = PyStackRef_FromPyObjectSteal(retval_o);
}
stack_pointer[0] = retval;
stack_pointer += 1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
DISPATCH();
}
@ -10852,7 +10821,7 @@
// _SEND_GEN_FRAME
{
v = stack_pointer[-1];
receiver = stack_pointer[-2];
receiver = stack_pointer[-3];
PyGenObject *gen = (PyGenObject *)PyStackRef_AsPyObjectBorrow(receiver);
if (Py_TYPE(gen) != &PyGen_Type && Py_TYPE(gen) != &PyCoro_Type) {
UPDATE_MISS_STATS(SEND);

View file

@ -16,10 +16,8 @@ static void *opcode_targets_table[256] = {
&&TARGET_FORMAT_WITH_SPEC,
&&TARGET_GET_AITER,
&&TARGET_GET_ANEXT,
&&TARGET_GET_ITER,
&&TARGET_RESERVED,
&&TARGET_GET_LEN,
&&TARGET_GET_YIELD_FROM_ITER,
&&TARGET_RESERVED,
&&TARGET_INTERPRETER_EXIT,
&&TARGET_LOAD_BUILD_CLASS,
&&TARGET_LOAD_LOCALS,
@ -72,6 +70,7 @@ static void *opcode_targets_table[256] = {
&&TARGET_EXTENDED_ARG,
&&TARGET_FOR_ITER,
&&TARGET_GET_AWAITABLE,
&&TARGET_GET_ITER,
&&TARGET_IMPORT_FROM,
&&TARGET_IMPORT_NAME,
&&TARGET_IS_OP,
@ -128,6 +127,7 @@ static void *opcode_targets_table[256] = {
&&_unknown_opcode,
&&_unknown_opcode,
&&_unknown_opcode,
&&_unknown_opcode,
&&TARGET_RESUME,
&&TARGET_BINARY_OP_ADD_FLOAT,
&&TARGET_BINARY_OP_ADD_INT,
@ -379,7 +379,7 @@ static void *opcode_tracing_targets_table[256] = {
&&TARGET_TRACE_RECORD,
&&TARGET_TRACE_RECORD,
&&TARGET_TRACE_RECORD,
&&TARGET_TRACE_RECORD,
&&_unknown_opcode,
&&_unknown_opcode,
&&_unknown_opcode,
&&_unknown_opcode,
@ -626,7 +626,6 @@ static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_GET_ANEXT(TAIL_CALL_PARAMS);
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_GET_AWAITABLE(TAIL_CALL_PARAMS);
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_GET_ITER(TAIL_CALL_PARAMS);
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_GET_LEN(TAIL_CALL_PARAMS);
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_GET_YIELD_FROM_ITER(TAIL_CALL_PARAMS);
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_IMPORT_FROM(TAIL_CALL_PARAMS);
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_IMPORT_NAME(TAIL_CALL_PARAMS);
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_INSTRUMENTED_CALL(TAIL_CALL_PARAMS);
@ -868,7 +867,6 @@ static py_tail_call_funcptr instruction_funcptr_handler_table[256] = {
[GET_AWAITABLE] = _TAIL_CALL_GET_AWAITABLE,
[GET_ITER] = _TAIL_CALL_GET_ITER,
[GET_LEN] = _TAIL_CALL_GET_LEN,
[GET_YIELD_FROM_ITER] = _TAIL_CALL_GET_YIELD_FROM_ITER,
[IMPORT_FROM] = _TAIL_CALL_IMPORT_FROM,
[IMPORT_NAME] = _TAIL_CALL_IMPORT_NAME,
[INSTRUMENTED_CALL] = _TAIL_CALL_INSTRUMENTED_CALL,
@ -1002,6 +1000,7 @@ static py_tail_call_funcptr instruction_funcptr_handler_table[256] = {
[UNPACK_SEQUENCE_TWO_TUPLE] = _TAIL_CALL_UNPACK_SEQUENCE_TWO_TUPLE,
[WITH_EXCEPT_START] = _TAIL_CALL_WITH_EXCEPT_START,
[YIELD_VALUE] = _TAIL_CALL_YIELD_VALUE,
[120] = _TAIL_CALL_UNKNOWN_OPCODE,
[121] = _TAIL_CALL_UNKNOWN_OPCODE,
[122] = _TAIL_CALL_UNKNOWN_OPCODE,
[123] = _TAIL_CALL_UNKNOWN_OPCODE,
@ -1126,7 +1125,6 @@ static py_tail_call_funcptr instruction_funcptr_tracing_table[256] = {
[GET_AWAITABLE] = _TAIL_CALL_TRACE_RECORD,
[GET_ITER] = _TAIL_CALL_TRACE_RECORD,
[GET_LEN] = _TAIL_CALL_TRACE_RECORD,
[GET_YIELD_FROM_ITER] = _TAIL_CALL_TRACE_RECORD,
[IMPORT_FROM] = _TAIL_CALL_TRACE_RECORD,
[IMPORT_NAME] = _TAIL_CALL_TRACE_RECORD,
[INSTRUMENTED_CALL] = _TAIL_CALL_TRACE_RECORD,
@ -1260,6 +1258,7 @@ static py_tail_call_funcptr instruction_funcptr_tracing_table[256] = {
[UNPACK_SEQUENCE_TWO_TUPLE] = _TAIL_CALL_TRACE_RECORD,
[WITH_EXCEPT_START] = _TAIL_CALL_TRACE_RECORD,
[YIELD_VALUE] = _TAIL_CALL_TRACE_RECORD,
[120] = _TAIL_CALL_UNKNOWN_OPCODE,
[121] = _TAIL_CALL_UNKNOWN_OPCODE,
[122] = _TAIL_CALL_UNKNOWN_OPCODE,
[123] = _TAIL_CALL_UNKNOWN_OPCODE,

View file

@ -1038,7 +1038,7 @@ dummy_func(void) {
gen_frame = PyJitRef_WrapInvalid(new_frame);
}
op(_SEND_GEN_FRAME, (receiver, v -- receiver, gen_frame)) {
op(_SEND_GEN_FRAME, (receiver, null, v -- receiver, null, gen_frame)) {
_Py_UOpsAbstractFrame *new_frame = frame_new_from_symbol(ctx, receiver, NULL, 0);
if (new_frame == NULL) {
ctx->done = true;
@ -1779,6 +1779,12 @@ dummy_func(void) {
sym_set_recorded_gen_func(nos, func);
}
op(_RECORD_3OS_GEN_FUNC, (gen, nos, tos -- gen, nos, tos)) {
PyFunctionObject *func = (PyFunctionObject *)this_instr->operand0;
assert(func == NULL || PyFunction_Check(func));
sym_set_recorded_gen_func(gen, func);
}
op(_GUARD_CODE_VERSION__PUSH_FRAME, (version/2 -- )) {
PyCodeObject *co = get_current_code_object(ctx);
if (co->co_version == version) {

View file

@ -209,9 +209,9 @@
case _END_SEND: {
JitOptRef val;
val = sym_new_not_null(ctx);
CHECK_STACK_BOUNDS(-1);
stack_pointer[-2] = val;
stack_pointer += -1;
CHECK_STACK_BOUNDS(-2);
stack_pointer[-3] = val;
stack_pointer += -2;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
break;
}
@ -1385,7 +1385,7 @@
JitOptRef receiver;
JitOptRef gen_frame;
v = stack_pointer[-1];
receiver = stack_pointer[-2];
receiver = stack_pointer[-3];
_Py_UOpsAbstractFrame *new_frame = frame_new_from_symbol(ctx, receiver, NULL, 0);
if (new_frame == NULL) {
ctx->done = true;
@ -2738,13 +2738,6 @@
break;
}
case _GET_YIELD_FROM_ITER: {
JitOptRef iter;
iter = sym_new_not_null(ctx);
stack_pointer[-1] = iter;
break;
}
/* _FOR_ITER is not a viable micro-op for tier 2 */
case _FOR_ITER_TIER_TWO: {
@ -4420,6 +4413,15 @@
break;
}
case _RECORD_3OS_GEN_FUNC: {
JitOptRef gen;
gen = stack_pointer[-3];
PyFunctionObject *func = (PyFunctionObject *)this_instr->operand0;
assert(func == NULL || PyFunction_Check(func));
sym_set_recorded_gen_func(gen, func);
break;
}
case _RECORD_4OS: {
JitOptRef value;
value = stack_pointer[-4];

View file

@ -41,6 +41,20 @@ void _PyOpcode_RecordFunction_NOS_GEN_FUNC(_PyInterpreterFrame *frame, _PyStackR
}
}
void _PyOpcode_RecordFunction_3OS_GEN_FUNC(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, int oparg, PyObject **recorded_value) {
_PyStackRef gen;
gen = stack_pointer[-3];
PyObject *obj = PyStackRef_AsPyObjectBorrow(gen);
if (PyGen_Check(obj)) {
PyGenObject *gen_obj = (PyGenObject *)obj;
_PyStackRef func = gen_obj->gi_iframe.f_funcobj;
if (!PyStackRef_IsNull(func)) {
*recorded_value = (PyObject *)PyStackRef_AsPyObjectBorrow(func);
Py_INCREF(*recorded_value);
}
}
}
void _PyOpcode_RecordFunction_4OS(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, int oparg, PyObject **recorded_value) {
_PyStackRef value;
value = stack_pointer[-4];
@ -73,14 +87,15 @@ void _PyOpcode_RecordFunction_CODE(_PyInterpreterFrame *frame, _PyStackRef *stac
#define _RECORD_TOS_TYPE_INDEX 1
#define _RECORD_NOS_INDEX 2
#define _RECORD_NOS_GEN_FUNC_INDEX 3
#define _RECORD_CALLABLE_INDEX 4
#define _RECORD_BOUND_METHOD_INDEX 5
#define _RECORD_4OS_INDEX 6
#define _RECORD_3OS_GEN_FUNC_INDEX 3
#define _RECORD_NOS_GEN_FUNC_INDEX 4
#define _RECORD_CALLABLE_INDEX 5
#define _RECORD_BOUND_METHOD_INDEX 6
#define _RECORD_4OS_INDEX 7
const uint8_t _PyOpcode_RecordFunctionIndices[256] = {
[TO_BOOL_ALWAYS_TRUE] = _RECORD_TOS_TYPE_INDEX,
[BINARY_OP_SUBSCR_GETITEM] = _RECORD_NOS_INDEX,
[SEND_GEN] = _RECORD_NOS_GEN_FUNC_INDEX,
[SEND_GEN] = _RECORD_3OS_GEN_FUNC_INDEX,
[LOAD_ATTR_INSTANCE_VALUE] = _RECORD_TOS_TYPE_INDEX,
[LOAD_ATTR_WITH_HINT] = _RECORD_TOS_TYPE_INDEX,
[LOAD_ATTR_SLOT] = _RECORD_TOS_TYPE_INDEX,
@ -110,10 +125,11 @@ const uint8_t _PyOpcode_RecordFunctionIndices[256] = {
[CALL_EX_PY] = _RECORD_4OS_INDEX,
};
const _Py_RecordFuncPtr _PyOpcode_RecordFunctions[7] = {
const _Py_RecordFuncPtr _PyOpcode_RecordFunctions[8] = {
[0] = NULL,
[_RECORD_TOS_TYPE_INDEX] = _PyOpcode_RecordFunction_TOS_TYPE,
[_RECORD_NOS_INDEX] = _PyOpcode_RecordFunction_NOS,
[_RECORD_3OS_GEN_FUNC_INDEX] = _PyOpcode_RecordFunction_3OS_GEN_FUNC,
[_RECORD_NOS_GEN_FUNC_INDEX] = _PyOpcode_RecordFunction_NOS_GEN_FUNC,
[_RECORD_CALLABLE_INDEX] = _PyOpcode_RecordFunction_CALLABLE,
[_RECORD_BOUND_METHOD_INDEX] = _PyOpcode_RecordFunction_BOUND_METHOD,

View file

@ -41,9 +41,24 @@ do { \
# define SPECIALIZATION_FAIL(opcode, kind) ((void)0)
#endif // Py_STATS
static void
fixup_getiter(_Py_CODEUNIT *instruction, int flags)
{
// Compiler can't know if types.coroutine() will be called,
// so fix up here
if (instruction->op.arg) {
if (flags & (CO_COROUTINE | CO_ITERABLE_COROUTINE)) {
instruction->op.arg = GET_ITER_YIELD_FROM_NO_CHECK;
}
else {
instruction->op.arg = GET_ITER_YIELD_FROM_CORO_CHECK;
}
}
}
// Initialize warmup counters and optimize instructions. This cannot fail.
void
_PyCode_Quicken(_Py_CODEUNIT *instructions, Py_ssize_t size, int enable_counters)
_PyCode_Quicken(_Py_CODEUNIT *instructions, Py_ssize_t size, int enable_counters, int flags)
{
#if ENABLE_SPECIALIZATION
_Py_BackoffCounter jump_counter, adaptive_counter, resume_counter;
@ -66,6 +81,9 @@ _PyCode_Quicken(_Py_CODEUNIT *instructions, Py_ssize_t size, int enable_counters
opcode = instructions[i].op.code;
int caches = _PyOpcode_Caches[opcode];
oparg = (oparg << 8) | instructions[i].op.arg;
if (opcode == GET_ITER) {
fixup_getiter(&instructions[i], flags);
}
if (caches) {
// The initial value depends on the opcode
switch (opcode) {
@ -91,6 +109,13 @@ _PyCode_Quicken(_Py_CODEUNIT *instructions, Py_ssize_t size, int enable_counters
oparg = 0;
}
}
#else
for (Py_ssize_t i = 0; i < size-1; i++) {
if (instructions[i].op.code == GET_ITER) {
fixup_getiter(&instructions[i], flags);
}
i += _PyOpcode_Caches[opcode];
}
#endif /* ENABLE_SPECIALIZATION */
}