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, pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy