From c05c2af6db2cdc3bb89d9ee3fd479e87ba5869ba Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Fri, 1 Apr 2022 16:52:44 -0700 Subject: [PATCH 01/10] Use a virtual try/except to handle close()/throw() --- Include/internal/pycore_global_strings.h | 1 + Include/internal/pycore_runtime_init.h | 1 + Lib/test/test_dis.py | 6 +++-- Objects/exceptions.c | 28 +++++++++++++-------- Objects/genobject.c | 23 +---------------- Python/ceval.c | 3 +++ Python/compile.c | 32 ++++++++++++++++++------ Tools/scripts/deepfreeze.py | 4 +++ Tools/scripts/umarshal.py | 2 ++ 9 files changed, 58 insertions(+), 42 deletions(-) diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index 3e533fd16509f3..71fab5d710c9ac 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -344,6 +344,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(top) STRUCT_FOR_ID(truncate) STRUCT_FOR_ID(unraisablehook) + STRUCT_FOR_ID(value) STRUCT_FOR_ID(values) STRUCT_FOR_ID(version) STRUCT_FOR_ID(warnings) diff --git a/Include/internal/pycore_runtime_init.h b/Include/internal/pycore_runtime_init.h index d5690d83a0482b..545d73aeaa69fb 100644 --- a/Include/internal/pycore_runtime_init.h +++ b/Include/internal/pycore_runtime_init.h @@ -967,6 +967,7 @@ extern "C" { INIT_ID(top), \ INIT_ID(truncate), \ INIT_ID(unraisablehook), \ + INIT_ID(value), \ INIT_ID(values), \ INIT_ID(version), \ INIT_ID(warnings), \ diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index 16bfee188e0461..665c1a4867989b 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -1023,9 +1023,11 @@ async def async_def(): Constants: 0: None 1: 1 + 2: Names: - 0: b - 1: c + 0: value + 1: b + 2: c Variable names: 0: a 1: d""" diff --git a/Objects/exceptions.c b/Objects/exceptions.c index 9dbbd40f1de1c4..f0e91159fcb4dc 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -585,17 +585,23 @@ StopIteration_traverse(PyStopIterationObject *self, visitproc visit, void *arg) return BaseException_traverse((PyBaseExceptionObject *)self, visit, arg); } -ComplexExtendsException( - PyExc_Exception, /* base */ - StopIteration, /* name */ - StopIteration, /* prefix for *_init, etc */ - 0, /* new */ - 0, /* methods */ - StopIteration_members, /* members */ - 0, /* getset */ - 0, /* str */ - "Signal the end from iterator.__next__()." -); +// Don't use ComplexExtendsException for this, since deepfreeze doesn't work if +// the type is static: +PyTypeObject _PyExc_StopIteration = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "StopIteration", + .tp_basicsize = sizeof(PyStopIterationObject), + .tp_dealloc = (destructor)StopIteration_dealloc, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, + .tp_doc = PyDoc_STR("Signal the end from iterator.__next__()."), + .tp_traverse = (traverseproc)StopIteration_traverse, + .tp_clear = (inquiry)StopIteration_clear, + .tp_members = StopIteration_members, + .tp_base = &_PyExc_Exception, + .tp_dictoffset = offsetof(PyStopIterationObject, dict), + .tp_init = (initproc)StopIteration_init, +}; +PyObject *PyExc_StopIteration = (PyObject *)&_PyExc_StopIteration; /* diff --git a/Objects/genobject.c b/Objects/genobject.c index f071390d6d32bb..a6258a1c67aff2 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -478,28 +478,7 @@ _gen_throw(PyGenObject *gen, int close_on_genexit, } Py_DECREF(yf); if (!ret) { - PyObject *val; - /* Pop subiterator from stack */ - assert(gen->gi_frame_state < FRAME_CLEARED); - ret = _PyFrame_StackPop((_PyInterpreterFrame *)gen->gi_iframe); - assert(ret == yf); - Py_DECREF(ret); - // XXX: Performing this jump ourselves is awkward and problematic. - // See https://github.com/python/cpython/pull/31968. - /* Termination repetition of SEND loop */ - assert(frame->f_lasti >= 0); - _Py_CODEUNIT *code = _PyCode_CODE(gen->gi_code); - /* Backup to SEND */ - frame->f_lasti--; - assert(_Py_OPCODE(code[frame->f_lasti]) == SEND); - int jump = _Py_OPARG(code[frame->f_lasti]); - frame->f_lasti += jump; - if (_PyGen_FetchStopIterationValue(&val) == 0) { - ret = gen_send(gen, val); - Py_DECREF(val); - } else { - ret = gen_send_ex(gen, Py_None, 1, 0); - } + ret = gen_send_ex(gen, Py_None, 1, 0); } return ret; } diff --git a/Python/ceval.c b/Python/ceval.c index a7b377724bb548..7a761aafa9ab17 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2580,6 +2580,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int } TARGET(YIELD_VALUE) { + // NOTE: It's important that YIELD_VALUE never raises an exception! + // The compiler treats *anything* raised here as part of a close() + // or throw() call. assert(frame->is_entry); PyObject *retval = POP(); _PyFrame_GetGenerator(frame)->gi_frame_state = FRAME_SUSPENDED; diff --git a/Python/compile.c b/Python/compile.c index 06edcf1810e640..c99492e22eb8f6 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -1875,19 +1875,37 @@ compiler_call_exit_with_nones(struct compiler *c) { static int compiler_add_yield_from(struct compiler *c, int await) { - basicblock *start, *resume, *exit; - start = compiler_new_block(c); - resume = compiler_new_block(c); - exit = compiler_new_block(c); - if (start == NULL || resume == NULL || exit == NULL) { - return 0; - } + basicblock *start, *resume, *stopiter, *error, *exit; + RETURN_IF_FALSE(start = compiler_new_block(c)); + RETURN_IF_FALSE(resume = compiler_new_block(c)); + RETURN_IF_FALSE(stopiter = compiler_new_block(c)); + RETURN_IF_FALSE(error = compiler_new_block(c)); + RETURN_IF_FALSE(exit = compiler_new_block(c)); + compiler_use_next_block(c, start); ADDOP_JUMP(c, SEND, exit); compiler_use_next_block(c, resume); + // Set up a virtual try/except to handle StopIteration raised during a + // close() or throw(): + ADDOP_JUMP(c, SETUP_FINALLY, stopiter); + RETURN_IF_FALSE(compiler_push_fblock(c, TRY_EXCEPT, resume, NULL, NULL)); + // The only way YIELD_VALUE can raise is if close() or throw() raises: ADDOP(c, YIELD_VALUE); + compiler_pop_fblock(c, TRY_EXCEPT, resume); + ADDOP_NOLINE(c, POP_BLOCK); ADDOP_I(c, RESUME, await ? 3 : 2); ADDOP_JUMP(c, JUMP_NO_INTERRUPT, start); + compiler_use_next_block(c, stopiter); + ADDOP_LOAD_CONST(c, PyExc_StopIteration); // StopIteration is marshallable! + ADDOP_JUMP(c, JUMP_IF_NOT_EXC_MATCH, error); + // StopIteration was raised. Push the return value and continue execution: + ADDOP_NAME(c, LOAD_ATTR, &_Py_ID(value), names); + ADDOP_I(c, SWAP, 3); + ADDOP(c, POP_TOP); + ADDOP(c, POP_TOP); + ADDOP_JUMP(c, JUMP_FORWARD, exit); + compiler_use_next_block(c, error); + ADDOP_I(c, RERAISE, 0); compiler_use_next_block(c, exit); return 1; } diff --git a/Tools/scripts/deepfreeze.py b/Tools/scripts/deepfreeze.py index dfa4b3a8eeb011..aeb1ddce7e1fa9 100644 --- a/Tools/scripts/deepfreeze.py +++ b/Tools/scripts/deepfreeze.py @@ -117,6 +117,8 @@ def __init__(self, file: TextIO) -> None: self.write('#include "internal/pycore_code.h"') self.write('#include "internal/pycore_long.h"') self.write("") + self.write("extern PyTypeObject _PyExc_StopIteration;") + self.write("") @contextlib.contextmanager def indent(self) -> None: @@ -404,6 +406,8 @@ def generate(self, name: str, obj: object) -> str: return "Py_Ellipsis" elif obj is None: return "Py_None" + elif obj is StopIteration: + return "(PyObject *)&_PyExc_StopIteration" else: raise TypeError( f"Cannot generate code for {type(obj).__name__} object") diff --git a/Tools/scripts/umarshal.py b/Tools/scripts/umarshal.py index 2eaaa7ce2d95bc..366eaaafef835e 100644 --- a/Tools/scripts/umarshal.py +++ b/Tools/scripts/umarshal.py @@ -298,6 +298,8 @@ def R_REF(obj: Any) -> Any: retval = self.refs[n] assert retval is not None return retval + elif type == Type.STOPITER: + return StopIteration else: breakpoint() raise AssertionError(f"Unknown type {type} {chr(type)!r}") From d557e418c3b63427bf2ca090bc339ffc61b17d4a Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Thu, 5 May 2022 20:38:07 -0700 Subject: [PATCH 02/10] Don't load StopIteration as a constant --- Doc/library/dis.rst | 10 ++++++---- Include/internal/pycore_opcode.h | 16 ++++++++-------- Include/opcode.h | 22 +++++++++++----------- Lib/dis.py | 3 +++ Lib/importlib/_bootstrap_external.py | 8 +++++--- Lib/opcode.py | 3 +-- Lib/test/test_dis.py | 3 +-- Objects/codeobject.c | 4 ++-- Objects/exceptions.c | 28 +++++++++++----------------- Python/ceval.c | 5 +++-- Python/compile.c | 7 +++---- Python/opcode_targets.h | 12 ++++++------ Tools/scripts/deepfreeze.py | 4 ---- Tools/scripts/umarshal.py | 2 -- 14 files changed, 60 insertions(+), 67 deletions(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 08e6c736d3e3c9..8bdd1259dfb304 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -671,12 +671,14 @@ iterations of the loop. Exception representation on the stack now consist of one, not three, items. -.. opcode:: LOAD_ASSERTION_ERROR +.. opcode:: LOAD_EXCEPTION_TYPE (type) - Pushes :exc:`AssertionError` onto the stack. Used by the :keyword:`assert` - statement. + Pushes an exception type onto the stack, depending on the value of *type*: - .. versionadded:: 3.9 + * ``0``: :exc:`AssertionError` + * ``1``: :exc:`StopIteration` + + .. versionadded:: 3.11 .. opcode:: LOAD_BUILD_CLASS diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index 09f65014671338..5fc7ed1ab42eb3 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -130,7 +130,6 @@ const uint8_t _PyOpcode_Deopt[256] = { [LIST_APPEND] = LIST_APPEND, [LIST_EXTEND] = LIST_EXTEND, [LIST_TO_TUPLE] = LIST_TO_TUPLE, - [LOAD_ASSERTION_ERROR] = LOAD_ASSERTION_ERROR, [LOAD_ATTR] = LOAD_ATTR, [LOAD_ATTR_ADAPTIVE] = LOAD_ATTR, [LOAD_ATTR_INSTANCE_VALUE] = LOAD_ATTR, @@ -143,6 +142,7 @@ const uint8_t _PyOpcode_Deopt[256] = { [LOAD_CONST] = LOAD_CONST, [LOAD_CONST__LOAD_FAST] = LOAD_CONST, [LOAD_DEREF] = LOAD_DEREF, + [LOAD_EXCEPTION_TYPE] = LOAD_EXCEPTION_TYPE, [LOAD_FAST] = LOAD_FAST, [LOAD_FAST__LOAD_CONST] = LOAD_FAST, [LOAD_FAST__LOAD_FAST] = LOAD_FAST, @@ -314,7 +314,6 @@ const uint8_t _PyOpcode_Original[256] = { [LIST_APPEND] = LIST_APPEND, [LIST_EXTEND] = LIST_EXTEND, [LIST_TO_TUPLE] = LIST_TO_TUPLE, - [LOAD_ASSERTION_ERROR] = LOAD_ASSERTION_ERROR, [LOAD_ATTR] = LOAD_ATTR, [LOAD_ATTR_ADAPTIVE] = LOAD_ATTR, [LOAD_ATTR_INSTANCE_VALUE] = LOAD_ATTR, @@ -327,6 +326,7 @@ const uint8_t _PyOpcode_Original[256] = { [LOAD_CONST] = LOAD_CONST, [LOAD_CONST__LOAD_FAST] = LOAD_CONST, [LOAD_DEREF] = LOAD_DEREF, + [LOAD_EXCEPTION_TYPE] = LOAD_EXCEPTION_TYPE, [LOAD_FAST] = LOAD_FAST, [LOAD_FAST__LOAD_CONST] = LOAD_FAST, [LOAD_FAST__LOAD_FAST] = LOAD_FAST, @@ -499,14 +499,14 @@ static const char *const _PyOpcode_OpName[256] = { [LOAD_BUILD_CLASS] = "LOAD_BUILD_CLASS", [PRECALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = "PRECALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS", [PRECALL_NO_KW_BUILTIN_FAST] = "PRECALL_NO_KW_BUILTIN_FAST", - [LOAD_ASSERTION_ERROR] = "LOAD_ASSERTION_ERROR", - [RETURN_GENERATOR] = "RETURN_GENERATOR", [PRECALL_NO_KW_BUILTIN_O] = "PRECALL_NO_KW_BUILTIN_O", + [RETURN_GENERATOR] = "RETURN_GENERATOR", [PRECALL_NO_KW_ISINSTANCE] = "PRECALL_NO_KW_ISINSTANCE", [PRECALL_NO_KW_LEN] = "PRECALL_NO_KW_LEN", [PRECALL_NO_KW_LIST_APPEND] = "PRECALL_NO_KW_LIST_APPEND", [PRECALL_NO_KW_METHOD_DESCRIPTOR_FAST] = "PRECALL_NO_KW_METHOD_DESCRIPTOR_FAST", [PRECALL_NO_KW_METHOD_DESCRIPTOR_NOARGS] = "PRECALL_NO_KW_METHOD_DESCRIPTOR_NOARGS", + [PRECALL_NO_KW_METHOD_DESCRIPTOR_O] = "PRECALL_NO_KW_METHOD_DESCRIPTOR_O", [LIST_TO_TUPLE] = "LIST_TO_TUPLE", [RETURN_VALUE] = "RETURN_VALUE", [IMPORT_STAR] = "IMPORT_STAR", @@ -538,7 +538,7 @@ static const char *const _PyOpcode_OpName[256] = { [JUMP_FORWARD] = "JUMP_FORWARD", [JUMP_IF_FALSE_OR_POP] = "JUMP_IF_FALSE_OR_POP", [JUMP_IF_TRUE_OR_POP] = "JUMP_IF_TRUE_OR_POP", - [PRECALL_NO_KW_METHOD_DESCRIPTOR_O] = "PRECALL_NO_KW_METHOD_DESCRIPTOR_O", + [PRECALL_NO_KW_STR_1] = "PRECALL_NO_KW_STR_1", [POP_JUMP_FORWARD_IF_FALSE] = "POP_JUMP_FORWARD_IF_FALSE", [POP_JUMP_FORWARD_IF_TRUE] = "POP_JUMP_FORWARD_IF_TRUE", [LOAD_GLOBAL] = "LOAD_GLOBAL", @@ -546,13 +546,13 @@ static const char *const _PyOpcode_OpName[256] = { [CONTAINS_OP] = "CONTAINS_OP", [RERAISE] = "RERAISE", [COPY] = "COPY", - [PRECALL_NO_KW_STR_1] = "PRECALL_NO_KW_STR_1", + [PRECALL_NO_KW_TUPLE_1] = "PRECALL_NO_KW_TUPLE_1", [BINARY_OP] = "BINARY_OP", [SEND] = "SEND", [LOAD_FAST] = "LOAD_FAST", [STORE_FAST] = "STORE_FAST", [DELETE_FAST] = "DELETE_FAST", - [PRECALL_NO_KW_TUPLE_1] = "PRECALL_NO_KW_TUPLE_1", + [PRECALL_NO_KW_TYPE_1] = "PRECALL_NO_KW_TYPE_1", [POP_JUMP_FORWARD_IF_NOT_NONE] = "POP_JUMP_FORWARD_IF_NOT_NONE", [POP_JUMP_FORWARD_IF_NONE] = "POP_JUMP_FORWARD_IF_NONE", [RAISE_VARARGS] = "RAISE_VARARGS", @@ -566,7 +566,7 @@ static const char *const _PyOpcode_OpName[256] = { [STORE_DEREF] = "STORE_DEREF", [DELETE_DEREF] = "DELETE_DEREF", [JUMP_BACKWARD] = "JUMP_BACKWARD", - [PRECALL_NO_KW_TYPE_1] = "PRECALL_NO_KW_TYPE_1", + [LOAD_EXCEPTION_TYPE] = "LOAD_EXCEPTION_TYPE", [CALL_FUNCTION_EX] = "CALL_FUNCTION_EX", [PRECALL_PYFUNC] = "PRECALL_PYFUNC", [EXTENDED_ARG] = "EXTENDED_ARG", diff --git a/Include/opcode.h b/Include/opcode.h index 084d34b8c73cd5..aed8380a8efb65 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -36,7 +36,6 @@ extern "C" { #define GET_YIELD_FROM_ITER 69 #define PRINT_EXPR 70 #define LOAD_BUILD_CLASS 71 -#define LOAD_ASSERTION_ERROR 74 #define RETURN_GENERATOR 75 #define LIST_TO_TUPLE 82 #define RETURN_VALUE 83 @@ -95,6 +94,7 @@ extern "C" { #define STORE_DEREF 138 #define DELETE_DEREF 139 #define JUMP_BACKWARD 140 +#define LOAD_EXCEPTION_TYPE 141 #define CALL_FUNCTION_EX 142 #define EXTENDED_ARG 144 #define LIST_APPEND 145 @@ -165,16 +165,16 @@ extern "C" { #define PRECALL_BUILTIN_FAST_WITH_KEYWORDS 67 #define PRECALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 72 #define PRECALL_NO_KW_BUILTIN_FAST 73 -#define PRECALL_NO_KW_BUILTIN_O 76 -#define PRECALL_NO_KW_ISINSTANCE 77 -#define PRECALL_NO_KW_LEN 78 -#define PRECALL_NO_KW_LIST_APPEND 79 -#define PRECALL_NO_KW_METHOD_DESCRIPTOR_FAST 80 -#define PRECALL_NO_KW_METHOD_DESCRIPTOR_NOARGS 81 -#define PRECALL_NO_KW_METHOD_DESCRIPTOR_O 113 -#define PRECALL_NO_KW_STR_1 121 -#define PRECALL_NO_KW_TUPLE_1 127 -#define PRECALL_NO_KW_TYPE_1 141 +#define PRECALL_NO_KW_BUILTIN_O 74 +#define PRECALL_NO_KW_ISINSTANCE 76 +#define PRECALL_NO_KW_LEN 77 +#define PRECALL_NO_KW_LIST_APPEND 78 +#define PRECALL_NO_KW_METHOD_DESCRIPTOR_FAST 79 +#define PRECALL_NO_KW_METHOD_DESCRIPTOR_NOARGS 80 +#define PRECALL_NO_KW_METHOD_DESCRIPTOR_O 81 +#define PRECALL_NO_KW_STR_1 113 +#define PRECALL_NO_KW_TUPLE_1 121 +#define PRECALL_NO_KW_TYPE_1 127 #define PRECALL_PYFUNC 143 #define RESUME_QUICK 150 #define STORE_ATTR_ADAPTIVE 153 diff --git a/Lib/dis.py b/Lib/dis.py index c0e5367afb55a3..68a0ec2331a8c9 100644 --- a/Lib/dis.py +++ b/Lib/dis.py @@ -31,6 +31,7 @@ LOAD_GLOBAL = opmap['LOAD_GLOBAL'] BINARY_OP = opmap['BINARY_OP'] JUMP_BACKWARD = opmap['JUMP_BACKWARD'] +LOAD_EXCEPTION_TYPE = opmap['LOAD_EXCEPTION_TYPE'] CACHE = opmap["CACHE"] @@ -491,6 +492,8 @@ def _get_instructions_bytes(code, varname_from_oparg=None, if arg & (1< at 0x..., file "%s", line %d>) MAKE_FUNCTION 0 LOAD_FAST 0 (x) @@ -1171,7 +1171,6 @@ async def async_def(): Constants: 0: None 1: 1 - 2: Names: 0: value 1: b diff --git a/Objects/codeobject.c b/Objects/codeobject.c index c2b29be1fe8693..5ed21aab0209d2 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -628,8 +628,8 @@ PyCode_New(int argcount, int kwonlyargcount, } static const char assert0[4] = { - LOAD_ASSERTION_ERROR, - 0, + LOAD_EXCEPTION_TYPE, + 0, // AssertionError RAISE_VARARGS, 1 }; diff --git a/Objects/exceptions.c b/Objects/exceptions.c index 50db51000ebe10..cf8258b0e244bb 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -600,23 +600,17 @@ StopIteration_traverse(PyStopIterationObject *self, visitproc visit, void *arg) return BaseException_traverse((PyBaseExceptionObject *)self, visit, arg); } -// Don't use ComplexExtendsException for this, since deepfreeze doesn't work if -// the type is static: -PyTypeObject _PyExc_StopIteration = { - PyVarObject_HEAD_INIT(NULL, 0) - .tp_name = "StopIteration", - .tp_basicsize = sizeof(PyStopIterationObject), - .tp_dealloc = (destructor)StopIteration_dealloc, - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, - .tp_doc = PyDoc_STR("Signal the end from iterator.__next__()."), - .tp_traverse = (traverseproc)StopIteration_traverse, - .tp_clear = (inquiry)StopIteration_clear, - .tp_members = StopIteration_members, - .tp_base = &_PyExc_Exception, - .tp_dictoffset = offsetof(PyStopIterationObject, dict), - .tp_init = (initproc)StopIteration_init, -}; -PyObject *PyExc_StopIteration = (PyObject *)&_PyExc_StopIteration; +ComplexExtendsException( + PyExc_Exception, /* base */ + StopIteration, /* name */ + StopIteration, /* prefix for *_init, etc */ + 0, /* new */ + 0, /* methods */ + StopIteration_members, /* members */ + 0, /* getset */ + 0, /* str */ + "Signal the end from iterator.__next__()." +); /* diff --git a/Python/ceval.c b/Python/ceval.c index 507d9f121ce896..7045a0ed6a0c56 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2778,8 +2778,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int } } - TARGET(LOAD_ASSERTION_ERROR) { - PyObject *value = PyExc_AssertionError; + TARGET(LOAD_EXCEPTION_TYPE) { + assert(oparg < 2); + PyObject *value = oparg ? PyExc_StopIteration: PyExc_AssertionError; Py_INCREF(value); PUSH(value); DISPATCH(); diff --git a/Python/compile.c b/Python/compile.c index ddef79a0ca14b7..7b5d2ba828d1b1 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -1169,7 +1169,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_ASSERTION_ERROR: + case LOAD_EXCEPTION_TYPE: return 1; case LIST_TO_TUPLE: return 0; @@ -1961,7 +1961,6 @@ compiler_add_yield_from(struct compiler *c, int await) RETURN_IF_FALSE(stopiter = compiler_new_block(c)); RETURN_IF_FALSE(error = compiler_new_block(c)); RETURN_IF_FALSE(exit = compiler_new_block(c)); - compiler_use_next_block(c, start); ADDOP_JUMP(c, SEND, exit); compiler_use_next_block(c, resume); @@ -1976,7 +1975,7 @@ compiler_add_yield_from(struct compiler *c, int await) ADDOP_I(c, RESUME, await ? 3 : 2); ADDOP_JUMP(c, JUMP_NO_INTERRUPT, start); compiler_use_next_block(c, stopiter); - ADDOP_LOAD_CONST(c, PyExc_StopIteration); // StopIteration is marshallable! + ADDOP_I(c, LOAD_EXCEPTION_TYPE, 1); // StopIteration ADDOP(c, CHECK_EXC_MATCH); ADDOP_JUMP(c, POP_JUMP_IF_FALSE, error); // StopIteration was raised. Push the return value and continue execution: @@ -4018,7 +4017,7 @@ compiler_assert(struct compiler *c, stmt_ty s) return 0; if (!compiler_jump_if(c, s->v.Assert.test, end, 1)) return 0; - ADDOP(c, LOAD_ASSERTION_ERROR); + ADDOP_I(c, LOAD_EXCEPTION_TYPE, 0); // AssertionError if (s->v.Assert.msg) { VISIT(c, expr, s->v.Assert.msg); ADDOP_I(c, PRECALL, 0); diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index d37c1326247185..6f963783baf20b 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -73,14 +73,14 @@ static void *opcode_targets[256] = { &&TARGET_LOAD_BUILD_CLASS, &&TARGET_PRECALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, &&TARGET_PRECALL_NO_KW_BUILTIN_FAST, - &&TARGET_LOAD_ASSERTION_ERROR, - &&TARGET_RETURN_GENERATOR, &&TARGET_PRECALL_NO_KW_BUILTIN_O, + &&TARGET_RETURN_GENERATOR, &&TARGET_PRECALL_NO_KW_ISINSTANCE, &&TARGET_PRECALL_NO_KW_LEN, &&TARGET_PRECALL_NO_KW_LIST_APPEND, &&TARGET_PRECALL_NO_KW_METHOD_DESCRIPTOR_FAST, &&TARGET_PRECALL_NO_KW_METHOD_DESCRIPTOR_NOARGS, + &&TARGET_PRECALL_NO_KW_METHOD_DESCRIPTOR_O, &&TARGET_LIST_TO_TUPLE, &&TARGET_RETURN_VALUE, &&TARGET_IMPORT_STAR, @@ -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_PRECALL_NO_KW_METHOD_DESCRIPTOR_O, + &&TARGET_PRECALL_NO_KW_STR_1, &&TARGET_POP_JUMP_FORWARD_IF_FALSE, &&TARGET_POP_JUMP_FORWARD_IF_TRUE, &&TARGET_LOAD_GLOBAL, @@ -120,13 +120,13 @@ static void *opcode_targets[256] = { &&TARGET_CONTAINS_OP, &&TARGET_RERAISE, &&TARGET_COPY, - &&TARGET_PRECALL_NO_KW_STR_1, + &&TARGET_PRECALL_NO_KW_TUPLE_1, &&TARGET_BINARY_OP, &&TARGET_SEND, &&TARGET_LOAD_FAST, &&TARGET_STORE_FAST, &&TARGET_DELETE_FAST, - &&TARGET_PRECALL_NO_KW_TUPLE_1, + &&TARGET_PRECALL_NO_KW_TYPE_1, &&TARGET_POP_JUMP_FORWARD_IF_NOT_NONE, &&TARGET_POP_JUMP_FORWARD_IF_NONE, &&TARGET_RAISE_VARARGS, @@ -140,7 +140,7 @@ static void *opcode_targets[256] = { &&TARGET_STORE_DEREF, &&TARGET_DELETE_DEREF, &&TARGET_JUMP_BACKWARD, - &&TARGET_PRECALL_NO_KW_TYPE_1, + &&TARGET_LOAD_EXCEPTION_TYPE, &&TARGET_CALL_FUNCTION_EX, &&TARGET_PRECALL_PYFUNC, &&TARGET_EXTENDED_ARG, diff --git a/Tools/scripts/deepfreeze.py b/Tools/scripts/deepfreeze.py index 7dc7db35c98052..5ee6c2f58e5999 100644 --- a/Tools/scripts/deepfreeze.py +++ b/Tools/scripts/deepfreeze.py @@ -117,8 +117,6 @@ def __init__(self, file: TextIO) -> None: self.write('#include "internal/pycore_code.h"') self.write('#include "internal/pycore_long.h"') self.write("") - self.write("extern PyTypeObject _PyExc_StopIteration;") - self.write("") @contextlib.contextmanager def indent(self) -> None: @@ -404,8 +402,6 @@ def generate(self, name: str, obj: object) -> str: return "Py_Ellipsis" elif obj is None: return "Py_None" - elif obj is StopIteration: - return "(PyObject *)&_PyExc_StopIteration" else: raise TypeError( f"Cannot generate code for {type(obj).__name__} object") diff --git a/Tools/scripts/umarshal.py b/Tools/scripts/umarshal.py index c9c543948c80dc..f61570cbaff751 100644 --- a/Tools/scripts/umarshal.py +++ b/Tools/scripts/umarshal.py @@ -296,8 +296,6 @@ def R_REF(obj: Any) -> Any: retval = self.refs[n] assert retval is not None return retval - elif type == Type.STOPITER: - return StopIteration else: breakpoint() raise AssertionError(f"Unknown type {type} {chr(type)!r}") From d5e033a5d53b912255c801bc6dfb2bb4e46d35c3 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Thu, 5 May 2022 20:52:13 -0700 Subject: [PATCH 03/10] Clean up control flow a bit --- Python/compile.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index 7b5d2ba828d1b1..eee7d75b2df82a 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -1955,18 +1955,18 @@ compiler_call_exit_with_nones(struct compiler *c) { static int compiler_add_yield_from(struct compiler *c, int await) { - basicblock *start, *resume, *stopiter, *error, *exit; + basicblock *start, *resume, *error, *stopiter, *exit; RETURN_IF_FALSE(start = compiler_new_block(c)); RETURN_IF_FALSE(resume = compiler_new_block(c)); - RETURN_IF_FALSE(stopiter = compiler_new_block(c)); RETURN_IF_FALSE(error = compiler_new_block(c)); + RETURN_IF_FALSE(stopiter = compiler_new_block(c)); RETURN_IF_FALSE(exit = compiler_new_block(c)); compiler_use_next_block(c, start); ADDOP_JUMP(c, SEND, exit); compiler_use_next_block(c, resume); // Set up a virtual try/except to handle StopIteration raised during a // close() or throw(): - ADDOP_JUMP(c, SETUP_FINALLY, stopiter); + ADDOP_JUMP(c, SETUP_FINALLY, error); RETURN_IF_FALSE(compiler_push_fblock(c, TRY_EXCEPT, resume, NULL, NULL)); // The only way YIELD_VALUE can raise is if close() or throw() raises: ADDOP(c, YIELD_VALUE); @@ -1974,18 +1974,17 @@ compiler_add_yield_from(struct compiler *c, int await) ADDOP_NOLINE(c, POP_BLOCK); ADDOP_I(c, RESUME, await ? 3 : 2); ADDOP_JUMP(c, JUMP_NO_INTERRUPT, start); - compiler_use_next_block(c, stopiter); + compiler_use_next_block(c, error); ADDOP_I(c, LOAD_EXCEPTION_TYPE, 1); // StopIteration ADDOP(c, CHECK_EXC_MATCH); - ADDOP_JUMP(c, POP_JUMP_IF_FALSE, error); + ADDOP_JUMP(c, POP_JUMP_IF_TRUE, stopiter); + ADDOP_I(c, RERAISE, 0); + compiler_use_next_block(c, stopiter); // StopIteration was raised. Push the return value and continue execution: ADDOP_NAME(c, LOAD_ATTR, &_Py_ID(value), names); ADDOP_I(c, SWAP, 3); ADDOP(c, POP_TOP); ADDOP(c, POP_TOP); - ADDOP_JUMP(c, JUMP, exit); - compiler_use_next_block(c, error); - ADDOP_I(c, RERAISE, 0); compiler_use_next_block(c, exit); return 1; } From 0cb78f205756659349270b4bdbe98f971ce29f20 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Mon, 15 Aug 2022 13:31:14 -0700 Subject: [PATCH 04/10] blurb add --- .../2022-08-15-11-58-05.gh-issue-90997.bWwV8Q.rst | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-08-15-11-58-05.gh-issue-90997.bWwV8Q.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-08-15-11-58-05.gh-issue-90997.bWwV8Q.rst b/Misc/NEWS.d/next/Core and Builtins/2022-08-15-11-58-05.gh-issue-90997.bWwV8Q.rst new file mode 100644 index 00000000000000..8db714e59e1592 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-08-15-11-58-05.gh-issue-90997.bWwV8Q.rst @@ -0,0 +1,3 @@ +Compile virtual :keyword:`try`/:keyword:`except` blocks to handle exceptions +raised during :meth:`~generator.close` or :meth:`~generator.throw` calls +through a suspended frame. From 4b0e60fd60332c5392dc7cb95832bed458b80f57 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Mon, 15 Aug 2022 13:31:34 -0700 Subject: [PATCH 05/10] Improve docs for SEND --- Doc/library/dis.rst | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index d1f58d3825a22b..2df9f0bdbbcec8 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -716,7 +716,7 @@ iterations of the loop. * ``0``: :exc:`AssertionError` * ``1``: :exc:`StopIteration` - .. versionadded:: 3.11 + .. versionadded:: 3.12 .. opcode:: LOAD_BUILD_CLASS @@ -1346,10 +1346,13 @@ iterations of the loop. .. versionadded:: 3.11 -.. opcode:: SEND +.. opcode:: SEND (delta) + + Equivalent to ``TOS = TOS1.send(TOS)``. Used in ``yield from`` and ``await`` + statements. - Sends ``None`` to the sub-generator of this generator. - Used in ``yield from`` and ``await`` statements. + If the call raises :exc:`StopIteration`, pop both values, push its return + value, and increment the bytecode counter by *delta*. .. versionadded:: 3.11 From a0953b13257de36d47ff41af6f8ef5171e63ab25 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Mon, 15 Aug 2022 13:31:40 -0700 Subject: [PATCH 06/10] Cleanup --- Python/compile.c | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index bc3b30a6074c31..eb131030a84ae9 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -1946,35 +1946,36 @@ compiler_call_exit_with_nones(struct compiler *c) { static int compiler_add_yield_from(struct compiler *c, int await) { - NEW_JUMP_TARGET_LABEL(c, start); - NEW_JUMP_TARGET_LABEL(c, resume); - NEW_JUMP_TARGET_LABEL(c, error); - NEW_JUMP_TARGET_LABEL(c, stopiter); + NEW_JUMP_TARGET_LABEL(c, send); + NEW_JUMP_TARGET_LABEL(c, fail); + NEW_JUMP_TARGET_LABEL(c, stop); NEW_JUMP_TARGET_LABEL(c, exit); - USE_LABEL(c, start); + + USE_LABEL(c, send); ADDOP_JUMP(c, SEND, exit); - USE_LABEL(c, resume); - // Set up a virtual try/except to handle StopIteration raised during a - // close() or throw(): - ADDOP_JUMP(c, SETUP_FINALLY, error); - RETURN_IF_FALSE(compiler_push_fblock(c, TRY_EXCEPT, resume, NO_LABEL, NULL)); - // The only way YIELD_VALUE can raise is if close() or throw() raises: + // Set up a virtual try/except to handle when StopIteration is raised during + // a close or throw call. The only way YIELD_VALUE raises if they do! + ADDOP_JUMP(c, SETUP_FINALLY, fail); + RETURN_IF_FALSE(compiler_push_fblock(c, TRY_EXCEPT, send, NO_LABEL, NULL)); ADDOP_I(c, YIELD_VALUE, 0); - compiler_pop_fblock(c, TRY_EXCEPT, resume); + compiler_pop_fblock(c, TRY_EXCEPT, send); ADDOP_NOLINE(c, POP_BLOCK); ADDOP_I(c, RESUME, await ? 3 : 2); - ADDOP_JUMP(c, JUMP_NO_INTERRUPT, start); - USE_LABEL(c, error); + ADDOP_JUMP(c, JUMP_NO_INTERRUPT, send); + + USE_LABEL(c, fail); ADDOP_I(c, LOAD_EXCEPTION_TYPE, 1); // StopIteration ADDOP(c, CHECK_EXC_MATCH); - ADDOP_JUMP(c, POP_JUMP_IF_TRUE, stopiter); + ADDOP_JUMP(c, POP_JUMP_IF_TRUE, stop); ADDOP_I(c, RERAISE, 0); - USE_LABEL(c, stopiter); - // StopIteration was raised. Push the return value and continue execution: + + USE_LABEL(c, stop); + // StopIteration was raised. Push the value and break out of the loop: ADDOP_NAME(c, LOAD_ATTR, &_Py_ID(value), names); ADDOP_I(c, SWAP, 3); - ADDOP(c, POP_TOP); - ADDOP(c, POP_TOP); + ADDOP(c, POP_TOP); // The thing we're yielding from. + ADDOP(c, POP_TOP); // The last sent value + USE_LABEL(c, exit); return 1; } From afdf25e52180da551eb6e42df01629f7407b76f9 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Mon, 15 Aug 2022 15:17:14 -0700 Subject: [PATCH 07/10] fixup --- Python/ceval.c | 2 +- Python/compile.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Python/ceval.c b/Python/ceval.c index 10b9f8846c77f8..5100387eb3efa9 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2751,7 +2751,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int TARGET(LOAD_EXCEPTION_TYPE) { assert(oparg < 2); - PyObject *value = oparg ? PyExc_StopIteration: PyExc_AssertionError; + PyObject *value = oparg ? PyExc_StopIteration : PyExc_AssertionError; Py_INCREF(value); PUSH(value); DISPATCH(); diff --git a/Python/compile.c b/Python/compile.c index eb131030a84ae9..471eb9ca876686 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -1974,7 +1974,7 @@ compiler_add_yield_from(struct compiler *c, int await) ADDOP_NAME(c, LOAD_ATTR, &_Py_ID(value), names); ADDOP_I(c, SWAP, 3); ADDOP(c, POP_TOP); // The thing we're yielding from. - ADDOP(c, POP_TOP); // The last sent value + ADDOP(c, POP_TOP); // The last sent value. USE_LABEL(c, exit); return 1; From 5348cbee031d32f9b7b8cb82770fcac43d408248 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Tue, 16 Aug 2022 22:57:46 -0700 Subject: [PATCH 08/10] Fix wording --- Doc/library/dis.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 2df9f0bdbbcec8..4a064616c00f02 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -1351,8 +1351,9 @@ iterations of the loop. Equivalent to ``TOS = TOS1.send(TOS)``. Used in ``yield from`` and ``await`` statements. - If the call raises :exc:`StopIteration`, pop both values, push its return - value, and increment the bytecode counter by *delta*. + If the call raises :exc:`StopIteration`, pop both items, push the + exception's ``value`` attribute, and increment the bytecode counter by + *delta*. .. versionadded:: 3.11 From f4cc3985ae642b712cf92a4d9ca348cc2fe991a1 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Wed, 17 Aug 2022 12:50:56 -0700 Subject: [PATCH 09/10] Pack everything into END_THROW --- Doc/library/dis.rst | 21 +++++-- Include/internal/pycore_opcode.h | 32 +++++------ Include/opcode.h | 85 ++++++++++++++-------------- Lib/dis.py | 3 - Lib/importlib/_bootstrap_external.py | 2 +- Lib/opcode.py | 4 +- Lib/test/test_dis.py | 46 ++++----------- Objects/codeobject.c | 2 +- Objects/frameobject.c | 7 +-- Python/ceval.c | 25 +++++++- Python/compile.c | 19 ++----- Python/opcode_targets.h | 28 ++++----- 12 files changed, 135 insertions(+), 139 deletions(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 4a064616c00f02..c55d12a6552b97 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -567,6 +567,17 @@ the original TOS1. .. versionchanged:: 3.11 Exception representation on the stack now consist of one, not three, items. + +.. opcode:: END_THROW + + Handles an exception raised during a :meth:`~generator.throw` or + :meth:`~generator.close` call through the current frame. If TOS is an + instance of :exc:`StopIteration`, pop three values from the stack and push + its ``value`` member. Otherwise, re-raise TOS. + + .. versionadded:: 3.12 + + .. opcode:: BEFORE_ASYNC_WITH Resolves ``__aenter__`` and ``__aexit__`` from the object on top of the @@ -709,14 +720,12 @@ iterations of the loop. Exception representation on the stack now consist of one, not three, items. -.. opcode:: LOAD_EXCEPTION_TYPE (type) - - Pushes an exception type onto the stack, depending on the value of *type*: +.. opcode:: LOAD_ASSERTION_ERROR - * ``0``: :exc:`AssertionError` - * ``1``: :exc:`StopIteration` + Pushes :exc:`AssertionError` onto the stack. Used by the :keyword:`assert` + statement. - .. versionadded:: 3.12 + .. versionadded:: 3.9 .. opcode:: LOAD_BUILD_CLASS diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index ba9a3bbb1fc6a3..d7cb58a1096d10 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -121,6 +121,7 @@ const uint8_t _PyOpcode_Deopt[256] = { [DICT_MERGE] = DICT_MERGE, [DICT_UPDATE] = DICT_UPDATE, [END_ASYNC_FOR] = END_ASYNC_FOR, + [END_THROW] = END_THROW, [EXTENDED_ARG] = EXTENDED_ARG, [EXTENDED_ARG_QUICK] = EXTENDED_ARG, [FORMAT_VALUE] = FORMAT_VALUE, @@ -148,6 +149,7 @@ const uint8_t _PyOpcode_Deopt[256] = { [LIST_APPEND] = LIST_APPEND, [LIST_EXTEND] = LIST_EXTEND, [LIST_TO_TUPLE] = LIST_TO_TUPLE, + [LOAD_ASSERTION_ERROR] = LOAD_ASSERTION_ERROR, [LOAD_ATTR] = LOAD_ATTR, [LOAD_ATTR_ADAPTIVE] = LOAD_ATTR, [LOAD_ATTR_CLASS] = LOAD_ATTR, @@ -166,7 +168,6 @@ const uint8_t _PyOpcode_Deopt[256] = { [LOAD_CONST] = LOAD_CONST, [LOAD_CONST__LOAD_FAST] = LOAD_CONST, [LOAD_DEREF] = LOAD_DEREF, - [LOAD_EXCEPTION_TYPE] = LOAD_EXCEPTION_TYPE, [LOAD_FAST] = LOAD_FAST, [LOAD_FAST_CHECK] = LOAD_FAST_CHECK, [LOAD_FAST__LOAD_CONST] = LOAD_FAST, @@ -297,38 +298,38 @@ static const char *const _PyOpcode_OpName[267] = { [BEFORE_ASYNC_WITH] = "BEFORE_ASYNC_WITH", [BEFORE_WITH] = "BEFORE_WITH", [END_ASYNC_FOR] = "END_ASYNC_FOR", + [END_THROW] = "END_THROW", [CALL_NO_KW_TYPE_1] = "CALL_NO_KW_TYPE_1", [COMPARE_OP_ADAPTIVE] = "COMPARE_OP_ADAPTIVE", [COMPARE_OP_FLOAT_JUMP] = "COMPARE_OP_FLOAT_JUMP", [COMPARE_OP_INT_JUMP] = "COMPARE_OP_INT_JUMP", - [COMPARE_OP_STR_JUMP] = "COMPARE_OP_STR_JUMP", [STORE_SUBSCR] = "STORE_SUBSCR", [DELETE_SUBSCR] = "DELETE_SUBSCR", + [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", [JUMP_BACKWARD_QUICK] = "JUMP_BACKWARD_QUICK", - [LOAD_ATTR_ADAPTIVE] = "LOAD_ATTR_ADAPTIVE", [GET_ITER] = "GET_ITER", [GET_YIELD_FROM_ITER] = "GET_YIELD_FROM_ITER", [PRINT_EXPR] = "PRINT_EXPR", [LOAD_BUILD_CLASS] = "LOAD_BUILD_CLASS", + [LOAD_ATTR_ADAPTIVE] = "LOAD_ATTR_ADAPTIVE", [LOAD_ATTR_CLASS] = "LOAD_ATTR_CLASS", + [LOAD_ASSERTION_ERROR] = "LOAD_ASSERTION_ERROR", + [RETURN_GENERATOR] = "RETURN_GENERATOR", [LOAD_ATTR_INSTANCE_VALUE] = "LOAD_ATTR_INSTANCE_VALUE", [LOAD_ATTR_MODULE] = "LOAD_ATTR_MODULE", - [RETURN_GENERATOR] = "RETURN_GENERATOR", [LOAD_ATTR_PROPERTY] = "LOAD_ATTR_PROPERTY", [LOAD_ATTR_SLOT] = "LOAD_ATTR_SLOT", [LOAD_ATTR_WITH_HINT] = "LOAD_ATTR_WITH_HINT", [LOAD_ATTR_METHOD_LAZY_DICT] = "LOAD_ATTR_METHOD_LAZY_DICT", - [LOAD_ATTR_METHOD_NO_DICT] = "LOAD_ATTR_METHOD_NO_DICT", - [LOAD_ATTR_METHOD_WITH_DICT] = "LOAD_ATTR_METHOD_WITH_DICT", [LIST_TO_TUPLE] = "LIST_TO_TUPLE", [RETURN_VALUE] = "RETURN_VALUE", [IMPORT_STAR] = "IMPORT_STAR", [SETUP_ANNOTATIONS] = "SETUP_ANNOTATIONS", - [LOAD_ATTR_METHOD_WITH_VALUES] = "LOAD_ATTR_METHOD_WITH_VALUES", + [LOAD_ATTR_METHOD_NO_DICT] = "LOAD_ATTR_METHOD_NO_DICT", [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[267] = { [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_CONST__LOAD_FAST] = "LOAD_CONST__LOAD_FAST", + [LOAD_ATTR_METHOD_WITH_DICT] = "LOAD_ATTR_METHOD_WITH_DICT", [POP_JUMP_FORWARD_IF_FALSE] = "POP_JUMP_FORWARD_IF_FALSE", [POP_JUMP_FORWARD_IF_TRUE] = "POP_JUMP_FORWARD_IF_TRUE", [LOAD_GLOBAL] = "LOAD_GLOBAL", @@ -363,7 +364,7 @@ static const char *const _PyOpcode_OpName[267] = { [CONTAINS_OP] = "CONTAINS_OP", [RERAISE] = "RERAISE", [COPY] = "COPY", - [LOAD_FAST__LOAD_CONST] = "LOAD_FAST__LOAD_CONST", + [LOAD_ATTR_METHOD_WITH_VALUES] = "LOAD_ATTR_METHOD_WITH_VALUES", [BINARY_OP] = "BINARY_OP", [SEND] = "SEND", [LOAD_FAST] = "LOAD_FAST", @@ -383,9 +384,9 @@ static const char *const _PyOpcode_OpName[267] = { [STORE_DEREF] = "STORE_DEREF", [DELETE_DEREF] = "DELETE_DEREF", [JUMP_BACKWARD] = "JUMP_BACKWARD", - [LOAD_EXCEPTION_TYPE] = "LOAD_EXCEPTION_TYPE", + [LOAD_CONST__LOAD_FAST] = "LOAD_CONST__LOAD_FAST", [CALL_FUNCTION_EX] = "CALL_FUNCTION_EX", - [LOAD_FAST__LOAD_FAST] = "LOAD_FAST__LOAD_FAST", + [LOAD_FAST__LOAD_CONST] = "LOAD_FAST__LOAD_CONST", [EXTENDED_ARG] = "EXTENDED_ARG", [LIST_APPEND] = "LIST_APPEND", [SET_ADD] = "SET_ADD", @@ -395,37 +396,37 @@ static const char *const _PyOpcode_OpName[267] = { [YIELD_VALUE] = "YIELD_VALUE", [RESUME] = "RESUME", [MATCH_CLASS] = "MATCH_CLASS", + [LOAD_FAST__LOAD_FAST] = "LOAD_FAST__LOAD_FAST", [LOAD_GLOBAL_ADAPTIVE] = "LOAD_GLOBAL_ADAPTIVE", - [LOAD_GLOBAL_BUILTIN] = "LOAD_GLOBAL_BUILTIN", [FORMAT_VALUE] = "FORMAT_VALUE", [BUILD_CONST_KEY_MAP] = "BUILD_CONST_KEY_MAP", [BUILD_STRING] = "BUILD_STRING", + [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", [LIST_EXTEND] = "LIST_EXTEND", [SET_UPDATE] = "SET_UPDATE", [DICT_MERGE] = "DICT_MERGE", [DICT_UPDATE] = "DICT_UPDATE", + [STORE_ATTR_INSTANCE_VALUE] = "STORE_ATTR_INSTANCE_VALUE", [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", - [STORE_SUBSCR_ADAPTIVE] = "STORE_SUBSCR_ADAPTIVE", [CALL] = "CALL", [KW_NAMES] = "KW_NAMES", [POP_JUMP_BACKWARD_IF_NOT_NONE] = "POP_JUMP_BACKWARD_IF_NOT_NONE", [POP_JUMP_BACKWARD_IF_NONE] = "POP_JUMP_BACKWARD_IF_NONE", [POP_JUMP_BACKWARD_IF_FALSE] = "POP_JUMP_BACKWARD_IF_FALSE", [POP_JUMP_BACKWARD_IF_TRUE] = "POP_JUMP_BACKWARD_IF_TRUE", + [STORE_SUBSCR_ADAPTIVE] = "STORE_SUBSCR_ADAPTIVE", [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT", [STORE_SUBSCR_LIST_INT] = "STORE_SUBSCR_LIST_INT", [UNPACK_SEQUENCE_ADAPTIVE] = "UNPACK_SEQUENCE_ADAPTIVE", [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>", @@ -513,7 +514,6 @@ static const char *const _PyOpcode_OpName[267] = { #endif #define EXTRA_CASES \ - case 183: \ case 184: \ case 185: \ case 186: \ diff --git a/Include/opcode.h b/Include/opcode.h index 75f74de5b38895..372d2337a95aa7 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -32,12 +32,14 @@ extern "C" { #define BEFORE_ASYNC_WITH 52 #define BEFORE_WITH 53 #define END_ASYNC_FOR 54 +#define END_THROW 55 #define STORE_SUBSCR 60 #define DELETE_SUBSCR 61 #define GET_ITER 68 #define GET_YIELD_FROM_ITER 69 #define PRINT_EXPR 70 #define LOAD_BUILD_CLASS 71 +#define LOAD_ASSERTION_ERROR 74 #define RETURN_GENERATOR 75 #define LIST_TO_TUPLE 82 #define RETURN_VALUE 83 @@ -96,7 +98,6 @@ extern "C" { #define STORE_DEREF 138 #define DELETE_DEREF 139 #define JUMP_BACKWARD 140 -#define LOAD_EXCEPTION_TYPE 141 #define CALL_FUNCTION_EX 142 #define EXTENDED_ARG 144 #define LIST_APPEND 145 @@ -164,47 +165,47 @@ extern "C" { #define CALL_NO_KW_METHOD_DESCRIPTOR_O 46 #define CALL_NO_KW_STR_1 47 #define CALL_NO_KW_TUPLE_1 48 -#define CALL_NO_KW_TYPE_1 55 -#define COMPARE_OP_ADAPTIVE 56 -#define COMPARE_OP_FLOAT_JUMP 57 -#define COMPARE_OP_INT_JUMP 58 -#define COMPARE_OP_STR_JUMP 59 -#define EXTENDED_ARG_QUICK 62 -#define FOR_ITER_ADAPTIVE 63 -#define FOR_ITER_LIST 64 -#define FOR_ITER_RANGE 65 -#define JUMP_BACKWARD_QUICK 66 -#define LOAD_ATTR_ADAPTIVE 67 -#define LOAD_ATTR_CLASS 72 -#define LOAD_ATTR_INSTANCE_VALUE 73 -#define LOAD_ATTR_MODULE 74 -#define LOAD_ATTR_PROPERTY 76 -#define LOAD_ATTR_SLOT 77 -#define LOAD_ATTR_WITH_HINT 78 -#define LOAD_ATTR_METHOD_LAZY_DICT 79 -#define LOAD_ATTR_METHOD_NO_DICT 80 -#define LOAD_ATTR_METHOD_WITH_DICT 81 -#define LOAD_ATTR_METHOD_WITH_VALUES 86 -#define LOAD_CONST__LOAD_FAST 113 -#define LOAD_FAST__LOAD_CONST 121 -#define LOAD_FAST__LOAD_FAST 143 -#define LOAD_GLOBAL_ADAPTIVE 153 -#define LOAD_GLOBAL_BUILTIN 154 -#define LOAD_GLOBAL_MODULE 158 -#define RESUME_QUICK 159 -#define STORE_ATTR_ADAPTIVE 160 -#define STORE_ATTR_INSTANCE_VALUE 161 -#define STORE_ATTR_SLOT 166 -#define STORE_ATTR_WITH_HINT 167 -#define STORE_FAST__LOAD_FAST 168 -#define STORE_FAST__STORE_FAST 169 -#define STORE_SUBSCR_ADAPTIVE 170 -#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 CALL_NO_KW_TYPE_1 56 +#define COMPARE_OP_ADAPTIVE 57 +#define COMPARE_OP_FLOAT_JUMP 58 +#define COMPARE_OP_INT_JUMP 59 +#define COMPARE_OP_STR_JUMP 62 +#define EXTENDED_ARG_QUICK 63 +#define FOR_ITER_ADAPTIVE 64 +#define FOR_ITER_LIST 65 +#define FOR_ITER_RANGE 66 +#define JUMP_BACKWARD_QUICK 67 +#define LOAD_ATTR_ADAPTIVE 72 +#define LOAD_ATTR_CLASS 73 +#define LOAD_ATTR_INSTANCE_VALUE 76 +#define LOAD_ATTR_MODULE 77 +#define LOAD_ATTR_PROPERTY 78 +#define LOAD_ATTR_SLOT 79 +#define LOAD_ATTR_WITH_HINT 80 +#define LOAD_ATTR_METHOD_LAZY_DICT 81 +#define LOAD_ATTR_METHOD_NO_DICT 86 +#define LOAD_ATTR_METHOD_WITH_DICT 113 +#define LOAD_ATTR_METHOD_WITH_VALUES 121 +#define LOAD_CONST__LOAD_FAST 141 +#define LOAD_FAST__LOAD_CONST 143 +#define LOAD_FAST__LOAD_FAST 153 +#define LOAD_GLOBAL_ADAPTIVE 154 +#define LOAD_GLOBAL_BUILTIN 158 +#define LOAD_GLOBAL_MODULE 159 +#define RESUME_QUICK 160 +#define STORE_ATTR_ADAPTIVE 161 +#define STORE_ATTR_INSTANCE_VALUE 166 +#define STORE_ATTR_SLOT 167 +#define STORE_ATTR_WITH_HINT 168 +#define STORE_FAST__LOAD_FAST 169 +#define STORE_FAST__STORE_FAST 170 +#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/dis.py b/Lib/dis.py index 7b0f15faf94923..a045d18241b465 100644 --- a/Lib/dis.py +++ b/Lib/dis.py @@ -39,7 +39,6 @@ JUMP_BACKWARD = opmap['JUMP_BACKWARD'] FOR_ITER = opmap['FOR_ITER'] LOAD_ATTR = opmap['LOAD_ATTR'] -LOAD_EXCEPTION_TYPE = opmap['LOAD_EXCEPTION_TYPE'] CACHE = opmap["CACHE"] @@ -498,8 +497,6 @@ def _get_instructions_bytes(code, varname_from_oparg=None, if arg & (1< at 0x..., file "%s", line %d>) MAKE_FUNCTION 0 LOAD_FAST 0 (x) @@ -507,47 +507,26 @@ async def _asyncwith(c): LOAD_CONST 0 (None) RETURN_VALUE -%3d >> LOAD_EXCEPTION_TYPE 1 (StopIteration) - CHECK_EXC_MATCH - POP_JUMP_FORWARD_IF_TRUE 1 (to 74) - RERAISE 0 - >> LOAD_ATTR 0 (value) - SWAP 3 - POP_TOP - POP_TOP - JUMP_BACKWARD 40 (to 22) - >> LOAD_EXCEPTION_TYPE 1 (StopIteration) - CHECK_EXC_MATCH - POP_JUMP_FORWARD_IF_TRUE 1 (to 110) - RERAISE 0 - >> LOAD_ATTR 0 (value) - SWAP 3 - POP_TOP - POP_TOP - JUMP_BACKWARD 41 (to 56) +%3d >> END_THROW + JUMP_BACKWARD 24 (to 22) + >> END_THROW + JUMP_BACKWARD 9 (to 56) >> PUSH_EXC_INFO WITH_EXCEPT_START GET_AWAITABLE 2 LOAD_CONST 0 (None) - >> SEND 20 (to 188) + >> SEND 4 (to 92) YIELD_VALUE 6 RESUME 3 - JUMP_BACKWARD_NO_INTERRUPT 4 (to 146) - >> LOAD_EXCEPTION_TYPE 1 (StopIteration) - CHECK_EXC_MATCH - POP_JUMP_FORWARD_IF_TRUE 1 (to 162) - RERAISE 0 - >> LOAD_ATTR 0 (value) - SWAP 3 - POP_TOP - POP_TOP - >> POP_JUMP_FORWARD_IF_TRUE 1 (to 192) + JUMP_BACKWARD_NO_INTERRUPT 4 (to 82) + >> END_THROW + >> POP_JUMP_FORWARD_IF_TRUE 1 (to 96) RERAISE 2 >> POP_TOP POP_EXCEPT POP_TOP POP_TOP - JUMP_BACKWARD 72 (to 58) + JUMP_BACKWARD 24 (to 58) >> COPY 3 POP_EXCEPT RERAISE 1 @@ -1376,9 +1355,8 @@ async def async_def(): 0: None 1: 1 Names: - 0: value - 1: b - 2: c + 0: b + 1: c Variable names: 0: a 1: d""" diff --git a/Objects/codeobject.c b/Objects/codeobject.c index 10f5d7afa3ce1d..aeb6a8c0804e54 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -640,7 +640,7 @@ PyCode_New(int argcount, int kwonlyargcount, static const char assert0[6] = { RESUME, 0, - LOAD_EXCEPTION_TYPE, 0, // AssertionError + LOAD_ASSERTION_ERROR, 0, RAISE_VARARGS, 1 }; diff --git a/Objects/frameobject.c b/Objects/frameobject.c index cef475ed419da5..26b38bae780c70 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -427,14 +427,13 @@ mark_stacks(PyCodeObject *code_obj, int len) } case LOAD_ATTR: { - assert(top_of_stack(next_stack) == Object || - top_of_stack(next_stack) == Except); + assert(top_of_stack(next_stack) == Object); int j = get_arg(code, i); - next_stack = pop_value(next_stack); if (j & 1) { + next_stack = pop_value(next_stack); next_stack = push_value(next_stack, Null); + next_stack = push_value(next_stack, Object); } - next_stack = push_value(next_stack, Object); stacks[i+1] = next_stack; break; } diff --git a/Python/ceval.c b/Python/ceval.c index 5100387eb3efa9..03dcf7068cdcbf 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2749,9 +2749,28 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int } } - TARGET(LOAD_EXCEPTION_TYPE) { - assert(oparg < 2); - PyObject *value = oparg ? PyExc_StopIteration : PyExc_AssertionError; + TARGET(END_THROW) { + assert(throwflag); + PyObject *exc_value = TOP(); + assert(exc_value && PyExceptionInstance_Check(exc_value)); + if (PyErr_GivenExceptionMatches(exc_value, PyExc_StopIteration)) { + PyObject *value = ((PyStopIterationObject *)exc_value)->value; + Py_INCREF(value); + Py_DECREF(POP()); // The StopIteration. + Py_DECREF(POP()); // The last sent value. + Py_DECREF(POP()); // The delegated sub-iterator. + PUSH(value); + DISPATCH(); + } + Py_INCREF(exc_value); + PyObject *exc_type = Py_NewRef(Py_TYPE(exc_value)); + PyObject *exc_traceback = PyException_GetTraceback(exc_value); + _PyErr_Restore(tstate, exc_type, exc_value, exc_traceback); + goto exception_unwind; + } + + TARGET(LOAD_ASSERTION_ERROR) { + PyObject *value = PyExc_AssertionError; Py_INCREF(value); PUSH(value); DISPATCH(); diff --git a/Python/compile.c b/Python/compile.c index 471eb9ca876686..b857677a11e97f 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -1234,13 +1234,15 @@ stack_effect(int opcode, int oparg, int jump) return 0; case END_ASYNC_FOR: return -2; + case END_THROW: + return -2; case FORMAT_VALUE: /* If there's a fmt_spec on the stack, we go from 2->1, else 1->1. */ return (oparg & FVS_MASK) == FVS_HAVE_SPEC ? -1 : 0; case LOAD_METHOD: return 1; - case LOAD_EXCEPTION_TYPE: + case LOAD_ASSERTION_ERROR: return 1; case LIST_TO_TUPLE: return 0; @@ -1948,7 +1950,6 @@ compiler_add_yield_from(struct compiler *c, int await) { NEW_JUMP_TARGET_LABEL(c, send); NEW_JUMP_TARGET_LABEL(c, fail); - NEW_JUMP_TARGET_LABEL(c, stop); NEW_JUMP_TARGET_LABEL(c, exit); USE_LABEL(c, send); @@ -1964,17 +1965,7 @@ compiler_add_yield_from(struct compiler *c, int await) ADDOP_JUMP(c, JUMP_NO_INTERRUPT, send); USE_LABEL(c, fail); - ADDOP_I(c, LOAD_EXCEPTION_TYPE, 1); // StopIteration - ADDOP(c, CHECK_EXC_MATCH); - ADDOP_JUMP(c, POP_JUMP_IF_TRUE, stop); - ADDOP_I(c, RERAISE, 0); - - USE_LABEL(c, stop); - // StopIteration was raised. Push the value and break out of the loop: - ADDOP_NAME(c, LOAD_ATTR, &_Py_ID(value), names); - ADDOP_I(c, SWAP, 3); - ADDOP(c, POP_TOP); // The thing we're yielding from. - ADDOP(c, POP_TOP); // The last sent value. + ADDOP(c, END_THROW); USE_LABEL(c, exit); return 1; @@ -3941,7 +3932,7 @@ compiler_assert(struct compiler *c, stmt_ty s) NEW_JUMP_TARGET_LABEL(c, end); if (!compiler_jump_if(c, s->v.Assert.test, end, 1)) return 0; - ADDOP_I(c, LOAD_EXCEPTION_TYPE, 0); // AssertionError + ADDOP(c, LOAD_ASSERTION_ERROR); if (s->v.Assert.msg) { VISIT(c, expr, s->v.Assert.msg); ADDOP_I(c, CALL, 0); diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index 842f8d4dcc44a3..f2461b029c62ae 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -54,38 +54,38 @@ static void *opcode_targets[256] = { &&TARGET_BEFORE_ASYNC_WITH, &&TARGET_BEFORE_WITH, &&TARGET_END_ASYNC_FOR, + &&TARGET_END_THROW, &&TARGET_CALL_NO_KW_TYPE_1, &&TARGET_COMPARE_OP_ADAPTIVE, &&TARGET_COMPARE_OP_FLOAT_JUMP, &&TARGET_COMPARE_OP_INT_JUMP, - &&TARGET_COMPARE_OP_STR_JUMP, &&TARGET_STORE_SUBSCR, &&TARGET_DELETE_SUBSCR, + &&TARGET_COMPARE_OP_STR_JUMP, &&TARGET_EXTENDED_ARG_QUICK, &&TARGET_FOR_ITER_ADAPTIVE, &&TARGET_FOR_ITER_LIST, &&TARGET_FOR_ITER_RANGE, &&TARGET_JUMP_BACKWARD_QUICK, - &&TARGET_LOAD_ATTR_ADAPTIVE, &&TARGET_GET_ITER, &&TARGET_GET_YIELD_FROM_ITER, &&TARGET_PRINT_EXPR, &&TARGET_LOAD_BUILD_CLASS, + &&TARGET_LOAD_ATTR_ADAPTIVE, &&TARGET_LOAD_ATTR_CLASS, + &&TARGET_LOAD_ASSERTION_ERROR, + &&TARGET_RETURN_GENERATOR, &&TARGET_LOAD_ATTR_INSTANCE_VALUE, &&TARGET_LOAD_ATTR_MODULE, - &&TARGET_RETURN_GENERATOR, &&TARGET_LOAD_ATTR_PROPERTY, &&TARGET_LOAD_ATTR_SLOT, &&TARGET_LOAD_ATTR_WITH_HINT, &&TARGET_LOAD_ATTR_METHOD_LAZY_DICT, - &&TARGET_LOAD_ATTR_METHOD_NO_DICT, - &&TARGET_LOAD_ATTR_METHOD_WITH_DICT, &&TARGET_LIST_TO_TUPLE, &&TARGET_RETURN_VALUE, &&TARGET_IMPORT_STAR, &&TARGET_SETUP_ANNOTATIONS, - &&TARGET_LOAD_ATTR_METHOD_WITH_VALUES, + &&TARGET_LOAD_ATTR_METHOD_NO_DICT, &&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_CONST__LOAD_FAST, + &&TARGET_LOAD_ATTR_METHOD_WITH_DICT, &&TARGET_POP_JUMP_FORWARD_IF_FALSE, &&TARGET_POP_JUMP_FORWARD_IF_TRUE, &&TARGET_LOAD_GLOBAL, @@ -120,7 +120,7 @@ static void *opcode_targets[256] = { &&TARGET_CONTAINS_OP, &&TARGET_RERAISE, &&TARGET_COPY, - &&TARGET_LOAD_FAST__LOAD_CONST, + &&TARGET_LOAD_ATTR_METHOD_WITH_VALUES, &&TARGET_BINARY_OP, &&TARGET_SEND, &&TARGET_LOAD_FAST, @@ -140,9 +140,9 @@ static void *opcode_targets[256] = { &&TARGET_STORE_DEREF, &&TARGET_DELETE_DEREF, &&TARGET_JUMP_BACKWARD, - &&TARGET_LOAD_EXCEPTION_TYPE, + &&TARGET_LOAD_CONST__LOAD_FAST, &&TARGET_CALL_FUNCTION_EX, - &&TARGET_LOAD_FAST__LOAD_FAST, + &&TARGET_LOAD_FAST__LOAD_CONST, &&TARGET_EXTENDED_ARG, &&TARGET_LIST_APPEND, &&TARGET_SET_ADD, @@ -152,30 +152,31 @@ static void *opcode_targets[256] = { &&TARGET_YIELD_VALUE, &&TARGET_RESUME, &&TARGET_MATCH_CLASS, + &&TARGET_LOAD_FAST__LOAD_FAST, &&TARGET_LOAD_GLOBAL_ADAPTIVE, - &&TARGET_LOAD_GLOBAL_BUILTIN, &&TARGET_FORMAT_VALUE, &&TARGET_BUILD_CONST_KEY_MAP, &&TARGET_BUILD_STRING, + &&TARGET_LOAD_GLOBAL_BUILTIN, &&TARGET_LOAD_GLOBAL_MODULE, &&TARGET_RESUME_QUICK, &&TARGET_STORE_ATTR_ADAPTIVE, - &&TARGET_STORE_ATTR_INSTANCE_VALUE, &&TARGET_LIST_EXTEND, &&TARGET_SET_UPDATE, &&TARGET_DICT_MERGE, &&TARGET_DICT_UPDATE, + &&TARGET_STORE_ATTR_INSTANCE_VALUE, &&TARGET_STORE_ATTR_SLOT, &&TARGET_STORE_ATTR_WITH_HINT, &&TARGET_STORE_FAST__LOAD_FAST, &&TARGET_STORE_FAST__STORE_FAST, - &&TARGET_STORE_SUBSCR_ADAPTIVE, &&TARGET_CALL, &&TARGET_KW_NAMES, &&TARGET_POP_JUMP_BACKWARD_IF_NOT_NONE, &&TARGET_POP_JUMP_BACKWARD_IF_NONE, &&TARGET_POP_JUMP_BACKWARD_IF_FALSE, &&TARGET_POP_JUMP_BACKWARD_IF_TRUE, + &&TARGET_STORE_SUBSCR_ADAPTIVE, &&TARGET_STORE_SUBSCR_DICT, &&TARGET_STORE_SUBSCR_LIST_INT, &&TARGET_UNPACK_SEQUENCE_ADAPTIVE, @@ -253,6 +254,5 @@ static void *opcode_targets[256] = { &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, - &&_unknown_opcode, &&TARGET_DO_TRACING }; From 296bc08609e0dc30bab620567d1492fb22a26a2c Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Fri, 19 Aug 2022 12:01:05 -0700 Subject: [PATCH 10/10] Feedback from code review --- Doc/library/dis.rst | 2 +- Include/internal/pycore_opcode.h | 4 ++-- Include/opcode.h | 2 +- Lib/importlib/_bootstrap_external.py | 2 +- Lib/opcode.py | 2 +- Lib/test/test_dis.py | 6 +++--- Python/ceval.c | 2 +- Python/compile.c | 6 ++---- Python/opcode_targets.h | 2 +- 9 files changed, 13 insertions(+), 15 deletions(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index c55d12a6552b97..691819fbca03a0 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -568,7 +568,7 @@ the original TOS1. Exception representation on the stack now consist of one, not three, items. -.. opcode:: END_THROW +.. opcode:: CLEANUP_THROW Handles an exception raised during a :meth:`~generator.throw` or :meth:`~generator.close` call through the current frame. If TOS is an diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index 01c672f7043389..587590172b5615 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -104,6 +104,7 @@ const uint8_t _PyOpcode_Deopt[256] = { [CALL_PY_WITH_DEFAULTS] = CALL, [CHECK_EG_MATCH] = CHECK_EG_MATCH, [CHECK_EXC_MATCH] = CHECK_EXC_MATCH, + [CLEANUP_THROW] = CLEANUP_THROW, [COMPARE_OP] = COMPARE_OP, [COMPARE_OP_ADAPTIVE] = COMPARE_OP, [COMPARE_OP_FLOAT_JUMP] = COMPARE_OP, @@ -121,7 +122,6 @@ const uint8_t _PyOpcode_Deopt[256] = { [DICT_MERGE] = DICT_MERGE, [DICT_UPDATE] = DICT_UPDATE, [END_ASYNC_FOR] = END_ASYNC_FOR, - [END_THROW] = END_THROW, [EXTENDED_ARG] = EXTENDED_ARG, [EXTENDED_ARG_QUICK] = EXTENDED_ARG, [FORMAT_VALUE] = FORMAT_VALUE, @@ -299,7 +299,7 @@ static const char *const _PyOpcode_OpName[267] = { [BEFORE_ASYNC_WITH] = "BEFORE_ASYNC_WITH", [BEFORE_WITH] = "BEFORE_WITH", [END_ASYNC_FOR] = "END_ASYNC_FOR", - [END_THROW] = "END_THROW", + [CLEANUP_THROW] = "CLEANUP_THROW", [CALL_NO_KW_TYPE_1] = "CALL_NO_KW_TYPE_1", [COMPARE_OP_ADAPTIVE] = "COMPARE_OP_ADAPTIVE", [COMPARE_OP_FLOAT_JUMP] = "COMPARE_OP_FLOAT_JUMP", diff --git a/Include/opcode.h b/Include/opcode.h index b2169996ed4642..cf11e5560674e1 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -32,7 +32,7 @@ extern "C" { #define BEFORE_ASYNC_WITH 52 #define BEFORE_WITH 53 #define END_ASYNC_FOR 54 -#define END_THROW 55 +#define CLEANUP_THROW 55 #define STORE_SUBSCR 60 #define DELETE_SUBSCR 61 #define GET_ITER 68 diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 8e47075a63b1b4..b30d0896c84996 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -411,7 +411,7 @@ def _write_atomic(path, data, mode=0o666): # Python 3.12a1 3505 (Specialization/Cache for FOR_ITER) # Python 3.12a1 3506 (Add BINARY_SLICE and STORE_SLICE instructions) # Python 3.12a1 3507 (Set lineno of module's RESUME to 0) -# Python 3.12a1 3508 (Add END_THROW) +# Python 3.12a1 3508 (Add CLEANUP_THROW) # Python 3.13 will start with 3550 diff --git a/Lib/opcode.py b/Lib/opcode.py index 770cfab1ba18a6..52c1271868e3ab 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -104,7 +104,7 @@ def pseudo_op(name, op, real_ops): def_op('BEFORE_ASYNC_WITH', 52) def_op('BEFORE_WITH', 53) def_op('END_ASYNC_FOR', 54) -def_op('END_THROW', 55) +def_op('CLEANUP_THROW', 55) def_op('STORE_SUBSCR', 60) def_op('DELETE_SUBSCR', 61) diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index 0ed04d3bb88c6d..67cb1502add925 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -507,9 +507,9 @@ async def _asyncwith(c): LOAD_CONST 0 (None) RETURN_VALUE -%3d >> END_THROW +%3d >> CLEANUP_THROW JUMP_BACKWARD 24 (to 22) - >> END_THROW + >> CLEANUP_THROW JUMP_BACKWARD 9 (to 56) >> PUSH_EXC_INFO WITH_EXCEPT_START @@ -519,7 +519,7 @@ async def _asyncwith(c): YIELD_VALUE 6 RESUME 3 JUMP_BACKWARD_NO_INTERRUPT 4 (to 82) - >> END_THROW + >> CLEANUP_THROW >> POP_JUMP_FORWARD_IF_TRUE 1 (to 96) RERAISE 2 >> POP_TOP diff --git a/Python/ceval.c b/Python/ceval.c index 3d3555831fea1a..7024addfe626cd 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2749,7 +2749,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int } } - TARGET(END_THROW) { + TARGET(CLEANUP_THROW) { assert(throwflag); PyObject *exc_value = TOP(); assert(exc_value && PyExceptionInstance_Check(exc_value)); diff --git a/Python/compile.c b/Python/compile.c index b857677a11e97f..339e0e792be416 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -1234,7 +1234,7 @@ stack_effect(int opcode, int oparg, int jump) return 0; case END_ASYNC_FOR: return -2; - case END_THROW: + case CLEANUP_THROW: return -2; case FORMAT_VALUE: /* If there's a fmt_spec on the stack, we go from 2->1, @@ -1957,15 +1957,13 @@ compiler_add_yield_from(struct compiler *c, int await) // Set up a virtual try/except to handle when StopIteration is raised during // a close or throw call. The only way YIELD_VALUE raises if they do! ADDOP_JUMP(c, SETUP_FINALLY, fail); - RETURN_IF_FALSE(compiler_push_fblock(c, TRY_EXCEPT, send, NO_LABEL, NULL)); ADDOP_I(c, YIELD_VALUE, 0); - compiler_pop_fblock(c, TRY_EXCEPT, send); ADDOP_NOLINE(c, POP_BLOCK); ADDOP_I(c, RESUME, await ? 3 : 2); ADDOP_JUMP(c, JUMP_NO_INTERRUPT, send); USE_LABEL(c, fail); - ADDOP(c, END_THROW); + ADDOP(c, CLEANUP_THROW); USE_LABEL(c, exit); return 1; diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index 21e6763da607c3..7c782d101c1b8c 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -54,7 +54,7 @@ static void *opcode_targets[256] = { &&TARGET_BEFORE_ASYNC_WITH, &&TARGET_BEFORE_WITH, &&TARGET_END_ASYNC_FOR, - &&TARGET_END_THROW, + &&TARGET_CLEANUP_THROW, &&TARGET_CALL_NO_KW_TYPE_1, &&TARGET_COMPARE_OP_ADAPTIVE, &&TARGET_COMPARE_OP_FLOAT_JUMP,