From e83a6d34c6da0a3b2d40866735a1873622f1f524 Mon Sep 17 00:00:00 2001 From: Matthieu Dartiailh Date: Wed, 31 Aug 2022 13:14:11 +0200 Subject: [PATCH 01/16] Doc: clarify the meaning of the oparg for CACHE and COPY opcode in dis doc --- Doc/library/dis.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 334b9df4fc1f1a..b98ea803dd97cb 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -427,6 +427,8 @@ The Python compiler currently generates the following bytecode instructions. Push the *i*-th item to the top of the stack. The item is not removed from its original location. + The stack is indexed from 1, so COPY 1 will copy TOS. + .. versionadded:: 3.11 @@ -434,6 +436,9 @@ The Python compiler currently generates the following bytecode instructions. Swap TOS with the item at position *i*. + The stack is indexed from 1, so SWAP 2 will swap the two element at the top + of the stack. + .. versionadded:: 3.11 From 038756d8437115e60395bbd2b07db8d710153d20 Mon Sep 17 00:00:00 2001 From: Matthieu Dartiailh Date: Thu, 1 Sep 2022 14:06:43 +0200 Subject: [PATCH 02/16] Doc: move TOS, TOS1, etc definitions to the beginning of instruction description --- Doc/library/dis.rst | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index b98ea803dd97cb..9fb48c2eb8aab1 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -402,6 +402,9 @@ The Python compiler currently generates the following bytecode instructions. **General instructions** +In the following, TOS is the top-of-stack. +TOS1, TOS2, TOS3 are the second, third and fourth items on the stack, respectively. + .. opcode:: NOP Do nothing code. Used as a placeholder by the bytecode optimizer, and to @@ -436,8 +439,7 @@ The Python compiler currently generates the following bytecode instructions. Swap TOS with the item at position *i*. - The stack is indexed from 1, so SWAP 2 will swap the two element at the top - of the stack. + The stack is indexed from 1, so SWAP 2 will swap TOS and TOS1. .. versionadded:: 3.11 @@ -496,9 +498,6 @@ result back on the stack. **Binary and in-place operations** -In the following, TOS is the top-of-stack. -TOS1, TOS2, TOS3 are the second, third and fourth items on the stack, respectively. - Binary operations remove the top two items from the stack (TOS and TOS1). They perform the operation, then put the result back on the stack. From 52191263ff8ff5ec3132a09e8aed0273664a5852 Mon Sep 17 00:00:00 2001 From: Matthieu Dartiailh Date: Thu, 1 Sep 2022 16:08:09 +0200 Subject: [PATCH 03/16] Doc: define TOS(i) and rewrite CACHE and SWAP description to use it --- Doc/library/dis.rst | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 9fb48c2eb8aab1..f503e60ab39594 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -402,7 +402,8 @@ The Python compiler currently generates the following bytecode instructions. **General instructions** -In the following, TOS is the top-of-stack. +In the following, TOS(i) refer to the *i*-th item on the stack which is index from 1. +We also use as shorthand TOS = TOS(1) which is the top-of-stack. TOS1, TOS2, TOS3 are the second, third and fourth items on the stack, respectively. .. opcode:: NOP @@ -427,19 +428,15 @@ TOS1, TOS2, TOS3 are the second, third and fourth items on the stack, respective .. opcode:: COPY (i) - Push the *i*-th item to the top of the stack. The item is not removed from its + Push TOS(i) to the top of the stack. The item is not removed from its original location. - The stack is indexed from 1, so COPY 1 will copy TOS. - .. versionadded:: 3.11 .. opcode:: SWAP (i) - Swap TOS with the item at position *i*. - - The stack is indexed from 1, so SWAP 2 will swap TOS and TOS1. + Swap TOS with TOS(i). .. versionadded:: 3.11 From 8cc016317f547c3afa670c425b118ae03e2e8f40 Mon Sep 17 00:00:00 2001 From: Matthieu Dartiailh Date: Thu, 1 Sep 2022 16:27:31 +0200 Subject: [PATCH 04/16] typo --- Doc/library/dis.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index f503e60ab39594..e2d77996972718 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -402,7 +402,7 @@ The Python compiler currently generates the following bytecode instructions. **General instructions** -In the following, TOS(i) refer to the *i*-th item on the stack which is index from 1. +In the following, TOS(i) refers to the *i*-th item on the stack which is index from 1. We also use as shorthand TOS = TOS(1) which is the top-of-stack. TOS1, TOS2, TOS3 are the second, third and fourth items on the stack, respectively. From 21f6716cf0d6c380c965231bda7a0b1420979991 Mon Sep 17 00:00:00 2001 From: Matthieu Dartiailh Date: Thu, 6 Oct 2022 21:42:44 +0200 Subject: [PATCH 05/16] Doc.dis: remove use of TOSi and only use TOS(i) --- Doc/library/dis.rst | 166 +++++++++++++++++++++++--------------------- 1 file changed, 85 insertions(+), 81 deletions(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index e2d77996972718..90a39ca750b2cb 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -403,8 +403,6 @@ The Python compiler currently generates the following bytecode instructions. **General instructions** In the following, TOS(i) refers to the *i*-th item on the stack which is index from 1. -We also use as shorthand TOS = TOS(1) which is the top-of-stack. -TOS1, TOS2, TOS3 are the second, third and fourth items on the stack, respectively. .. opcode:: NOP @@ -414,7 +412,7 @@ TOS1, TOS2, TOS3 are the second, third and fourth items on the stack, respective .. opcode:: POP_TOP - Removes the top-of-stack (TOS) item. + Removes the top-of-stack (TOS(1)) item. .. opcode:: END_FOR @@ -436,7 +434,7 @@ TOS1, TOS2, TOS3 are the second, third and fourth items on the stack, respective .. opcode:: SWAP (i) - Swap TOS with TOS(i). + Swap TOS(1) with TOS(i). .. versionadded:: 3.11 @@ -467,76 +465,76 @@ result back on the stack. .. opcode:: UNARY_NEGATIVE - Implements ``TOS = -TOS``. + Implements ``TOS(1) = -TOS(1)``. .. opcode:: UNARY_NOT - Implements ``TOS = not TOS``. + Implements ``TOS(1) = not TOS(1)``. .. opcode:: UNARY_INVERT - Implements ``TOS = ~TOS``. + Implements ``TOS(1) = ~TOS(1)``. .. opcode:: GET_ITER - Implements ``TOS = iter(TOS)``. + Implements ``TOS(1) = iter(TOS(1))``. .. opcode:: GET_YIELD_FROM_ITER - If ``TOS`` is a :term:`generator iterator` or :term:`coroutine` object - it is left as is. Otherwise, implements ``TOS = iter(TOS)``. + If ``TOS(1)`` is a :term:`generator iterator` or :term:`coroutine` object + it is left as is. Otherwise, implements ``TOS(1) = iter(TOS(1))``. .. versionadded:: 3.5 **Binary and in-place operations** -Binary operations remove the top two items from the stack (TOS and TOS1). +Binary operations remove the top two items from the stack (TOS(1) and TOS(2)). They perform the operation, then put the result back on the stack. In-place operations are like binary operations, but the operation is done in-place -when TOS1 supports it, and the resulting TOS may be (but does not have to be) -the original TOS1. +when TOS(2) supports it, and the resulting TOS(1) may be (but does not have to be) +the original TOS(2). .. opcode:: BINARY_OP (op) Implements the binary and in-place operators (depending on the value of *op*). - ``TOS = TOS1 op TOS``. + ``TOS(1) = TOS(2) op TOS(1)``. .. versionadded:: 3.11 .. opcode:: BINARY_SUBSCR - Implements ``TOS = TOS1[TOS]``. + Implements ``TOS(1) = TOS(2)[TOS(1)]``. .. opcode:: STORE_SUBSCR - Implements ``TOS1[TOS] = TOS2``. + Implements ``TOS(2)[TOS(1)] = TOS(3)``. .. opcode:: DELETE_SUBSCR - Implements ``del TOS1[TOS]``. + Implements ``del TOS(2)[TOS(1)]``. .. opcode:: BINARY_SLICE - Implements ``TOS = TOS2[TOS1:TOS]``. + Implements ``TOS(1) = TOS(3)[TOS(2):TOS(1)]``. .. versionadded:: 3.12 .. opcode:: STORE_SLICE - Implements ``TOS2[TOS1:TOS] = TOS3``. + Implements ``TOS(3)[TOS(2):TOS(1)] = TOS(4)``. .. versionadded:: 3.12 @@ -545,7 +543,7 @@ the original TOS1. .. opcode:: GET_AWAITABLE (where) - Implements ``TOS = get_awaitable(TOS)``, where ``get_awaitable(o)`` + Implements ``TOS(1) = get_awaitable(TOS(1))``, 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__``. @@ -564,7 +562,7 @@ the original TOS1. .. opcode:: GET_AITER - Implements ``TOS = TOS.__aiter__()``. + Implements ``TOS(1) = TOS(1).__aiter__()``. .. versionadded:: 3.5 .. versionchanged:: 3.7 @@ -574,7 +572,7 @@ the original TOS1. .. opcode:: GET_ANEXT - Pushes ``get_awaitable(TOS.__anext__())`` to the stack. See + Pushes ``get_awaitable(TOS(1).__anext__())`` to the stack. See ``GET_AWAITABLE`` for details about ``get_awaitable``. .. versionadded:: 3.5 @@ -583,7 +581,7 @@ the original TOS1. .. opcode:: END_ASYNC_FOR Terminates an :keyword:`async for` loop. Handles an exception raised - when awaiting a next item. If TOS is :exc:`StopAsyncIteration` pop 3 + when awaiting a next item. If TOS(1) is :exc:`StopAsyncIteration` pop 3 values from the stack and restore the exception state using the second of them. Otherwise re-raise the exception using the value from the stack. An exception handler block is removed from the block stack. @@ -597,9 +595,9 @@ the original TOS1. .. 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 + :meth:`~generator.close` call through the current frame. If TOS(1) is an instance of :exc:`StopIteration`, pop three values from the stack and push - its ``value`` member. Otherwise, re-raise TOS. + its ``value`` member. Otherwise, re-raise TOS(1). .. versionadded:: 3.12 @@ -617,22 +615,22 @@ the original TOS1. .. opcode:: SET_ADD (i) - Calls ``set.add(TOS1[-i], TOS)``. Used to implement set comprehensions. + Calls ``set.add(TOS(2)[-i], TOS(1))``. Used to implement set comprehensions. .. opcode:: LIST_APPEND (i) - Calls ``list.append(TOS1[-i], TOS)``. Used to implement list comprehensions. + Calls ``list.append(TOS(2)[-i], TOS(1))``. Used to implement list comprehensions. .. opcode:: MAP_ADD (i) - Calls ``dict.__setitem__(TOS1[-i], TOS1, TOS)``. Used to implement dict + Calls ``dict.__setitem__(TOS(2)[-i], TOS(2), TOS(1))``. Used to implement dict comprehensions. .. versionadded:: 3.1 .. versionchanged:: 3.8 - Map value is TOS and map key is TOS1. Before, those were reversed. + Map value is TOS(1) and map key is TOS(2). Before, those were reversed. For all of the :opcode:`SET_ADD`, :opcode:`LIST_APPEND` and :opcode:`MAP_ADD` instructions, while the added value or key/value pair is popped off, the @@ -642,12 +640,12 @@ iterations of the loop. .. opcode:: RETURN_VALUE - Returns with TOS to the caller of the function. + Returns with TOS(1) to the caller of the function. .. opcode:: YIELD_VALUE - Pops TOS and yields it from a :term:`generator`. + Pops TOS(1) and yields it from a :term:`generator`. .. versionchanged:: 3.11 oparg set to be the stack depth, for efficient handling on frames. @@ -691,15 +689,15 @@ iterations of the loop. .. opcode:: CHECK_EXC_MATCH - Performs exception matching for ``except``. Tests whether the TOS1 is an exception - matching TOS. Pops TOS and pushes the boolean result of the test. + Performs exception matching for ``except``. Tests whether the TOS(2) is an exception + matching TOS(1). Pops TOS(1) and pushes the boolean result of the test. .. versionadded:: 3.11 .. opcode:: CHECK_EG_MATCH - Performs exception matching for ``except*``. Applies ``split(TOS)`` on - the exception group representing TOS1. + Performs exception matching for ``except*``. Applies ``split(TOS(1))`` on + the exception group representing TOS(2). In case of a match, pops two items from the stack and pushes the non-matching subgroup (``None`` in case of full match) followed by the @@ -710,9 +708,9 @@ iterations of the loop. .. opcode:: PREP_RERAISE_STAR - Combines the raised and reraised exceptions list from TOS, into an exception + Combines the raised and reraised exceptions list from TOS(1), into an exception group to propagate from a try-except* block. Uses the original exception - group from TOS1 to reconstruct the structure of reraised exceptions. Pops + group from TOS(2) to reconstruct the structure of reraised exceptions. Pops two items from the stack and pushes the exception to reraise or ``None`` if there isn't one. @@ -759,14 +757,14 @@ iterations of the loop. .. opcode:: GET_LEN - Push ``len(TOS)`` onto the stack. + Push ``len(TOS(1))`` onto the stack. .. versionadded:: 3.10 .. opcode:: MATCH_MAPPING - If TOS is an instance of :class:`collections.abc.Mapping` (or, more technically: if + If TOS(1) is an instance of :class:`collections.abc.Mapping` (or, more technically: if it has the :const:`Py_TPFLAGS_MAPPING` flag set in its :c:member:`~PyTypeObject.tp_flags`), push ``True`` onto the stack. Otherwise, push ``False``. @@ -776,7 +774,7 @@ iterations of the loop. .. opcode:: MATCH_SEQUENCE - If TOS is an instance of :class:`collections.abc.Sequence` and is *not* an instance + If TOS(1) is an instance of :class:`collections.abc.Sequence` and is *not* an instance of :class:`str`/:class:`bytes`/:class:`bytearray` (or, more technically: if it has the :const:`Py_TPFLAGS_SEQUENCE` flag set in its :c:member:`~PyTypeObject.tp_flags`), push ``True`` onto the stack. Otherwise, push ``False``. @@ -786,8 +784,8 @@ iterations of the loop. .. opcode:: MATCH_KEYS - TOS is a tuple of mapping keys, and TOS1 is the match subject. If TOS1 - contains all of the keys in TOS, push a :class:`tuple` containing the + TOS(1) is a tuple of mapping keys, and TOS(2) is the match subject. If TOS(2) + contains all of the keys in TOS(1), push a :class:`tuple` containing the corresponding values. Otherwise, push ``None``. .. versionadded:: 3.10 @@ -799,7 +797,7 @@ iterations of the loop. .. opcode:: STORE_NAME (namei) - Implements ``name = TOS``. *namei* is the index of *name* in the attribute + Implements ``name = TOS(1)``. *namei* is the index of *name* in the attribute :attr:`co_names` of the code object. The compiler tries to use :opcode:`STORE_FAST` or :opcode:`STORE_GLOBAL` if possible. @@ -812,13 +810,13 @@ iterations of the loop. .. opcode:: UNPACK_SEQUENCE (count) - Unpacks TOS into *count* individual values, which are put onto the stack + Unpacks TOS(1) into *count* individual values, which are put onto the stack right-to-left. .. opcode:: UNPACK_EX (counts) - Implements assignment with a starred target: Unpacks an iterable in TOS into + Implements assignment with a starred target: Unpacks an iterable in TOS(1) into individual values, where the total number of values can be smaller than the number of items in the iterable: one of the new values will be a list of all leftover items. @@ -830,13 +828,13 @@ iterations of the loop. .. opcode:: STORE_ATTR (namei) - Implements ``TOS.name = TOS1``, where *namei* is the index of name in + Implements ``TOS(1).name = TOS(2)``, where *namei* is the index of name in :attr:`co_names`. .. opcode:: DELETE_ATTR (namei) - Implements ``del TOS.name``, using *namei* as index into :attr:`co_names`. + Implements ``del TOS(1).name``, using *namei* as index into :attr:`co_names`. .. opcode:: STORE_GLOBAL (namei) @@ -879,7 +877,7 @@ iterations of the loop. Pushes a new dictionary object onto the stack. Pops ``2 * count`` items so that the dictionary holds *count* entries: - ``{..., TOS3: TOS2, TOS1: TOS}``. + ``{..., TOS(4): TOS(3), TOS(2): TOS(1)}``. .. versionchanged:: 3.5 The dictionary is created from stack items instead of creating an @@ -890,7 +888,7 @@ iterations of the loop. The version of :opcode:`BUILD_MAP` specialized for constant keys. Pops the top element on the stack which contains a tuple of keys, then starting from - ``TOS1``, pops *count* values to form values in the built dictionary. + ``TOS(2)``, pops *count* values to form values in the built dictionary. .. versionadded:: 3.6 @@ -905,21 +903,21 @@ iterations of the loop. .. opcode:: LIST_EXTEND (i) - Calls ``list.extend(TOS1[-i], TOS)``. Used to build lists. + Calls ``list.extend(TOS(2)[-i], TOS(1))``. Used to build lists. .. versionadded:: 3.9 .. opcode:: SET_UPDATE (i) - Calls ``set.update(TOS1[-i], TOS)``. Used to build sets. + Calls ``set.update(TOS(2)[-i], TOS(1))``. Used to build sets. .. versionadded:: 3.9 .. opcode:: DICT_UPDATE (i) - Calls ``dict.update(TOS1[-i], TOS)``. Used to build dicts. + Calls ``dict.update(TOS(2)[-i], TOS(1))``. Used to build dicts. .. versionadded:: 3.9 @@ -933,13 +931,13 @@ iterations of the loop. .. opcode:: LOAD_ATTR (namei) - If the low bit of ``namei`` is not set, this replaces TOS with - ``getattr(TOS, co_names[namei>>1])``. + If the low bit of ``namei`` is not set, this replaces TOS(1) with + ``getattr(TOS(1), co_names[namei>>1])``. If the low bit of ``namei`` is set, this will attempt to load a method named - ``co_names[namei>>1]`` from the TOS object. TOS is popped. - This bytecode distinguishes two cases: if TOS has a method with the correct - name, the bytecode pushes the unbound method and TOS. TOS will be used as + ``co_names[namei>>1]`` from the TOS(1) object. TOS(1) is popped. + This bytecode distinguishes two cases: if TOS(1) has a method with the correct + name, the bytecode pushes the unbound method and TOS(1). TOS(1) will be used as the first argument (``self``) by :opcode:`CALL` when calling the unbound method. Otherwise, ``NULL`` and the object return by the attribute lookup are pushed. @@ -971,7 +969,7 @@ iterations of the loop. .. opcode:: IMPORT_NAME (namei) - Imports the module ``co_names[namei]``. TOS and TOS1 are popped and provide + Imports the module ``co_names[namei]``. TOS(1) and TOS(2) are popped and provide the *fromlist* and *level* arguments of :func:`__import__`. The module object is pushed onto the stack. The current namespace is not affected: for a proper import statement, a subsequent :opcode:`STORE_FAST` instruction @@ -980,7 +978,7 @@ iterations of the loop. .. opcode:: IMPORT_FROM (namei) - Loads the attribute ``co_names[namei]`` from the module found in TOS. The + Loads the attribute ``co_names[namei]`` from the module found in TOS(1). The resulting object is pushed onto the stack, to be subsequently stored by a :opcode:`STORE_FAST` instruction. @@ -1006,7 +1004,7 @@ iterations of the loop. .. opcode:: POP_JUMP_IF_TRUE (delta) - If TOS is true, increments the bytecode counter by *delta*. TOS is popped. + If TOS(1) is true, increments the bytecode counter by *delta*. TOS(1) is popped. .. versionchanged:: 3.11 The oparg is now a relative delta rather than an absolute target. @@ -1018,7 +1016,7 @@ iterations of the loop. .. opcode:: POP_JUMP_IF_FALSE (delta) - If TOS is false, increments the bytecode counter by *delta*. TOS is popped. + If TOS(1) is false, increments the bytecode counter by *delta*. TOS(1) is popped. .. versionchanged:: 3.11 The oparg is now a relative delta rather than an absolute target. @@ -1030,7 +1028,10 @@ iterations of the loop. .. opcode:: POP_JUMP_IF_NOT_NONE (delta) - If TOS is not ``None``, increments the bytecode counter by *delta*. TOS is popped. + If TOS(1) is not ``None``, increments the bytecode counter by *delta*. TOS(1) is popped. + + This opcode is a pseudo-instruction, replaced in final bytecode by + the directed versions (forward/backward). .. versionadded:: 3.11 @@ -1040,8 +1041,11 @@ iterations of the loop. .. opcode:: POP_JUMP_IF_NONE (delta) - If TOS is ``None``, increments the bytecode counter by *delta*. TOS is popped. + If TOS(1) is ``None``, increments the bytecode counter by *delta*. TOS(1) is popped. + This opcode is a pseudo-instruction, replaced in final bytecode by + the directed versions (forward/backward). + .. versionadded:: 3.11 .. versionchanged:: 3.12 @@ -1050,8 +1054,8 @@ iterations of the loop. .. opcode:: JUMP_IF_TRUE_OR_POP (delta) - If TOS is true, increments the bytecode counter by *delta* and leaves TOS on the - stack. Otherwise (TOS is false), TOS is popped. + If TOS(1) is true, increments the bytecode counter by *delta* and leaves TOS(1) on the + stack. Otherwise (TOS(1) is false), TOS(1) is popped. .. versionadded:: 3.1 @@ -1060,8 +1064,8 @@ iterations of the loop. .. opcode:: JUMP_IF_FALSE_OR_POP (delta) - If TOS is false, increments the bytecode counter by *delta* and leaves TOS on the - stack. Otherwise (TOS is true), TOS is popped. + If TOS(1) is false, increments the bytecode counter by *delta* and leaves TOS(1) on the + stack. Otherwise (TOS(1) is true), TOS(1) is popped. .. versionadded:: 3.1 @@ -1071,7 +1075,7 @@ iterations of the loop. .. opcode:: FOR_ITER (delta) - TOS is an :term:`iterator`. Call its :meth:`~iterator.__next__` method. If + TOS(1) is an :term:`iterator`. Call its :meth:`~iterator.__next__` method. If this yields a new value, push it on the stack (leaving the iterator below it). If the iterator indicates it is exhausted then the byte code counter is incremented by *delta*. @@ -1105,7 +1109,7 @@ iterations of the loop. .. opcode:: STORE_FAST (var_num) - Stores TOS into the local ``co_varnames[var_num]``. + Stores TOS(1) into the local ``co_varnames[var_num]``. .. opcode:: DELETE_FAST (var_num) @@ -1156,7 +1160,7 @@ iterations of the loop. .. opcode:: STORE_DEREF (i) - Stores TOS into the cell contained in slot ``i`` of the "fast locals" + Stores TOS(1) into the cell contained in slot ``i`` of the "fast locals" storage. .. versionchanged:: 3.11 @@ -1189,9 +1193,9 @@ iterations of the loop. depending on the value of *argc*: * 0: ``raise`` (re-raise previous exception) - * 1: ``raise TOS`` (raise exception instance or type at ``TOS``) - * 2: ``raise TOS1 from TOS`` (raise exception instance or type at ``TOS1`` - with ``__cause__`` set to ``TOS``) + * 1: ``raise TOS(1)`` (raise exception instance or type at ``TOS(1)``) + * 2: ``raise TOS(2) from TOS(1)`` (raise exception instance or type at ``TOS(2)`` + with ``__cause__`` set to ``TOS(1)``) .. opcode:: CALL (argc) @@ -1266,8 +1270,8 @@ iterations of the loop. * ``0x02`` a dictionary of keyword-only parameters' default values * ``0x04`` a tuple of strings containing parameters' annotations * ``0x08`` a tuple containing cells for free variables, making a closure - * the code associated with the function (at TOS1) - * the :term:`qualified name` of the function (at TOS) + * the code associated with the function (at TOS(2)) + * the :term:`qualified name` of the function (at TOS(1)) .. versionchanged:: 3.10 Flag value ``0x04`` is a tuple of strings instead of dictionary @@ -1277,7 +1281,7 @@ iterations of the loop. .. index:: builtin: slice Pushes a slice object on the stack. *argc* must be 2 or 3. If it is 2, - ``slice(TOS1, TOS)`` is pushed; if it is 3, ``slice(TOS2, TOS1, TOS)`` is + ``slice(TOS(2), TOS(1))`` is pushed; if it is 3, ``slice(TOS(3), TOS(2), TOS(1))`` is pushed. See the :func:`slice` built-in function for more information. @@ -1313,12 +1317,12 @@ iterations of the loop. .. opcode:: MATCH_CLASS (count) - TOS is a tuple of keyword attribute names, TOS1 is the class being matched - against, and TOS2 is the match subject. *count* is the number of positional + TOS(1) is a tuple of keyword attribute names, TOS(2) is the class being matched + against, and TOS(3) is the match subject. *count* is the number of positional sub-patterns. - Pop TOS, TOS1, and TOS2. If TOS2 is an instance of TOS1 and has the - positional and keyword attributes required by *count* and TOS, push a tuple + Pop TOS(1), TOS(2), and TOS(3). If TOS(3) is an instance of TOS(2) and has the + positional and keyword attributes required by *count* and TOS(1), push a tuple of extracted attributes. Otherwise, push ``None``. .. versionadded:: 3.10 @@ -1352,7 +1356,7 @@ iterations of the loop. .. opcode:: SEND (delta) - Equivalent to ``TOS = TOS1.send(TOS)``. Used in ``yield from`` and ``await`` + Equivalent to ``TOS(1) = TOS(2).send(TOS(1))``. Used in ``yield from`` and ``await`` statements. If the call raises :exc:`StopIteration`, pop both items, push the From 717f2e59f0268b1a7364031c97e461cc4ff3e78b Mon Sep 17 00:00:00 2001 From: Matthieu Dartiailh Date: Tue, 8 Nov 2022 09:48:29 +0100 Subject: [PATCH 06/16] docs: use STACK to describe stack operation in analogy with a Python list --- Doc/library/dis.rst | 227 ++++++++++++++++++++++++-------------------- 1 file changed, 125 insertions(+), 102 deletions(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 90a39ca750b2cb..d1a1967d8bda6e 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -402,7 +402,9 @@ The Python compiler currently generates the following bytecode instructions. **General instructions** -In the following, TOS(i) refers to the *i*-th item on the stack which is index from 1. +In the following, We will refer to the interpreter stack as STACK and describe +operations on it as if it was a Python list. The top of the stack corresponds to +STACK[-1] in this language. .. opcode:: NOP @@ -412,7 +414,9 @@ In the following, TOS(i) refers to the *i*-th item on the stack which is index f .. opcode:: POP_TOP - Removes the top-of-stack (TOS(1)) item. + Removes the top-of-stack item.:: + + STACK.pop() .. opcode:: END_FOR @@ -426,15 +430,21 @@ In the following, TOS(i) refers to the *i*-th item on the stack which is index f .. opcode:: COPY (i) - Push TOS(i) to the top of the stack. The item is not removed from its - original location. + Push the i-th to the top of the stack without removing it from its original + location.:: + + STACK.append(STACK[-i] .. versionadded:: 3.11 .. opcode:: SWAP (i) - Swap TOS(1) with TOS(i). + Swap the top of the stack with the i-th element.:: + + target = STACK[-i] + STACK[-i] = STACK[-1] + STACK[-1] = target .. versionadded:: 3.11 @@ -465,76 +475,76 @@ result back on the stack. .. opcode:: UNARY_NEGATIVE - Implements ``TOS(1) = -TOS(1)``. + Implements ``STACK[-1] = -STACK[-1]``. .. opcode:: UNARY_NOT - Implements ``TOS(1) = not TOS(1)``. + Implements ``STACK[-1] = not STACK[-1]``. .. opcode:: UNARY_INVERT - Implements ``TOS(1) = ~TOS(1)``. + Implements ``STACK[-1] = ~STACK[-1]``. .. opcode:: GET_ITER - Implements ``TOS(1) = iter(TOS(1))``. + Implements ``STACK[-1] = iter(STACK[-1])``. .. opcode:: GET_YIELD_FROM_ITER - If ``TOS(1)`` is a :term:`generator iterator` or :term:`coroutine` object - it is left as is. Otherwise, implements ``TOS(1) = iter(TOS(1))``. + If ``STACK[-1]`` is a :term:`generator iterator` or :term:`coroutine` object + it is left as is. Otherwise, implements ``STACK[-1] = iter(STACK[-1])``. .. versionadded:: 3.5 **Binary and in-place operations** -Binary operations remove the top two items from the stack (TOS(1) and TOS(2)). -They perform the operation, then put the result back on the stack. +Binary operations remove the top two items from the stack (``STACK[-1]`` and +``STACK[-2]``). They perform the operation, then put the result back on the stack. In-place operations are like binary operations, but the operation is done in-place -when TOS(2) supports it, and the resulting TOS(1) may be (but does not have to be) -the original TOS(2). +when ``STACK[-2]`` supports it, and the resulting ``STACK[-1]`` may be (but does +not have to be) the original ``STACK[-2]``. .. opcode:: BINARY_OP (op) Implements the binary and in-place operators (depending on the value of *op*). - ``TOS(1) = TOS(2) op TOS(1)``. + ``STACK[-1] = op STACK[-1]``. .. versionadded:: 3.11 .. opcode:: BINARY_SUBSCR - Implements ``TOS(1) = TOS(2)[TOS(1)]``. + Implements ``STACK[-1] = STACK[-2][STACK[-1]]``. .. opcode:: STORE_SUBSCR - Implements ``TOS(2)[TOS(1)] = TOS(3)``. + Implements ``STACK[-2][STACK[-1]] = STACK[-3]``. .. opcode:: DELETE_SUBSCR - Implements ``del TOS(2)[TOS(1)]``. + Implements ``del STACK[-2][STACK[-1]]``. .. opcode:: BINARY_SLICE - Implements ``TOS(1) = TOS(3)[TOS(2):TOS(1)]``. + Implements ``STACK[-1] = STACK[-3][STACK[-2]:STACK[-1]]``. .. versionadded:: 3.12 .. opcode:: STORE_SLICE - Implements ``TOS(3)[TOS(2):TOS(1)] = TOS(4)``. + Implements ``STACK[-3][STACK[-2]:STACK[-1]] = STACK[-4]``. .. versionadded:: 3.12 @@ -543,7 +553,7 @@ the original TOS(2). .. opcode:: GET_AWAITABLE (where) - Implements ``TOS(1) = get_awaitable(TOS(1))``, where ``get_awaitable(o)`` + Implements ``STACK[-1] = get_awaitable(STACK[-1])``, 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__``. @@ -562,7 +572,7 @@ the original TOS(2). .. opcode:: GET_AITER - Implements ``TOS(1) = TOS(1).__aiter__()``. + Implements ``STACK[-1] = STACK[-1].__aiter__()``. .. versionadded:: 3.5 .. versionchanged:: 3.7 @@ -572,8 +582,8 @@ the original TOS(2). .. opcode:: GET_ANEXT - Pushes ``get_awaitable(TOS(1).__anext__())`` to the stack. See - ``GET_AWAITABLE`` for details about ``get_awaitable``. + Implement ``STACK.append(get_awaitable(STACK[-1].__anext__()))`` to the stack. + See ``GET_AWAITABLE`` for details about ``get_awaitable``. .. versionadded:: 3.5 @@ -581,7 +591,7 @@ the original TOS(2). .. opcode:: END_ASYNC_FOR Terminates an :keyword:`async for` loop. Handles an exception raised - when awaiting a next item. If TOS(1) is :exc:`StopAsyncIteration` pop 3 + when awaiting a next item. If ``STACK[-1]`` is :exc:`StopAsyncIteration` pop 3 values from the stack and restore the exception state using the second of them. Otherwise re-raise the exception using the value from the stack. An exception handler block is removed from the block stack. @@ -595,17 +605,19 @@ the original TOS(2). .. opcode:: CLEANUP_THROW Handles an exception raised during a :meth:`~generator.throw` or - :meth:`~generator.close` call through the current frame. If TOS(1) is an + :meth:`~generator.close` call through the current frame. If ``STACK[-1]`` is an instance of :exc:`StopIteration`, pop three values from the stack and push - its ``value`` member. Otherwise, re-raise TOS(1). + its ``value`` member. Otherwise, re-raise ``STACK[-1]``. .. versionadded:: 3.12 .. opcode:: BEFORE_ASYNC_WITH - Resolves ``__aenter__`` and ``__aexit__`` from the object on top of the - stack. Pushes ``__aexit__`` and result of ``__aenter__()`` to the stack. + Resolves ``__aenter__`` and ``__aexit__`` from ``STACK[-1]``. + Pushes ``__aexit__`` and result of ``__aenter__()`` to the stack:: + + STACK.extend((__aexit__, __aenter__()) .. versionadded:: 3.5 @@ -615,22 +627,23 @@ the original TOS(2). .. opcode:: SET_ADD (i) - Calls ``set.add(TOS(2)[-i], TOS(1))``. Used to implement set comprehensions. + Calls ``set.add(STACK[-i], STACK[-1])``. Used to implement set comprehensions. .. opcode:: LIST_APPEND (i) - Calls ``list.append(TOS(2)[-i], TOS(1))``. Used to implement list comprehensions. + Calls ``list.append(STACK[-i], STACK[-1])``. Used to implement list comprehensions. .. opcode:: MAP_ADD (i) - Calls ``dict.__setitem__(TOS(2)[-i], TOS(2), TOS(1))``. Used to implement dict + Calls ``dict.__setitem__(STACK[-i], STACK[-2], STACK[-1])``. Used to implement dict comprehensions. .. versionadded:: 3.1 .. versionchanged:: 3.8 - Map value is TOS(1) and map key is TOS(2). Before, those were reversed. + Map value is ``STACK[-1]`` and map key is ``STACK[-2]``. Before, those + were reversed. For all of the :opcode:`SET_ADD`, :opcode:`LIST_APPEND` and :opcode:`MAP_ADD` instructions, while the added value or key/value pair is popped off, the @@ -640,12 +653,12 @@ iterations of the loop. .. opcode:: RETURN_VALUE - Returns with TOS(1) to the caller of the function. + Returns with ``STACK[-1]`` to the caller of the function. .. opcode:: YIELD_VALUE - Pops TOS(1) and yields it from a :term:`generator`. + Yields ``STACK.pop()`` from a :term:`generator`. .. versionchanged:: 3.11 oparg set to be the stack depth, for efficient handling on frames. @@ -689,15 +702,16 @@ iterations of the loop. .. opcode:: CHECK_EXC_MATCH - Performs exception matching for ``except``. Tests whether the TOS(2) is an exception - matching TOS(1). Pops TOS(1) and pushes the boolean result of the test. + Performs exception matching for ``except``. Tests whether the ``STACK[-2]`` + is an exception matching ``STACK[-1]``. Pops STACK[-1] and pushes the boolean + result of the test. .. versionadded:: 3.11 .. opcode:: CHECK_EG_MATCH - Performs exception matching for ``except*``. Applies ``split(TOS(1))`` on - the exception group representing TOS(2). + Performs exception matching for ``except*``. Applies ``split(STACK[-1])`` on + the exception group representing ``STACK[-2]``. In case of a match, pops two items from the stack and pushes the non-matching subgroup (``None`` in case of full match) followed by the @@ -708,9 +722,9 @@ iterations of the loop. .. opcode:: PREP_RERAISE_STAR - Combines the raised and reraised exceptions list from TOS(1), into an exception - group to propagate from a try-except* block. Uses the original exception - group from TOS(2) to reconstruct the structure of reraised exceptions. Pops + Combines the raised and reraised exceptions list from ``STACK[-1]``, into an + exception group to propagate from a try-except* block. Uses the original exception + group from ``STACK[-2]`` to reconstruct the structure of reraised exceptions. Pops two items from the stack and pushes the exception to reraise or ``None`` if there isn't one. @@ -757,24 +771,24 @@ iterations of the loop. .. opcode:: GET_LEN - Push ``len(TOS(1))`` onto the stack. + Perform ``STACK.append(len(STACK[-1]))``. .. versionadded:: 3.10 .. opcode:: MATCH_MAPPING - If TOS(1) is an instance of :class:`collections.abc.Mapping` (or, more technically: if - it has the :const:`Py_TPFLAGS_MAPPING` flag set in its - :c:member:`~PyTypeObject.tp_flags`), push ``True`` onto the stack. Otherwise, push - ``False``. + If ``STACK[-1]`` is an instance of :class:`collections.abc.Mapping` (or, more + technically: if it has the :const:`Py_TPFLAGS_MAPPING` flag set in its + :c:member:`~PyTypeObject.tp_flags`), push ``True`` onto the stack. Otherwise, + push ``False``. .. versionadded:: 3.10 .. opcode:: MATCH_SEQUENCE - If TOS(1) is an instance of :class:`collections.abc.Sequence` and is *not* an instance + If ``STACK[-1]`` is an instance of :class:`collections.abc.Sequence` and is *not* an instance of :class:`str`/:class:`bytes`/:class:`bytearray` (or, more technically: if it has the :const:`Py_TPFLAGS_SEQUENCE` flag set in its :c:member:`~PyTypeObject.tp_flags`), push ``True`` onto the stack. Otherwise, push ``False``. @@ -784,9 +798,9 @@ iterations of the loop. .. opcode:: MATCH_KEYS - TOS(1) is a tuple of mapping keys, and TOS(2) is the match subject. If TOS(2) - contains all of the keys in TOS(1), push a :class:`tuple` containing the - corresponding values. Otherwise, push ``None``. + ``STACK[-1]`` is a tuple of mapping keys, and ``STACK[-2]`` is the match subject. + If ``STACK[-2]`` contains all of the keys in ``STACK[-1]``, push a :class:`tuple` + containing the corresponding values. Otherwise, push ``None``. .. versionadded:: 3.10 @@ -797,7 +811,7 @@ iterations of the loop. .. opcode:: STORE_NAME (namei) - Implements ``name = TOS(1)``. *namei* is the index of *name* in the attribute + Implements ``name = STACK[-1]``. *namei* is the index of *name* in the attribute :attr:`co_names` of the code object. The compiler tries to use :opcode:`STORE_FAST` or :opcode:`STORE_GLOBAL` if possible. @@ -810,8 +824,10 @@ iterations of the loop. .. opcode:: UNPACK_SEQUENCE (count) - Unpacks TOS(1) into *count* individual values, which are put onto the stack - right-to-left. + Unpacks ``STACK[-1]`` into *count* individual values, which are put onto the stack + right-to-left.:: + + STACK.extend(STACK.pop()[:count:-1]) .. opcode:: UNPACK_EX (counts) @@ -828,13 +844,13 @@ iterations of the loop. .. opcode:: STORE_ATTR (namei) - Implements ``TOS(1).name = TOS(2)``, where *namei* is the index of name in - :attr:`co_names`. + Implements ``STACK[-1].name = STACK[-2]``, where *namei* is the index of name in + :attr:`co_names`. Both values are popped from the stack. .. opcode:: DELETE_ATTR (namei) - Implements ``del TOS(1).name``, using *namei* as index into :attr:`co_names`. + Implements ``del STACK[-1].name``, using *namei* as index into :attr:`co_names`. .. opcode:: STORE_GLOBAL (namei) @@ -860,7 +876,9 @@ iterations of the loop. .. opcode:: BUILD_TUPLE (count) Creates a tuple consuming *count* items from the stack, and pushes the - resulting tuple onto the stack. + resulting tuple onto the stack.:: + + STACK.append(tuple(STACK[-count:])) .. opcode:: BUILD_LIST (count) @@ -877,7 +895,7 @@ iterations of the loop. Pushes a new dictionary object onto the stack. Pops ``2 * count`` items so that the dictionary holds *count* entries: - ``{..., TOS(4): TOS(3), TOS(2): TOS(1)}``. + ``{..., STACK[-4]: STACK[-3], STACK[-2]: STACK[-1]}``. .. versionchanged:: 3.5 The dictionary is created from stack items instead of creating an @@ -888,7 +906,7 @@ iterations of the loop. The version of :opcode:`BUILD_MAP` specialized for constant keys. Pops the top element on the stack which contains a tuple of keys, then starting from - ``TOS(2)``, pops *count* values to form values in the built dictionary. + ``STACK[-2]``, pops *count* values to form values in the built dictionary. .. versionadded:: 3.6 @@ -903,21 +921,21 @@ iterations of the loop. .. opcode:: LIST_EXTEND (i) - Calls ``list.extend(TOS(2)[-i], TOS(1))``. Used to build lists. + Calls ``list.extend(STACK[-i], STACK[-1])``. Used to build lists. .. versionadded:: 3.9 .. opcode:: SET_UPDATE (i) - Calls ``set.update(TOS(2)[-i], TOS(1))``. Used to build sets. + Calls ``set.update(STACK[-i], STACK[-1])``. Used to build sets. .. versionadded:: 3.9 .. opcode:: DICT_UPDATE (i) - Calls ``dict.update(TOS(2)[-i], TOS(1))``. Used to build dicts. + Calls ``dict.update(STACK[-i], STACK[-1])``. Used to build dicts. .. versionadded:: 3.9 @@ -931,16 +949,16 @@ iterations of the loop. .. opcode:: LOAD_ATTR (namei) - If the low bit of ``namei`` is not set, this replaces TOS(1) with - ``getattr(TOS(1), co_names[namei>>1])``. + If the low bit of ``namei`` is not set, this replaces ``STACK[-1]`` with + ``getattr(STACK[-1], co_names[namei>>1])``. If the low bit of ``namei`` is set, this will attempt to load a method named - ``co_names[namei>>1]`` from the TOS(1) object. TOS(1) is popped. - This bytecode distinguishes two cases: if TOS(1) has a method with the correct - name, the bytecode pushes the unbound method and TOS(1). TOS(1) will be used as - the first argument (``self``) by :opcode:`CALL` when calling the - unbound method. Otherwise, ``NULL`` and the object return by the attribute - lookup are pushed. + ``co_names[namei>>1]`` from the ``STACK[-1]`` object. ``STACK[-1]`` is popped. + This bytecode distinguishes two cases: if ``STACK[-1]`` has a method with the + correct name, the bytecode pushes the unbound method and ``STACK[-1]``. + ``STACK[-1]`` will be used as the first argument (``self``) by :opcode:`CALL` + when calling the unbound method. Otherwise, ``NULL`` and the object return by + the attribute lookup are pushed. .. versionchanged:: 3.12 If the low bit of ``namei`` is set, then a ``NULL`` or ``self`` is @@ -969,17 +987,16 @@ iterations of the loop. .. opcode:: IMPORT_NAME (namei) - Imports the module ``co_names[namei]``. TOS(1) and TOS(2) are popped and provide - the *fromlist* and *level* arguments of :func:`__import__`. The module - object is pushed onto the stack. The current namespace is not affected: for - a proper import statement, a subsequent :opcode:`STORE_FAST` instruction + Imports the module ``co_names[namei]``. ``STACK[-1]`` and ``STACK[-2]`` are + popped and provide the *fromlist* and *level* arguments of :func:`__import__`. + The module object is pushed onto the stack. The current namespace is not affected: for a proper import statement, a subsequent :opcode:`STORE_FAST` instruction modifies the namespace. .. opcode:: IMPORT_FROM (namei) - Loads the attribute ``co_names[namei]`` from the module found in TOS(1). The - resulting object is pushed onto the stack, to be subsequently stored by a + Loads the attribute ``co_names[namei]`` from the module found in ``STACK[-1]``. + The resulting object is pushed onto the stack, to be subsequently stored by a :opcode:`STORE_FAST` instruction. @@ -1004,7 +1021,8 @@ iterations of the loop. .. opcode:: POP_JUMP_IF_TRUE (delta) - If TOS(1) is true, increments the bytecode counter by *delta*. TOS(1) is popped. + If ``STACK[-1]`` is true, increments the bytecode counter by *delta*. + ``STACK[-1]`` is popped. .. versionchanged:: 3.11 The oparg is now a relative delta rather than an absolute target. @@ -1016,7 +1034,8 @@ iterations of the loop. .. opcode:: POP_JUMP_IF_FALSE (delta) - If TOS(1) is false, increments the bytecode counter by *delta*. TOS(1) is popped. + If ``STACK[-1]`` is false, increments the bytecode counter by *delta*. + ``STACK[-1]`` is popped. .. versionchanged:: 3.11 The oparg is now a relative delta rather than an absolute target. @@ -1028,7 +1047,8 @@ iterations of the loop. .. opcode:: POP_JUMP_IF_NOT_NONE (delta) - If TOS(1) is not ``None``, increments the bytecode counter by *delta*. TOS(1) is popped. + If ``STACK[-1]`` is not ``None``, increments the bytecode counter by *delta*. + ``STACK[-1]`` is popped. This opcode is a pseudo-instruction, replaced in final bytecode by the directed versions (forward/backward). @@ -1041,7 +1061,8 @@ iterations of the loop. .. opcode:: POP_JUMP_IF_NONE (delta) - If TOS(1) is ``None``, increments the bytecode counter by *delta*. TOS(1) is popped. + If ``STACK[-1]`` is ``None``, increments the bytecode counter by *delta*. + ``STACK[-1]`` is popped. This opcode is a pseudo-instruction, replaced in final bytecode by the directed versions (forward/backward). @@ -1054,8 +1075,9 @@ iterations of the loop. .. opcode:: JUMP_IF_TRUE_OR_POP (delta) - If TOS(1) is true, increments the bytecode counter by *delta* and leaves TOS(1) on the - stack. Otherwise (TOS(1) is false), TOS(1) is popped. + If ``STACK[-1]`` is true, increments the bytecode counter by *delta* and leaves + ``STACK[-1]`` on the stack. Otherwise (``STACK[-1]`` is false), ``STACK[-1]`` + is popped. .. versionadded:: 3.1 @@ -1064,8 +1086,9 @@ iterations of the loop. .. opcode:: JUMP_IF_FALSE_OR_POP (delta) - If TOS(1) is false, increments the bytecode counter by *delta* and leaves TOS(1) on the - stack. Otherwise (TOS(1) is true), TOS(1) is popped. + If ``STACK[-1]`` is false, increments the bytecode counter by *delta* and leaves + ``STACK[-1]`` on the stack. Otherwise (``STACK[-1]`` is true), ``STACK[-1]`` is + popped. .. versionadded:: 3.1 @@ -1075,7 +1098,7 @@ iterations of the loop. .. opcode:: FOR_ITER (delta) - TOS(1) is an :term:`iterator`. Call its :meth:`~iterator.__next__` method. If + ``STACK[-1]`` is an :term:`iterator`. Call its :meth:`~iterator.__next__` method. If this yields a new value, push it on the stack (leaving the iterator below it). If the iterator indicates it is exhausted then the byte code counter is incremented by *delta*. @@ -1109,7 +1132,7 @@ iterations of the loop. .. opcode:: STORE_FAST (var_num) - Stores TOS(1) into the local ``co_varnames[var_num]``. + Stores ``STACK.pop()`` into the local ``co_varnames[var_num]``. .. opcode:: DELETE_FAST (var_num) @@ -1160,7 +1183,7 @@ iterations of the loop. .. opcode:: STORE_DEREF (i) - Stores TOS(1) into the cell contained in slot ``i`` of the "fast locals" + Stores ``STACK.pop()`` into the cell contained in slot ``i`` of the "fast locals" storage. .. versionchanged:: 3.11 @@ -1193,9 +1216,9 @@ iterations of the loop. depending on the value of *argc*: * 0: ``raise`` (re-raise previous exception) - * 1: ``raise TOS(1)`` (raise exception instance or type at ``TOS(1)``) - * 2: ``raise TOS(2) from TOS(1)`` (raise exception instance or type at ``TOS(2)`` - with ``__cause__`` set to ``TOS(1)``) + * 1: ``raise STACK[-1]`` (raise exception instance or type at ``STACK[-1]``) + * 2: ``raise STACK[-2] from STACK[-1]`` (raise exception instance or type at + ``STACK[-2]`` with ``__cause__`` set to ``STACK[-1]``) .. opcode:: CALL (argc) @@ -1270,8 +1293,8 @@ iterations of the loop. * ``0x02`` a dictionary of keyword-only parameters' default values * ``0x04`` a tuple of strings containing parameters' annotations * ``0x08`` a tuple containing cells for free variables, making a closure - * the code associated with the function (at TOS(2)) - * the :term:`qualified name` of the function (at TOS(1)) + * the code associated with the function (at ``STACK[-2]``) + * the :term:`qualified name` of the function (at ``STACK[-1]``) .. versionchanged:: 3.10 Flag value ``0x04`` is a tuple of strings instead of dictionary @@ -1281,7 +1304,7 @@ iterations of the loop. .. index:: builtin: slice Pushes a slice object on the stack. *argc* must be 2 or 3. If it is 2, - ``slice(TOS(2), TOS(1))`` is pushed; if it is 3, ``slice(TOS(3), TOS(2), TOS(1))`` is + ``slice(STACK[-2], STACK[-1])`` is pushed; if it is 3, ``slice(STACK[-3], STACK[-2], STACK[-1])`` is pushed. See the :func:`slice` built-in function for more information. @@ -1317,13 +1340,13 @@ iterations of the loop. .. opcode:: MATCH_CLASS (count) - TOS(1) is a tuple of keyword attribute names, TOS(2) is the class being matched - against, and TOS(3) is the match subject. *count* is the number of positional - sub-patterns. + ``STACK[-1]`` is a tuple of keyword attribute names, ``STACK[-2]`` is the class + being matched against, and ``STACK[-3]`` is the match subject. *count* is the + number of positional sub-patterns. - Pop TOS(1), TOS(2), and TOS(3). If TOS(3) is an instance of TOS(2) and has the - positional and keyword attributes required by *count* and TOS(1), push a tuple - of extracted attributes. Otherwise, push ``None``. + Pop ``STACK[-1]``, ``STACK[-2]``, and ``STACK[-3]``. If ``STACK[-3]`` is an + instance of ``STACK[-2]`` and has the positional and keyword attributes + required by *count* and ``STACK[-1]``, push a tuple of extracted attributes. Otherwise, push ``None``. .. versionadded:: 3.10 @@ -1356,7 +1379,7 @@ iterations of the loop. .. opcode:: SEND (delta) - Equivalent to ``TOS(1) = TOS(2).send(TOS(1))``. Used in ``yield from`` and ``await`` + Equivalent to ``STACK[-1] = STACK[-2].send(STACK[-1])``. Used in ``yield from`` and ``await`` statements. If the call raises :exc:`StopIteration`, pop both items, push the From 2ebf26c9a37ea08296304c3b842740e14af86d1b Mon Sep 17 00:00:00 2001 From: Matthieu Dartiailh Date: Tue, 8 Nov 2022 09:49:04 +0100 Subject: [PATCH 07/16] docs: remove (delta) from BEFORE_WITH since BEFORE_WITH does not take an argument --- Doc/library/dis.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index d1a1967d8bda6e..8dbbb22003e399 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -758,7 +758,7 @@ iterations of the loop. to construct a class. -.. opcode:: BEFORE_WITH (delta) +.. opcode:: BEFORE_WITH This opcode performs several operations before a with block starts. First, it loads :meth:`~object.__exit__` from the context manager and pushes it onto From 62f007c2bad239a71f28bc5b2b981c1cfb0ff280 Mon Sep 17 00:00:00 2001 From: Matthieu Dartiailh Date: Tue, 8 Nov 2022 09:49:30 +0100 Subject: [PATCH 08/16] docs: clarify UNPACK_EX documentation --- Doc/library/dis.rst | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 8dbbb22003e399..8c8b1be2baed72 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -832,14 +832,21 @@ iterations of the loop. .. opcode:: UNPACK_EX (counts) - Implements assignment with a starred target: Unpacks an iterable in TOS(1) into - individual values, where the total number of values can be smaller than the + Implements assignment with a starred target: Unpacks an iterable in ``STACK[-1]`` + into individual values, where the total number of values can be smaller than the number of items in the iterable: one of the new values will be a list of all leftover items. - The low byte of *counts* is the number of values before the list value, the - high byte of *counts* the number of values after it. The resulting values - are put onto the stack right-to-left. + The number of values before and after the list value is limited to 255. + + The number of values before the list value is encoded in the argument of the + opcode. The number of values after the list if any is encoded using an + ``EXTENDED_ARG``. As a consequence, the argument can be seen as a two bytes values + where the low byte of *counts* is the number of values before the list value, the + high byte of *counts* the number of values after it. + + The extracted values are put onto the stack right-to-left, i.e. ``a, *b, c = d`` + will be stored after execution as ``STACK.extend((a, b, c))``. .. opcode:: STORE_ATTR (namei) From f5542af85bda66530168d64779a149d4255faf8b Mon Sep 17 00:00:00 2001 From: Matthieu Dartiailh Date: Tue, 8 Nov 2022 09:49:59 +0100 Subject: [PATCH 09/16] docs: fix typo in KW_NAMES documentation (i -> consti) --- Doc/library/dis.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 8c8b1be2baed72..5906bf3044cdfb 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -1281,7 +1281,7 @@ iterations of the loop. .. versionadded:: 3.11 -.. opcode:: KW_NAMES (i) +.. opcode:: KW_NAMES (consti) Prefixes :opcode:`CALL`. Stores a reference to ``co_consts[consti]`` into an internal variable From 7c11ec0dc7578599df2ae3b28b8d3a2cc18bbfe6 Mon Sep 17 00:00:00 2001 From: Matthieu Dartiailh Date: Tue, 8 Nov 2022 09:50:29 +0100 Subject: [PATCH 10/16] docs: clarify the use of RESUME and RETURN_GENERATOR opcodes --- Doc/library/dis.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 5906bf3044cdfb..95d545b3a2dfba 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -1368,7 +1368,8 @@ iterations of the loop. The ``where`` operand marks where the ``RESUME`` occurs: - * ``0`` The start of a function + * ``0`` The start of a function, which is neither a generator, coroutine + nor an async generator * ``1`` After a ``yield`` expression * ``2`` After a ``yield from`` expression * ``3`` After an ``await`` expression @@ -1379,6 +1380,7 @@ iterations of the loop. .. opcode:: RETURN_GENERATOR Create a generator, coroutine, or async generator from the current frame. + Used as first opcode of in code object for the above mentioned callables. Clear the current frame and return the newly created generator. .. versionadded:: 3.11 From 8d9585274fec7eac18211aa692aca7bd5f7e17ad Mon Sep 17 00:00:00 2001 From: Matthieu Dartiailh Date: Tue, 8 Nov 2022 09:54:11 +0100 Subject: [PATCH 11/16] docs: simplify SWAP documentation --- Doc/library/dis.rst | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 95d545b3a2dfba..141b53050de7b7 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -442,9 +442,7 @@ STACK[-1] in this language. Swap the top of the stack with the i-th element.:: - target = STACK[-i] - STACK[-i] = STACK[-1] - STACK[-1] = target + STACK[-i], STACK[-1] = stack[-1], STACK[-i] .. versionadded:: 3.11 From e37fd63fcbc1defe58fdcd84d3a630b3a6aec191 Mon Sep 17 00:00:00 2001 From: Matthieu Dartiailh Date: Thu, 22 Dec 2022 16:04:25 +0100 Subject: [PATCH 12/16] Apply suggestions from code review Co-authored-by: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> --- Doc/library/dis.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 141b53050de7b7..f70ab36f32f71c 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -430,10 +430,10 @@ STACK[-1] in this language. .. opcode:: COPY (i) - Push the i-th to the top of the stack without removing it from its original + Push the i-th item to the top of the stack without removing it from its original location.:: - STACK.append(STACK[-i] + STACK.append(STACK[-i]) .. versionadded:: 3.11 From 5564a055e625db0461df80d379fce07bbdf2801f Mon Sep 17 00:00:00 2001 From: Matthieu Dartiailh Date: Fri, 23 Dec 2022 15:50:16 +0100 Subject: [PATCH 13/16] docs: remove trailing whitespaces --- Doc/library/dis.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index f70ab36f32f71c..99c41b5c08dd47 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -1071,7 +1071,7 @@ iterations of the loop. This opcode is a pseudo-instruction, replaced in final bytecode by the directed versions (forward/backward). - + .. versionadded:: 3.11 .. versionchanged:: 3.12 From f0d7f1782442cb2fd3725326ad7ced375d12ba90 Mon Sep 17 00:00:00 2001 From: Matthieu Dartiailh Date: Sun, 25 Dec 2022 14:28:45 +0100 Subject: [PATCH 14/16] docs: fix the description of the stack impact of multiple opcodes --- Doc/library/dis.rst | 134 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 105 insertions(+), 29 deletions(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 99c41b5c08dd47..1449392bd9256e 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -404,7 +404,7 @@ The Python compiler currently generates the following bytecode instructions. In the following, We will refer to the interpreter stack as STACK and describe operations on it as if it was a Python list. The top of the stack corresponds to -STACK[-1] in this language. +``STACK[-1]`` in this language. .. opcode:: NOP @@ -512,37 +512,63 @@ not have to be) the original ``STACK[-2]``. .. opcode:: BINARY_OP (op) Implements the binary and in-place operators (depending on the value of - *op*). - ``STACK[-1] = op STACK[-1]``. + *op*).:: + + rhs = STACK.pop() + lhs = STACK.pop() + STACK.append(lhs op rhs) .. versionadded:: 3.11 .. opcode:: BINARY_SUBSCR - Implements ``STACK[-1] = STACK[-2][STACK[-1]]``. + Implements:: + + key = STACK.pop() + container = STACK.pop() + STACK.append(container[index]) .. opcode:: STORE_SUBSCR - Implements ``STACK[-2][STACK[-1]] = STACK[-3]``. + Implements:: + + key = STACK.pop() + container = STACK.pop() + value = STACK.pop() + container[key] = value .. opcode:: DELETE_SUBSCR - Implements ``del STACK[-2][STACK[-1]]``. + Implements:: + key = STACK.pop() + container = STACK.pop() + del container[key] .. opcode:: BINARY_SLICE - Implements ``STACK[-1] = STACK[-3][STACK[-2]:STACK[-1]]``. + Implements:: + + end = STACK.pop() + start = STACK.pop() + container = STACK.pop() + STACK.append(container[start:end]) .. versionadded:: 3.12 .. opcode:: STORE_SLICE - Implements ``STACK[-3][STACK[-2]:STACK[-1]] = STACK[-4]``. + Implements:: + + end = STACK.pop() + start = STACK.pop() + container = STACK.pop() + values = STACK.pop() + container[start:end] = value .. versionadded:: 3.12 @@ -625,18 +651,32 @@ not have to be) the original ``STACK[-2]``. .. opcode:: SET_ADD (i) - Calls ``set.add(STACK[-i], STACK[-1])``. Used to implement set comprehensions. + Implements:: + item = STACK.pop() + set.add(STACK[-i], item) + + Used to implement set comprehensions. .. opcode:: LIST_APPEND (i) - Calls ``list.append(STACK[-i], STACK[-1])``. Used to implement list comprehensions. + Implements:: + + item = STACK.pop() + list.append(STACK[-i], item) + + Used to implement list comprehensions. .. opcode:: MAP_ADD (i) - Calls ``dict.__setitem__(STACK[-i], STACK[-2], STACK[-1])``. Used to implement dict - comprehensions. + Implements:: + + value = STACK.pop() + key = STACK.pop() + dict.__setitem__(STACK[-i], key, value) + + Used to implement dict comprehensions. .. versionadded:: 3.1 .. versionchanged:: 3.8 @@ -809,7 +849,7 @@ iterations of the loop. .. opcode:: STORE_NAME (namei) - Implements ``name = STACK[-1]``. *namei* is the index of *name* in the attribute + Implements ``name = STACK.pop()``. *namei* is the index of *name* in the attribute :attr:`co_names` of the code object. The compiler tries to use :opcode:`STORE_FAST` or :opcode:`STORE_GLOBAL` if possible. @@ -849,13 +889,22 @@ iterations of the loop. .. opcode:: STORE_ATTR (namei) - Implements ``STACK[-1].name = STACK[-2]``, where *namei* is the index of name in - :attr:`co_names`. Both values are popped from the stack. + Implements:: + + obj = STACK.pop() + value = STACK.pop() + obj.name = value + where *namei* is the index of name in :attr:`co_names`. .. opcode:: DELETE_ATTR (namei) - Implements ``del STACK[-1].name``, using *namei* as index into :attr:`co_names`. + Implements:: + + obj = STACK.pop() + del obj.name + + where *namei* is the index of name into :attr:`co_names`. .. opcode:: STORE_GLOBAL (namei) @@ -926,21 +975,36 @@ iterations of the loop. .. opcode:: LIST_EXTEND (i) - Calls ``list.extend(STACK[-i], STACK[-1])``. Used to build lists. + Implements:: + + seq = STACK.pop() + list.extend(STACK[-i], seq) + + Used to build lists. .. versionadded:: 3.9 .. opcode:: SET_UPDATE (i) - Calls ``set.update(STACK[-i], STACK[-1])``. Used to build sets. + Implements:: + + seq = STACK.pop() + set.update(STACK[-i], seq) + + Used to build sets. .. versionadded:: 3.9 .. opcode:: DICT_UPDATE (i) - Calls ``dict.update(STACK[-i], STACK[-1])``. Used to build dicts. + Implements:: + + map = STACK.pop() + dict.update(STACK[-i], map) + + Used to build dicts. .. versionadded:: 3.9 @@ -1103,10 +1167,10 @@ iterations of the loop. .. opcode:: FOR_ITER (delta) - ``STACK[-1]`` is an :term:`iterator`. Call its :meth:`~iterator.__next__` method. If - this yields a new value, push it on the stack (leaving the iterator below - it). If the iterator indicates it is exhausted then the byte - code counter is incremented by *delta*. + ``STACK[-1]`` is an :term:`iterator`. Call its :meth:`~iterator.__next__` method. + If this yields a new value, push it on the stack (leaving the iterator below + it). If the iterator indicates it is exhausted then the byte code counter is + incremented by *delta*. .. versionchanged:: 3.12 Up until 3.11 the iterator was popped when it was exhausted. @@ -1308,9 +1372,20 @@ iterations of the loop. .. index:: builtin: slice - Pushes a slice object on the stack. *argc* must be 2 or 3. If it is 2, - ``slice(STACK[-2], STACK[-1])`` is pushed; if it is 3, ``slice(STACK[-3], STACK[-2], STACK[-1])`` is - pushed. See the :func:`slice` built-in function for more information. + Pushes a slice object on the stack. *argc* must be 2 or 3. If it is 2, implements:: + + end = STACK.pop() + start = STACK.pop() + STACK.append(slice(start, stop)) + + if it is 3, implements:: + + step = STACK.pop() + end = STACK.pop() + start = STACK.pop() + STACK.append(slice(start, end, step)) + + See the :func:`slice` built-in function for more information. .. opcode:: EXTENDED_ARG (ext) @@ -1351,7 +1426,8 @@ iterations of the loop. Pop ``STACK[-1]``, ``STACK[-2]``, and ``STACK[-3]``. If ``STACK[-3]`` is an instance of ``STACK[-2]`` and has the positional and keyword attributes - required by *count* and ``STACK[-1]``, push a tuple of extracted attributes. Otherwise, push ``None``. + required by *count* and ``STACK[-1]``, push a tuple of extracted attributes. + Otherwise, push ``None``. .. versionadded:: 3.10 @@ -1386,8 +1462,8 @@ iterations of the loop. .. opcode:: SEND (delta) - Equivalent to ``STACK[-1] = STACK[-2].send(STACK[-1])``. Used in ``yield from`` and ``await`` - statements. + Equivalent to ``STACK[-1] = STACK[-2].send(STACK[-1])``. Used in ``yield from`` + and ``await`` statements. If the call raises :exc:`StopIteration`, pop both items, push the exception's ``value`` attribute, and increment the bytecode counter by From b84a7752799201020e67a8c40db111e9d93e564b Mon Sep 17 00:00:00 2001 From: Matthieu Dartiailh Date: Thu, 12 Jan 2023 16:08:09 +0100 Subject: [PATCH 15/16] dis.rst: use STACK in the CALL_INSTRINSIC_1 description --- Doc/library/dis.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 1449392bd9256e..8a086e810e92bd 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -1493,9 +1493,8 @@ iterations of the loop. .. opcode:: CALL_INTRINSIC_1 - Calls an intrinsic function with one argument. Passes the TOS as the argument - and sets TOS to the result. Used to implement functionality that is necessary - but not performance critical. + Calls an intrinsic function with one argument. Passes ``STACK[-1]`` as the + argument and sets ``STACK[-1]`` to the result. Used to implement functionality that is necessary but not performance critical. The operand determines which intrinsic function is called: From e8ec505cb392c042c8a54bb4d8a6d8f2d27ad7f0 Mon Sep 17 00:00:00 2001 From: Matthieu Dartiailh Date: Thu, 12 Jan 2023 16:47:23 +0100 Subject: [PATCH 16/16] dis.rst: address review comments --- Doc/library/dis.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 8a086e810e92bd..8e586e6c5dda4e 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -433,6 +433,7 @@ operations on it as if it was a Python list. The top of the stack corresponds to Push the i-th item to the top of the stack without removing it from its original location.:: + assert i > 0 STACK.append(STACK[-i]) .. versionadded:: 3.11 @@ -932,7 +933,9 @@ iterations of the loop. Creates a tuple consuming *count* items from the stack, and pushes the resulting tuple onto the stack.:: - STACK.append(tuple(STACK[-count:])) + assert count > 0 + STACK, values = STACK[:-count], STACK[-count:] + STACK.append(tuple(values)) .. opcode:: BUILD_LIST (count)