From 65d303f8ca2f7482c7dbb5711a95bb4b315fac9f Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Tue, 1 Nov 2022 16:14:27 +0000 Subject: [PATCH 1/7] Handle converting StopIteration to RuntimeError in bytecode. --- Include/internal/pycore_opcode.h | 14 ++++---- Include/opcode.h | 45 +++++++++++------------ Lib/importlib/_bootstrap_external.py | 5 ++- Lib/opcode.py | 2 +- Lib/test/test_dis.py | 12 ++++++- Lib/test/test_sys.py | 2 +- Lib/test/test_sys_settrace.py | 2 +- Python/ceval.c | 20 +++++++++++ Python/compile.c | 54 ++++++++++++++++++++++++++++ Python/opcode_targets.h | 12 +++---- 10 files changed, 128 insertions(+), 40 deletions(-) diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index 33617b4be444f4..cbd72d8510c497 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -170,6 +170,7 @@ const uint8_t _PyOpcode_Deopt[256] = { [LOAD_CONST] = LOAD_CONST, [LOAD_CONST__LOAD_FAST] = LOAD_CONST, [LOAD_DEREF] = LOAD_DEREF, + [LOAD_ERROR] = LOAD_ERROR, [LOAD_FAST] = LOAD_FAST, [LOAD_FAST_CHECK] = LOAD_FAST_CHECK, [LOAD_FAST__LOAD_CONST] = LOAD_FAST, @@ -382,9 +383,9 @@ static const char *const _PyOpcode_OpName[263] = { [STORE_DEREF] = "STORE_DEREF", [DELETE_DEREF] = "DELETE_DEREF", [JUMP_BACKWARD] = "JUMP_BACKWARD", - [LOAD_ATTR_METHOD_WITH_DICT] = "LOAD_ATTR_METHOD_WITH_DICT", + [LOAD_ERROR] = "LOAD_ERROR", [CALL_FUNCTION_EX] = "CALL_FUNCTION_EX", - [LOAD_ATTR_METHOD_WITH_VALUES] = "LOAD_ATTR_METHOD_WITH_VALUES", + [LOAD_ATTR_METHOD_WITH_DICT] = "LOAD_ATTR_METHOD_WITH_DICT", [EXTENDED_ARG] = "EXTENDED_ARG", [LIST_APPEND] = "LIST_APPEND", [SET_ADD] = "SET_ADD", @@ -394,26 +395,27 @@ static const char *const _PyOpcode_OpName[263] = { [YIELD_VALUE] = "YIELD_VALUE", [RESUME] = "RESUME", [MATCH_CLASS] = "MATCH_CLASS", + [LOAD_ATTR_METHOD_WITH_VALUES] = "LOAD_ATTR_METHOD_WITH_VALUES", [LOAD_CONST__LOAD_FAST] = "LOAD_CONST__LOAD_FAST", - [LOAD_FAST__LOAD_CONST] = "LOAD_FAST__LOAD_CONST", [FORMAT_VALUE] = "FORMAT_VALUE", [BUILD_CONST_KEY_MAP] = "BUILD_CONST_KEY_MAP", [BUILD_STRING] = "BUILD_STRING", + [LOAD_FAST__LOAD_CONST] = "LOAD_FAST__LOAD_CONST", [LOAD_FAST__LOAD_FAST] = "LOAD_FAST__LOAD_FAST", [LOAD_GLOBAL_ADAPTIVE] = "LOAD_GLOBAL_ADAPTIVE", [LOAD_GLOBAL_BUILTIN] = "LOAD_GLOBAL_BUILTIN", - [LOAD_GLOBAL_MODULE] = "LOAD_GLOBAL_MODULE", [LIST_EXTEND] = "LIST_EXTEND", [SET_UPDATE] = "SET_UPDATE", [DICT_MERGE] = "DICT_MERGE", [DICT_UPDATE] = "DICT_UPDATE", + [LOAD_GLOBAL_MODULE] = "LOAD_GLOBAL_MODULE", [RESUME_QUICK] = "RESUME_QUICK", [STORE_ATTR_ADAPTIVE] = "STORE_ATTR_ADAPTIVE", [STORE_ATTR_INSTANCE_VALUE] = "STORE_ATTR_INSTANCE_VALUE", [STORE_ATTR_SLOT] = "STORE_ATTR_SLOT", - [STORE_ATTR_WITH_HINT] = "STORE_ATTR_WITH_HINT", [CALL] = "CALL", [KW_NAMES] = "KW_NAMES", + [STORE_ATTR_WITH_HINT] = "STORE_ATTR_WITH_HINT", [STORE_FAST__LOAD_FAST] = "STORE_FAST__LOAD_FAST", [STORE_FAST__STORE_FAST] = "STORE_FAST__STORE_FAST", [STORE_SUBSCR_ADAPTIVE] = "STORE_SUBSCR_ADAPTIVE", @@ -423,7 +425,6 @@ static const char *const _PyOpcode_OpName[263] = { [UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST", [UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE", [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE", - [182] = "<182>", [183] = "<183>", [184] = "<184>", [185] = "<185>", @@ -508,7 +509,6 @@ static const char *const _PyOpcode_OpName[263] = { #endif #define EXTRA_CASES \ - case 182: \ case 183: \ case 184: \ case 185: \ diff --git a/Include/opcode.h b/Include/opcode.h index 9b9414cff401f0..96b761aa178710 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -99,6 +99,7 @@ extern "C" { #define STORE_DEREF 138 #define DELETE_DEREF 139 #define JUMP_BACKWARD 140 +#define LOAD_ERROR 141 #define CALL_FUNCTION_EX 142 #define EXTENDED_ARG 144 #define LIST_APPEND 145 @@ -178,28 +179,28 @@ extern "C" { #define LOAD_ATTR_WITH_HINT 86 #define LOAD_ATTR_METHOD_LAZY_DICT 113 #define LOAD_ATTR_METHOD_NO_DICT 121 -#define LOAD_ATTR_METHOD_WITH_DICT 141 -#define LOAD_ATTR_METHOD_WITH_VALUES 143 -#define LOAD_CONST__LOAD_FAST 153 -#define LOAD_FAST__LOAD_CONST 154 -#define LOAD_FAST__LOAD_FAST 158 -#define LOAD_GLOBAL_ADAPTIVE 159 -#define LOAD_GLOBAL_BUILTIN 160 -#define LOAD_GLOBAL_MODULE 161 -#define RESUME_QUICK 166 -#define STORE_ATTR_ADAPTIVE 167 -#define STORE_ATTR_INSTANCE_VALUE 168 -#define STORE_ATTR_SLOT 169 -#define STORE_ATTR_WITH_HINT 170 -#define STORE_FAST__LOAD_FAST 173 -#define STORE_FAST__STORE_FAST 174 -#define STORE_SUBSCR_ADAPTIVE 175 -#define STORE_SUBSCR_DICT 176 -#define STORE_SUBSCR_LIST_INT 177 -#define UNPACK_SEQUENCE_ADAPTIVE 178 -#define UNPACK_SEQUENCE_LIST 179 -#define UNPACK_SEQUENCE_TUPLE 180 -#define UNPACK_SEQUENCE_TWO_TUPLE 181 +#define LOAD_ATTR_METHOD_WITH_DICT 143 +#define LOAD_ATTR_METHOD_WITH_VALUES 153 +#define LOAD_CONST__LOAD_FAST 154 +#define LOAD_FAST__LOAD_CONST 158 +#define LOAD_FAST__LOAD_FAST 159 +#define LOAD_GLOBAL_ADAPTIVE 160 +#define LOAD_GLOBAL_BUILTIN 161 +#define LOAD_GLOBAL_MODULE 166 +#define RESUME_QUICK 167 +#define STORE_ATTR_ADAPTIVE 168 +#define STORE_ATTR_INSTANCE_VALUE 169 +#define STORE_ATTR_SLOT 170 +#define STORE_ATTR_WITH_HINT 173 +#define STORE_FAST__LOAD_FAST 174 +#define STORE_FAST__STORE_FAST 175 +#define STORE_SUBSCR_ADAPTIVE 176 +#define STORE_SUBSCR_DICT 177 +#define STORE_SUBSCR_LIST_INT 178 +#define UNPACK_SEQUENCE_ADAPTIVE 179 +#define UNPACK_SEQUENCE_LIST 180 +#define UNPACK_SEQUENCE_TUPLE 181 +#define UNPACK_SEQUENCE_TWO_TUPLE 182 #define DO_TRACING 255 #define HAS_ARG(op) ((((op) >= HAVE_ARGUMENT) && (!IS_PSEUDO_OPCODE(op)))\ diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 9c14f71b6c0739..86fc93d58a4285 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -425,6 +425,9 @@ def _write_atomic(path, data, mode=0o666): # Python 3.12a1 3509 (Conditional jumps only jump forward) # Python 3.12a1 3510 (FOR_ITER leaves iterator on the stack) + +# Python 3.12a1 3514 (Add LOAD_ERROR instruction) + # Python 3.13 will start with 3550 # MAGIC must change whenever the bytecode emitted by the compiler may no @@ -436,7 +439,7 @@ def _write_atomic(path, data, mode=0o666): # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array # in PC/launcher.c must also be updated. -MAGIC_NUMBER = (3510).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3514).to_bytes(2, 'little') + b'\r\n' _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c diff --git a/Lib/opcode.py b/Lib/opcode.py index d655b0e44a4c19..c2cdf058054604 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -190,7 +190,7 @@ def pseudo_op(name, op, real_ops): def_op('DELETE_DEREF', 139) hasfree.append(139) jrel_op('JUMP_BACKWARD', 140) # Number of words to skip (backwards) - +def_op('LOAD_ERROR', 141) def_op('CALL_FUNCTION_EX', 142) # Flags def_op('EXTENDED_ARG', 144) diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index c986a6b538f2ac..baa22092b6d031 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -543,8 +543,16 @@ async def _asyncwith(c): >> COPY 3 POP_EXCEPT RERAISE 1 + >> LOAD_ERROR 1 + CHECK_EXC_MATCH + POP_JUMP_IF_FALSE 8 (to 140) + LOAD_ERROR 2 + LOAD_CONST 3 ('coroutine raised StopIteration') + CALL 0 + RAISE_VARARGS 2 + >> RERAISE 1 ExceptionTable: -6 rows +12 rows """ % (_asyncwith.__code__.co_firstlineno, _asyncwith.__code__.co_firstlineno + 1, _asyncwith.__code__.co_firstlineno + 2, @@ -1256,6 +1264,7 @@ def f(c=c): Constants: 0: None 1: + 2: 'generator raised StopIteration' Variable names: 0: a 1: b @@ -1362,6 +1371,7 @@ async def async_def(): Constants: 0: None 1: 1 + 2: 'coroutine raised StopIteration' Names: 0: b 1: c diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index 9184e9a42f1941..7bf84df5d23c92 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -1439,7 +1439,7 @@ def bar(cls): check(bar, size('PP')) # generator def get_gen(): yield 1 - check(get_gen(), size('P2P4P4c7P2ic??P')) + check(get_gen(), size('P2P4P4c7P2ic??4P')) # iterator check(iter('abc'), size('lP')) # callable-iterator diff --git a/Lib/test/test_sys_settrace.py b/Lib/test/test_sys_settrace.py index a448f80449ca3d..a251b2272e95eb 100644 --- a/Lib/test/test_sys_settrace.py +++ b/Lib/test/test_sys_settrace.py @@ -346,7 +346,7 @@ def make_tracer(): return Tracer() def compare_events(self, line_offset, events, expected_events): - events = [(l - line_offset, e) for (l, e) in events] + events = [(l - line_offset if l is not None else None, e) for (l, e) in events] if events != expected_events: self.fail( "events did not match expectation:\n" + diff --git a/Python/ceval.c b/Python/ceval.c index 100aa3d727e468..5e62cd5ff91723 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2175,6 +2175,26 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int goto exception_unwind; } + TARGET(LOAD_ERROR) { + PyObject *value; + switch(oparg) { + case 0: + value = PyExc_AssertionError; + break; + case 1: + value = PyExc_StopIteration; + break; + case 2: + value = PyExc_RuntimeError; + break; + default: + Py_UNREACHABLE(); + } + Py_INCREF(value); + PUSH(value); + DISPATCH(); + } + TARGET(LOAD_ASSERTION_ERROR) { PyObject *value = PyExc_AssertionError; Py_INCREF(value); diff --git a/Python/compile.c b/Python/compile.c index f8924789f4e954..388bd8905b6ee8 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -1254,6 +1254,7 @@ stack_effect(int opcode, int oparg, int jump) return (oparg & FVS_MASK) == FVS_HAVE_SPEC ? -1 : 0; case LOAD_METHOD: return 1; + case LOAD_ERROR: case LOAD_ASSERTION_ERROR: return 1; case LIST_TO_TUPLE: @@ -2567,6 +2568,42 @@ compiler_check_debug_args(struct compiler *c, arguments_ty args) return 1; } +static int +coroutine_stopiteration_handler(struct compiler *c, jump_target_label *handler) +{ + ADDOP_LOAD_CONST(c, NO_LOCATION, Py_None); + ADDOP(c, NO_LOCATION, RETURN_VALUE); + if (cfg_builder_use_label(CFG_BUILDER(c), *handler) < 0) { + return 0; + } + jump_target_label other = cfg_new_label(CFG_BUILDER(c)); + if (!IS_LABEL(other)) { + return 0; + } + USE_LABEL(c, *handler); + ADDOP_I(c, NO_LOCATION, LOAD_ERROR, 1); // StopIteration + ADDOP(c, NO_LOCATION, CHECK_EXC_MATCH); + ADDOP_JUMP(c, NO_LOCATION, POP_JUMP_IF_FALSE, other); + ADDOP_I(c, NO_LOCATION, LOAD_ERROR, 2); // RuntimeError + const char *msg = c->u->u_ste->ste_coroutine ? + (c->u->u_ste->ste_generator ? + "async generator raised StopIteration" : + "coroutine raised StopIteration" + ) : + "generator raised StopIteration"; + PyObject *message = _PyUnicode_FromASCII(msg, strlen(msg)); + if (message == NULL) { + return 0; + } + ADDOP_LOAD_CONST_NEW(c, NO_LOCATION, message); + ADDOP_I(c, NO_LOCATION, CALL, 0); + ADDOP_I(c, NO_LOCATION, RAISE_VARARGS, 2); + + USE_LABEL(c, other); + ADDOP_I(c, NO_LOCATION, RERAISE, 1); + return 1; +} + static int compiler_function(struct compiler *c, stmt_ty s, int is_async) { @@ -2632,6 +2669,17 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async) return 0; } + bool is_coro = (c->u->u_ste->ste_coroutine || c->u->u_ste->ste_generator); + jump_target_label handler; + if (is_coro) { + handler = cfg_new_label(CFG_BUILDER(c)); + if (!IS_LABEL(handler)) { + compiler_exit_scope(c); + return 0; + } + ADDOP_JUMP(c, NO_LOCATION, SETUP_CLEANUP, handler); + } + /* if not -OO mode, add docstring */ if (c->c_optimize < 2) { docstring = _PyAST_GetDocString(body); @@ -2647,6 +2695,12 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async) for (i = docstring ? 1 : 0; i < asdl_seq_LEN(body); i++) { VISIT_IN_SCOPE(c, stmt, (stmt_ty)asdl_seq_GET(body, i)); } + if (is_coro) { + if (!coroutine_stopiteration_handler(c, &handler)) { + compiler_exit_scope(c); + return 0; + } + } co = assemble(c, 1); qualname = c->u->u_qualname; Py_INCREF(qualname); diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index 53b2770607b40e..33358873012f64 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -140,9 +140,9 @@ static void *opcode_targets[256] = { &&TARGET_STORE_DEREF, &&TARGET_DELETE_DEREF, &&TARGET_JUMP_BACKWARD, - &&TARGET_LOAD_ATTR_METHOD_WITH_DICT, + &&TARGET_LOAD_ERROR, &&TARGET_CALL_FUNCTION_EX, - &&TARGET_LOAD_ATTR_METHOD_WITH_VALUES, + &&TARGET_LOAD_ATTR_METHOD_WITH_DICT, &&TARGET_EXTENDED_ARG, &&TARGET_LIST_APPEND, &&TARGET_SET_ADD, @@ -152,26 +152,27 @@ static void *opcode_targets[256] = { &&TARGET_YIELD_VALUE, &&TARGET_RESUME, &&TARGET_MATCH_CLASS, + &&TARGET_LOAD_ATTR_METHOD_WITH_VALUES, &&TARGET_LOAD_CONST__LOAD_FAST, - &&TARGET_LOAD_FAST__LOAD_CONST, &&TARGET_FORMAT_VALUE, &&TARGET_BUILD_CONST_KEY_MAP, &&TARGET_BUILD_STRING, + &&TARGET_LOAD_FAST__LOAD_CONST, &&TARGET_LOAD_FAST__LOAD_FAST, &&TARGET_LOAD_GLOBAL_ADAPTIVE, &&TARGET_LOAD_GLOBAL_BUILTIN, - &&TARGET_LOAD_GLOBAL_MODULE, &&TARGET_LIST_EXTEND, &&TARGET_SET_UPDATE, &&TARGET_DICT_MERGE, &&TARGET_DICT_UPDATE, + &&TARGET_LOAD_GLOBAL_MODULE, &&TARGET_RESUME_QUICK, &&TARGET_STORE_ATTR_ADAPTIVE, &&TARGET_STORE_ATTR_INSTANCE_VALUE, &&TARGET_STORE_ATTR_SLOT, - &&TARGET_STORE_ATTR_WITH_HINT, &&TARGET_CALL, &&TARGET_KW_NAMES, + &&TARGET_STORE_ATTR_WITH_HINT, &&TARGET_STORE_FAST__LOAD_FAST, &&TARGET_STORE_FAST__STORE_FAST, &&TARGET_STORE_SUBSCR_ADAPTIVE, @@ -253,6 +254,5 @@ static void *opcode_targets[256] = { &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, - &&_unknown_opcode, &&TARGET_DO_TRACING }; From 9cda4fcd71cb5967a34886c997a78072016611a5 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 2 Nov 2022 11:27:05 +0000 Subject: [PATCH 2/7] Wrap async generators and generator expressions in handler for Stop[Async]Iteration. --- Lib/test/test_dis.py | 16 +++++++- Lib/test/test_sys.py | 2 +- Objects/genobject.c | 22 ++--------- Python/ceval.c | 3 ++ Python/compile.c | 94 +++++++++++++++++++++++++++----------------- 5 files changed, 80 insertions(+), 57 deletions(-) diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index baa22092b6d031..6215a4a8460384 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -545,10 +545,12 @@ async def _asyncwith(c): RERAISE 1 >> LOAD_ERROR 1 CHECK_EXC_MATCH - POP_JUMP_IF_FALSE 8 (to 140) + POP_JUMP_IF_FALSE 10 (to 144) + PUSH_EXC_INFO LOAD_ERROR 2 LOAD_CONST 3 ('coroutine raised StopIteration') CALL 0 + SWAP 2 RAISE_VARARGS 2 >> RERAISE 1 ExceptionTable: @@ -710,6 +712,18 @@ def foo(x): JUMP_BACKWARD 9 (to 8) >> END_FOR RETURN_VALUE + >> LOAD_ERROR 1 + CHECK_EXC_MATCH + POP_JUMP_IF_FALSE 10 (to 56) + PUSH_EXC_INFO + LOAD_ERROR 2 + LOAD_CONST 1 ('generator raised StopIteration') + CALL 0 + SWAP 2 + RAISE_VARARGS 2 + >> RERAISE 1 +ExceptionTable: +1 row """ % (dis_nested_1, __file__, _h.__code__.co_firstlineno + 3, diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index 7bf84df5d23c92..8e228b010c8107 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -1439,7 +1439,7 @@ def bar(cls): check(bar, size('PP')) # generator def get_gen(): yield 1 - check(get_gen(), size('P2P4P4c7P2ic??4P')) + check(get_gen(), size('P2P4P4c7P2ic??5P')) # iterator check(iter('abc'), size('lP')) # callable-iterator diff --git a/Objects/genobject.c b/Objects/genobject.c index ad4fbed6d8d579..5e535817155058 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -247,25 +247,9 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult, } } else { - if (PyErr_ExceptionMatches(PyExc_StopIteration)) { - const char *msg = "generator raised StopIteration"; - if (PyCoro_CheckExact(gen)) { - msg = "coroutine raised StopIteration"; - } - else if (PyAsyncGen_CheckExact(gen)) { - msg = "async generator raised StopIteration"; - } - _PyErr_FormatFromCause(PyExc_RuntimeError, "%s", msg); - } - else if (PyAsyncGen_CheckExact(gen) && - PyErr_ExceptionMatches(PyExc_StopAsyncIteration)) - { - /* code in `gen` raised a StopAsyncIteration error: - raise a RuntimeError. - */ - const char *msg = "async generator raised StopAsyncIteration"; - _PyErr_FormatFromCause(PyExc_RuntimeError, "%s", msg); - } + assert(!PyErr_ExceptionMatches(PyExc_StopIteration)); + assert(!PyAsyncGen_CheckExact(gen) || + !PyErr_ExceptionMatches(PyExc_StopAsyncIteration)); } /* generator can't be rerun, so release the frame */ diff --git a/Python/ceval.c b/Python/ceval.c index 5e62cd5ff91723..476928171c785d 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2187,6 +2187,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int case 2: value = PyExc_RuntimeError; break; + case 3: + value = PyExc_StopAsyncIteration; + break; default: Py_UNREACHABLE(); } diff --git a/Python/compile.c b/Python/compile.c index 388bd8905b6ee8..64b24d5ce3b3fd 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -2568,22 +2568,42 @@ compiler_check_debug_args(struct compiler *c, arguments_ty args) return 1; } +static inline int +insert_instruction(basicblock *block, int pos, struct instr *instr) { + if (basicblock_next_instr(block) < 0) { + return -1; + } + for (int i = block->b_iused - 1; i > pos; i--) { + block->b_instr[i] = block->b_instr[i-1]; + } + block->b_instr[pos] = *instr; + return 0; +} + static int -coroutine_stopiteration_handler(struct compiler *c, jump_target_label *handler) +wrap_in_stopiteration_handler(struct compiler *c) { - ADDOP_LOAD_CONST(c, NO_LOCATION, Py_None); - ADDOP(c, NO_LOCATION, RETURN_VALUE); - if (cfg_builder_use_label(CFG_BUILDER(c), *handler) < 0) { - return 0; - } - jump_target_label other = cfg_new_label(CFG_BUILDER(c)); - if (!IS_LABEL(other)) { + NEW_JUMP_TARGET_LABEL(c, handler); + NEW_JUMP_TARGET_LABEL(c, next); + + /* Insert SETUP_CLEANUP at start */ + struct instr setup = { + .i_opcode = SETUP_CLEANUP, + .i_oparg = handler.id, + .i_loc = NO_LOCATION, + .i_target = NULL, + }; + if (insert_instruction(c->u->u_cfg_builder.g_entryblock, 0, &setup)) { return 0; } - USE_LABEL(c, *handler); + + ADDOP_LOAD_CONST(c, NO_LOCATION, Py_None); + ADDOP(c, NO_LOCATION, RETURN_VALUE); + USE_LABEL(c, handler); ADDOP_I(c, NO_LOCATION, LOAD_ERROR, 1); // StopIteration ADDOP(c, NO_LOCATION, CHECK_EXC_MATCH); - ADDOP_JUMP(c, NO_LOCATION, POP_JUMP_IF_FALSE, other); + ADDOP_JUMP(c, NO_LOCATION, POP_JUMP_IF_FALSE, next); + ADDOP(c, NO_LOCATION, PUSH_EXC_INFO); ADDOP_I(c, NO_LOCATION, LOAD_ERROR, 2); // RuntimeError const char *msg = c->u->u_ste->ste_coroutine ? (c->u->u_ste->ste_generator ? @@ -2597,9 +2617,31 @@ coroutine_stopiteration_handler(struct compiler *c, jump_target_label *handler) } ADDOP_LOAD_CONST_NEW(c, NO_LOCATION, message); ADDOP_I(c, NO_LOCATION, CALL, 0); + ADDOP_I(c, NO_LOCATION, SWAP, 2); ADDOP_I(c, NO_LOCATION, RAISE_VARARGS, 2); - USE_LABEL(c, other); + USE_LABEL(c, next); + if (c->u->u_ste->ste_coroutine && + c->u->u_ste->ste_generator) + { + NEW_JUMP_TARGET_LABEL(c, next); + ADDOP_I(c, NO_LOCATION, LOAD_ERROR, 3); // StopAsyncIteration + ADDOP(c, NO_LOCATION, CHECK_EXC_MATCH); + ADDOP_JUMP(c, NO_LOCATION, POP_JUMP_IF_FALSE, next); + ADDOP(c, NO_LOCATION, PUSH_EXC_INFO); + ADDOP_I(c, NO_LOCATION, LOAD_ERROR, 2); // RuntimeError + const char *msg = "async generator raised StopAsyncIteration"; + PyObject *message = _PyUnicode_FromASCII(msg, strlen(msg)); + if (message == NULL) { + return 0; + } + ADDOP_LOAD_CONST_NEW(c, NO_LOCATION, message); + ADDOP_I(c, NO_LOCATION, CALL, 0); + ADDOP_I(c, NO_LOCATION, SWAP, 2); + ADDOP_I(c, NO_LOCATION, RAISE_VARARGS, 2); + + USE_LABEL(c, next); + } ADDOP_I(c, NO_LOCATION, RERAISE, 1); return 1; } @@ -2669,17 +2711,6 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async) return 0; } - bool is_coro = (c->u->u_ste->ste_coroutine || c->u->u_ste->ste_generator); - jump_target_label handler; - if (is_coro) { - handler = cfg_new_label(CFG_BUILDER(c)); - if (!IS_LABEL(handler)) { - compiler_exit_scope(c); - return 0; - } - ADDOP_JUMP(c, NO_LOCATION, SETUP_CLEANUP, handler); - } - /* if not -OO mode, add docstring */ if (c->c_optimize < 2) { docstring = _PyAST_GetDocString(body); @@ -2695,8 +2726,8 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async) for (i = docstring ? 1 : 0; i < asdl_seq_LEN(body); i++) { VISIT_IN_SCOPE(c, stmt, (stmt_ty)asdl_seq_GET(body, i)); } - if (is_coro) { - if (!coroutine_stopiteration_handler(c, &handler)) { + if (c->u->u_ste->ste_coroutine || c->u->u_ste->ste_generator) { + if (!wrap_in_stopiteration_handler(c)) { compiler_exit_scope(c); return 0; } @@ -5542,6 +5573,9 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, if (type != COMP_GENEXP) { ADDOP(c, LOC(e), RETURN_VALUE); } + if (!wrap_in_stopiteration_handler(c)) { + goto error_in_scope; + } co = assemble(c, 1); qualname = c->u->u_qualname; @@ -8606,18 +8640,6 @@ build_cellfixedoffsets(struct compiler *c) return fixed; } -static inline int -insert_instruction(basicblock *block, int pos, struct instr *instr) { - if (basicblock_next_instr(block) < 0) { - return -1; - } - for (int i = block->b_iused - 1; i > pos; i--) { - block->b_instr[i] = block->b_instr[i-1]; - } - block->b_instr[pos] = *instr; - return 0; -} - static int insert_prefix_instructions(struct compiler *c, basicblock *entryblock, int *fixed, int nfreevars, int code_flags) From 194722704577eab0849d17cd6c3d3b2157d81fcf Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 2 Nov 2022 13:20:28 +0000 Subject: [PATCH 3/7] Add custom instruction for converting StopIteration into RuntimeError. --- Include/internal/pycore_opcode.h | 24 ++++----- Include/opcode.h | 77 ++++++++++++++-------------- Lib/importlib/_bootstrap_external.py | 4 +- Lib/opcode.py | 2 + Lib/test/test_dis.py | 26 +--------- Lib/test/test_sys.py | 2 +- Python/ceval.c | 42 +++++++++++++++ Python/compile.c | 53 +++---------------- Python/opcode_targets.h | 22 ++++---- 9 files changed, 118 insertions(+), 134 deletions(-) diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index cbd72d8510c497..193abd6545875e 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -208,6 +208,7 @@ const uint8_t _PyOpcode_Deopt[256] = { [SETUP_ANNOTATIONS] = SETUP_ANNOTATIONS, [SET_ADD] = SET_ADD, [SET_UPDATE] = SET_UPDATE, + [STOPITERATION_ERROR] = STOPITERATION_ERROR, [STORE_ATTR] = STORE_ATTR, [STORE_ATTR_ADAPTIVE] = STORE_ATTR, [STORE_ATTR_INSTANCE_VALUE] = STORE_ATTR, @@ -305,30 +306,30 @@ static const char *const _PyOpcode_OpName[263] = { [STORE_SUBSCR] = "STORE_SUBSCR", [DELETE_SUBSCR] = "DELETE_SUBSCR", [COMPARE_OP_INT_JUMP] = "COMPARE_OP_INT_JUMP", + [STOPITERATION_ERROR] = "STOPITERATION_ERROR", [COMPARE_OP_STR_JUMP] = "COMPARE_OP_STR_JUMP", [EXTENDED_ARG_QUICK] = "EXTENDED_ARG_QUICK", [FOR_ITER_ADAPTIVE] = "FOR_ITER_ADAPTIVE", [FOR_ITER_LIST] = "FOR_ITER_LIST", - [FOR_ITER_RANGE] = "FOR_ITER_RANGE", [GET_ITER] = "GET_ITER", [GET_YIELD_FROM_ITER] = "GET_YIELD_FROM_ITER", [PRINT_EXPR] = "PRINT_EXPR", [LOAD_BUILD_CLASS] = "LOAD_BUILD_CLASS", + [FOR_ITER_RANGE] = "FOR_ITER_RANGE", [JUMP_BACKWARD_QUICK] = "JUMP_BACKWARD_QUICK", - [LOAD_ATTR_ADAPTIVE] = "LOAD_ATTR_ADAPTIVE", [LOAD_ASSERTION_ERROR] = "LOAD_ASSERTION_ERROR", [RETURN_GENERATOR] = "RETURN_GENERATOR", + [LOAD_ATTR_ADAPTIVE] = "LOAD_ATTR_ADAPTIVE", [LOAD_ATTR_CLASS] = "LOAD_ATTR_CLASS", [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = "LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN", [LOAD_ATTR_INSTANCE_VALUE] = "LOAD_ATTR_INSTANCE_VALUE", [LOAD_ATTR_MODULE] = "LOAD_ATTR_MODULE", [LOAD_ATTR_PROPERTY] = "LOAD_ATTR_PROPERTY", - [LOAD_ATTR_SLOT] = "LOAD_ATTR_SLOT", [LIST_TO_TUPLE] = "LIST_TO_TUPLE", [RETURN_VALUE] = "RETURN_VALUE", [IMPORT_STAR] = "IMPORT_STAR", [SETUP_ANNOTATIONS] = "SETUP_ANNOTATIONS", - [LOAD_ATTR_WITH_HINT] = "LOAD_ATTR_WITH_HINT", + [LOAD_ATTR_SLOT] = "LOAD_ATTR_SLOT", [ASYNC_GEN_WRAP] = "ASYNC_GEN_WRAP", [PREP_RERAISE_STAR] = "PREP_RERAISE_STAR", [POP_EXCEPT] = "POP_EXCEPT", @@ -355,7 +356,7 @@ static const char *const _PyOpcode_OpName[263] = { [JUMP_FORWARD] = "JUMP_FORWARD", [JUMP_IF_FALSE_OR_POP] = "JUMP_IF_FALSE_OR_POP", [JUMP_IF_TRUE_OR_POP] = "JUMP_IF_TRUE_OR_POP", - [LOAD_ATTR_METHOD_LAZY_DICT] = "LOAD_ATTR_METHOD_LAZY_DICT", + [LOAD_ATTR_WITH_HINT] = "LOAD_ATTR_WITH_HINT", [POP_JUMP_IF_FALSE] = "POP_JUMP_IF_FALSE", [POP_JUMP_IF_TRUE] = "POP_JUMP_IF_TRUE", [LOAD_GLOBAL] = "LOAD_GLOBAL", @@ -363,7 +364,7 @@ static const char *const _PyOpcode_OpName[263] = { [CONTAINS_OP] = "CONTAINS_OP", [RERAISE] = "RERAISE", [COPY] = "COPY", - [LOAD_ATTR_METHOD_NO_DICT] = "LOAD_ATTR_METHOD_NO_DICT", + [LOAD_ATTR_METHOD_LAZY_DICT] = "LOAD_ATTR_METHOD_LAZY_DICT", [BINARY_OP] = "BINARY_OP", [SEND] = "SEND", [LOAD_FAST] = "LOAD_FAST", @@ -385,7 +386,7 @@ static const char *const _PyOpcode_OpName[263] = { [JUMP_BACKWARD] = "JUMP_BACKWARD", [LOAD_ERROR] = "LOAD_ERROR", [CALL_FUNCTION_EX] = "CALL_FUNCTION_EX", - [LOAD_ATTR_METHOD_WITH_DICT] = "LOAD_ATTR_METHOD_WITH_DICT", + [LOAD_ATTR_METHOD_NO_DICT] = "LOAD_ATTR_METHOD_NO_DICT", [EXTENDED_ARG] = "EXTENDED_ARG", [LIST_APPEND] = "LIST_APPEND", [SET_ADD] = "SET_ADD", @@ -395,26 +396,27 @@ static const char *const _PyOpcode_OpName[263] = { [YIELD_VALUE] = "YIELD_VALUE", [RESUME] = "RESUME", [MATCH_CLASS] = "MATCH_CLASS", + [LOAD_ATTR_METHOD_WITH_DICT] = "LOAD_ATTR_METHOD_WITH_DICT", [LOAD_ATTR_METHOD_WITH_VALUES] = "LOAD_ATTR_METHOD_WITH_VALUES", - [LOAD_CONST__LOAD_FAST] = "LOAD_CONST__LOAD_FAST", [FORMAT_VALUE] = "FORMAT_VALUE", [BUILD_CONST_KEY_MAP] = "BUILD_CONST_KEY_MAP", [BUILD_STRING] = "BUILD_STRING", + [LOAD_CONST__LOAD_FAST] = "LOAD_CONST__LOAD_FAST", [LOAD_FAST__LOAD_CONST] = "LOAD_FAST__LOAD_CONST", [LOAD_FAST__LOAD_FAST] = "LOAD_FAST__LOAD_FAST", [LOAD_GLOBAL_ADAPTIVE] = "LOAD_GLOBAL_ADAPTIVE", - [LOAD_GLOBAL_BUILTIN] = "LOAD_GLOBAL_BUILTIN", [LIST_EXTEND] = "LIST_EXTEND", [SET_UPDATE] = "SET_UPDATE", [DICT_MERGE] = "DICT_MERGE", [DICT_UPDATE] = "DICT_UPDATE", + [LOAD_GLOBAL_BUILTIN] = "LOAD_GLOBAL_BUILTIN", [LOAD_GLOBAL_MODULE] = "LOAD_GLOBAL_MODULE", [RESUME_QUICK] = "RESUME_QUICK", [STORE_ATTR_ADAPTIVE] = "STORE_ATTR_ADAPTIVE", [STORE_ATTR_INSTANCE_VALUE] = "STORE_ATTR_INSTANCE_VALUE", - [STORE_ATTR_SLOT] = "STORE_ATTR_SLOT", [CALL] = "CALL", [KW_NAMES] = "KW_NAMES", + [STORE_ATTR_SLOT] = "STORE_ATTR_SLOT", [STORE_ATTR_WITH_HINT] = "STORE_ATTR_WITH_HINT", [STORE_FAST__LOAD_FAST] = "STORE_FAST__LOAD_FAST", [STORE_FAST__STORE_FAST] = "STORE_FAST__STORE_FAST", @@ -425,7 +427,6 @@ static const char *const _PyOpcode_OpName[263] = { [UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST", [UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE", [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE", - [183] = "<183>", [184] = "<184>", [185] = "<185>", [186] = "<186>", @@ -509,7 +510,6 @@ static const char *const _PyOpcode_OpName[263] = { #endif #define EXTRA_CASES \ - case 183: \ case 184: \ case 185: \ case 186: \ diff --git a/Include/opcode.h b/Include/opcode.h index 96b761aa178710..c5b4cabcb18e52 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -36,6 +36,7 @@ extern "C" { #define CLEANUP_THROW 55 #define STORE_SUBSCR 60 #define DELETE_SUBSCR 61 +#define STOPITERATION_ERROR 63 #define GET_ITER 68 #define GET_YIELD_FROM_ITER 69 #define PRINT_EXPR 70 @@ -163,44 +164,44 @@ extern "C" { #define COMPARE_OP_ADAPTIVE 58 #define COMPARE_OP_FLOAT_JUMP 59 #define COMPARE_OP_INT_JUMP 62 -#define COMPARE_OP_STR_JUMP 63 -#define EXTENDED_ARG_QUICK 64 -#define FOR_ITER_ADAPTIVE 65 -#define FOR_ITER_LIST 66 -#define FOR_ITER_RANGE 67 -#define JUMP_BACKWARD_QUICK 72 -#define LOAD_ATTR_ADAPTIVE 73 -#define LOAD_ATTR_CLASS 76 -#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 77 -#define LOAD_ATTR_INSTANCE_VALUE 78 -#define LOAD_ATTR_MODULE 79 -#define LOAD_ATTR_PROPERTY 80 -#define LOAD_ATTR_SLOT 81 -#define LOAD_ATTR_WITH_HINT 86 -#define LOAD_ATTR_METHOD_LAZY_DICT 113 -#define LOAD_ATTR_METHOD_NO_DICT 121 -#define LOAD_ATTR_METHOD_WITH_DICT 143 -#define LOAD_ATTR_METHOD_WITH_VALUES 153 -#define LOAD_CONST__LOAD_FAST 154 -#define LOAD_FAST__LOAD_CONST 158 -#define LOAD_FAST__LOAD_FAST 159 -#define LOAD_GLOBAL_ADAPTIVE 160 -#define LOAD_GLOBAL_BUILTIN 161 -#define LOAD_GLOBAL_MODULE 166 -#define RESUME_QUICK 167 -#define STORE_ATTR_ADAPTIVE 168 -#define STORE_ATTR_INSTANCE_VALUE 169 -#define STORE_ATTR_SLOT 170 -#define STORE_ATTR_WITH_HINT 173 -#define STORE_FAST__LOAD_FAST 174 -#define STORE_FAST__STORE_FAST 175 -#define STORE_SUBSCR_ADAPTIVE 176 -#define STORE_SUBSCR_DICT 177 -#define STORE_SUBSCR_LIST_INT 178 -#define UNPACK_SEQUENCE_ADAPTIVE 179 -#define UNPACK_SEQUENCE_LIST 180 -#define UNPACK_SEQUENCE_TUPLE 181 -#define UNPACK_SEQUENCE_TWO_TUPLE 182 +#define COMPARE_OP_STR_JUMP 64 +#define EXTENDED_ARG_QUICK 65 +#define FOR_ITER_ADAPTIVE 66 +#define FOR_ITER_LIST 67 +#define FOR_ITER_RANGE 72 +#define JUMP_BACKWARD_QUICK 73 +#define LOAD_ATTR_ADAPTIVE 76 +#define LOAD_ATTR_CLASS 77 +#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 78 +#define LOAD_ATTR_INSTANCE_VALUE 79 +#define LOAD_ATTR_MODULE 80 +#define LOAD_ATTR_PROPERTY 81 +#define LOAD_ATTR_SLOT 86 +#define LOAD_ATTR_WITH_HINT 113 +#define LOAD_ATTR_METHOD_LAZY_DICT 121 +#define LOAD_ATTR_METHOD_NO_DICT 143 +#define LOAD_ATTR_METHOD_WITH_DICT 153 +#define LOAD_ATTR_METHOD_WITH_VALUES 154 +#define LOAD_CONST__LOAD_FAST 158 +#define LOAD_FAST__LOAD_CONST 159 +#define LOAD_FAST__LOAD_FAST 160 +#define LOAD_GLOBAL_ADAPTIVE 161 +#define LOAD_GLOBAL_BUILTIN 166 +#define LOAD_GLOBAL_MODULE 167 +#define RESUME_QUICK 168 +#define STORE_ATTR_ADAPTIVE 169 +#define STORE_ATTR_INSTANCE_VALUE 170 +#define STORE_ATTR_SLOT 173 +#define STORE_ATTR_WITH_HINT 174 +#define STORE_FAST__LOAD_FAST 175 +#define STORE_FAST__STORE_FAST 176 +#define STORE_SUBSCR_ADAPTIVE 177 +#define STORE_SUBSCR_DICT 178 +#define STORE_SUBSCR_LIST_INT 179 +#define UNPACK_SEQUENCE_ADAPTIVE 180 +#define UNPACK_SEQUENCE_LIST 181 +#define UNPACK_SEQUENCE_TUPLE 182 +#define UNPACK_SEQUENCE_TWO_TUPLE 183 #define DO_TRACING 255 #define HAS_ARG(op) ((((op) >= HAVE_ARGUMENT) && (!IS_PSEUDO_OPCODE(op)))\ diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 86fc93d58a4285..8d2e04a72f17c9 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -424,9 +424,7 @@ def _write_atomic(path, data, mode=0o666): # Python 3.12a1 3508 (Add CLEANUP_THROW) # Python 3.12a1 3509 (Conditional jumps only jump forward) # Python 3.12a1 3510 (FOR_ITER leaves iterator on the stack) - - -# Python 3.12a1 3514 (Add LOAD_ERROR instruction) +# Python 3.12a1 3511 (Add STOPITERATION_ERROR instruction) # Python 3.13 will start with 3550 diff --git a/Lib/opcode.py b/Lib/opcode.py index c2cdf058054604..86706563eb9756 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -111,6 +111,8 @@ def pseudo_op(name, op, real_ops): def_op('STORE_SUBSCR', 60) def_op('DELETE_SUBSCR', 61) +def_op('STOPITERATION_ERROR', 63) + def_op('GET_ITER', 68) def_op('GET_YIELD_FROM_ITER', 69) def_op('PRINT_EXPR', 70) diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index 6215a4a8460384..613ed1a29ea8eb 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -543,16 +543,8 @@ async def _asyncwith(c): >> COPY 3 POP_EXCEPT RERAISE 1 - >> LOAD_ERROR 1 - CHECK_EXC_MATCH - POP_JUMP_IF_FALSE 10 (to 144) - PUSH_EXC_INFO - LOAD_ERROR 2 - LOAD_CONST 3 ('coroutine raised StopIteration') - CALL 0 - SWAP 2 - RAISE_VARARGS 2 - >> RERAISE 1 + >> STOPITERATION_ERROR + RERAISE 1 ExceptionTable: 12 rows """ % (_asyncwith.__code__.co_firstlineno, @@ -712,18 +704,6 @@ def foo(x): JUMP_BACKWARD 9 (to 8) >> END_FOR RETURN_VALUE - >> LOAD_ERROR 1 - CHECK_EXC_MATCH - POP_JUMP_IF_FALSE 10 (to 56) - PUSH_EXC_INFO - LOAD_ERROR 2 - LOAD_CONST 1 ('generator raised StopIteration') - CALL 0 - SWAP 2 - RAISE_VARARGS 2 - >> RERAISE 1 -ExceptionTable: -1 row """ % (dis_nested_1, __file__, _h.__code__.co_firstlineno + 3, @@ -1278,7 +1258,6 @@ def f(c=c): Constants: 0: None 1: - 2: 'generator raised StopIteration' Variable names: 0: a 1: b @@ -1385,7 +1364,6 @@ async def async_def(): Constants: 0: None 1: 1 - 2: 'coroutine raised StopIteration' Names: 0: b 1: c diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index 8e228b010c8107..2403c7c815f2c0 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -1439,7 +1439,7 @@ def bar(cls): check(bar, size('PP')) # generator def get_gen(): yield 1 - check(get_gen(), size('P2P4P4c7P2ic??5P')) + check(get_gen(), size('P2P4P4c7P2ic??2P')) # iterator check(iter('abc'), size('lP')) # callable-iterator diff --git a/Python/ceval.c b/Python/ceval.c index 476928171c785d..68fb69f2b9a363 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2198,6 +2198,48 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int DISPATCH(); } + TARGET(STOPITERATION_ERROR) { + assert(frame->owner == FRAME_OWNED_BY_GENERATOR); + PyObject *exc = TOP(); + assert(PyExceptionInstance_Check(exc)); + const char *msg = NULL; + if (PyErr_GivenExceptionMatches(exc, PyExc_StopIteration)) { + msg = "generator raised StopIteration"; + if (frame->f_code->co_flags & CO_ASYNC_GENERATOR) { + msg = "async generator raised StopIteration"; + } + else if (frame->f_code->co_flags & CO_COROUTINE) { + msg = "coroutine raised StopIteration"; + } + } + else if ((frame->f_code->co_flags & CO_ASYNC_GENERATOR) && + PyErr_GivenExceptionMatches(exc, PyExc_StopAsyncIteration)) + { + /* code in `gen` raised a StopAsyncIteration error: + raise a RuntimeError. + */ + msg = "async generator raised StopAsyncIteration"; + } + if (msg != NULL) { + PyObject *message = _PyUnicode_FromASCII(msg, strlen(msg)); + if (message == NULL) { + goto error; + } + PyObject *error = PyObject_CallOneArg(PyExc_RuntimeError, message); + if (error == NULL) { + Py_DECREF(message); + goto error; + } + assert(PyExceptionInstance_Check(error)); + SET_TOP(error); + PyException_SetCause(error, exc); + Py_INCREF(exc); + PyException_SetContext(error, exc); + Py_DECREF(message); + } + DISPATCH(); + } + TARGET(LOAD_ASSERTION_ERROR) { PyObject *value = PyExc_AssertionError; Py_INCREF(value); diff --git a/Python/compile.c b/Python/compile.c index 64b24d5ce3b3fd..9c63008fcf4770 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -1176,6 +1176,9 @@ stack_effect(int opcode, int oparg, int jump) * if an exception be raised. */ return jump ? 1 : 0; + case STOPITERATION_ERROR: + return 0; + case PREP_RERAISE_STAR: return -1; case RERAISE: @@ -2584,7 +2587,6 @@ static int wrap_in_stopiteration_handler(struct compiler *c) { NEW_JUMP_TARGET_LABEL(c, handler); - NEW_JUMP_TARGET_LABEL(c, next); /* Insert SETUP_CLEANUP at start */ struct instr setup = { @@ -2600,48 +2602,7 @@ wrap_in_stopiteration_handler(struct compiler *c) ADDOP_LOAD_CONST(c, NO_LOCATION, Py_None); ADDOP(c, NO_LOCATION, RETURN_VALUE); USE_LABEL(c, handler); - ADDOP_I(c, NO_LOCATION, LOAD_ERROR, 1); // StopIteration - ADDOP(c, NO_LOCATION, CHECK_EXC_MATCH); - ADDOP_JUMP(c, NO_LOCATION, POP_JUMP_IF_FALSE, next); - ADDOP(c, NO_LOCATION, PUSH_EXC_INFO); - ADDOP_I(c, NO_LOCATION, LOAD_ERROR, 2); // RuntimeError - const char *msg = c->u->u_ste->ste_coroutine ? - (c->u->u_ste->ste_generator ? - "async generator raised StopIteration" : - "coroutine raised StopIteration" - ) : - "generator raised StopIteration"; - PyObject *message = _PyUnicode_FromASCII(msg, strlen(msg)); - if (message == NULL) { - return 0; - } - ADDOP_LOAD_CONST_NEW(c, NO_LOCATION, message); - ADDOP_I(c, NO_LOCATION, CALL, 0); - ADDOP_I(c, NO_LOCATION, SWAP, 2); - ADDOP_I(c, NO_LOCATION, RAISE_VARARGS, 2); - - USE_LABEL(c, next); - if (c->u->u_ste->ste_coroutine && - c->u->u_ste->ste_generator) - { - NEW_JUMP_TARGET_LABEL(c, next); - ADDOP_I(c, NO_LOCATION, LOAD_ERROR, 3); // StopAsyncIteration - ADDOP(c, NO_LOCATION, CHECK_EXC_MATCH); - ADDOP_JUMP(c, NO_LOCATION, POP_JUMP_IF_FALSE, next); - ADDOP(c, NO_LOCATION, PUSH_EXC_INFO); - ADDOP_I(c, NO_LOCATION, LOAD_ERROR, 2); // RuntimeError - const char *msg = "async generator raised StopAsyncIteration"; - PyObject *message = _PyUnicode_FromASCII(msg, strlen(msg)); - if (message == NULL) { - return 0; - } - ADDOP_LOAD_CONST_NEW(c, NO_LOCATION, message); - ADDOP_I(c, NO_LOCATION, CALL, 0); - ADDOP_I(c, NO_LOCATION, SWAP, 2); - ADDOP_I(c, NO_LOCATION, RAISE_VARARGS, 2); - - USE_LABEL(c, next); - } + ADDOP(c, NO_LOCATION, STOPITERATION_ERROR); ADDOP_I(c, NO_LOCATION, RERAISE, 1); return 1; } @@ -5573,8 +5534,10 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, if (type != COMP_GENEXP) { ADDOP(c, LOC(e), RETURN_VALUE); } - if (!wrap_in_stopiteration_handler(c)) { - goto error_in_scope; + if (type == COMP_GENEXP) { + if (!wrap_in_stopiteration_handler(c)) { + goto error_in_scope; + } } co = assemble(c, 1); diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index 33358873012f64..9d5f764ed16c5d 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -62,30 +62,30 @@ static void *opcode_targets[256] = { &&TARGET_STORE_SUBSCR, &&TARGET_DELETE_SUBSCR, &&TARGET_COMPARE_OP_INT_JUMP, + &&TARGET_STOPITERATION_ERROR, &&TARGET_COMPARE_OP_STR_JUMP, &&TARGET_EXTENDED_ARG_QUICK, &&TARGET_FOR_ITER_ADAPTIVE, &&TARGET_FOR_ITER_LIST, - &&TARGET_FOR_ITER_RANGE, &&TARGET_GET_ITER, &&TARGET_GET_YIELD_FROM_ITER, &&TARGET_PRINT_EXPR, &&TARGET_LOAD_BUILD_CLASS, + &&TARGET_FOR_ITER_RANGE, &&TARGET_JUMP_BACKWARD_QUICK, - &&TARGET_LOAD_ATTR_ADAPTIVE, &&TARGET_LOAD_ASSERTION_ERROR, &&TARGET_RETURN_GENERATOR, + &&TARGET_LOAD_ATTR_ADAPTIVE, &&TARGET_LOAD_ATTR_CLASS, &&TARGET_LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN, &&TARGET_LOAD_ATTR_INSTANCE_VALUE, &&TARGET_LOAD_ATTR_MODULE, &&TARGET_LOAD_ATTR_PROPERTY, - &&TARGET_LOAD_ATTR_SLOT, &&TARGET_LIST_TO_TUPLE, &&TARGET_RETURN_VALUE, &&TARGET_IMPORT_STAR, &&TARGET_SETUP_ANNOTATIONS, - &&TARGET_LOAD_ATTR_WITH_HINT, + &&TARGET_LOAD_ATTR_SLOT, &&TARGET_ASYNC_GEN_WRAP, &&TARGET_PREP_RERAISE_STAR, &&TARGET_POP_EXCEPT, @@ -112,7 +112,7 @@ static void *opcode_targets[256] = { &&TARGET_JUMP_FORWARD, &&TARGET_JUMP_IF_FALSE_OR_POP, &&TARGET_JUMP_IF_TRUE_OR_POP, - &&TARGET_LOAD_ATTR_METHOD_LAZY_DICT, + &&TARGET_LOAD_ATTR_WITH_HINT, &&TARGET_POP_JUMP_IF_FALSE, &&TARGET_POP_JUMP_IF_TRUE, &&TARGET_LOAD_GLOBAL, @@ -120,7 +120,7 @@ static void *opcode_targets[256] = { &&TARGET_CONTAINS_OP, &&TARGET_RERAISE, &&TARGET_COPY, - &&TARGET_LOAD_ATTR_METHOD_NO_DICT, + &&TARGET_LOAD_ATTR_METHOD_LAZY_DICT, &&TARGET_BINARY_OP, &&TARGET_SEND, &&TARGET_LOAD_FAST, @@ -142,7 +142,7 @@ static void *opcode_targets[256] = { &&TARGET_JUMP_BACKWARD, &&TARGET_LOAD_ERROR, &&TARGET_CALL_FUNCTION_EX, - &&TARGET_LOAD_ATTR_METHOD_WITH_DICT, + &&TARGET_LOAD_ATTR_METHOD_NO_DICT, &&TARGET_EXTENDED_ARG, &&TARGET_LIST_APPEND, &&TARGET_SET_ADD, @@ -152,26 +152,27 @@ static void *opcode_targets[256] = { &&TARGET_YIELD_VALUE, &&TARGET_RESUME, &&TARGET_MATCH_CLASS, + &&TARGET_LOAD_ATTR_METHOD_WITH_DICT, &&TARGET_LOAD_ATTR_METHOD_WITH_VALUES, - &&TARGET_LOAD_CONST__LOAD_FAST, &&TARGET_FORMAT_VALUE, &&TARGET_BUILD_CONST_KEY_MAP, &&TARGET_BUILD_STRING, + &&TARGET_LOAD_CONST__LOAD_FAST, &&TARGET_LOAD_FAST__LOAD_CONST, &&TARGET_LOAD_FAST__LOAD_FAST, &&TARGET_LOAD_GLOBAL_ADAPTIVE, - &&TARGET_LOAD_GLOBAL_BUILTIN, &&TARGET_LIST_EXTEND, &&TARGET_SET_UPDATE, &&TARGET_DICT_MERGE, &&TARGET_DICT_UPDATE, + &&TARGET_LOAD_GLOBAL_BUILTIN, &&TARGET_LOAD_GLOBAL_MODULE, &&TARGET_RESUME_QUICK, &&TARGET_STORE_ATTR_ADAPTIVE, &&TARGET_STORE_ATTR_INSTANCE_VALUE, - &&TARGET_STORE_ATTR_SLOT, &&TARGET_CALL, &&TARGET_KW_NAMES, + &&TARGET_STORE_ATTR_SLOT, &&TARGET_STORE_ATTR_WITH_HINT, &&TARGET_STORE_FAST__LOAD_FAST, &&TARGET_STORE_FAST__STORE_FAST, @@ -253,6 +254,5 @@ static void *opcode_targets[256] = { &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, - &&_unknown_opcode, &&TARGET_DO_TRACING }; From f86c5e464fed4e7732d9798071639d727cdf6813 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 2 Nov 2022 13:22:17 +0000 Subject: [PATCH 4/7] Remove LOAD_ERROR instruction. --- Include/internal/pycore_opcode.h | 14 +++++----- Include/opcode.h | 47 ++++++++++++++++---------------- Lib/opcode.py | 2 +- Python/ceval.c | 23 ---------------- Python/compile.c | 1 - Python/opcode_targets.h | 12 ++++---- 6 files changed, 37 insertions(+), 62 deletions(-) diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index 193abd6545875e..3b61c25b19d3d4 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -170,7 +170,6 @@ const uint8_t _PyOpcode_Deopt[256] = { [LOAD_CONST] = LOAD_CONST, [LOAD_CONST__LOAD_FAST] = LOAD_CONST, [LOAD_DEREF] = LOAD_DEREF, - [LOAD_ERROR] = LOAD_ERROR, [LOAD_FAST] = LOAD_FAST, [LOAD_FAST_CHECK] = LOAD_FAST_CHECK, [LOAD_FAST__LOAD_CONST] = LOAD_FAST, @@ -384,9 +383,9 @@ static const char *const _PyOpcode_OpName[263] = { [STORE_DEREF] = "STORE_DEREF", [DELETE_DEREF] = "DELETE_DEREF", [JUMP_BACKWARD] = "JUMP_BACKWARD", - [LOAD_ERROR] = "LOAD_ERROR", - [CALL_FUNCTION_EX] = "CALL_FUNCTION_EX", [LOAD_ATTR_METHOD_NO_DICT] = "LOAD_ATTR_METHOD_NO_DICT", + [CALL_FUNCTION_EX] = "CALL_FUNCTION_EX", + [LOAD_ATTR_METHOD_WITH_DICT] = "LOAD_ATTR_METHOD_WITH_DICT", [EXTENDED_ARG] = "EXTENDED_ARG", [LIST_APPEND] = "LIST_APPEND", [SET_ADD] = "SET_ADD", @@ -396,27 +395,26 @@ static const char *const _PyOpcode_OpName[263] = { [YIELD_VALUE] = "YIELD_VALUE", [RESUME] = "RESUME", [MATCH_CLASS] = "MATCH_CLASS", - [LOAD_ATTR_METHOD_WITH_DICT] = "LOAD_ATTR_METHOD_WITH_DICT", [LOAD_ATTR_METHOD_WITH_VALUES] = "LOAD_ATTR_METHOD_WITH_VALUES", + [LOAD_CONST__LOAD_FAST] = "LOAD_CONST__LOAD_FAST", [FORMAT_VALUE] = "FORMAT_VALUE", [BUILD_CONST_KEY_MAP] = "BUILD_CONST_KEY_MAP", [BUILD_STRING] = "BUILD_STRING", - [LOAD_CONST__LOAD_FAST] = "LOAD_CONST__LOAD_FAST", [LOAD_FAST__LOAD_CONST] = "LOAD_FAST__LOAD_CONST", [LOAD_FAST__LOAD_FAST] = "LOAD_FAST__LOAD_FAST", [LOAD_GLOBAL_ADAPTIVE] = "LOAD_GLOBAL_ADAPTIVE", + [LOAD_GLOBAL_BUILTIN] = "LOAD_GLOBAL_BUILTIN", [LIST_EXTEND] = "LIST_EXTEND", [SET_UPDATE] = "SET_UPDATE", [DICT_MERGE] = "DICT_MERGE", [DICT_UPDATE] = "DICT_UPDATE", - [LOAD_GLOBAL_BUILTIN] = "LOAD_GLOBAL_BUILTIN", [LOAD_GLOBAL_MODULE] = "LOAD_GLOBAL_MODULE", [RESUME_QUICK] = "RESUME_QUICK", [STORE_ATTR_ADAPTIVE] = "STORE_ATTR_ADAPTIVE", [STORE_ATTR_INSTANCE_VALUE] = "STORE_ATTR_INSTANCE_VALUE", + [STORE_ATTR_SLOT] = "STORE_ATTR_SLOT", [CALL] = "CALL", [KW_NAMES] = "KW_NAMES", - [STORE_ATTR_SLOT] = "STORE_ATTR_SLOT", [STORE_ATTR_WITH_HINT] = "STORE_ATTR_WITH_HINT", [STORE_FAST__LOAD_FAST] = "STORE_FAST__LOAD_FAST", [STORE_FAST__STORE_FAST] = "STORE_FAST__STORE_FAST", @@ -427,6 +425,7 @@ static const char *const _PyOpcode_OpName[263] = { [UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST", [UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE", [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE", + [183] = "<183>", [184] = "<184>", [185] = "<185>", [186] = "<186>", @@ -510,6 +509,7 @@ static const char *const _PyOpcode_OpName[263] = { #endif #define EXTRA_CASES \ + case 183: \ case 184: \ case 185: \ case 186: \ diff --git a/Include/opcode.h b/Include/opcode.h index c5b4cabcb18e52..a5aa0867826584 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -100,7 +100,6 @@ extern "C" { #define STORE_DEREF 138 #define DELETE_DEREF 139 #define JUMP_BACKWARD 140 -#define LOAD_ERROR 141 #define CALL_FUNCTION_EX 142 #define EXTENDED_ARG 144 #define LIST_APPEND 145 @@ -179,29 +178,29 @@ extern "C" { #define LOAD_ATTR_SLOT 86 #define LOAD_ATTR_WITH_HINT 113 #define LOAD_ATTR_METHOD_LAZY_DICT 121 -#define LOAD_ATTR_METHOD_NO_DICT 143 -#define LOAD_ATTR_METHOD_WITH_DICT 153 -#define LOAD_ATTR_METHOD_WITH_VALUES 154 -#define LOAD_CONST__LOAD_FAST 158 -#define LOAD_FAST__LOAD_CONST 159 -#define LOAD_FAST__LOAD_FAST 160 -#define LOAD_GLOBAL_ADAPTIVE 161 -#define LOAD_GLOBAL_BUILTIN 166 -#define LOAD_GLOBAL_MODULE 167 -#define RESUME_QUICK 168 -#define STORE_ATTR_ADAPTIVE 169 -#define STORE_ATTR_INSTANCE_VALUE 170 -#define STORE_ATTR_SLOT 173 -#define STORE_ATTR_WITH_HINT 174 -#define STORE_FAST__LOAD_FAST 175 -#define STORE_FAST__STORE_FAST 176 -#define STORE_SUBSCR_ADAPTIVE 177 -#define STORE_SUBSCR_DICT 178 -#define STORE_SUBSCR_LIST_INT 179 -#define UNPACK_SEQUENCE_ADAPTIVE 180 -#define UNPACK_SEQUENCE_LIST 181 -#define UNPACK_SEQUENCE_TUPLE 182 -#define UNPACK_SEQUENCE_TWO_TUPLE 183 +#define LOAD_ATTR_METHOD_NO_DICT 141 +#define LOAD_ATTR_METHOD_WITH_DICT 143 +#define LOAD_ATTR_METHOD_WITH_VALUES 153 +#define LOAD_CONST__LOAD_FAST 154 +#define LOAD_FAST__LOAD_CONST 158 +#define LOAD_FAST__LOAD_FAST 159 +#define LOAD_GLOBAL_ADAPTIVE 160 +#define LOAD_GLOBAL_BUILTIN 161 +#define LOAD_GLOBAL_MODULE 166 +#define RESUME_QUICK 167 +#define STORE_ATTR_ADAPTIVE 168 +#define STORE_ATTR_INSTANCE_VALUE 169 +#define STORE_ATTR_SLOT 170 +#define STORE_ATTR_WITH_HINT 173 +#define STORE_FAST__LOAD_FAST 174 +#define STORE_FAST__STORE_FAST 175 +#define STORE_SUBSCR_ADAPTIVE 176 +#define STORE_SUBSCR_DICT 177 +#define STORE_SUBSCR_LIST_INT 178 +#define UNPACK_SEQUENCE_ADAPTIVE 179 +#define UNPACK_SEQUENCE_LIST 180 +#define UNPACK_SEQUENCE_TUPLE 181 +#define UNPACK_SEQUENCE_TWO_TUPLE 182 #define DO_TRACING 255 #define HAS_ARG(op) ((((op) >= HAVE_ARGUMENT) && (!IS_PSEUDO_OPCODE(op)))\ diff --git a/Lib/opcode.py b/Lib/opcode.py index 86706563eb9756..7a2862547b1e60 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -192,7 +192,7 @@ def pseudo_op(name, op, real_ops): def_op('DELETE_DEREF', 139) hasfree.append(139) jrel_op('JUMP_BACKWARD', 140) # Number of words to skip (backwards) -def_op('LOAD_ERROR', 141) + def_op('CALL_FUNCTION_EX', 142) # Flags def_op('EXTENDED_ARG', 144) diff --git a/Python/ceval.c b/Python/ceval.c index 68fb69f2b9a363..26b4c906fd95b9 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2175,29 +2175,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int goto exception_unwind; } - TARGET(LOAD_ERROR) { - PyObject *value; - switch(oparg) { - case 0: - value = PyExc_AssertionError; - break; - case 1: - value = PyExc_StopIteration; - break; - case 2: - value = PyExc_RuntimeError; - break; - case 3: - value = PyExc_StopAsyncIteration; - break; - default: - Py_UNREACHABLE(); - } - Py_INCREF(value); - PUSH(value); - DISPATCH(); - } - TARGET(STOPITERATION_ERROR) { assert(frame->owner == FRAME_OWNED_BY_GENERATOR); PyObject *exc = TOP(); diff --git a/Python/compile.c b/Python/compile.c index 9c63008fcf4770..3613d41b2b99e5 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -1257,7 +1257,6 @@ stack_effect(int opcode, int oparg, int jump) return (oparg & FVS_MASK) == FVS_HAVE_SPEC ? -1 : 0; case LOAD_METHOD: return 1; - case LOAD_ERROR: case LOAD_ASSERTION_ERROR: return 1; case LIST_TO_TUPLE: diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index 9d5f764ed16c5d..58d12b8685feab 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -140,9 +140,9 @@ static void *opcode_targets[256] = { &&TARGET_STORE_DEREF, &&TARGET_DELETE_DEREF, &&TARGET_JUMP_BACKWARD, - &&TARGET_LOAD_ERROR, - &&TARGET_CALL_FUNCTION_EX, &&TARGET_LOAD_ATTR_METHOD_NO_DICT, + &&TARGET_CALL_FUNCTION_EX, + &&TARGET_LOAD_ATTR_METHOD_WITH_DICT, &&TARGET_EXTENDED_ARG, &&TARGET_LIST_APPEND, &&TARGET_SET_ADD, @@ -152,27 +152,26 @@ static void *opcode_targets[256] = { &&TARGET_YIELD_VALUE, &&TARGET_RESUME, &&TARGET_MATCH_CLASS, - &&TARGET_LOAD_ATTR_METHOD_WITH_DICT, &&TARGET_LOAD_ATTR_METHOD_WITH_VALUES, + &&TARGET_LOAD_CONST__LOAD_FAST, &&TARGET_FORMAT_VALUE, &&TARGET_BUILD_CONST_KEY_MAP, &&TARGET_BUILD_STRING, - &&TARGET_LOAD_CONST__LOAD_FAST, &&TARGET_LOAD_FAST__LOAD_CONST, &&TARGET_LOAD_FAST__LOAD_FAST, &&TARGET_LOAD_GLOBAL_ADAPTIVE, + &&TARGET_LOAD_GLOBAL_BUILTIN, &&TARGET_LIST_EXTEND, &&TARGET_SET_UPDATE, &&TARGET_DICT_MERGE, &&TARGET_DICT_UPDATE, - &&TARGET_LOAD_GLOBAL_BUILTIN, &&TARGET_LOAD_GLOBAL_MODULE, &&TARGET_RESUME_QUICK, &&TARGET_STORE_ATTR_ADAPTIVE, &&TARGET_STORE_ATTR_INSTANCE_VALUE, + &&TARGET_STORE_ATTR_SLOT, &&TARGET_CALL, &&TARGET_KW_NAMES, - &&TARGET_STORE_ATTR_SLOT, &&TARGET_STORE_ATTR_WITH_HINT, &&TARGET_STORE_FAST__LOAD_FAST, &&TARGET_STORE_FAST__STORE_FAST, @@ -254,5 +253,6 @@ static void *opcode_targets[256] = { &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, + &&_unknown_opcode, &&TARGET_DO_TRACING }; From 7e74daa4fa6b2ac5c05f1ccd4e8a1d3fc3317800 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 2 Nov 2022 14:40:00 +0000 Subject: [PATCH 5/7] Document new instruction --- Doc/library/dis.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 1eaa9f32442deb..30bbf95be63417 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -607,6 +607,15 @@ the original TOS1. .. versionadded:: 3.12 +.. opcode:: STOPITERATION_ERROR + + Handles a StopIteration raised in a generator or coroutine. + If TOS is an instance of :exc:`StopIteration`, or :exc:`StopAsyncIteration` + replace it with a :exc:`RuntimeError`. + + .. versionadded:: 3.12 + + .. opcode:: BEFORE_ASYNC_WITH Resolves ``__aenter__`` and ``__aexit__`` from the object on top of the From 089ddcb6393b84256fd3bc788c770c53399d69a7 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 2 Nov 2022 14:42:46 +0000 Subject: [PATCH 6/7] Add news --- .../2022-11-02-14-42-35.gh-issue-96793.q0Oi74.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-11-02-14-42-35.gh-issue-96793.q0Oi74.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-11-02-14-42-35.gh-issue-96793.q0Oi74.rst b/Misc/NEWS.d/next/Core and Builtins/2022-11-02-14-42-35.gh-issue-96793.q0Oi74.rst new file mode 100644 index 00000000000000..0a4b4913061013 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-11-02-14-42-35.gh-issue-96793.q0Oi74.rst @@ -0,0 +1,2 @@ +Handle StopIteration and StopAsyncIteration raised in generator or +coroutines in the bytecode, rather than in wrapping C code. From 13cf7e2a28a597631b8e8694ed14b342f5ef602f Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 2 Nov 2022 14:44:32 +0000 Subject: [PATCH 7/7] Fix magic number --- Lib/importlib/_bootstrap_external.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 8d2e04a72f17c9..8cbc962cfa56f0 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -437,7 +437,7 @@ def _write_atomic(path, data, mode=0o666): # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array # in PC/launcher.c must also be updated. -MAGIC_NUMBER = (3514).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3511).to_bytes(2, 'little') + b'\r\n' _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c