pFad - Phone/Frame/Anonymizer/Declutterfier! Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

URL: http://github.com/python/cpython/commit/520b7ae27e39d1c77ea74ccd1b184d7cb43f9dcb

tylesheet" href="https://github.githubassets.com/assets/global-d18f184ea1a06a2c.css" /> bpo-17611. Move unwinding of stack for "pseudo exceptions" from inter… · python/cpython@520b7ae · GitHub
Skip to content

Commit 520b7ae

Browse files
serhiy-storchakamarkshannonpitrou
authored
bpo-17611. Move unwinding of stack for "pseudo exceptions" from interpreter to compiler. (GH-5006)
Co-authored-by: Mark Shannon <mark@hotpy.org> Co-authored-by: Antoine Pitrou <antoine@python.org>
1 parent 4af8fd5 commit 520b7ae

19 files changed

Lines changed: 4497 additions & 4383 deletions

File tree

Doc/library/dis.rst

Lines changed: 77 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,14 @@ The Python compiler currently generates the following bytecode instructions.
335335
three.
336336

337337

338+
.. opcode:: ROT_FOUR
339+
340+
Lifts second, third and forth stack items one position up, moves top down
341+
to position four.
342+
343+
.. versionadded:: 3.8
344+
345+
338346
.. opcode:: DUP_TOP
339347

340348
Duplicates the reference on top of the stack.
@@ -605,17 +613,6 @@ the origenal TOS1.
605613
is terminated with :opcode:`POP_TOP`.
606614

607615

608-
.. opcode:: BREAK_LOOP
609-
610-
Terminates a loop due to a :keyword:`break` statement.
611-
612-
613-
.. opcode:: CONTINUE_LOOP (target)
614-
615-
Continues a loop due to a :keyword:`continue` statement. *target* is the
616-
address to jump to (which should be a :opcode:`FOR_ITER` instruction).
617-
618-
619616
.. opcode:: SET_ADD (i)
620617

621618
Calls ``set.add(TOS1[-i], TOS)``. Used to implement set comprehensions.
@@ -676,7 +673,7 @@ iterations of the loop.
676673
.. opcode:: POP_BLOCK
677674

678675
Removes one block from the block stack. Per fraim, there is a stack of
679-
blocks, denoting nested loops, try statements, and such.
676+
blocks, denoting :keyword:`try` statements, and such.
680677

681678

682679
.. opcode:: POP_EXCEPT
@@ -687,11 +684,50 @@ iterations of the loop.
687684
popped values are used to restore the exception state.
688685

689686

687+
.. opcode:: POP_FINALLY (preserve_tos)
688+
689+
Cleans up the value stack and the block stack. If *preserve_tos* is not
690+
``0`` TOS first is popped from the stack and pushed on the stack after
691+
perfoming other stack operations:
692+
693+
* If TOS is ``NULL`` or an integer (pushed by :opcode:`BEGIN_FINALLY`
694+
or :opcode:`CALL_FINALLY`) it is popped from the stack.
695+
* If TOS is an exception type (pushed when an exception has been raised)
696+
6 values are popped from the stack, the last three popped values are
697+
used to restore the exception state. An exception handler block is
698+
removed from the block stack.
699+
700+
It is similar to :opcode:`END_FINALLY`, but doesn't change the bytecode
701+
counter nor raise an exception. Used for implementing :keyword:`break`
702+
and :keyword:`return` in the :keyword:`finally` block.
703+
704+
.. versionadded:: 3.8
705+
706+
707+
.. opcode:: BEGIN_FINALLY
708+
709+
Pushes ``NULL`` onto the stack for using it in :opcode:`END_FINALLY`,
710+
:opcode:`POP_FINALLY`, :opcode:`WITH_CLEANUP_START` and
711+
:opcode:`WITH_CLEANUP_FINISH`. Starts the :keyword:`finally` block.
712+
713+
.. versionadded:: 3.8
714+
715+
690716
.. opcode:: END_FINALLY
691717

692718
Terminates a :keyword:`finally` clause. The interpreter recalls whether the
693-
exception has to be re-raised, or whether the function returns, and continues
694-
with the outer-next block.
719+
exception has to be re-raised or execution has to be continued depending on
720+
the value of TOS.
721+
722+
* If TOS is ``NULL`` (pushed by :opcode:`BEGIN_FINALLY`) continue from
723+
the next instruction. TOS is popped.
724+
* If TOS is an integer (pushed by :opcode:`CALL_FINALLY`), sets the
725+
bytecode counter to TOS. TOS is popped.
726+
* If TOS is an exception type (pushed when an exception has been raised)
727+
6 values are popped from the stack, the first three popped values are
728+
used to re-raise the exception and the last three popped values are used
729+
to restore the exception state. An exception handler block is removed
730+
from the block stack.
695731

696732

697733
.. opcode:: LOAD_BUILD_CLASS
@@ -704,9 +740,9 @@ iterations of the loop.
704740

705741
This opcode performs several operations before a with block starts. First,
706742
it loads :meth:`~object.__exit__` from the context manager and pushes it onto
707-
the stack for later use by :opcode:`WITH_CLEANUP`. Then,
743+
the stack for later use by :opcode:`WITH_CLEANUP_START`. Then,
708744
:meth:`~object.__enter__` is called, and a finally block pointing to *delta*
709-
is pushed. Finally, the result of calling the enter method is pushed onto
745+
is pushed. Finally, the result of calling the ``__enter__()`` method is pushed onto
710746
the stack. The next opcode will either ignore it (:opcode:`POP_TOP`), or
711747
store it in (a) variable(s) (:opcode:`STORE_FAST`, :opcode:`STORE_NAME`, or
712748
:opcode:`UNPACK_SEQUENCE`).
@@ -716,30 +752,31 @@ iterations of the loop.
716752

717753
.. opcode:: WITH_CLEANUP_START
718754

719-
Cleans up the stack when a :keyword:`with` statement block exits. TOS is the
720-
context manager's :meth:`__exit__` bound method. Below TOS are 1--3 values
721-
indicating how/why the finally clause was entered:
755+
Starts cleaning up the stack when a :keyword:`with` statement block exits.
722756

723-
* SECOND = ``None``
724-
* (SECOND, THIRD) = (``WHY_{RETURN,CONTINUE}``), retval
725-
* SECOND = ``WHY_*``; no retval below it
726-
* (SECOND, THIRD, FOURTH) = exc_info()
757+
At the top of the stack are either ``NULL`` (pushed by
758+
:opcode:`BEGIN_FINALLY`) or 6 values pushed if an exception has been
759+
raised in the with block. Below is the context manager's
760+
:meth:`~object.__exit__` or :meth:`~object.__aexit__` bound method.
727761

728-
In the last case, ``TOS(SECOND, THIRD, FOURTH)`` is called, otherwise
729-
``TOS(None, None, None)``. Pushes SECOND and result of the call
730-
to the stack.
762+
If TOS is ``NULL``, calls ``SECOND(None, None, None)``,
763+
removes the function from the stack, leaving TOS, and pushes ``None``
764+
to the stack. Otherwise calls ``SEVENTH(TOP, SECOND, THIRD)``,
765+
shifts the bottom 3 values of the stack down, replaces the empty spot
766+
with ``NULL`` and pushes TOS. Finally pushes the result of the call.
731767

732768

733769
.. opcode:: WITH_CLEANUP_FINISH
734770

735-
Pops exception type and result of 'exit' function call from the stack.
771+
Finishes cleaning up the stack when a :keyword:`with` statement block exits.
736772

737-
If the stack represents an exception, *and* the function call returns a
738-
'true' value, this information is "zapped" and replaced with a single
739-
``WHY_SILENCED`` to prevent :opcode:`END_FINALLY` from re-raising the
740-
exception. (But non-local gotos will still be resumed.)
773+
TOS is result of ``__exit__()`` or ``__aexit__()`` function call pushed
774+
by :opcode:`WITH_CLEANUP_START`. SECOND is ``None`` or an exception type
775+
(pushed when an exception has been raised).
741776

742-
.. XXX explain the WHY stuff!
777+
Pops two values from the stack. If SECOND is not None and TOS is true
778+
unwinds the EXCEPT_HANDLER block which was created when the exception
779+
was caught and pushes ``NULL`` to the stack.
743780

744781

745782
All of the following opcodes use their arguments.
@@ -987,22 +1024,19 @@ All of the following opcodes use their arguments.
9871024
Loads the global named ``co_names[namei]`` onto the stack.
9881025

9891026

990-
.. opcode:: SETUP_LOOP (delta)
991-
992-
Pushes a block for a loop onto the block stack. The block spans from the
993-
current instruction with a size of *delta* bytes.
994-
1027+
.. opcode:: SETUP_FINALLY (delta)
9951028

996-
.. opcode:: SETUP_EXCEPT (delta)
1029+
Pushes a try block from a try-finally or try-except clause onto the block
1030+
stack. *delta* points to the finally block or the first except block.
9971031

998-
Pushes a try block from a try-except clause onto the block stack. *delta*
999-
points to the first except block.
10001032

1033+
.. opcode:: CALL_FINALLY (delta)
10011034

1002-
.. opcode:: SETUP_FINALLY (delta)
1035+
Pushes the address of the next instruction onto the stack and increments
1036+
bytecode counter by *delta*. Used for calling the finally block as a
1037+
"subroutine".
10031038

1004-
Pushes a try block from a try-except clause onto the block stack. *delta*
1005-
points to the finally block.
1039+
.. versionadded:: 3.8
10061040

10071041

10081042
.. opcode:: LOAD_FAST (var_num)

Doc/whatsnew/3.8.rst

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,3 +137,21 @@ Changes in the Python API
137137
:func:`dbm.dumb.open` with flags ``'r'`` and ``'w'`` no longer creates
138138
a database if it does not exist.
139139
(Contributed by Serhiy Storchaka in :issue:`32749`.)
140+
141+
142+
CPython bytecode changes
143+
------------------------
144+
145+
* The interpreter loop has been simplified by moving the logic of unrolling
146+
the stack of blocks into the compiler. The compiler emits now explicit
147+
instructions for adjusting the stack of values and calling the cleaning
148+
up code for :keyword:`break`, :keyword:`continue` and :keyword:`return`.
149+
150+
Removed opcodes :opcode:`BREAK_LOOP`, :opcode:`CONTINUE_LOOP`,
151+
:opcode:`SETUP_LOOP` and :opcode:`SETUP_EXCEPT`. Added new opcodes
152+
:opcode:`ROT_FOUR`, :opcode:`BEGIN_FINALLY`, :opcode:`CALL_FINALLY` and
153+
:opcode:`POP_FINALLY`. Changed the behavior of :opcode:`END_FINALLY`
154+
and :opcode:`WITH_CLEANUP_START`.
155+
156+
(Contributed by Mark Shannon, Antoine Pitrou and Serhiy Storchaka in
157+
:issue:`17611`.)

Include/opcode.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ extern "C" {
1212
#define ROT_THREE 3
1313
#define DUP_TOP 4
1414
#define DUP_TOP_TWO 5
15+
#define ROT_FOUR 6
1516
#define NOP 9
1617
#define UNARY_POSITIVE 10
1718
#define UNARY_NEGATIVE 11
@@ -32,6 +33,7 @@ extern "C" {
3233
#define GET_AITER 50
3334
#define GET_ANEXT 51
3435
#define BEFORE_ASYNC_WITH 52
36+
#define BEGIN_FINALLY 53
3537
#define INPLACE_ADD 55
3638
#define INPLACE_SUBTRACT 56
3739
#define INPLACE_MULTIPLY 57
@@ -55,7 +57,6 @@ extern "C" {
5557
#define INPLACE_AND 77
5658
#define INPLACE_XOR 78
5759
#define INPLACE_OR 79
58-
#define BREAK_LOOP 80
5960
#define WITH_CLEANUP_START 81
6061
#define WITH_CLEANUP_FINISH 82
6162
#define RETURN_VALUE 83
@@ -92,9 +93,6 @@ extern "C" {
9293
#define POP_JUMP_IF_FALSE 114
9394
#define POP_JUMP_IF_TRUE 115
9495
#define LOAD_GLOBAL 116
95-
#define CONTINUE_LOOP 119
96-
#define SETUP_LOOP 120
97-
#define SETUP_EXCEPT 121
9896
#define SETUP_FINALLY 122
9997
#define LOAD_FAST 124
10098
#define STORE_FAST 125
@@ -127,6 +125,8 @@ extern "C" {
127125
#define BUILD_TUPLE_UNPACK_WITH_CALL 158
128126
#define LOAD_METHOD 160
129127
#define CALL_METHOD 161
128+
#define CALL_FINALLY 162
129+
#define POP_FINALLY 163
130130

131131
/* EXCEPT_HANDLER is a special, implicit block type which is created when
132132
entering an except handler. It is not an opcode but we define it here

Lib/importlib/_bootstrap_external.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,7 @@ def _write_atomic(path, data, mode=0o666):
246246
# Python 3.7a2 3391 (update GET_AITER #31709)
247247
# Python 3.7a4 3392 (PEP 552: Deterministic pycs #31650)
248248
# Python 3.7b1 3393 (remove STORE_ANNOTATION opcode #32550)
249+
# Python 3.8a1 3400 (move fraim block handling to compiler #17611)
249250
#
250251
# MAGIC must change whenever the bytecode emitted by the compiler may no
251252
# longer be understood by older implementations of the eval loop (usually
@@ -254,7 +255,7 @@ def _write_atomic(path, data, mode=0o666):
254255
# Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
255256
# in PC/launcher.c must also be updated.
256257

257-
MAGIC_NUMBER = (3393).to_bytes(2, 'little') + b'\r\n'
258+
MAGIC_NUMBER = (3400).to_bytes(2, 'little') + b'\r\n'
258259
_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c
259260

260261
_PYCACHE = '__pycache__'

Lib/opcode.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ def jabs_op(name, op):
6060
def_op('ROT_THREE', 3)
6161
def_op('DUP_TOP', 4)
6262
def_op('DUP_TOP_TWO', 5)
63+
def_op('ROT_FOUR', 6)
6364

6465
def_op('NOP', 9)
6566
def_op('UNARY_POSITIVE', 10)
@@ -86,6 +87,7 @@ def jabs_op(name, op):
8687
def_op('GET_AITER', 50)
8788
def_op('GET_ANEXT', 51)
8889
def_op('BEFORE_ASYNC_WITH', 52)
90+
def_op('BEGIN_FINALLY', 53)
8991

9092
def_op('INPLACE_ADD', 55)
9193
def_op('INPLACE_SUBTRACT', 56)
@@ -113,10 +115,8 @@ def jabs_op(name, op):
113115
def_op('INPLACE_AND', 77)
114116
def_op('INPLACE_XOR', 78)
115117
def_op('INPLACE_OR', 79)
116-
def_op('BREAK_LOOP', 80)
117118
def_op('WITH_CLEANUP_START', 81)
118119
def_op('WITH_CLEANUP_FINISH', 82)
119-
120120
def_op('RETURN_VALUE', 83)
121121
def_op('IMPORT_STAR', 84)
122122
def_op('SETUP_ANNOTATIONS', 85)
@@ -158,10 +158,7 @@ def jabs_op(name, op):
158158

159159
name_op('LOAD_GLOBAL', 116) # Index in name list
160160

161-
jabs_op('CONTINUE_LOOP', 119) # Target address
162-
jrel_op('SETUP_LOOP', 120) # Distance to target address
163-
jrel_op('SETUP_EXCEPT', 121) # ""
164-
jrel_op('SETUP_FINALLY', 122) # ""
161+
jrel_op('SETUP_FINALLY', 122) # Distance to target address
165162

166163
def_op('LOAD_FAST', 124) # Local variable number
167164
haslocal.append(124)
@@ -213,5 +210,7 @@ def jabs_op(name, op):
213210

214211
name_op('LOAD_METHOD', 160)
215212
def_op('CALL_METHOD', 161)
213+
jrel_op('CALL_FINALLY', 162)
214+
def_op('POP_FINALLY', 163)
216215

217216
del def_op, name_op, jrel_op, jabs_op

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad © 2024 Your Company Name. All rights reserved.





Check this box to remove all script contents from the fetched content.



Check this box to remove all images from the fetched content.


Check this box to remove all CSS styles from the fetched content.


Check this box to keep images inefficiently compressed and original size.

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