summaryrefslogtreecommitdiffstats
path: root/Python
diff options
context:
space:
mode:
authorMark Shannon <mark@hotpy.org>2021-12-15 10:30:09 (GMT)
committerGitHub <noreply@github.com>2021-12-15 10:30:09 (GMT)
commit0b50a4f0cdee41a18fb4ba6e75569f9cfaceb39e (patch)
tree307cc32e8ca72f71eaa8250e976306adc939e9fd /Python
parent86de99588db3beff964137f4fe27dd1077a09b35 (diff)
downloadcpython-0b50a4f0cdee41a18fb4ba6e75569f9cfaceb39e.zip
cpython-0b50a4f0cdee41a18fb4ba6e75569f9cfaceb39e.tar.gz
cpython-0b50a4f0cdee41a18fb4ba6e75569f9cfaceb39e.tar.bz2
bpo-46039: Split yield from in two (GH-30035)
* Split YIELD_FROM opcode into SEND and JUMP_ABSOLUTE. * Remove YIELD_FROM opcode.
Diffstat (limited to 'Python')
-rw-r--r--Python/ceval.c21
-rw-r--r--Python/compile.c55
-rw-r--r--Python/opcode_targets.h8
3 files changed, 54 insertions, 30 deletions
diff --git a/Python/ceval.c b/Python/ceval.c
index 6d27848..7932433 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -1798,7 +1798,8 @@ check_eval_breaker:
if (_Py_atomic_load_relaxed(eval_breaker)) {
opcode = _Py_OPCODE(*next_instr);
if (opcode != BEFORE_ASYNC_WITH &&
- opcode != YIELD_FROM) {
+ opcode != SEND &&
+ _Py_OPCODE(next_instr[-1]) != SEND) {
/* Few cases where we skip running signal handlers and other
pending calls:
- If we're about to enter the 'with:'. It will prevent
@@ -2642,8 +2643,9 @@ check_eval_breaker:
DISPATCH();
}
- TARGET(YIELD_FROM) {
+ TARGET(SEND) {
assert(frame->depth == 0);
+ assert(STACK_LEVEL() >= 2);
PyObject *v = POP();
PyObject *receiver = TOP();
PySendResult gen_status;
@@ -2680,17 +2682,13 @@ check_eval_breaker:
}
if (gen_status == PYGEN_RETURN) {
assert (retval != NULL);
-
Py_DECREF(receiver);
SET_TOP(retval);
- retval = NULL;
+ JUMPBY(oparg);
DISPATCH();
}
assert (gen_status == PYGEN_NEXT);
- /* receiver remains on stack, retval is value to be yielded */
- /* and repeat... */
- assert(frame->f_lasti > 0);
- frame->f_lasti -= 1;
+ assert (retval != NULL);
frame->f_state = FRAME_SUSPENDED;
_PyFrame_SetStackPointer(frame, stack_pointer);
TRACE_FUNCTION_EXIT();
@@ -6770,8 +6768,11 @@ maybe_call_line_trace(Py_tracefunc func, PyObject *obj,
return -1;
}
if (line != -1 && f->f_trace_lines) {
- /* Trace backward edges or if line number has changed */
- if (frame->f_lasti < instr_prev || line != lastline) {
+ /* Trace backward edges (except in 'yield from') or if line number has changed */
+ int trace = line != lastline ||
+ (frame->f_lasti < instr_prev &&
+ _Py_OPCODE(frame->f_code->co_firstinstr[frame->f_lasti]) != SEND);
+ if (trace) {
result = call_trace(func, obj, tstate, frame, PyTrace_LINE, Py_None);
}
}
diff --git a/Python/compile.c b/Python/compile.c
index afd9a62..6179ad9 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -1045,8 +1045,6 @@ stack_effect(int opcode, int oparg, int jump)
return 0;
case YIELD_VALUE:
return 0;
- case YIELD_FROM:
- return -1;
case POP_BLOCK:
return 0;
case POP_EXCEPT:
@@ -1065,7 +1063,8 @@ stack_effect(int opcode, int oparg, int jump)
case FOR_ITER:
/* -1 at end of iterator, 1 if continue iterating. */
return jump > 0 ? -1 : 1;
-
+ case SEND:
+ return jump > 0 ? -1 : 0;
case STORE_ATTR:
return -2;
case DELETE_ATTR:
@@ -1667,6 +1666,9 @@ compiler_addop_j_noline(struct compiler *c, int opcode, basicblock *b)
the ASDL name to synthesize the name of the C type and the visit function.
*/
+#define ADD_YIELD_FROM(C) \
+ RETURN_IF_FALSE(compiler_add_yield_from((C)))
+
#define VISIT(C, TYPE, V) {\
if (!compiler_visit_ ## TYPE((C), (V))) \
return 0; \
@@ -1819,6 +1821,24 @@ compiler_call_exit_with_nones(struct compiler *c) {
return 1;
}
+static int
+compiler_add_yield_from(struct compiler *c)
+{
+ basicblock *start, *jump, *exit;
+ start = compiler_new_block(c);
+ jump = compiler_new_block(c);
+ exit = compiler_new_block(c);
+ if (start == NULL || jump == NULL || exit == NULL) {
+ return 0;
+ }
+ compiler_use_next_block(c, start);
+ ADDOP_JUMP(c, SEND, exit);
+ compiler_use_next_block(c, jump);
+ ADDOP_JUMP(c, JUMP_ABSOLUTE, start);
+ compiler_use_next_block(c, exit);
+ return 1;
+}
+
/* Unwind a frame block. If preserve_tos is true, the TOS before
* popping the blocks will be restored afterwards, unless another
* return, break or continue is found. In which case, the TOS will
@@ -1893,7 +1913,7 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info,
if (info->fb_type == ASYNC_WITH) {
ADDOP(c, GET_AWAITABLE);
ADDOP_LOAD_CONST(c, Py_None);
- ADDOP(c, YIELD_FROM);
+ ADD_YIELD_FROM(c);
}
ADDOP(c, POP_TOP);
/* The exit block should appear to execute after the
@@ -3006,7 +3026,7 @@ compiler_async_for(struct compiler *c, stmt_ty s)
ADDOP_JUMP(c, SETUP_FINALLY, except);
ADDOP(c, GET_ANEXT);
ADDOP_LOAD_CONST(c, Py_None);
- ADDOP(c, YIELD_FROM);
+ ADD_YIELD_FROM(c);
ADDOP(c, POP_BLOCK); /* for SETUP_FINALLY */
/* Success block for __anext__ */
@@ -5192,7 +5212,7 @@ compiler_async_comprehension_generator(struct compiler *c,
ADDOP_JUMP(c, SETUP_FINALLY, except);
ADDOP(c, GET_ANEXT);
ADDOP_LOAD_CONST(c, Py_None);
- ADDOP(c, YIELD_FROM);
+ ADD_YIELD_FROM(c);
ADDOP(c, POP_BLOCK);
VISIT(c, expr, gen->target);
@@ -5342,7 +5362,7 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type,
if (is_async_generator && type != COMP_GENEXP) {
ADDOP(c, GET_AWAITABLE);
ADDOP_LOAD_CONST(c, Py_None);
- ADDOP(c, YIELD_FROM);
+ ADD_YIELD_FROM(c);
}
return 1;
@@ -5493,7 +5513,7 @@ compiler_async_with(struct compiler *c, stmt_ty s, int pos)
ADDOP(c, BEFORE_ASYNC_WITH);
ADDOP(c, GET_AWAITABLE);
ADDOP_LOAD_CONST(c, Py_None);
- ADDOP(c, YIELD_FROM);
+ ADD_YIELD_FROM(c);
ADDOP_JUMP(c, SETUP_WITH, final);
@@ -5530,7 +5550,7 @@ compiler_async_with(struct compiler *c, stmt_ty s, int pos)
return 0;
ADDOP(c, GET_AWAITABLE);
ADDOP_LOAD_CONST(c, Py_None);
- ADDOP(c, YIELD_FROM);
+ ADD_YIELD_FROM(c);
ADDOP(c, POP_TOP);
@@ -5544,7 +5564,7 @@ compiler_async_with(struct compiler *c, stmt_ty s, int pos)
ADDOP(c, WITH_EXCEPT_START);
ADDOP(c, GET_AWAITABLE);
ADDOP_LOAD_CONST(c, Py_None);
- ADDOP(c, YIELD_FROM);
+ ADD_YIELD_FROM(c);
compiler_with_except_finish(c, cleanup);
compiler_use_next_block(c, exit);
@@ -5701,7 +5721,7 @@ compiler_visit_expr1(struct compiler *c, expr_ty e)
VISIT(c, expr, e->v.YieldFrom.value);
ADDOP(c, GET_YIELD_FROM_ITER);
ADDOP_LOAD_CONST(c, Py_None);
- ADDOP(c, YIELD_FROM);
+ ADD_YIELD_FROM(c);
break;
case Await_kind:
if (!IS_TOP_LEVEL_AWAIT(c)){
@@ -5718,7 +5738,7 @@ compiler_visit_expr1(struct compiler *c, expr_ty e)
VISIT(c, expr, e->v.Await.value);
ADDOP(c, GET_AWAITABLE);
ADDOP_LOAD_CONST(c, Py_None);
- ADDOP(c, YIELD_FROM);
+ ADD_YIELD_FROM(c);
break;
case Compare_kind:
return compiler_compare(c, e);
@@ -7544,10 +7564,13 @@ normalize_jumps(struct assembler *a)
continue;
}
struct instr *last = &b->b_instr[b->b_iused-1];
- if (last->i_opcode == JUMP_ABSOLUTE &&
- last->i_target->b_visited == 0
- ) {
- last->i_opcode = JUMP_FORWARD;
+ if (last->i_opcode == JUMP_ABSOLUTE) {
+ if (last->i_target->b_visited == 0) {
+ last->i_opcode = JUMP_FORWARD;
+ }
+ else if (b->b_iused >= 2 && b->b_instr[b->b_iused-2].i_opcode == SEND) {
+ last->i_opcode = JUMP_ABSOLUTE_QUICK;
+ }
}
}
}
diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h
index 05bd939..3b2e99d 100644
--- a/Python/opcode_targets.h
+++ b/Python/opcode_targets.h
@@ -71,22 +71,22 @@ static void *opcode_targets[256] = {
&&TARGET_GET_YIELD_FROM_ITER,
&&TARGET_PRINT_EXPR,
&&TARGET_LOAD_BUILD_CLASS,
- &&TARGET_YIELD_FROM,
+ &&TARGET_LOAD_METHOD_CLASS,
&&TARGET_GET_AWAITABLE,
&&TARGET_LOAD_ASSERTION_ERROR,
- &&TARGET_LOAD_METHOD_CLASS,
&&TARGET_LOAD_METHOD_MODULE,
&&TARGET_LOAD_METHOD_NO_DICT,
&&TARGET_STORE_ATTR_ADAPTIVE,
&&TARGET_STORE_ATTR_INSTANCE_VALUE,
&&TARGET_STORE_ATTR_SLOT,
&&TARGET_STORE_ATTR_WITH_HINT,
+ &&TARGET_LOAD_FAST__LOAD_FAST,
&&TARGET_LIST_TO_TUPLE,
&&TARGET_RETURN_VALUE,
&&TARGET_IMPORT_STAR,
&&TARGET_SETUP_ANNOTATIONS,
&&TARGET_YIELD_VALUE,
- &&TARGET_LOAD_FAST__LOAD_FAST,
+ &&TARGET_STORE_FAST__LOAD_FAST,
&&TARGET_PREP_RERAISE_STAR,
&&TARGET_POP_EXCEPT,
&&TARGET_STORE_NAME,
@@ -122,7 +122,7 @@ static void *opcode_targets[256] = {
&&TARGET_COPY,
&&TARGET_JUMP_IF_NOT_EXC_MATCH,
&&TARGET_BINARY_OP,
- &&TARGET_STORE_FAST__LOAD_FAST,
+ &&TARGET_SEND,
&&TARGET_LOAD_FAST,
&&TARGET_STORE_FAST,
&&TARGET_DELETE_FAST,