mirror of https://github.com/python/cpython
bpo-43683: Streamline YIELD_VALUE and SEND (GH-30723)
* Split YIELD_VALUE into ASYNC_GEN_WRAP; YIELD_VALUE for async generators. * Split SEND into SEND; YIELD_VALUE. * Document new opcodes.
This commit is contained in:
parent
d75a51bea3
commit
0367a36fdc
|
@ -1233,6 +1233,22 @@ All of the following opcodes use their arguments.
|
|||
.. versionadded:: 3.11
|
||||
|
||||
|
||||
.. opcode:: SEND
|
||||
|
||||
Sends ``None`` to the sub-generator of this generator.
|
||||
Used in ``yield from`` and ``await`` statements.
|
||||
|
||||
.. versionadded:: 3.11
|
||||
|
||||
|
||||
.. opcode:: ASYNC_GEN_WRAP
|
||||
|
||||
Wraps the value on top of the stack in an ``async_generator_wrapped_value``.
|
||||
Used to yield in async generators.
|
||||
|
||||
.. versionadded:: 3.11
|
||||
|
||||
|
||||
.. opcode:: HAVE_ARGUMENT
|
||||
|
||||
This is not really an opcode. It identifies the dividing line between
|
||||
|
|
|
@ -44,6 +44,7 @@ extern "C" {
|
|||
#define IMPORT_STAR 84
|
||||
#define SETUP_ANNOTATIONS 85
|
||||
#define YIELD_VALUE 86
|
||||
#define ASYNC_GEN_WRAP 87
|
||||
#define PREP_RERAISE_STAR 88
|
||||
#define POP_EXCEPT 89
|
||||
#define HAVE_ARGUMENT 90
|
||||
|
@ -165,12 +166,12 @@ extern "C" {
|
|||
#define STORE_ATTR_ADAPTIVE 79
|
||||
#define STORE_ATTR_INSTANCE_VALUE 80
|
||||
#define STORE_ATTR_SLOT 81
|
||||
#define STORE_ATTR_WITH_HINT 87
|
||||
#define LOAD_FAST__LOAD_FAST 131
|
||||
#define STORE_FAST__LOAD_FAST 140
|
||||
#define LOAD_FAST__LOAD_CONST 141
|
||||
#define LOAD_CONST__LOAD_FAST 143
|
||||
#define STORE_FAST__STORE_FAST 150
|
||||
#define STORE_ATTR_WITH_HINT 131
|
||||
#define LOAD_FAST__LOAD_FAST 140
|
||||
#define STORE_FAST__LOAD_FAST 141
|
||||
#define LOAD_FAST__LOAD_CONST 143
|
||||
#define LOAD_CONST__LOAD_FAST 150
|
||||
#define STORE_FAST__STORE_FAST 153
|
||||
#define DO_TRACING 255
|
||||
#ifdef NEED_OPCODE_JUMP_TABLES
|
||||
static uint32_t _PyOpcode_RelativeJump[8] = {
|
||||
|
|
|
@ -381,6 +381,7 @@ _code_type = type(_write_atomic.__code__)
|
|||
# Python 3.11a4 3473 (Add POP_JUMP_IF_NOT_NONE/POP_JUMP_IF_NONE opcodes)
|
||||
# Python 3.11a4 3474 (Add RESUME opcode)
|
||||
# Python 3.11a5 3475 (Add RETURN_GENERATOR opcode)
|
||||
# Python 3.11a5 3476 (Add ASYNC_GEN_WRAP opcode)
|
||||
|
||||
# Python 3.12 will start with magic number 3500
|
||||
|
||||
|
@ -394,7 +395,7 @@ _code_type = type(_write_atomic.__code__)
|
|||
# Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
|
||||
# in PC/launcher.c must also be updated.
|
||||
|
||||
MAGIC_NUMBER = (3475).to_bytes(2, 'little') + b'\r\n'
|
||||
MAGIC_NUMBER = (3476).to_bytes(2, 'little') + b'\r\n'
|
||||
_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c
|
||||
|
||||
_PYCACHE = '__pycache__'
|
||||
|
|
|
@ -101,7 +101,7 @@ def_op('RETURN_VALUE', 83)
|
|||
def_op('IMPORT_STAR', 84)
|
||||
def_op('SETUP_ANNOTATIONS', 85)
|
||||
def_op('YIELD_VALUE', 86)
|
||||
|
||||
def_op('ASYNC_GEN_WRAP', 87)
|
||||
def_op('PREP_RERAISE_STAR', 88)
|
||||
def_op('POP_EXCEPT', 89)
|
||||
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
Add ASYNC_GEN_WRAP opcode to wrap the value to be yielded in async
|
||||
generators. Removes the need to special case async generators in the
|
||||
``YIELD_VALUE`` instruction.
|
|
@ -353,7 +353,7 @@ _PyGen_yf(PyGenObject *gen)
|
|||
PyObject *bytecode = gen->gi_code->co_code;
|
||||
unsigned char *code = (unsigned char *)PyBytes_AS_STRING(bytecode);
|
||||
|
||||
if (frame->f_lasti < 0) {
|
||||
if (frame->f_lasti < 1) {
|
||||
/* Return immediately if the frame didn't start yet. SEND
|
||||
always come after LOAD_CONST: a code object should not start
|
||||
with SEND */
|
||||
|
@ -361,7 +361,7 @@ _PyGen_yf(PyGenObject *gen)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (code[frame->f_lasti*sizeof(_Py_CODEUNIT)] != SEND || frame->stacktop < 0)
|
||||
if (code[(frame->f_lasti-1)*sizeof(_Py_CODEUNIT)] != SEND || frame->stacktop < 0)
|
||||
return NULL;
|
||||
yf = _PyFrame_StackPeek(frame);
|
||||
Py_INCREF(yf);
|
||||
|
@ -488,6 +488,8 @@ _gen_throw(PyGenObject *gen, int close_on_genexit,
|
|||
assert(frame->f_lasti >= 0);
|
||||
PyObject *bytecode = gen->gi_code->co_code;
|
||||
unsigned char *code = (unsigned char *)PyBytes_AS_STRING(bytecode);
|
||||
/* Backup to SEND */
|
||||
frame->f_lasti--;
|
||||
assert(code[frame->f_lasti*sizeof(_Py_CODEUNIT)] == SEND);
|
||||
int jump = code[frame->f_lasti*sizeof(_Py_CODEUNIT)+1];
|
||||
frame->f_lasti += jump;
|
||||
|
|
|
@ -2650,32 +2650,25 @@ handle_eval_breaker:
|
|||
}
|
||||
assert (gen_status == PYGEN_NEXT);
|
||||
assert (retval != NULL);
|
||||
frame->f_state = FRAME_SUSPENDED;
|
||||
_PyFrame_SetStackPointer(frame, stack_pointer);
|
||||
TRACE_FUNCTION_EXIT();
|
||||
DTRACE_FUNCTION_EXIT();
|
||||
_Py_LeaveRecursiveCall(tstate);
|
||||
/* Restore previous cframe and return. */
|
||||
tstate->cframe = cframe.previous;
|
||||
tstate->cframe->use_tracing = cframe.use_tracing;
|
||||
assert(tstate->cframe->current_frame == frame->previous);
|
||||
assert(!_PyErr_Occurred(tstate));
|
||||
return retval;
|
||||
PUSH(retval);
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
TARGET(ASYNC_GEN_WRAP) {
|
||||
PyObject *v = TOP();
|
||||
assert(frame->f_code->co_flags & CO_ASYNC_GENERATOR);
|
||||
PyObject *w = _PyAsyncGenValueWrapperNew(v);
|
||||
if (w == NULL) {
|
||||
goto error;
|
||||
}
|
||||
SET_TOP(w);
|
||||
Py_DECREF(v);
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
TARGET(YIELD_VALUE) {
|
||||
assert(frame->is_entry);
|
||||
PyObject *retval = POP();
|
||||
|
||||
if (frame->f_code->co_flags & CO_ASYNC_GENERATOR) {
|
||||
PyObject *w = _PyAsyncGenValueWrapperNew(retval);
|
||||
Py_DECREF(retval);
|
||||
if (w == NULL) {
|
||||
retval = NULL;
|
||||
goto error;
|
||||
}
|
||||
retval = w;
|
||||
}
|
||||
frame->f_state = FRAME_SUSPENDED;
|
||||
_PyFrame_SetStackPointer(frame, stack_pointer);
|
||||
TRACE_FUNCTION_EXIT();
|
||||
|
|
|
@ -910,6 +910,7 @@ stack_effect(int opcode, int oparg, int jump)
|
|||
return -1;
|
||||
case SETUP_ANNOTATIONS:
|
||||
return 0;
|
||||
case ASYNC_GEN_WRAP:
|
||||
case YIELD_VALUE:
|
||||
return 0;
|
||||
case POP_BLOCK:
|
||||
|
@ -1541,6 +1542,9 @@ compiler_addop_j_noline(struct compiler *c, int opcode, basicblock *b)
|
|||
#define POP_EXCEPT_AND_RERAISE(C) \
|
||||
RETURN_IF_FALSE(compiler_pop_except_and_reraise((C)))
|
||||
|
||||
#define ADDOP_YIELD(C) \
|
||||
RETURN_IF_FALSE(addop_yield(C))
|
||||
|
||||
#define VISIT(C, TYPE, V) {\
|
||||
if (!compiler_visit_ ## TYPE((C), (V))) \
|
||||
return 0; \
|
||||
|
@ -1844,6 +1848,7 @@ compiler_add_yield_from(struct compiler *c, int await)
|
|||
compiler_use_next_block(c, start);
|
||||
ADDOP_JUMP(c, SEND, exit);
|
||||
compiler_use_next_block(c, resume);
|
||||
ADDOP(c, YIELD_VALUE);
|
||||
ADDOP_I(c, RESUME, await ? 3 : 2);
|
||||
ADDOP_JUMP(c, JUMP_NO_INTERRUPT, start);
|
||||
compiler_use_next_block(c, exit);
|
||||
|
@ -4094,6 +4099,17 @@ addop_binary(struct compiler *c, operator_ty binop, bool inplace)
|
|||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
addop_yield(struct compiler *c) {
|
||||
if (c->u->u_ste->ste_generator && c->u->u_ste->ste_coroutine) {
|
||||
ADDOP(c, ASYNC_GEN_WRAP);
|
||||
}
|
||||
ADDOP(c, YIELD_VALUE);
|
||||
ADDOP_I(c, RESUME, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
compiler_nameop(struct compiler *c, identifier name, expr_context_ty ctx)
|
||||
{
|
||||
|
@ -5144,8 +5160,7 @@ compiler_sync_comprehension_generator(struct compiler *c,
|
|||
switch (type) {
|
||||
case COMP_GENEXP:
|
||||
VISIT(c, expr, elt);
|
||||
ADDOP(c, YIELD_VALUE);
|
||||
ADDOP_I(c, RESUME, 1);
|
||||
ADDOP_YIELD(c);
|
||||
ADDOP(c, POP_TOP);
|
||||
break;
|
||||
case COMP_LISTCOMP:
|
||||
|
@ -5243,8 +5258,7 @@ compiler_async_comprehension_generator(struct compiler *c,
|
|||
switch (type) {
|
||||
case COMP_GENEXP:
|
||||
VISIT(c, expr, elt);
|
||||
ADDOP(c, YIELD_VALUE);
|
||||
ADDOP_I(c, RESUME, 1);
|
||||
ADDOP_YIELD(c);
|
||||
ADDOP(c, POP_TOP);
|
||||
break;
|
||||
case COMP_LISTCOMP:
|
||||
|
@ -5714,8 +5728,7 @@ compiler_visit_expr1(struct compiler *c, expr_ty e)
|
|||
else {
|
||||
ADDOP_LOAD_CONST(c, Py_None);
|
||||
}
|
||||
ADDOP(c, YIELD_VALUE);
|
||||
ADDOP_I(c, RESUME, 1);
|
||||
ADDOP_YIELD(c);
|
||||
break;
|
||||
case YieldFrom_kind:
|
||||
if (c->u->u_ste->ste_type != FunctionBlock)
|
||||
|
|
|
@ -86,7 +86,7 @@ static void *opcode_targets[256] = {
|
|||
&&TARGET_IMPORT_STAR,
|
||||
&&TARGET_SETUP_ANNOTATIONS,
|
||||
&&TARGET_YIELD_VALUE,
|
||||
&&TARGET_STORE_ATTR_WITH_HINT,
|
||||
&&TARGET_ASYNC_GEN_WRAP,
|
||||
&&TARGET_PREP_RERAISE_STAR,
|
||||
&&TARGET_POP_EXCEPT,
|
||||
&&TARGET_STORE_NAME,
|
||||
|
@ -130,7 +130,7 @@ static void *opcode_targets[256] = {
|
|||
&&TARGET_POP_JUMP_IF_NOT_NONE,
|
||||
&&TARGET_POP_JUMP_IF_NONE,
|
||||
&&TARGET_RAISE_VARARGS,
|
||||
&&TARGET_LOAD_FAST__LOAD_FAST,
|
||||
&&TARGET_STORE_ATTR_WITH_HINT,
|
||||
&&TARGET_MAKE_FUNCTION,
|
||||
&&TARGET_BUILD_SLICE,
|
||||
&&TARGET_JUMP_NO_INTERRUPT,
|
||||
|
@ -139,20 +139,20 @@ static void *opcode_targets[256] = {
|
|||
&&TARGET_LOAD_DEREF,
|
||||
&&TARGET_STORE_DEREF,
|
||||
&&TARGET_DELETE_DEREF,
|
||||
&&TARGET_LOAD_FAST__LOAD_FAST,
|
||||
&&TARGET_STORE_FAST__LOAD_FAST,
|
||||
&&TARGET_LOAD_FAST__LOAD_CONST,
|
||||
&&TARGET_CALL_FUNCTION_EX,
|
||||
&&TARGET_LOAD_CONST__LOAD_FAST,
|
||||
&&TARGET_LOAD_FAST__LOAD_CONST,
|
||||
&&TARGET_EXTENDED_ARG,
|
||||
&&TARGET_LIST_APPEND,
|
||||
&&TARGET_SET_ADD,
|
||||
&&TARGET_MAP_ADD,
|
||||
&&TARGET_LOAD_CLASSDEREF,
|
||||
&&TARGET_COPY_FREE_VARS,
|
||||
&&TARGET_STORE_FAST__STORE_FAST,
|
||||
&&TARGET_LOAD_CONST__LOAD_FAST,
|
||||
&&TARGET_RESUME,
|
||||
&&TARGET_MATCH_CLASS,
|
||||
&&_unknown_opcode,
|
||||
&&TARGET_STORE_FAST__STORE_FAST,
|
||||
&&_unknown_opcode,
|
||||
&&TARGET_FORMAT_VALUE,
|
||||
&&TARGET_BUILD_CONST_KEY_MAP,
|
||||
|
|
Loading…
Reference in New Issue