From 24541ba4a6d1016d9673970fc2408fbcfafa55cf Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Thu, 3 Mar 2022 12:35:38 -0800 Subject: [PATCH 1/3] Use an oparg to discover context for GET_AWAITABLE --- Doc/library/dis.rst | 12 +++++++++++- Include/opcode.h | 16 ++++++++-------- Lib/importlib/_bootstrap_external.py | 3 ++- Lib/opcode.py | 3 +-- Python/ceval.c | 16 +++++----------- Python/compile.c | 12 ++++++------ Python/opcode_targets.h | 6 +++--- 7 files changed, 36 insertions(+), 32 deletions(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 3dac3911da2767..bd412ec703fea8 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -475,15 +475,25 @@ the original TOS1. **Coroutine opcodes** -.. opcode:: GET_AWAITABLE +.. opcode:: GET_AWAITABLE (where) Implements ``TOS = get_awaitable(TOS)``, where ``get_awaitable(o)`` returns ``o`` if ``o`` is a coroutine object or a generator object with the CO_ITERABLE_COROUTINE flag, or resolves ``o.__await__``. + If the ``where`` operand is nonzero, it indicates where the instruction + occurs: + + * ``1`` After a call to ``__aenter__`` + * ``2`` After a call to ``__aexit__`` + .. versionadded:: 3.5 + .. versionchanged:: 3.11 + Previously, this instruction did not have an oparg. + + .. opcode:: GET_AITER diff --git a/Include/opcode.h b/Include/opcode.h index f6330d9056aa12..e897a77a07837b 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -33,7 +33,6 @@ extern "C" { #define GET_YIELD_FROM_ITER 69 #define PRINT_EXPR 70 #define LOAD_BUILD_CLASS 71 -#define GET_AWAITABLE 73 #define LOAD_ASSERTION_ERROR 74 #define RETURN_GENERATOR 75 #define LIST_TO_TUPLE 82 @@ -86,6 +85,7 @@ extern "C" { #define POP_JUMP_IF_NOT_NONE 128 #define POP_JUMP_IF_NONE 129 #define RAISE_VARARGS 130 +#define GET_AWAITABLE 131 #define MAKE_FUNCTION 132 #define BUILD_SLICE 133 #define JUMP_NO_INTERRUPT 134 @@ -160,13 +160,13 @@ extern "C" { #define PRECALL_BUILTIN_FAST_WITH_KEYWORDS 66 #define PRECALL_NO_KW_LEN 67 #define PRECALL_NO_KW_ISINSTANCE 72 -#define PRECALL_NO_KW_LIST_APPEND 76 -#define PRECALL_NO_KW_METHOD_DESCRIPTOR_O 77 -#define PRECALL_NO_KW_METHOD_DESCRIPTOR_NOARGS 78 -#define PRECALL_NO_KW_STR_1 79 -#define PRECALL_NO_KW_TUPLE_1 80 -#define PRECALL_NO_KW_TYPE_1 81 -#define PRECALL_NO_KW_METHOD_DESCRIPTOR_FAST 131 +#define PRECALL_NO_KW_LIST_APPEND 73 +#define PRECALL_NO_KW_METHOD_DESCRIPTOR_O 76 +#define PRECALL_NO_KW_METHOD_DESCRIPTOR_NOARGS 77 +#define PRECALL_NO_KW_STR_1 78 +#define PRECALL_NO_KW_TUPLE_1 79 +#define PRECALL_NO_KW_TYPE_1 80 +#define PRECALL_NO_KW_METHOD_DESCRIPTOR_FAST 81 #define PRECALL_BOUND_METHOD 140 #define PRECALL_PYFUNC 141 #define RESUME_QUICK 143 diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index dd1f6ffd64cee5..cc6b57c4ecc92e 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -390,6 +390,7 @@ def _write_atomic(path, data, mode=0o666): # Python 3.11a5 3481 (Use inline cache for BINARY_OP) # Python 3.11a5 3482 (Use inline caching for UNPACK_SEQUENCE and LOAD_GLOBAL) # Python 3.11a5 3483 (Use inline caching for COMPARE_OP and BINARY_SUBSCR) +# Python 3.11a5 3484 (Add an oparg to GET_AWAITABLE) # Python 3.12 will start with magic number 3500 @@ -404,7 +405,7 @@ def _write_atomic(path, data, mode=0o666): # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array # in PC/launcher.c must also be updated. -MAGIC_NUMBER = (3483).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3484).to_bytes(2, 'little') + b'\r\n' _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c _PYCACHE = '__pycache__' diff --git a/Lib/opcode.py b/Lib/opcode.py index 9b08562cd04f69..b6b8349613f48e 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -92,7 +92,6 @@ def jabs_op(name, op, entries=0): def_op('PRINT_EXPR', 70) def_op('LOAD_BUILD_CLASS', 71) -def_op('GET_AWAITABLE', 73) def_op('LOAD_ASSERTION_ERROR', 74) def_op('RETURN_GENERATOR', 75) @@ -153,7 +152,7 @@ def jabs_op(name, op, entries=0): jabs_op('POP_JUMP_IF_NOT_NONE', 128) jabs_op('POP_JUMP_IF_NONE', 129) def_op('RAISE_VARARGS', 130) # Number of raise arguments (1, 2, or 3) - +def_op('GET_AWAITABLE', 131) def_op('MAKE_FUNCTION', 132) # Flags def_op('BUILD_SLICE', 133) # Number of items jabs_op('JUMP_NO_INTERRUPT', 134) # Target byte offset from beginning of code diff --git a/Python/ceval.c b/Python/ceval.c index e47e0521ea9413..ae098edea15803 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -95,7 +95,7 @@ static int check_args_iterable(PyThreadState *, PyObject *func, PyObject *vararg static int check_except_type_valid(PyThreadState *tstate, PyObject* right); static int check_except_star_type_valid(PyThreadState *tstate, PyObject* right); static void format_kwargs_error(PyThreadState *, PyObject *func, PyObject *kwargs); -static void format_awaitable_error(PyThreadState *, PyTypeObject *, int, int); +static void format_awaitable_error(PyThreadState *, PyTypeObject *, int); static int get_exception_handler(PyCodeObject *, int, int*, int*, int*); static _PyInterpreterFrame * _PyEvalFramePushAndInit(PyThreadState *tstate, PyFunctionObject *func, @@ -2519,13 +2519,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int PyObject *iter = _PyCoro_GetAwaitableIter(iterable); if (iter == NULL) { - int opcode_at_minus_4 = 0; - if ((next_instr - first_instr) > 4) { - opcode_at_minus_4 = _Py_OPCODE(next_instr[-4]); - } - format_awaitable_error(tstate, Py_TYPE(iterable), - opcode_at_minus_4, - _Py_OPCODE(next_instr[-2])); + format_awaitable_error(tstate, Py_TYPE(iterable), oparg); } Py_DECREF(iterable); @@ -7711,16 +7705,16 @@ format_exc_unbound(PyThreadState *tstate, PyCodeObject *co, int oparg) } static void -format_awaitable_error(PyThreadState *tstate, PyTypeObject *type, int prevprevprevopcode, int prevopcode) +format_awaitable_error(PyThreadState *tstate, PyTypeObject *type, int oparg) { if (type->tp_as_async == NULL || type->tp_as_async->am_await == NULL) { - if (prevopcode == BEFORE_ASYNC_WITH) { + if (oparg == 1) { _PyErr_Format(tstate, PyExc_TypeError, "'async with' received an object from __aenter__ " "that does not implement __await__: %.100s", type->tp_name); } - else if (prevopcode == WITH_EXCEPT_START || (prevopcode == CALL && prevprevprevopcode == LOAD_CONST)) { + else if (oparg == 2) { _PyErr_Format(tstate, PyExc_TypeError, "'async with' received an object from __aexit__ " "that does not implement __await__: %.100s", diff --git a/Python/compile.c b/Python/compile.c index 3609ff8f4fb9e5..c50f5119c56430 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -1978,7 +1978,7 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info, return 0; } if (info->fb_type == ASYNC_WITH) { - ADDOP(c, GET_AWAITABLE); + ADDOP_I(c, GET_AWAITABLE, 2); ADDOP_LOAD_CONST(c, Py_None); ADD_YIELD_FROM(c, 1); } @@ -5354,7 +5354,7 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, ADDOP_I(c, CALL, 0); if (is_async_generator && type != COMP_GENEXP) { - ADDOP(c, GET_AWAITABLE); + ADDOP_I(c, GET_AWAITABLE, 0); ADDOP_LOAD_CONST(c, Py_None); ADD_YIELD_FROM(c, 1); } @@ -5486,7 +5486,7 @@ compiler_async_with(struct compiler *c, stmt_ty s, int pos) VISIT(c, expr, item->context_expr); ADDOP(c, BEFORE_ASYNC_WITH); - ADDOP(c, GET_AWAITABLE); + ADDOP_I(c, GET_AWAITABLE, 1); ADDOP_LOAD_CONST(c, Py_None); ADD_YIELD_FROM(c, 1); @@ -5523,7 +5523,7 @@ compiler_async_with(struct compiler *c, stmt_ty s, int pos) SET_LOC(c, s); if(!compiler_call_exit_with_nones(c)) return 0; - ADDOP(c, GET_AWAITABLE); + ADDOP_I(c, GET_AWAITABLE, 2); ADDOP_LOAD_CONST(c, Py_None); ADD_YIELD_FROM(c, 1); @@ -5537,7 +5537,7 @@ compiler_async_with(struct compiler *c, stmt_ty s, int pos) ADDOP_JUMP(c, SETUP_CLEANUP, cleanup); ADDOP(c, PUSH_EXC_INFO); ADDOP(c, WITH_EXCEPT_START); - ADDOP(c, GET_AWAITABLE); + ADDOP_I(c, GET_AWAITABLE, 2); ADDOP_LOAD_CONST(c, Py_None); ADD_YIELD_FROM(c, 1); compiler_with_except_finish(c, cleanup); @@ -5711,7 +5711,7 @@ compiler_visit_expr1(struct compiler *c, expr_ty e) } VISIT(c, expr, e->v.Await.value); - ADDOP(c, GET_AWAITABLE); + ADDOP_I(c, GET_AWAITABLE, 0); ADDOP_LOAD_CONST(c, Py_None); ADD_YIELD_FROM(c, 1); break; diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index d463e303e27ac7..422a723d56f7ae 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -72,15 +72,15 @@ static void *opcode_targets[256] = { &&TARGET_PRINT_EXPR, &&TARGET_LOAD_BUILD_CLASS, &&TARGET_PRECALL_NO_KW_ISINSTANCE, - &&TARGET_GET_AWAITABLE, + &&TARGET_PRECALL_NO_KW_LIST_APPEND, &&TARGET_LOAD_ASSERTION_ERROR, &&TARGET_RETURN_GENERATOR, - &&TARGET_PRECALL_NO_KW_LIST_APPEND, &&TARGET_PRECALL_NO_KW_METHOD_DESCRIPTOR_O, &&TARGET_PRECALL_NO_KW_METHOD_DESCRIPTOR_NOARGS, &&TARGET_PRECALL_NO_KW_STR_1, &&TARGET_PRECALL_NO_KW_TUPLE_1, &&TARGET_PRECALL_NO_KW_TYPE_1, + &&TARGET_PRECALL_NO_KW_METHOD_DESCRIPTOR_FAST, &&TARGET_LIST_TO_TUPLE, &&TARGET_RETURN_VALUE, &&TARGET_IMPORT_STAR, @@ -130,7 +130,7 @@ static void *opcode_targets[256] = { &&TARGET_POP_JUMP_IF_NOT_NONE, &&TARGET_POP_JUMP_IF_NONE, &&TARGET_RAISE_VARARGS, - &&TARGET_PRECALL_NO_KW_METHOD_DESCRIPTOR_FAST, + &&TARGET_GET_AWAITABLE, &&TARGET_MAKE_FUNCTION, &&TARGET_BUILD_SLICE, &&TARGET_JUMP_NO_INTERRUPT, From be453c57e219ecf029c9ad443c5c512e91d43a28 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Thu, 3 Mar 2022 12:36:37 -0800 Subject: [PATCH 2/3] blurb add --- .../Core and Builtins/2022-03-03-12-36-15.bpo-46841.apPev2.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-03-03-12-36-15.bpo-46841.apPev2.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-03-03-12-36-15.bpo-46841.apPev2.rst b/Misc/NEWS.d/next/Core and Builtins/2022-03-03-12-36-15.bpo-46841.apPev2.rst new file mode 100644 index 00000000000000..6a45e6e88241be --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-03-03-12-36-15.bpo-46841.apPev2.rst @@ -0,0 +1,2 @@ +Use an oparg to simplify the construction of helpful error messages in +:opcode:`GET_AWAITABLE`. From 78b90e845ca81d04714edcb10b094182ca6ec6ed Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Thu, 3 Mar 2022 12:42:08 -0800 Subject: [PATCH 3/3] Fix vertical whitespace --- Doc/library/dis.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index bd412ec703fea8..65e888dc86a194 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -494,7 +494,6 @@ the original TOS1. Previously, this instruction did not have an oparg. - .. opcode:: GET_AITER Implements ``TOS = TOS.__aiter__()``.