summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIrit Katriel <1055913+iritkatriel@users.noreply.github.com>2022-06-10 17:53:34 +0100
committerGitHub <noreply@github.com>2022-06-10 17:53:34 +0100
commitcf730b595eea0460a7305205f7dfb6ecf0346351 (patch)
tree9a82669efe06e9d7d988ed0a1861e3a71000e345
parent2ba0fd5767577954f331ecbd53596cd8035d7186 (diff)
downloadcpython-git-cf730b595eea0460a7305205f7dfb6ecf0346351.tar.gz
GH-93621: reorder code in with/async-with exception exit path to reduce the size of the exception table (GH-93622)
-rw-r--r--Lib/test/test_dis.py167
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2022-06-09-09-08-29.gh-issue-93621.-_Pn1d.rst1
-rw-r--r--Python/compile.c20
3 files changed, 173 insertions, 15 deletions
diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py
index a94cd6432e..656d801107 100644
--- a/Lib/test/test_dis.py
+++ b/Lib/test/test_dis.py
@@ -389,6 +389,7 @@ dis_traceback = """\
POP_EXCEPT
RERAISE 1
ExceptionTable:
+4 rows
""" % (TRACEBACK_CODE.co_firstlineno,
TRACEBACK_CODE.co_firstlineno + 1,
TRACEBACK_CODE.co_firstlineno + 2,
@@ -421,6 +422,133 @@ dis_fstring = """\
RETURN_VALUE
""" % (_fstring.__code__.co_firstlineno, _fstring.__code__.co_firstlineno + 1)
+def _with(c):
+ with c:
+ x = 1
+ y = 2
+
+dis_with = """\
+%3d RESUME 0
+
+%3d LOAD_FAST 0 (c)
+ BEFORE_WITH
+ POP_TOP
+
+%3d LOAD_CONST 1 (1)
+ STORE_FAST 1 (x)
+
+%3d LOAD_CONST 0 (None)
+ LOAD_CONST 0 (None)
+ LOAD_CONST 0 (None)
+ CALL 2
+ POP_TOP
+
+%3d LOAD_CONST 2 (2)
+ STORE_FAST 2 (y)
+ LOAD_CONST 0 (None)
+ RETURN_VALUE
+
+%3d >> PUSH_EXC_INFO
+ WITH_EXCEPT_START
+ POP_JUMP_FORWARD_IF_TRUE 1 (to 46)
+ RERAISE 2
+ >> POP_TOP
+ POP_EXCEPT
+ POP_TOP
+ POP_TOP
+
+%3d LOAD_CONST 2 (2)
+ STORE_FAST 2 (y)
+ LOAD_CONST 0 (None)
+ RETURN_VALUE
+ >> COPY 3
+ POP_EXCEPT
+ RERAISE 1
+ExceptionTable:
+2 rows
+""" % (_with.__code__.co_firstlineno,
+ _with.__code__.co_firstlineno + 1,
+ _with.__code__.co_firstlineno + 2,
+ _with.__code__.co_firstlineno + 1,
+ _with.__code__.co_firstlineno + 3,
+ _with.__code__.co_firstlineno + 1,
+ _with.__code__.co_firstlineno + 3,
+ )
+
+async def _asyncwith(c):
+ async with c:
+ x = 1
+ y = 2
+
+dis_asyncwith = """\
+%3d RETURN_GENERATOR
+ POP_TOP
+ RESUME 0
+
+%3d LOAD_FAST 0 (c)
+ BEFORE_ASYNC_WITH
+ GET_AWAITABLE 1
+ LOAD_CONST 0 (None)
+ >> SEND 3 (to 22)
+ YIELD_VALUE 3
+ RESUME 3
+ JUMP_BACKWARD_NO_INTERRUPT 4 (to 14)
+ >> POP_TOP
+
+%3d LOAD_CONST 1 (1)
+ STORE_FAST 1 (x)
+
+%3d LOAD_CONST 0 (None)
+ LOAD_CONST 0 (None)
+ LOAD_CONST 0 (None)
+ CALL 2
+ GET_AWAITABLE 2
+ LOAD_CONST 0 (None)
+ >> SEND 3 (to 56)
+ YIELD_VALUE 2
+ RESUME 3
+ JUMP_BACKWARD_NO_INTERRUPT 4 (to 48)
+ >> POP_TOP
+
+%3d LOAD_CONST 2 (2)
+ STORE_FAST 2 (y)
+ LOAD_CONST 0 (None)
+ RETURN_VALUE
+
+%3d >> PUSH_EXC_INFO
+ WITH_EXCEPT_START
+ GET_AWAITABLE 2
+ LOAD_CONST 0 (None)
+ >> SEND 3 (to 82)
+ YIELD_VALUE 6
+ RESUME 3
+ JUMP_BACKWARD_NO_INTERRUPT 4 (to 74)
+ >> POP_JUMP_FORWARD_IF_TRUE 1 (to 86)
+ RERAISE 2
+ >> POP_TOP
+ POP_EXCEPT
+ POP_TOP
+ POP_TOP
+
+%3d LOAD_CONST 2 (2)
+ STORE_FAST 2 (y)
+ LOAD_CONST 0 (None)
+ RETURN_VALUE
+ >> COPY 3
+ POP_EXCEPT
+ RERAISE 1
+ExceptionTable:
+2 rows
+""" % (_asyncwith.__code__.co_firstlineno,
+ _asyncwith.__code__.co_firstlineno + 1,
+ _asyncwith.__code__.co_firstlineno + 2,
+ _asyncwith.__code__.co_firstlineno + 1,
+ _asyncwith.__code__.co_firstlineno + 3,
+ _asyncwith.__code__.co_firstlineno + 1,
+ _asyncwith.__code__.co_firstlineno + 3,
+ )
+
+
def _tryfinally(a, b):
try:
return a
@@ -455,6 +583,7 @@ dis_tryfinally = """\
POP_EXCEPT
RERAISE 1
ExceptionTable:
+2 rows
""" % (_tryfinally.__code__.co_firstlineno,
_tryfinally.__code__.co_firstlineno + 1,
_tryfinally.__code__.co_firstlineno + 2,
@@ -484,6 +613,7 @@ dis_tryfinallyconst = """\
POP_EXCEPT
RERAISE 1
ExceptionTable:
+1 row
""" % (_tryfinallyconst.__code__.co_firstlineno,
_tryfinallyconst.__code__.co_firstlineno + 1,
_tryfinallyconst.__code__.co_firstlineno + 2,
@@ -678,6 +808,18 @@ class DisTestBase(unittest.TestCase):
self.assertGreaterEqual(offset, expected_offset, line)
expected_offset = offset + delta
+ def assert_exception_table_increasing(self, lines):
+ prev_start, prev_end = -1, -1
+ count = 0
+ for line in lines:
+ m = re.match(r' (\d+) to (\d+) -> \d+ \[\d+\]', line)
+ start, end = [int(g) for g in m.groups()]
+ self.assertGreaterEqual(end, start)
+ self.assertGreater(start, prev_end)
+ prev_start, prev_end = start, end
+ count += 1
+ return count
+
def strip_offsets(self, text):
lines = text.splitlines(True)
start, end = self.find_offset_column(lines)
@@ -691,6 +833,9 @@ class DisTestBase(unittest.TestCase):
res.append(line)
else:
res.append(line[:start] + line[end:])
+ num_rows = self.assert_exception_table_increasing(lines)
+ if num_rows:
+ res.append(f"{num_rows} row{'s' if num_rows > 1 else ''}\n")
return "".join(res)
def do_disassembly_compare(self, got, expected, with_offsets=False):
@@ -883,6 +1028,12 @@ class DisTests(DisTestBase):
def test_disassemble_fstring(self):
self.do_disassembly_test(_fstring, dis_fstring)
+ def test_disassemble_with(self):
+ self.do_disassembly_test(_with, dis_with)
+
+ def test_disassemble_asyncwith(self):
+ self.do_disassembly_test(_asyncwith, dis_asyncwith)
+
def test_disassemble_try_finally(self):
self.do_disassembly_test(_tryfinally, dis_tryfinally)
self.do_disassembly_test(_tryfinallyconst, dis_tryfinallyconst)
@@ -1471,16 +1622,16 @@ expected_opinfo_jumpy = [
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=302, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=304, starts_line=25, is_jump_target=False, positions=None),
Instruction(opname='WITH_EXCEPT_START', opcode=49, arg=None, argval=None, argrepr='', offset=306, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_JUMP_FORWARD_IF_TRUE', opcode=115, arg=4, argval=318, argrepr='to 318', offset=308, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='POP_JUMP_FORWARD_IF_TRUE', opcode=115, arg=1, argval=312, argrepr='to 312', offset=308, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='RERAISE', opcode=119, arg=2, argval=2, argrepr='', offset=310, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=312, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=312, starts_line=None, is_jump_target=True, positions=None),
Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=314, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=316, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=318, starts_line=None, is_jump_target=True, positions=None),
- Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=320, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=322, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=324, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='JUMP_BACKWARD', opcode=140, arg=27, argval=274, argrepr='to 274', offset=326, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=316, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=318, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='JUMP_BACKWARD', opcode=140, arg=24, argval=274, argrepr='to 274', offset=320, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=322, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=324, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=326, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=328, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=4, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=330, starts_line=22, is_jump_target=False, positions=None),
Instruction(opname='CHECK_EXC_MATCH', opcode=36, arg=None, argval=None, argrepr='', offset=342, starts_line=None, is_jump_target=False, positions=None),
diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-06-09-09-08-29.gh-issue-93621.-_Pn1d.rst b/Misc/NEWS.d/next/Core and Builtins/2022-06-09-09-08-29.gh-issue-93621.-_Pn1d.rst
new file mode 100644
index 0000000000..388540982f
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2022-06-09-09-08-29.gh-issue-93621.-_Pn1d.rst
@@ -0,0 +1 @@
+Change order of bytecode instructions emitted for :keyword:`with` and :keyword:`async with` to reduce the number of entries in the exception table.
diff --git a/Python/compile.c b/Python/compile.c
index bbd71936cf..b922e01454 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -5551,20 +5551,26 @@ compiler_visit_keyword(struct compiler *c, keyword_ty k)
static int
compiler_with_except_finish(struct compiler *c, basicblock * cleanup) {
UNSET_LOC(c);
- basicblock *exit;
- exit = compiler_new_block(c);
- if (exit == NULL)
+ basicblock *suppress = compiler_new_block(c);
+ if (suppress == NULL) {
return 0;
- ADDOP_JUMP(c, POP_JUMP_IF_TRUE, exit);
+ }
+ ADDOP_JUMP(c, POP_JUMP_IF_TRUE, suppress);
ADDOP_I(c, RERAISE, 2);
- compiler_use_next_block(c, cleanup);
- POP_EXCEPT_AND_RERAISE(c);
- compiler_use_next_block(c, exit);
+ compiler_use_next_block(c, suppress);
ADDOP(c, POP_TOP); /* exc_value */
ADDOP(c, POP_BLOCK);
ADDOP(c, POP_EXCEPT);
ADDOP(c, POP_TOP);
ADDOP(c, POP_TOP);
+ basicblock *exit = compiler_new_block(c);
+ if (exit == NULL) {
+ return 0;
+ }
+ ADDOP_JUMP(c, JUMP, exit);
+ compiler_use_next_block(c, cleanup);
+ POP_EXCEPT_AND_RERAISE(c);
+ compiler_use_next_block(c, exit);
return 1;
}