diff options
author | Mark Shannon <mark@hotpy.org> | 2021-12-15 10:30:09 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-12-15 10:30:09 (GMT) |
commit | 0b50a4f0cdee41a18fb4ba6e75569f9cfaceb39e (patch) | |
tree | 307cc32e8ca72f71eaa8250e976306adc939e9fd /Python | |
parent | 86de99588db3beff964137f4fe27dd1077a09b35 (diff) | |
download | cpython-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.c | 21 | ||||
-rw-r--r-- | Python/compile.c | 55 | ||||
-rw-r--r-- | Python/opcode_targets.h | 8 |
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, |