bpo-42246: Eliminate jumps to exit blocks by copying those blocks. (#23251)

* Compiler: eliminate jumps to short exit blocks by copying.
This commit is contained in:
Mark Shannon 2020-11-12 19:49:33 +00:00 committed by GitHub
parent 750c5abf43
commit cc75ab791d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 4662 additions and 4664 deletions

View File

@ -264,47 +264,47 @@ dis_compound_stmt_str = """\
8 INPLACE_ADD 8 INPLACE_ADD
10 STORE_NAME 0 (x) 10 STORE_NAME 0 (x)
12 JUMP_ABSOLUTE 4 12 JUMP_ABSOLUTE 4
14 LOAD_CONST 2 (None)
16 RETURN_VALUE
""" """
dis_traceback = """\ dis_traceback = """\
%3d 0 SETUP_FINALLY 12 (to 14) %3d 0 SETUP_FINALLY 14 (to 16)
%3d 2 LOAD_CONST 1 (1) %3d 2 LOAD_CONST 1 (1)
4 LOAD_CONST 2 (0) 4 LOAD_CONST 2 (0)
--> 6 BINARY_TRUE_DIVIDE --> 6 BINARY_TRUE_DIVIDE
8 POP_TOP 8 POP_TOP
10 POP_BLOCK 10 POP_BLOCK
12 JUMP_FORWARD 42 (to 56)
%3d >> 14 DUP_TOP %3d 12 LOAD_FAST 1 (tb)
16 LOAD_GLOBAL 0 (Exception) 14 RETURN_VALUE
18 JUMP_IF_NOT_EXC_MATCH 54
20 POP_TOP
22 STORE_FAST 0 (e)
24 POP_TOP
26 SETUP_FINALLY 18 (to 46)
%3d 28 LOAD_FAST 0 (e) %3d >> 16 DUP_TOP
30 LOAD_ATTR 1 (__traceback__) 18 LOAD_GLOBAL 0 (Exception)
32 STORE_FAST 1 (tb) 20 JUMP_IF_NOT_EXC_MATCH 58
34 POP_BLOCK 22 POP_TOP
36 POP_EXCEPT 24 STORE_FAST 0 (e)
38 LOAD_CONST 0 (None) 26 POP_TOP
40 STORE_FAST 0 (e) 28 SETUP_FINALLY 20 (to 50)
42 DELETE_FAST 0 (e)
44 JUMP_FORWARD 10 (to 56)
>> 46 LOAD_CONST 0 (None)
48 STORE_FAST 0 (e)
50 DELETE_FAST 0 (e)
52 RERAISE
>> 54 RERAISE
%3d >> 56 LOAD_FAST 1 (tb) %3d 30 LOAD_FAST 0 (e)
58 RETURN_VALUE 32 LOAD_ATTR 1 (__traceback__)
34 STORE_FAST 1 (tb)
36 POP_BLOCK
38 POP_EXCEPT
40 LOAD_CONST 0 (None)
42 STORE_FAST 0 (e)
44 DELETE_FAST 0 (e)
%3d 46 LOAD_FAST 1 (tb)
48 RETURN_VALUE
>> 50 LOAD_CONST 0 (None)
52 STORE_FAST 0 (e)
54 DELETE_FAST 0 (e)
56 RERAISE
>> 58 RERAISE
""" % (TRACEBACK_CODE.co_firstlineno + 1, """ % (TRACEBACK_CODE.co_firstlineno + 1,
TRACEBACK_CODE.co_firstlineno + 2, TRACEBACK_CODE.co_firstlineno + 2,
TRACEBACK_CODE.co_firstlineno + 5,
TRACEBACK_CODE.co_firstlineno + 3, TRACEBACK_CODE.co_firstlineno + 3,
TRACEBACK_CODE.co_firstlineno + 4, TRACEBACK_CODE.co_firstlineno + 4,
TRACEBACK_CODE.co_firstlineno + 5) TRACEBACK_CODE.co_firstlineno + 5)
@ -992,7 +992,7 @@ expected_opinfo_jumpy = [
Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=10, argrepr='10', offset=2, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=10, argrepr='10', offset=2, starts_line=None, is_jump_target=False),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=4, starts_line=None, is_jump_target=False), Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=4, starts_line=None, is_jump_target=False),
Instruction(opname='GET_ITER', opcode=68, arg=None, argval=None, argrepr='', offset=6, starts_line=None, is_jump_target=False), Instruction(opname='GET_ITER', opcode=68, arg=None, argval=None, argrepr='', offset=6, starts_line=None, is_jump_target=False),
Instruction(opname='FOR_ITER', opcode=93, arg=34, argval=44, argrepr='to 44', offset=8, starts_line=None, is_jump_target=True), Instruction(opname='FOR_ITER', opcode=93, arg=32, argval=42, argrepr='to 42', offset=8, starts_line=None, is_jump_target=True),
Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=10, starts_line=None, is_jump_target=False), Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=10, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=12, starts_line=4, is_jump_target=False), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=12, starts_line=4, is_jump_target=False),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=14, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=14, starts_line=None, is_jump_target=False),
@ -1008,93 +1008,90 @@ expected_opinfo_jumpy = [
Instruction(opname='COMPARE_OP', opcode=107, arg=4, argval='>', argrepr='>', offset=34, starts_line=None, is_jump_target=False), Instruction(opname='COMPARE_OP', opcode=107, arg=4, argval='>', argrepr='>', offset=34, starts_line=None, is_jump_target=False),
Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=8, argval=8, argrepr='', offset=36, starts_line=None, is_jump_target=False), Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=8, argval=8, argrepr='', offset=36, starts_line=None, is_jump_target=False),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=38, starts_line=8, is_jump_target=False), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=38, starts_line=8, is_jump_target=False),
Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=52, argval=52, argrepr='', offset=40, starts_line=None, is_jump_target=False), Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=50, argval=50, argrepr='', offset=40, starts_line=None, is_jump_target=False),
Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=8, argval=8, argrepr='', offset=42, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=42, starts_line=10, is_jump_target=True),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=44, starts_line=10, is_jump_target=True), Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='I can haz else clause?', argrepr="'I can haz else clause?'", offset=44, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='I can haz else clause?', argrepr="'I can haz else clause?'", offset=46, starts_line=None, is_jump_target=False), Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=46, starts_line=None, is_jump_target=False),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=48, starts_line=None, is_jump_target=False), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=48, starts_line=None, is_jump_target=False),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=50, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=50, starts_line=11, is_jump_target=True),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=52, starts_line=11, is_jump_target=True), Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=90, argval=90, argrepr='', offset=52, starts_line=None, is_jump_target=False),
Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=94, argval=94, argrepr='', offset=54, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=54, starts_line=12, is_jump_target=False),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=56, starts_line=12, is_jump_target=False), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=56, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=58, starts_line=None, is_jump_target=False), Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=58, starts_line=None, is_jump_target=False),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=60, starts_line=None, is_jump_target=False), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=60, starts_line=None, is_jump_target=False),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=62, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=62, starts_line=13, is_jump_target=False),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=64, starts_line=13, is_jump_target=False), Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=64, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=66, starts_line=None, is_jump_target=False), Instruction(opname='INPLACE_SUBTRACT', opcode=56, arg=None, argval=None, argrepr='', offset=66, starts_line=None, is_jump_target=False),
Instruction(opname='INPLACE_SUBTRACT', opcode=56, arg=None, argval=None, argrepr='', offset=68, starts_line=None, is_jump_target=False), Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=68, starts_line=None, is_jump_target=False),
Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=70, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=70, starts_line=14, is_jump_target=False),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=72, starts_line=14, is_jump_target=False), Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=72, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=74, starts_line=None, is_jump_target=False), Instruction(opname='COMPARE_OP', opcode=107, arg=4, argval='>', argrepr='>', offset=74, starts_line=None, is_jump_target=False),
Instruction(opname='COMPARE_OP', opcode=107, arg=4, argval='>', argrepr='>', offset=76, starts_line=None, is_jump_target=False), Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=80, argval=80, argrepr='', offset=76, starts_line=None, is_jump_target=False),
Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=82, argval=82, argrepr='', offset=78, starts_line=None, is_jump_target=False), Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=50, argval=50, argrepr='', offset=78, starts_line=15, is_jump_target=False),
Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=52, argval=52, argrepr='', offset=80, starts_line=15, is_jump_target=False), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=80, starts_line=16, is_jump_target=True),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=82, starts_line=16, is_jump_target=True), Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=82, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=84, starts_line=None, is_jump_target=False), Instruction(opname='COMPARE_OP', opcode=107, arg=0, argval='<', argrepr='<', offset=84, starts_line=None, is_jump_target=False),
Instruction(opname='COMPARE_OP', opcode=107, arg=0, argval='<', argrepr='<', offset=86, starts_line=None, is_jump_target=False), Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=50, argval=50, argrepr='', offset=86, starts_line=None, is_jump_target=False),
Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=52, argval=52, argrepr='', offset=88, starts_line=None, is_jump_target=False), Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=98, argval=98, argrepr='', offset=88, starts_line=17, is_jump_target=False),
Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=102, argval=102, argrepr='', offset=90, starts_line=17, is_jump_target=False), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=90, starts_line=19, is_jump_target=True),
Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=52, argval=52, argrepr='', offset=92, starts_line=None, is_jump_target=False), 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=92, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=94, starts_line=19, is_jump_target=True), Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=94, starts_line=None, is_jump_target=False),
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='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', 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='SETUP_FINALLY', opcode=122, arg=98, argval=198, argrepr='to 198', offset=98, starts_line=20, is_jump_target=True),
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=12, argval=114, argrepr='to 114', offset=100, starts_line=None, is_jump_target=False),
Instruction(opname='SETUP_FINALLY', opcode=122, arg=96, argval=200, argrepr='to 200', offset=102, starts_line=20, is_jump_target=True), Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=102, starts_line=21, is_jump_target=False),
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=7, argval=0, argrepr='0', 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='BINARY_TRUE_DIVIDE', opcode=27, arg=None, argval=None, argrepr='', offset=106, starts_line=None, 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), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=108, starts_line=None, is_jump_target=False),
Instruction(opname='BINARY_TRUE_DIVIDE', opcode=27, arg=None, argval=None, argrepr='', offset=110, starts_line=None, is_jump_target=False), Instruction(opname='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=110, starts_line=None, is_jump_target=False),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=112, starts_line=None, is_jump_target=False), Instruction(opname='JUMP_FORWARD', opcode=110, arg=26, argval=140, argrepr='to 140', offset=112, starts_line=None, is_jump_target=False),
Instruction(opname='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=114, starts_line=None, is_jump_target=False), Instruction(opname='DUP_TOP', opcode=4, arg=None, argval=None, argrepr='', offset=114, starts_line=22, is_jump_target=True),
Instruction(opname='JUMP_FORWARD', opcode=110, arg=26, argval=144, argrepr='to 144', offset=116, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=2, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=116, starts_line=None, is_jump_target=False),
Instruction(opname='DUP_TOP', opcode=4, arg=None, argval=None, argrepr='', offset=118, starts_line=22, is_jump_target=True), Instruction(opname='JUMP_IF_NOT_EXC_MATCH', opcode=121, arg=138, argval=138, argrepr='', offset=118, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=2, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=120, starts_line=None, is_jump_target=False), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=120, starts_line=None, is_jump_target=False),
Instruction(opname='JUMP_IF_NOT_EXC_MATCH', opcode=121, arg=142, argval=142, argrepr='', offset=122, starts_line=None, is_jump_target=False), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=122, starts_line=None, is_jump_target=False),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=124, starts_line=None, is_jump_target=False), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=124, starts_line=None, is_jump_target=False),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=126, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=126, starts_line=23, is_jump_target=False),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=128, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_CONST', opcode=100, arg=8, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=128, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=130, starts_line=23, is_jump_target=False), Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=130, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=8, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=132, starts_line=None, is_jump_target=False), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=132, starts_line=None, is_jump_target=False),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=134, starts_line=None, is_jump_target=False), Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=134, starts_line=None, is_jump_target=False),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=136, starts_line=None, is_jump_target=False), Instruction(opname='JUMP_FORWARD', opcode=110, arg=46, argval=184, argrepr='to 184', offset=136, starts_line=None, is_jump_target=False),
Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=138, starts_line=None, is_jump_target=False), Instruction(opname='RERAISE', opcode=48, arg=None, argval=None, argrepr='', offset=138, starts_line=None, is_jump_target=True),
Instruction(opname='JUMP_FORWARD', opcode=110, arg=46, argval=188, argrepr='to 188', offset=140, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=140, starts_line=25, is_jump_target=True),
Instruction(opname='RERAISE', opcode=48, arg=None, argval=None, argrepr='', offset=142, starts_line=None, is_jump_target=True), Instruction(opname='SETUP_WITH', opcode=143, arg=24, argval=168, argrepr='to 168', offset=142, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=144, starts_line=25, is_jump_target=True), Instruction(opname='STORE_FAST', opcode=125, arg=1, argval='dodgy', argrepr='dodgy', offset=144, starts_line=None, is_jump_target=False),
Instruction(opname='SETUP_WITH', opcode=143, arg=24, argval=172, argrepr='to 172', offset=146, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=146, starts_line=26, is_jump_target=False),
Instruction(opname='STORE_FAST', opcode=125, arg=1, argval='dodgy', argrepr='dodgy', offset=148, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_CONST', opcode=100, arg=9, argval='Never reach this', argrepr="'Never reach this'", offset=148, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=150, starts_line=26, is_jump_target=False), Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=150, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=9, argval='Never reach this', argrepr="'Never reach this'", offset=152, starts_line=None, is_jump_target=False), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=152, starts_line=None, is_jump_target=False),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=154, starts_line=None, is_jump_target=False), Instruction(opname='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=154, starts_line=None, is_jump_target=False),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=156, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=156, starts_line=None, is_jump_target=False),
Instruction(opname='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=158, starts_line=None, is_jump_target=False), Instruction(opname='DUP_TOP', opcode=4, arg=None, argval=None, argrepr='', offset=158, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=160, starts_line=None, is_jump_target=False), Instruction(opname='DUP_TOP', opcode=4, arg=None, argval=None, argrepr='', offset=160, starts_line=None, is_jump_target=False),
Instruction(opname='DUP_TOP', opcode=4, arg=None, argval=None, argrepr='', offset=162, starts_line=None, is_jump_target=False), Instruction(opname='CALL_FUNCTION', opcode=131, arg=3, argval=3, argrepr='', offset=162, starts_line=None, is_jump_target=False),
Instruction(opname='DUP_TOP', opcode=4, arg=None, argval=None, argrepr='', offset=164, starts_line=None, is_jump_target=False), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=164, starts_line=None, is_jump_target=False),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=3, argval=3, argrepr='', offset=166, starts_line=None, is_jump_target=False), Instruction(opname='JUMP_FORWARD', opcode=110, arg=16, argval=184, argrepr='to 184', offset=166, starts_line=None, is_jump_target=False),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=168, starts_line=None, is_jump_target=False), Instruction(opname='WITH_EXCEPT_START', opcode=49, arg=None, argval=None, argrepr='', offset=168, starts_line=None, is_jump_target=True),
Instruction(opname='JUMP_FORWARD', opcode=110, arg=16, argval=188, argrepr='to 188', offset=170, starts_line=None, is_jump_target=False), Instruction(opname='POP_JUMP_IF_TRUE', opcode=115, arg=174, argval=174, argrepr='', offset=170, starts_line=None, is_jump_target=False),
Instruction(opname='WITH_EXCEPT_START', opcode=49, arg=None, argval=None, argrepr='', offset=172, starts_line=None, is_jump_target=True), Instruction(opname='RERAISE', opcode=48, arg=None, argval=None, argrepr='', offset=172, starts_line=None, is_jump_target=False),
Instruction(opname='POP_JUMP_IF_TRUE', opcode=115, arg=178, argval=178, argrepr='', offset=174, starts_line=None, is_jump_target=False), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=174, starts_line=None, is_jump_target=True),
Instruction(opname='RERAISE', opcode=48, arg=None, argval=None, argrepr='', offset=176, starts_line=None, is_jump_target=False), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=176, starts_line=None, is_jump_target=False),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=178, starts_line=None, is_jump_target=True), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, 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='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=180, starts_line=None, is_jump_target=False),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=182, starts_line=None, is_jump_target=False), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=182, starts_line=None, is_jump_target=False),
Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=184, starts_line=None, is_jump_target=False), Instruction(opname='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=184, starts_line=None, is_jump_target=True),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=186, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=186, starts_line=28, is_jump_target=False),
Instruction(opname='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=188, starts_line=None, 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=188, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=190, starts_line=28, is_jump_target=False), Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=190, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=192, starts_line=None, is_jump_target=False), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=192, starts_line=None, is_jump_target=False),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=194, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=194, starts_line=None, is_jump_target=False),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=196, starts_line=None, is_jump_target=False), Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=196, starts_line=None, is_jump_target=False),
Instruction(opname='JUMP_FORWARD', opcode=110, arg=10, argval=210, argrepr='to 210', offset=198, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=198, starts_line=None, is_jump_target=True),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=200, starts_line=None, 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=200, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=202, starts_line=None, is_jump_target=False), Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=202, starts_line=None, is_jump_target=False),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=204, starts_line=None, is_jump_target=False), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=204, starts_line=None, is_jump_target=False),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=206, starts_line=None, is_jump_target=False), Instruction(opname='RERAISE', opcode=48, arg=None, argval=None, argrepr='', offset=206, starts_line=None, is_jump_target=False),
Instruction(opname='RERAISE', opcode=48, arg=None, argval=None, argrepr='', offset=208, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=210, starts_line=None, is_jump_target=True),
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=212, starts_line=None, is_jump_target=False),
] ]
# One last piece of inspect fodder to check the default line number handling # One last piece of inspect fodder to check the default line number handling

View File

@ -990,7 +990,7 @@ class JumpTestCase(unittest.TestCase):
pass pass
output.append(12) output.append(12)
@jump_test(3, 4, [1], (ValueError, 'unreachable')) @jump_test(3, 4, [1], (ValueError, 'after'))
def test_no_jump_infinite_while_loop(output): def test_no_jump_infinite_while_loop(output):
output.append(1) output.append(1)
while True: while True:

View File

@ -96,6 +96,10 @@ typedef struct basicblock_ {
/* b_return is true if a RETURN_VALUE opcode is inserted. */ /* b_return is true if a RETURN_VALUE opcode is inserted. */
unsigned b_return : 1; unsigned b_return : 1;
unsigned b_reachable : 1; unsigned b_reachable : 1;
/* Basic block has no fall through (it ends with a return, raise or jump) */
unsigned b_nofallthrough : 1;
/* Basic block exits scope (it ends with a return or raise) */
unsigned b_exit : 1;
/* depth of stack upon entry of block, computed by stackdepth() */ /* depth of stack upon entry of block, computed by stackdepth() */
int b_startdepth; int b_startdepth;
/* instruction offset for block, computed by assemble_jump_offsets() */ /* instruction offset for block, computed by assemble_jump_offsets() */
@ -5434,28 +5438,14 @@ struct assembler {
PyObject *a_bytecode; /* string containing bytecode */ PyObject *a_bytecode; /* string containing bytecode */
int a_offset; /* offset into bytecode */ int a_offset; /* offset into bytecode */
int a_nblocks; /* number of reachable blocks */ int a_nblocks; /* number of reachable blocks */
basicblock **a_reverse_postorder; /* list of blocks in dfs postorder */
PyObject *a_lnotab; /* string containing lnotab */ PyObject *a_lnotab; /* string containing lnotab */
int a_lnotab_off; /* offset into lnotab */ int a_lnotab_off; /* offset into lnotab */
int a_prevlineno; /* lineno of last emitted line in line table */ int a_prevlineno; /* lineno of last emitted line in line table */
int a_lineno; /* lineno of last emitted instruction */ int a_lineno; /* lineno of last emitted instruction */
int a_lineno_start; /* bytecode start offset of current lineno */ int a_lineno_start; /* bytecode start offset of current lineno */
basicblock *a_entry;
}; };
static void
dfs(struct compiler *c, basicblock *b, struct assembler *a, int end)
{
/* There is no real depth-first-search to do here because all the
* blocks are emitted in topological order already, so we just need to
* follow the b_next pointers and place them in a->a_reverse_postorder in
* reverse order and make sure that the first one starts at 0. */
for (a->a_nblocks = 0; b != NULL; b = b->b_next) {
a->a_reverse_postorder[a->a_nblocks++] = b;
}
}
Py_LOCAL_INLINE(void) Py_LOCAL_INLINE(void)
stackdepth_push(basicblock ***sp, basicblock *b, int depth) stackdepth_push(basicblock ***sp, basicblock *b, int depth)
{ {
@ -5553,12 +5543,7 @@ assemble_init(struct assembler *a, int nblocks, int firstlineno)
PyErr_NoMemory(); PyErr_NoMemory();
return 0; return 0;
} }
a->a_reverse_postorder = (basicblock **)PyObject_Malloc(
sizeof(basicblock *) * nblocks);
if (!a->a_reverse_postorder) {
PyErr_NoMemory();
return 0;
}
return 1; return 1;
} }
@ -5567,8 +5552,6 @@ assemble_free(struct assembler *a)
{ {
Py_XDECREF(a->a_bytecode); Py_XDECREF(a->a_bytecode);
Py_XDECREF(a->a_lnotab); Py_XDECREF(a->a_lnotab);
if (a->a_reverse_postorder)
PyObject_Free(a->a_reverse_postorder);
} }
static int static int
@ -5697,8 +5680,7 @@ assemble_jump_offsets(struct assembler *a, struct compiler *c)
Replace block pointer with position in bytecode. */ Replace block pointer with position in bytecode. */
do { do {
totsize = 0; totsize = 0;
for (i = 0; i < a->a_nblocks; i++) { for (basicblock *b = a->a_entry; b != NULL; b = b->b_next) {
b = a->a_reverse_postorder[i];
bsize = blocksize(b); bsize = blocksize(b);
b->b_offset = totsize; b->b_offset = totsize;
totsize += bsize; totsize += bsize;
@ -5966,7 +5948,7 @@ assemble(struct compiler *c, int addNone)
{ {
basicblock *b, *entryblock; basicblock *b, *entryblock;
struct assembler a; struct assembler a;
int i, j, nblocks; int j, nblocks;
PyCodeObject *co = NULL; PyCodeObject *co = NULL;
PyObject *consts = NULL; PyObject *consts = NULL;
@ -5997,7 +5979,8 @@ assemble(struct compiler *c, int addNone)
} }
if (!assemble_init(&a, nblocks, c->u->u_firstlineno)) if (!assemble_init(&a, nblocks, c->u->u_firstlineno))
goto error; goto error;
dfs(c, entryblock, &a, nblocks); a.a_entry = entryblock;
a.a_nblocks = nblocks;
consts = consts_dict_keys_inorder(c->u->u_consts); consts = consts_dict_keys_inorder(c->u->u_consts);
if (consts == NULL) { if (consts == NULL) {
@ -6010,9 +5993,8 @@ assemble(struct compiler *c, int addNone)
/* Can't modify the bytecode after computing jump offsets. */ /* Can't modify the bytecode after computing jump offsets. */
assemble_jump_offsets(&a, c); assemble_jump_offsets(&a, c);
/* Emit code in reverse postorder from dfs. */ /* Emit code. */
for (i = 0; i < a.a_nblocks; i++) { for(b = entryblock; b != NULL; b = b->b_next) {
b = a.a_reverse_postorder[i];
for (j = 0; j < b->b_iused; j++) for (j = 0; j < b->b_iused; j++)
if (!assemble_emit(&a, &b->b_instr[j])) if (!assemble_emit(&a, &b->b_instr[j]))
goto error; goto error;
@ -6097,6 +6079,8 @@ fold_tuple_on_constants(struct instr *inst,
return 0; return 0;
} }
/* Maximum size of basic block that should be copied in optimizer */
#define MAX_COPY_SIZE 4
/* Optimization */ /* Optimization */
static int static int
@ -6238,19 +6222,29 @@ optimize_basic_block(basicblock *bb, PyObject *consts)
case JUMP_ABSOLUTE: case JUMP_ABSOLUTE:
case JUMP_FORWARD: case JUMP_FORWARD:
assert (i == bb->b_iused-1);
switch(target->i_opcode) { switch(target->i_opcode) {
case JUMP_FORWARD: case JUMP_FORWARD:
inst->i_target = target->i_target; inst->i_target = target->i_target;
break; break;
case JUMP_ABSOLUTE: case JUMP_ABSOLUTE:
case RETURN_VALUE:
case RERAISE:
case RAISE_VARARGS:
lineno = inst->i_lineno; lineno = inst->i_lineno;
*inst = *target; *inst = *target;
inst->i_lineno = lineno; inst->i_lineno = lineno;
break; break;
} }
if (inst->i_target->b_exit && inst->i_target->b_iused <= MAX_COPY_SIZE) {
basicblock *to_copy = inst->i_target;
*inst = to_copy->b_instr[0];
for (i = 1; i < to_copy->b_iused; i++) {
int index = compiler_next_instr(bb);
if (index < 0) {
return -1;
}
bb->b_instr[index] = to_copy->b_instr[i];
}
bb->b_exit = 1;
}
break; break;
} }
} }
@ -6262,52 +6256,63 @@ error:
static void static void
clean_basic_block(basicblock *bb) { clean_basic_block(basicblock *bb) {
/* Remove NOPs and any code following a return or re-raise. */ /* Remove NOPs. */
int dest = 0; int dest = 0;
int prev_lineno = -1; int prev_lineno = -1;
for (int src = 0; src < bb->b_iused; src++) { for (int src = 0; src < bb->b_iused; src++) {
int lineno = bb->b_instr[src].i_lineno; int lineno = bb->b_instr[src].i_lineno;
switch(bb->b_instr[src].i_opcode) { if (bb->b_instr[src].i_opcode == NOP) {
case RETURN_VALUE:
case RERAISE:
bb->b_next = NULL;
bb->b_instr[dest] = bb->b_instr[src];
dest++;
goto end;
case NOP:
{
/* Eliminate no-op if it doesn't have a line number, or /* Eliminate no-op if it doesn't have a line number, or
* if the next instruction has same line number or no line number, or * if the next instruction has same line number or no line number, or
* if the previous instruction had the same line number. */ * if the previous instruction had the same line number. */
if (lineno < 0) { if (lineno < 0) {
break; continue;
} }
if (prev_lineno == lineno) { if (prev_lineno == lineno) {
break; continue;
} }
if (src < bb->b_iused - 1) { if (src < bb->b_iused - 1) {
int next_lineno = bb->b_instr[src+1].i_lineno; int next_lineno = bb->b_instr[src+1].i_lineno;
if (next_lineno < 0 || next_lineno == lineno) { if (next_lineno < 0 || next_lineno == lineno) {
bb->b_instr[src+1].i_lineno = lineno; bb->b_instr[src+1].i_lineno = lineno;
break; continue;
} }
} }
} }
/* fallthrough */
default:
if (dest != src) { if (dest != src) {
bb->b_instr[dest] = bb->b_instr[src]; bb->b_instr[dest] = bb->b_instr[src];
} }
dest++; dest++;
prev_lineno = lineno; prev_lineno = lineno;
break;
} }
}
end:
assert(dest <= bb->b_iused); assert(dest <= bb->b_iused);
bb->b_iused = dest; bb->b_iused = dest;
} }
static void
normalise_basic_block(basicblock *bb) {
/* Remove any code following a return or re-raise,
and mark those blocks as exit and/or nofallthrough. */
for (int i = 0; i < bb->b_iused; i++) {
switch(bb->b_instr[i].i_opcode) {
case RETURN_VALUE:
case RAISE_VARARGS:
case RERAISE:
bb->b_iused = i+1;
bb->b_exit = 1;
bb->b_nofallthrough = 1;
return;
case JUMP_ABSOLUTE:
case JUMP_FORWARD:
bb->b_iused = i+1;
bb->b_nofallthrough = 1;
return;
}
}
}
static int static int
mark_reachable(struct assembler *a) { mark_reachable(struct assembler *a) {
basicblock **stack, **sp; basicblock **stack, **sp;
@ -6315,12 +6320,11 @@ mark_reachable(struct assembler *a) {
if (stack == NULL) { if (stack == NULL) {
return -1; return -1;
} }
basicblock *entry = a->a_reverse_postorder[0]; a->a_entry->b_reachable = 1;
entry->b_reachable = 1; *sp++ = a->a_entry;
*sp++ = entry;
while (sp > stack) { while (sp > stack) {
basicblock *b = *(--sp); basicblock *b = *(--sp);
if (b->b_next && b->b_next->b_reachable == 0) { if (b->b_next && !b->b_nofallthrough && b->b_next->b_reachable == 0) {
b->b_next->b_reachable = 1; b->b_next->b_reachable = 1;
*sp++ = b->b_next; *sp++ = b->b_next;
} }
@ -6352,20 +6356,23 @@ mark_reachable(struct assembler *a) {
static int static int
optimize_cfg(struct assembler *a, PyObject *consts) optimize_cfg(struct assembler *a, PyObject *consts)
{ {
for (int i = 0; i < a->a_nblocks; i++) { for (basicblock *b = a->a_entry; b != NULL; b = b->b_next) {
if (optimize_basic_block(a->a_reverse_postorder[i], consts)) { normalise_basic_block(b);
}
for (basicblock *b = a->a_entry; b != NULL; b = b->b_next) {
if (optimize_basic_block(b, consts)) {
return -1; return -1;
} }
clean_basic_block(a->a_reverse_postorder[i]); clean_basic_block(b);
assert(a->a_reverse_postorder[i]->b_reachable == 0); assert(b->b_reachable == 0);
} }
if (mark_reachable(a)) { if (mark_reachable(a)) {
return -1; return -1;
} }
/* Delete unreachable instructions */ /* Delete unreachable instructions */
for (int i = 0; i < a->a_nblocks; i++) { for (basicblock *b = a->a_entry; b != NULL; b = b->b_next) {
if (a->a_reverse_postorder[i]->b_reachable == 0) { if (b->b_reachable == 0) {
a->a_reverse_postorder[i]->b_iused = 0; b->b_iused = 0;
} }
} }
return 0; return 0;

2820
Python/importlib.h generated

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff