Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 16 additions & 15 deletions Doc/library/dis.rst
Original file line number Diff line number Diff line change
Expand Up @@ -726,9 +726,8 @@ iterations of the loop.

.. opcode:: BEGIN_FINALLY

Pushes ``NULL`` onto the stack for using it in :opcode:`END_FINALLY`,
:opcode:`POP_FINALLY`, :opcode:`WITH_CLEANUP_START` and
:opcode:`WITH_CLEANUP_FINISH`. Starts the :keyword:`finally` block.
Pushes ``NULL`` onto the stack for using it in :opcode:`END_FINALLY` and
:opcode:`POP_FINALLY`. Starts the :keyword:`finally` block.

.. versionadded:: 3.8

Expand Down Expand Up @@ -774,29 +773,31 @@ iterations of the loop.

Starts cleaning up the stack when a :keyword:`with` statement block exits.

At the top of the stack are either ``NULL`` (pushed by
:opcode:`BEGIN_FINALLY`) or 6 values pushed if an exception has been
At the top of the stack are 6 values pushed when an exception has been
raised in the with block. Below is the context manager's
:meth:`~object.__exit__` or :meth:`~object.__aexit__` bound method.

If TOS is ``NULL``, calls ``SECOND(None, None, None)``,
removes the function from the stack, leaving TOS, and pushes ``None``
to the stack. Otherwise calls ``SEVENTH(TOP, SECOND, THIRD)``,
shifts the bottom 3 values of the stack down, replaces the empty spot
with ``NULL`` and pushes TOS. Finally pushes the result of the call.
Pushes the result of ``TOS6(TOS, TOS1, TOS2)``.

.. versionchanged:: 3.8


.. opcode:: WITH_CLEANUP_FINISH

Finishes cleaning up the stack when a :keyword:`with` statement block exits.

TOS is result of ``__exit__()`` or ``__aexit__()`` function call pushed
by :opcode:`WITH_CLEANUP_START`. SECOND is ``None`` or an exception type
(pushed when an exception has been raised).
by :opcode:`WITH_CLEANUP_START`. Below are 6 values pushed when an exception
has been raised in the with block and the exit function.

Pops two values from the stack. If SECOND is not None and TOS is true
unwinds the EXCEPT_HANDLER block which was created when the exception
was caught and pushes ``NULL`` to the stack.
Pops TOS from the stack. If it is true unwinds the EXCEPT_HANDLER block
which was created when the exception was caught. Otherwise the next three
values will be used to re-raise the exception, the other three
values will be used to restore the exception state, and the exit function
will be popped from the stack. An exception handler block will be removed
from the block stack.

.. versionchanged:: 3.8


All of the following opcodes use their arguments.
Expand Down
3 changes: 2 additions & 1 deletion Lib/importlib/_bootstrap_external.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@ def _write_atomic(path, data, mode=0o666):
# Python 3.8a1 3400 (move frame block handling to compiler #17611)
# Python 3.8a1 3401 (add END_ASYNC_FOR #33041)
# Python 3.8a1 3410 (PEP570 Python Positional-Only Parameters #36540)
# Python 3.8b1 3411 (simplify "with"-related opcodes #32949)
#
# MAGIC must change whenever the bytecode emitted by the compiler may no
# longer be understood by older implementations of the eval loop (usually
Expand All @@ -274,7 +275,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 = (3410).to_bytes(2, 'little') + b'\r\n'
MAGIC_NUMBER = (3411).to_bytes(2, 'little') + b'\r\n'
_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c

_PYCACHE = '__pycache__'
Expand Down
39 changes: 21 additions & 18 deletions Lib/test/test_dis.py
Original file line number Diff line number Diff line change
Expand Up @@ -752,11 +752,12 @@ async def async_def():
Positional-only arguments: 0
Kw-only arguments: 0
Number of locals: 2
Stack size: 10
Stack size: 9
Flags: OPTIMIZED, NEWLOCALS, NOFREE, COROUTINE
Constants:
0: None
1: 1
2: \\(None, None, None\\)
Names:
0: b
1: c
Expand Down Expand Up @@ -977,7 +978,7 @@ def jumpy():
Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval='Who let lolcatz into this test suite?', argrepr="'Who let lolcatz into this test suite?'", offset=96, starts_line=None, is_jump_target=False),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=98, starts_line=None, is_jump_target=False),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=100, starts_line=None, is_jump_target=False),
Instruction(opname='SETUP_FINALLY', opcode=122, arg=70, argval=174, argrepr='to 174', offset=102, starts_line=20, is_jump_target=True),
Instruction(opname='SETUP_FINALLY', opcode=122, arg=74, argval=178, argrepr='to 178', offset=102, starts_line=20, is_jump_target=True),
Instruction(opname='SETUP_FINALLY', opcode=122, arg=12, argval=118, argrepr='to 118', offset=104, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=106, starts_line=21, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=7, argval=0, argrepr='0', offset=108, starts_line=None, is_jump_target=False),
Expand All @@ -997,29 +998,31 @@ def jumpy():
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=136, starts_line=None, is_jump_target=False),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=138, starts_line=None, is_jump_target=False),
Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=140, starts_line=None, is_jump_target=False),
Instruction(opname='JUMP_FORWARD', opcode=110, arg=26, argval=170, argrepr='to 170', offset=142, starts_line=None, is_jump_target=False),
Instruction(opname='JUMP_FORWARD', opcode=110, arg=30, argval=174, argrepr='to 174', offset=142, starts_line=None, is_jump_target=False),
Instruction(opname='END_FINALLY', opcode=88, arg=None, argval=None, argrepr='', offset=144, starts_line=None, is_jump_target=True),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=146, starts_line=25, is_jump_target=True),
Instruction(opname='SETUP_WITH', opcode=143, arg=14, argval=164, argrepr='to 164', offset=148, starts_line=None, is_jump_target=False),
Instruction(opname='SETUP_WITH', opcode=143, arg=20, argval=170, argrepr='to 170', offset=148, starts_line=None, is_jump_target=False),
Instruction(opname='STORE_FAST', opcode=125, arg=1, argval='dodgy', argrepr='dodgy', offset=150, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=152, starts_line=26, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=9, argval='Never reach this', argrepr="'Never reach this'", offset=154, starts_line=None, is_jump_target=False),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=156, starts_line=None, is_jump_target=False),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=158, starts_line=None, is_jump_target=False),
Instruction(opname='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=160, starts_line=None, is_jump_target=False),
Instruction(opname='BEGIN_FINALLY', opcode=53, arg=None, argval=None, argrepr='', offset=162, starts_line=None, is_jump_target=False),
Instruction(opname='WITH_CLEANUP_START', opcode=81, arg=None, argval=None, argrepr='', offset=164, starts_line=None, is_jump_target=True),
Instruction(opname='WITH_CLEANUP_FINISH', opcode=82, arg=None, argval=None, argrepr='', offset=166, starts_line=None, is_jump_target=False),
Instruction(opname='END_FINALLY', opcode=88, arg=None, argval=None, argrepr='', offset=168, starts_line=None, is_jump_target=False),
Instruction(opname='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=170, starts_line=None, is_jump_target=True),
Instruction(opname='BEGIN_FINALLY', opcode=53, arg=None, argval=None, argrepr='', offset=172, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=174, starts_line=28, is_jump_target=True),
Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=176, starts_line=None, is_jump_target=False),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=178, starts_line=None, is_jump_target=False),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=180, starts_line=None, is_jump_target=False),
Instruction(opname='END_FINALLY', opcode=88, arg=None, argval=None, argrepr='', offset=182, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=184, starts_line=None, is_jump_target=False),
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=186, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval=(None, None, None), argrepr='(None, None, None)', offset=160, starts_line=None, is_jump_target=False),
Instruction(opname='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=162, starts_line=None, is_jump_target=False),
Instruction(opname='CALL_FUNCTION_EX', opcode=142, arg=0, argval=0, argrepr='', offset=164, starts_line=None, is_jump_target=False),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=166, starts_line=None, is_jump_target=False),
Instruction(opname='JUMP_FORWARD', opcode=110, arg=4, argval=174, argrepr='to 174', offset=168, starts_line=None, is_jump_target=False),
Instruction(opname='WITH_CLEANUP_START', opcode=81, arg=None, argval=None, argrepr='', offset=170, starts_line=None, is_jump_target=True),
Instruction(opname='WITH_CLEANUP_FINISH', opcode=82, arg=None, argval=None, argrepr='', offset=172, starts_line=None, is_jump_target=False),
Instruction(opname='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=174, starts_line=None, is_jump_target=True),
Instruction(opname='BEGIN_FINALLY', opcode=53, arg=None, argval=None, argrepr='', offset=176, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=178, starts_line=28, is_jump_target=True),
Instruction(opname='LOAD_CONST', opcode=100, arg=11, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=180, starts_line=None, is_jump_target=False),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=182, starts_line=None, is_jump_target=False),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=184, starts_line=None, is_jump_target=False),
Instruction(opname='END_FINALLY', opcode=88, arg=None, argval=None, argrepr='', offset=186, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=188, starts_line=None, is_jump_target=False),
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=190, starts_line=None, is_jump_target=False),
]

# One last piece of inspect fodder to check the default line number handling
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Simplified and changed opcodes WITH_CLEANUP_START and WITH_CLEANUP_FINISH.
The trivial "with" statement is now up to 10% faster.
2 changes: 1 addition & 1 deletion Objects/frameobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore
delta++;
}
}
if (op != FOR_ITER && code[target_addr] != END_ASYNC_FOR) {
if (op == SETUP_FINALLY && code[target_addr] != END_ASYNC_FOR) {
blockstack[blockstack_top++] = target_addr;
}
break;
Expand Down
Loading