mirror of
https://github.com/python/cpython.git
synced 2025-08-03 16:39:00 +00:00
GH-93621: reorder code in with/async-with exception exit path to reduce the size of the exception table (GH-93622)
This commit is contained in:
parent
2ba0fd5767
commit
cf730b595e
3 changed files with 173 additions and 15 deletions
|
@ -389,6 +389,7 @@ dis_traceback = """\
|
||||||
POP_EXCEPT
|
POP_EXCEPT
|
||||||
RERAISE 1
|
RERAISE 1
|
||||||
ExceptionTable:
|
ExceptionTable:
|
||||||
|
4 rows
|
||||||
""" % (TRACEBACK_CODE.co_firstlineno,
|
""" % (TRACEBACK_CODE.co_firstlineno,
|
||||||
TRACEBACK_CODE.co_firstlineno + 1,
|
TRACEBACK_CODE.co_firstlineno + 1,
|
||||||
TRACEBACK_CODE.co_firstlineno + 2,
|
TRACEBACK_CODE.co_firstlineno + 2,
|
||||||
|
@ -421,6 +422,133 @@ dis_fstring = """\
|
||||||
RETURN_VALUE
|
RETURN_VALUE
|
||||||
""" % (_fstring.__code__.co_firstlineno, _fstring.__code__.co_firstlineno + 1)
|
""" % (_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):
|
def _tryfinally(a, b):
|
||||||
try:
|
try:
|
||||||
return a
|
return a
|
||||||
|
@ -455,6 +583,7 @@ dis_tryfinally = """\
|
||||||
POP_EXCEPT
|
POP_EXCEPT
|
||||||
RERAISE 1
|
RERAISE 1
|
||||||
ExceptionTable:
|
ExceptionTable:
|
||||||
|
2 rows
|
||||||
""" % (_tryfinally.__code__.co_firstlineno,
|
""" % (_tryfinally.__code__.co_firstlineno,
|
||||||
_tryfinally.__code__.co_firstlineno + 1,
|
_tryfinally.__code__.co_firstlineno + 1,
|
||||||
_tryfinally.__code__.co_firstlineno + 2,
|
_tryfinally.__code__.co_firstlineno + 2,
|
||||||
|
@ -484,6 +613,7 @@ dis_tryfinallyconst = """\
|
||||||
POP_EXCEPT
|
POP_EXCEPT
|
||||||
RERAISE 1
|
RERAISE 1
|
||||||
ExceptionTable:
|
ExceptionTable:
|
||||||
|
1 row
|
||||||
""" % (_tryfinallyconst.__code__.co_firstlineno,
|
""" % (_tryfinallyconst.__code__.co_firstlineno,
|
||||||
_tryfinallyconst.__code__.co_firstlineno + 1,
|
_tryfinallyconst.__code__.co_firstlineno + 1,
|
||||||
_tryfinallyconst.__code__.co_firstlineno + 2,
|
_tryfinallyconst.__code__.co_firstlineno + 2,
|
||||||
|
@ -678,6 +808,18 @@ class DisTestBase(unittest.TestCase):
|
||||||
self.assertGreaterEqual(offset, expected_offset, line)
|
self.assertGreaterEqual(offset, expected_offset, line)
|
||||||
expected_offset = offset + delta
|
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):
|
def strip_offsets(self, text):
|
||||||
lines = text.splitlines(True)
|
lines = text.splitlines(True)
|
||||||
start, end = self.find_offset_column(lines)
|
start, end = self.find_offset_column(lines)
|
||||||
|
@ -691,6 +833,9 @@ class DisTestBase(unittest.TestCase):
|
||||||
res.append(line)
|
res.append(line)
|
||||||
else:
|
else:
|
||||||
res.append(line[:start] + line[end:])
|
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)
|
return "".join(res)
|
||||||
|
|
||||||
def do_disassembly_compare(self, got, expected, with_offsets=False):
|
def do_disassembly_compare(self, got, expected, with_offsets=False):
|
||||||
|
@ -883,6 +1028,12 @@ class DisTests(DisTestBase):
|
||||||
def test_disassemble_fstring(self):
|
def test_disassemble_fstring(self):
|
||||||
self.do_disassembly_test(_fstring, dis_fstring)
|
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):
|
def test_disassemble_try_finally(self):
|
||||||
self.do_disassembly_test(_tryfinally, dis_tryfinally)
|
self.do_disassembly_test(_tryfinally, dis_tryfinally)
|
||||||
self.do_disassembly_test(_tryfinallyconst, dis_tryfinallyconst)
|
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='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='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='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='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='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=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_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=318, starts_line=None, is_jump_target=False, 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='JUMP_BACKWARD', opcode=140, arg=24, argval=274, argrepr='to 274', 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='COPY', opcode=120, arg=3, argval=3, 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='POP_EXCEPT', opcode=89, 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='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='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='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),
|
Instruction(opname='CHECK_EXC_MATCH', opcode=36, arg=None, argval=None, argrepr='', offset=342, starts_line=None, is_jump_target=False, positions=None),
|
||||||
|
|
|
@ -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.
|
|
@ -5551,20 +5551,26 @@ compiler_visit_keyword(struct compiler *c, keyword_ty k)
|
||||||
static int
|
static int
|
||||||
compiler_with_except_finish(struct compiler *c, basicblock * cleanup) {
|
compiler_with_except_finish(struct compiler *c, basicblock * cleanup) {
|
||||||
UNSET_LOC(c);
|
UNSET_LOC(c);
|
||||||
basicblock *exit;
|
basicblock *suppress = compiler_new_block(c);
|
||||||
exit = compiler_new_block(c);
|
if (suppress == NULL) {
|
||||||
if (exit == NULL)
|
|
||||||
return 0;
|
return 0;
|
||||||
ADDOP_JUMP(c, POP_JUMP_IF_TRUE, exit);
|
}
|
||||||
|
ADDOP_JUMP(c, POP_JUMP_IF_TRUE, suppress);
|
||||||
ADDOP_I(c, RERAISE, 2);
|
ADDOP_I(c, RERAISE, 2);
|
||||||
compiler_use_next_block(c, cleanup);
|
compiler_use_next_block(c, suppress);
|
||||||
POP_EXCEPT_AND_RERAISE(c);
|
|
||||||
compiler_use_next_block(c, exit);
|
|
||||||
ADDOP(c, POP_TOP); /* exc_value */
|
ADDOP(c, POP_TOP); /* exc_value */
|
||||||
ADDOP(c, POP_BLOCK);
|
ADDOP(c, POP_BLOCK);
|
||||||
ADDOP(c, POP_EXCEPT);
|
ADDOP(c, POP_EXCEPT);
|
||||||
ADDOP(c, POP_TOP);
|
ADDOP(c, POP_TOP);
|
||||||
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue