From 586abbe4e5541636e48f635442c4ad9695ba209d Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Thu, 21 Apr 2022 22:41:51 +0100 Subject: [PATCH 01/26] emit except handlers at end of function --- Python/compile.c | 46 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index 4108b896ade46d..9b7bf7937fd9c1 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -261,6 +261,8 @@ typedef struct basicblock_ { unsigned b_exit : 1; /* b_return is true if a RETURN_VALUE opcode is inserted. */ unsigned b_return : 1; + /* b_cold is true if this block is not perf critical (like an exception handler) */ + unsigned b_cold : 1; } basicblock; /* fblockinfo tracks the current frame block. @@ -333,6 +335,8 @@ struct compiler_unit { /* true if we need to create an implicit basicblock before the next instr */ int u_need_new_implicit_block; + /* >0 if we are generating cold code */ + int u_cold; }; /* This struct captures the global state of a compilation. @@ -826,6 +830,7 @@ static basicblock * compiler_use_next_block(struct compiler *c, basicblock *block) { assert(block != NULL); + block->b_cold = c->u->u_cold > 0; c->u->u_curblock->b_next = block; c->u->u_curblock = block; c->u->u_need_new_implicit_block = 0; @@ -901,6 +906,9 @@ compiler_next_instr(basicblock *b) return b->b_iused++; } +#define ENTER_COLD(c) (c)->u->u_cold++; +#define EXIT_COLD(c) (c)->u->u_cold--; assert((c)->u->u_cold >= 0); + /* Set the line number and column offset for the following instructions. The line number is reset in the following cases: @@ -3465,6 +3473,7 @@ compiler_try_except(struct compiler *c, stmt_ty s) } ADDOP_JUMP_NOLINE(c, JUMP, end); n = asdl_seq_LEN(s->v.Try.handlers); + ENTER_COLD(c); compiler_use_next_block(c, except); UNSET_LOC(c); @@ -3567,6 +3576,7 @@ compiler_try_except(struct compiler *c, stmt_ty s) ADDOP_I(c, RERAISE, 0); compiler_use_next_block(c, cleanup); POP_EXCEPT_AND_RERAISE(c); + EXIT_COLD(c); compiler_use_next_block(c, end); return 1; } @@ -7390,6 +7400,35 @@ label_exception_targets(basicblock *entry) { return -1; } +static void +push_cold_blocks_to_end(basicblock *entry) { + if (entry->b_next == NULL) { + /* single basicblock, no need to reorder */ + return; + } + assert(!entry->b_cold); /* First block can't be cold */ + basicblock *tail = entry; + while (tail->b_next) { + tail = tail->b_next; + } + basicblock *origtail = tail; + basicblock *b = entry; + while(b) { + basicblock *next = b->b_next; + if (next == NULL || next == origtail) { + break; + } + if (next->b_cold) { + b->b_next = next->b_next; + next->b_next = NULL; + tail->b_next = next; + tail = next; + } else { + b = next; + } + } + return; +} static void convert_exception_handlers_to_nops(basicblock *entry) { @@ -8037,8 +8076,8 @@ static void dump_basicblock(const basicblock *b) { const char *b_return = b->b_return ? "return " : ""; - fprintf(stderr, "used: %d, depth: %d, offset: %d %s\n", - b->b_iused, b->b_startdepth, b->b_offset, b_return); + fprintf(stderr, "[%d %p] used: %d, depth: %d, offset: %d %s\n", + b->b_cold, b, b->b_iused, b->b_startdepth, b->b_offset, b_return); if (b->b_instr) { int i; for (i = 0; i < b->b_iused; i++) { @@ -8393,6 +8432,9 @@ assemble(struct compiler *c, int addNone) goto error; } convert_exception_handlers_to_nops(entryblock); + + push_cold_blocks_to_end(a.a_entry); + for (basicblock *b = a.a_entry; b != NULL; b = b->b_next) { clean_basic_block(b); } From 7cee46ca5be05943001e11476afd4bd448668ddb Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Thu, 21 Apr 2022 23:27:53 +0100 Subject: [PATCH 02/26] remove redundant jumps after reordering cold blocks --- Python/compile.c | 60 +++++++++++++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index 9b7bf7937fd9c1..6be57052e01b9a 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -8322,6 +8322,38 @@ fix_cell_offsets(struct compiler *c, basicblock *entryblock, int *fixedmap) static void propagate_line_numbers(struct assembler *a); +static void +eliminate_empty_basic_blocks(basicblock *entry); + + +static void +remove_redundant_jumps(basicblock *entry) { + /* If a non-empty block ends with a jump instruction, check if the next + * non-empty block reached through normal flow control is the target + * of that jump. If it is, then the jump instruction is redundant and + * can be deleted. + */ + int removed = 0; + for (basicblock *b = entry; b != NULL; b = b->b_next) { + if (b->b_iused > 0) { + struct instr *b_last_instr = &b->b_instr[b->b_iused - 1]; + assert(!IS_ASSEMBLER_OPCODE(b_last_instr->i_opcode)); + if (b_last_instr->i_opcode == JUMP || + b_last_instr->i_opcode == JUMP_NO_INTERRUPT) { + if (b_last_instr->i_target == b->b_next) { + assert(b->b_next->b_iused); + b->b_nofallthrough = 0; + b_last_instr->i_opcode = NOP; + removed++; + } + } + } + } + if (removed) { + eliminate_empty_basic_blocks(entry); + } +} + static PyCodeObject * assemble(struct compiler *c, int addNone) { @@ -8435,6 +8467,8 @@ assemble(struct compiler *c, int addNone) push_cold_blocks_to_end(a.a_entry); + remove_redundant_jumps(a.a_entry); + for (basicblock *b = a.a_entry; b != NULL; b = b->b_next) { clean_basic_block(b); } @@ -9279,30 +9313,8 @@ optimize_cfg(struct compiler *c, struct assembler *a, PyObject *consts) for (basicblock *b = a->a_entry; b != NULL; b = b->b_next) { clean_basic_block(b); } - /* Delete jump instructions made redundant by previous step. If a non-empty - block ends with a jump instruction, check if the next non-empty block - reached through normal flow control is the target of that jump. If it - is, then the jump instruction is redundant and can be deleted. - */ - int maybe_empty_blocks = 0; - for (basicblock *b = a->a_entry; b != NULL; b = b->b_next) { - if (b->b_iused > 0) { - struct instr *b_last_instr = &b->b_instr[b->b_iused - 1]; - assert(!IS_ASSEMBLER_OPCODE(b_last_instr->i_opcode)); - if (b_last_instr->i_opcode == JUMP || - b_last_instr->i_opcode == JUMP_NO_INTERRUPT) { - if (b_last_instr->i_target == b->b_next) { - assert(b->b_next->b_iused); - b->b_nofallthrough = 0; - b_last_instr->i_opcode = NOP; - maybe_empty_blocks = 1; - } - } - } - } - if (maybe_empty_blocks) { - eliminate_empty_basic_blocks(a->a_entry); - } + /* Delete jump instructions made redundant by previous step. */ + remove_redundant_jumps(a->a_entry); return 0; } From a1ab27d929f78841033f32128f47b9c4c1238a47 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Fri, 22 Apr 2022 16:03:40 +0100 Subject: [PATCH 03/26] add some sanity checks --- Python/compile.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Python/compile.c b/Python/compile.c index 6be57052e01b9a..0ea9873737e9fc 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -906,6 +906,7 @@ compiler_next_instr(basicblock *b) return b->b_iused++; } +#define COLD_VALUE(c) (c)->u->u_cold #define ENTER_COLD(c) (c)->u->u_cold++; #define EXIT_COLD(c) (c)->u->u_cold--; assert((c)->u->u_cold >= 0); @@ -7409,6 +7410,7 @@ push_cold_blocks_to_end(basicblock *entry) { assert(!entry->b_cold); /* First block can't be cold */ basicblock *tail = entry; while (tail->b_next) { + assert(tail->b_nofallthrough || (tail->b_cold == tail->b_next->b_cold)); tail = tail->b_next; } basicblock *origtail = tail; @@ -8363,6 +8365,9 @@ assemble(struct compiler *c, int addNone) PyCodeObject *co = NULL; PyObject *consts = NULL; + /* Check that ENTER_COLD/EXIT_COLD calls are balanced */ + assert(COLD_VALUE(c) == 0); + /* Make sure every block that falls off the end returns None. */ if (!c->u->u_curblock->b_return) { UNSET_LOC(c); From 5cbffc2d87729011dd759cd386ca9bb5e9befd1d Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Fri, 22 Apr 2022 17:57:35 +0100 Subject: [PATCH 04/26] fix test_dis and test_code --- Lib/test/test_code.py | 6 +-- Lib/test/test_dis.py | 89 +++++++++++++++++++++---------------------- Python/compile.c | 4 +- 3 files changed, 49 insertions(+), 50 deletions(-) diff --git a/Lib/test/test_code.py b/Lib/test/test_code.py index 872f7283fc504e..20b3a247617841 100644 --- a/Lib/test/test_code.py +++ b/Lib/test/test_code.py @@ -379,13 +379,13 @@ def test_co_positions_artificial_instructions(self): ], [ ('RESUME', 0), + ("COPY", 3), + ("POP_EXCEPT", None), + ("RERAISE", 1), ("PUSH_EXC_INFO", None), ("LOAD_CONST", None), # artificial 'None' ("STORE_NAME", "e"), # XX: we know the location for this ("DELETE_NAME", "e"), - ("RERAISE", 1), - ("COPY", 3), - ("POP_EXCEPT", None), ("RERAISE", 1) ] ) diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index f560a5556c8b0e..aa78573292adc7 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -369,11 +369,14 @@ def bug42562(): %3d LOAD_FAST 1 (tb) RETURN_VALUE + >> COPY 3 + POP_EXCEPT + RERAISE 1 >> PUSH_EXC_INFO %3d LOAD_GLOBAL 0 (Exception) CHECK_EXC_MATCH - POP_JUMP_FORWARD_IF_FALSE 18 (to 72) + POP_JUMP_FORWARD_IF_FALSE 18 (to 78) STORE_FAST 0 (e) %3d LOAD_FAST 0 (e) @@ -392,9 +395,6 @@ def bug42562(): RERAISE 1 %3d >> RERAISE 0 - >> COPY 3 - POP_EXCEPT - RERAISE 1 ExceptionTable: """ % (TRACEBACK_CODE.co_firstlineno, TRACEBACK_CODE.co_firstlineno + 1, @@ -1435,48 +1435,47 @@ def _prepare_test_cases(): Instruction(opname='POP_EXCEPT', opcode=89, 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='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=326, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='JUMP_FORWARD', opcode=110, arg=31, argval=392, argrepr='to 392', offset=328, starts_line=None, is_jump_target=True, positions=None), - Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=330, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=4, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=332, starts_line=22, is_jump_target=False, positions=None), - Instruction(opname='CHECK_EXC_MATCH', opcode=36, arg=None, argval=None, argrepr='', offset=344, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_JUMP_FORWARD_IF_FALSE', opcode=114, arg=18, argval=384, argrepr='to 384', offset=346, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=348, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=350, starts_line=23, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=9, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=362, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=364, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=368, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=378, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=380, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='JUMP_FORWARD', opcode=110, arg=21, argval=426, argrepr='to 426', offset=382, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=384, starts_line=22, is_jump_target=True, positions=None), - Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=386, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=388, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=390, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=392, starts_line=28, is_jump_target=True, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=404, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=406, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=410, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=420, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=422, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=424, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='NOP', opcode=9, arg=None, argval=None, argrepr='', offset=426, starts_line=23, is_jump_target=True, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=428, starts_line=28, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=440, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=442, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=446, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=328, starts_line=28, is_jump_target=True, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=340, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=342, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=346, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=356, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=358, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=360, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='NOP', opcode=9, arg=None, argval=None, argrepr='', offset=362, starts_line=23, is_jump_target=True, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=364, starts_line=28, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=376, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=378, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=382, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=392, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=394, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=396, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=398, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=400, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=412, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=414, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=418, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=428, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=430, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=432, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=434, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=436, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=438, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=4, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=440, starts_line=22, is_jump_target=False, positions=None), + Instruction(opname='CHECK_EXC_MATCH', opcode=36, arg=None, argval=None, argrepr='', offset=452, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_JUMP_FORWARD_IF_FALSE', opcode=114, arg=18, argval=492, argrepr='to 492', offset=454, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=456, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=458, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=460, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=462, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=464, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=476, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=478, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=482, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=492, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=494, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=496, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=498, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=500, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=458, starts_line=23, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=9, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=470, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=472, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=476, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=486, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=488, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='JUMP_BACKWARD', opcode=140, arg=65, argval=362, argrepr='to 362', offset=490, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=492, starts_line=22, is_jump_target=True, positions=None), + Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=494, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=496, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=498, starts_line=None, is_jump_target=False, positions=None) ] # One last piece of inspect fodder to check the default line number handling diff --git a/Python/compile.c b/Python/compile.c index 0ea9873737e9fc..6f38214cfa244d 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -8470,9 +8470,9 @@ assemble(struct compiler *c, int addNone) } convert_exception_handlers_to_nops(entryblock); - push_cold_blocks_to_end(a.a_entry); + push_cold_blocks_to_end(entryblock); - remove_redundant_jumps(a.a_entry); + remove_redundant_jumps(entryblock); for (basicblock *b = a.a_entry; b != NULL; b = b->b_next) { clean_basic_block(b); From 30c85e36cd8fa927dbeaa2012ef184bcffecb8d8 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Tue, 10 May 2022 15:34:11 +0100 Subject: [PATCH 05/26] update test_dis after merge --- Lib/test/test_dis.py | 73 ++++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 37 deletions(-) diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index af736d6fe96141..247ad2101efbfa 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -369,11 +369,14 @@ def bug42562(): %3d LOAD_FAST 1 (tb) RETURN_VALUE + >> COPY 3 + POP_EXCEPT + RERAISE 1 >> PUSH_EXC_INFO %3d LOAD_GLOBAL 0 (Exception) CHECK_EXC_MATCH - POP_JUMP_FORWARD_IF_FALSE 18 (to 72) + POP_JUMP_FORWARD_IF_FALSE 18 (to 78) STORE_FAST 0 (e) %3d LOAD_FAST 0 (e) @@ -392,9 +395,6 @@ def bug42562(): RERAISE 1 %3d >> RERAISE 0 - >> COPY 3 - POP_EXCEPT - RERAISE 1 ExceptionTable: """ % (TRACEBACK_CODE.co_firstlineno, TRACEBACK_CODE.co_firstlineno + 1, @@ -1478,40 +1478,39 @@ def _prepare_test_cases(): Instruction(opname='POP_EXCEPT', opcode=89, 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='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=326, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='JUMP_FORWARD', opcode=110, arg=31, argval=392, argrepr='to 392', offset=328, starts_line=None, is_jump_target=True, positions=None), - Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=330, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=4, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=332, starts_line=22, is_jump_target=False, positions=None), - Instruction(opname='CHECK_EXC_MATCH', opcode=36, arg=None, argval=None, argrepr='', offset=344, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_JUMP_FORWARD_IF_FALSE', opcode=114, arg=18, argval=384, argrepr='to 384', offset=346, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=348, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=350, starts_line=23, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=9, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=362, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=364, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=368, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=378, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=380, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='JUMP_FORWARD', opcode=110, arg=4, argval=392, argrepr='to 392', offset=382, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=384, starts_line=22, is_jump_target=True, positions=None), - Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=386, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=388, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=390, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=392, starts_line=28, is_jump_target=True, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=404, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=406, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=410, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=328, starts_line=28, is_jump_target=True, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=340, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=342, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=346, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=356, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=358, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=360, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=362, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=364, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=376, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=378, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=382, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=392, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=394, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=396, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=398, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=400, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=402, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=4, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=404, starts_line=22, is_jump_target=False, positions=None), + Instruction(opname='CHECK_EXC_MATCH', opcode=36, arg=None, argval=None, argrepr='', offset=416, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_JUMP_FORWARD_IF_FALSE', opcode=114, arg=18, argval=456, argrepr='to 456', offset=418, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=420, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=422, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=424, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=426, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=428, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=440, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=442, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=446, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=456, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=458, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=460, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=462, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=464, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=422, starts_line=23, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=9, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=434, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=436, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=440, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=450, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=452, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='JUMP_BACKWARD', opcode=140, arg=64, argval=328, argrepr='to 328', offset=454, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=456, starts_line=22, is_jump_target=True, positions=None), + Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=458, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=460, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=462, starts_line=None, is_jump_target=False, positions=None), ] # One last piece of inspect fodder to check the default line number handling From 23b7b11eda0db3470e282b1ddfba0ec2f42990a2 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Thu, 12 May 2022 22:27:48 +0100 Subject: [PATCH 06/26] most tests pass --- Lib/importlib/_bootstrap_external.py | 2 +- Lib/test/test_dis.py | 99 ++++++++++---------- Python/compile.c | 133 ++++++++++++++++++++++----- 3 files changed, 159 insertions(+), 75 deletions(-) diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 5f67226adfc522..9fd7aaf457edb3 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -416,7 +416,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 = (3494).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3999).to_bytes(2, 'little') + b'\r\n' _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index 247ad2101efbfa..cdd07a11637385 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -369,14 +369,11 @@ def bug42562(): %3d LOAD_FAST 1 (tb) RETURN_VALUE - >> COPY 3 - POP_EXCEPT - RERAISE 1 >> PUSH_EXC_INFO %3d LOAD_GLOBAL 0 (Exception) CHECK_EXC_MATCH - POP_JUMP_FORWARD_IF_FALSE 18 (to 78) + POP_JUMP_FORWARD_IF_FALSE 18 (to 72) STORE_FAST 0 (e) %3d LOAD_FAST 0 (e) @@ -395,6 +392,9 @@ def bug42562(): RERAISE 1 %3d >> RERAISE 0 + >> COPY 3 + POP_EXCEPT + RERAISE 1 ExceptionTable: """ % (TRACEBACK_CODE.co_firstlineno, TRACEBACK_CODE.co_firstlineno + 1, @@ -1466,51 +1466,52 @@ def _prepare_test_cases(): Instruction(opname='PRECALL', opcode=166, arg=2, argval=2, argrepr='', offset=288, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL', opcode=171, arg=2, argval=2, argrepr='', offset=292, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=302, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='JUMP_FORWARD', opcode=110, arg=11, argval=328, argrepr='to 328', offset=304, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='PUSH_EXC_INFO', opcode=35, 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=308, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_JUMP_FORWARD_IF_TRUE', opcode=115, arg=4, argval=320, argrepr='to 320', offset=310, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=2, argval=2, argrepr='', offset=312, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=314, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=316, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=318, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=320, starts_line=None, is_jump_target=True, positions=None), - Instruction(opname='POP_EXCEPT', opcode=89, 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='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=326, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=328, starts_line=28, is_jump_target=True, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=340, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=342, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=346, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=356, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=358, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=360, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=362, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=364, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=376, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=378, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=382, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=392, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=394, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=396, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=398, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=400, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=402, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=4, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=404, starts_line=22, is_jump_target=False, positions=None), - Instruction(opname='CHECK_EXC_MATCH', opcode=36, arg=None, argval=None, argrepr='', offset=416, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_JUMP_FORWARD_IF_FALSE', opcode=114, arg=18, argval=456, argrepr='to 456', offset=418, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=420, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=422, starts_line=23, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=9, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=434, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=436, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=440, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=450, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=452, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='JUMP_BACKWARD', opcode=140, arg=64, argval=328, argrepr='to 328', offset=454, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=456, starts_line=22, is_jump_target=True, positions=None), - Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=458, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=460, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=462, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='NOP', opcode=9, arg=None, argval=None, argrepr='', offset=304, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=306, starts_line=28, is_jump_target=True, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=318, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=320, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=324, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=334, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=336, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=338, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=340, starts_line=25, is_jump_target=False, positions=None), + Instruction(opname='WITH_EXCEPT_START', opcode=49, arg=None, argval=None, argrepr='', offset=342, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_JUMP_FORWARD_IF_TRUE', opcode=115, arg=4, argval=354, argrepr='to 354', offset=344, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=2, argval=2, argrepr='', offset=346, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=348, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=350, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=352, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=354, starts_line=None, is_jump_target=True, positions=None), + Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=356, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=358, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=360, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='JUMP_BACKWARD', opcode=140, arg=29, argval=306, argrepr='to 306', offset=362, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=364, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=4, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=366, starts_line=22, is_jump_target=False, positions=None), + Instruction(opname='CHECK_EXC_MATCH', opcode=36, arg=None, argval=None, argrepr='', offset=378, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_JUMP_FORWARD_IF_FALSE', opcode=114, arg=18, argval=418, argrepr='to 418', offset=380, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=382, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=384, starts_line=23, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=9, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=396, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=398, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=402, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=412, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=414, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='JUMP_BACKWARD', opcode=140, arg=56, argval=306, argrepr='to 306', offset=416, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=418, starts_line=22, is_jump_target=True, positions=None), + Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=420, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=422, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=424, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=426, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=428, starts_line=28, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=440, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=442, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=446, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=456, starts_line=None, is_jump_target=False, positions=None), +Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=458, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=460, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=462, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=464, starts_line=None, is_jump_target=False, positions=None), ] # One last piece of inspect fodder to check the default line number handling diff --git a/Python/compile.c b/Python/compile.c index 0c1d10d17376d3..2335416b2cae3e 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -191,6 +191,9 @@ is_jump(struct instr *i) is_bit_set_in_table(_PyOpcode_Jump, i->i_opcode); } +static void +dump_instr(struct instr *i); + static int instr_size(struct instr *instruction) { @@ -248,6 +251,8 @@ typedef struct basicblock_ { int b_ialloc; /* Number of predecssors that a block has. */ int b_predecessors; + /* Number of predecssors that a block has as an exception handler. */ + int b_except_predecessors; /* depth of stack upon entry of block, computed by stackdepth() */ int b_startdepth; /* instruction offset for block, computed by assemble_jump_offsets() */ @@ -264,6 +269,8 @@ typedef struct basicblock_ { unsigned b_return : 1; /* b_cold is true if this block is not perf critical (like an exception handler) */ unsigned b_cold : 1; + /* b_warm is used by the cold-detection algorithm to mark blocks which are definitely not cold */ + unsigned b_warm : 1; } basicblock; /* fblockinfo tracks the current frame block. @@ -336,8 +343,6 @@ struct compiler_unit { /* true if we need to create an implicit basicblock before the next instr */ int u_need_new_implicit_block; - /* >0 if we are generating cold code */ - int u_cold; }; /* This struct captures the global state of a compilation. @@ -832,7 +837,6 @@ static basicblock * compiler_use_next_block(struct compiler *c, basicblock *block) { assert(block != NULL); - block->b_cold = c->u->u_cold > 0; c->u->u_curblock->b_next = block; c->u->u_curblock = block; c->u->u_need_new_implicit_block = 0; @@ -908,10 +912,6 @@ compiler_next_instr(basicblock *b) return b->b_iused++; } -#define COLD_VALUE(c) (c)->u->u_cold -#define ENTER_COLD(c) (c)->u->u_cold++; -#define EXIT_COLD(c) (c)->u->u_cold--; assert((c)->u->u_cold >= 0); - /* Set the line number and column offset for the following instructions. The line number is reset in the following cases: @@ -3476,7 +3476,6 @@ compiler_try_except(struct compiler *c, stmt_ty s) } ADDOP_JUMP_NOLINE(c, JUMP, end); n = asdl_seq_LEN(s->v.Try.handlers); - ENTER_COLD(c); compiler_use_next_block(c, except); UNSET_LOC(c); @@ -3579,7 +3578,6 @@ compiler_try_except(struct compiler *c, stmt_ty s) ADDOP_I(c, RERAISE, 0); compiler_use_next_block(c, cleanup); POP_EXCEPT_AND_RERAISE(c); - EXIT_COLD(c); compiler_use_next_block(c, end); return 1; } @@ -5663,6 +5661,7 @@ compiler_async_with(struct compiler *c, stmt_ty s, int pos) ADDOP_LOAD_CONST(c, Py_None); ADD_YIELD_FROM(c, 1); compiler_with_except_finish(c, cleanup); + ADDOP_JUMP(c, JUMP, exit); compiler_use_next_block(c, exit); return 1; @@ -5756,6 +5755,7 @@ compiler_with(struct compiler *c, stmt_ty s, int pos) ADDOP(c, PUSH_EXC_INFO); ADDOP(c, WITH_EXCEPT_START); compiler_with_except_finish(c, cleanup); + ADDOP_JUMP(c, JUMP, exit); compiler_use_next_block(c, exit); return 1; @@ -7371,25 +7371,98 @@ label_exception_targets(basicblock *entry) { } static void -push_cold_blocks_to_end(basicblock *entry) { +mark_warm(struct compiler *c, struct assembler *a, basicblock **stack) { + basicblock **sp = stack; + + for (basicblock *b = c->u->u_blocks; b != NULL; b = b->b_list) { + b->b_visited = 0; + } + *sp++ = a->a_entry; + while (sp > stack) { + basicblock *b = *(--sp); + b->b_visited = 1; + assert(!b->b_except_predecessors); + b->b_warm = 1; + basicblock *next = b->b_next; + if (next && !b->b_nofallthrough && !next->b_visited) { + *sp++ = next; + } + for (int i=0; i < b->b_iused; i++) { + struct instr *instr = &b->b_instr[i]; + if (is_jump(instr) && !instr->i_target->b_visited) { + *sp++ = instr->i_target; + } + } + } +} + +static int +mark_cold(struct compiler *c, struct assembler *a) { + basicblock **stack = (basicblock **)PyObject_Malloc(sizeof(basicblock *) * a->a_nblocks * 2 /* TODO: remove *2, count again? */); + basicblock **sp = stack; + if (stack == NULL) { + return -1; + } + mark_warm(c, a, stack); + + sp = stack; + for (basicblock *b = c->u->u_blocks; b != NULL; b = b->b_list) { + b->b_visited = 0; + if (b->b_except_predecessors) { + assert(b->b_except_predecessors == b->b_predecessors); + assert(!b->b_warm); + *sp++ = b; + } + } + + while (sp > stack) { + basicblock *b = *(--sp); + b->b_cold = 1; + b->b_visited = 1; + basicblock *next = b->b_next; + if (next && !b->b_nofallthrough) { + if (!next->b_warm && !next->b_visited) { + *sp++ = next; + } + } + for (int i = 0; i < b->b_iused; i++) { + struct instr *instr = &b->b_instr[i]; + if (is_jump(instr)) { + assert(i == b->b_iused-1); + basicblock *target = b->b_instr[i].i_target; + if (!target->b_warm && !target->b_visited) { + *sp++ = target; + } + } + } + } + PyObject_Free(stack); + return 0; +} + +static int +push_cold_blocks_to_end(struct compiler *c, struct assembler *a, basicblock *entry) { if (entry->b_next == NULL) { /* single basicblock, no need to reorder */ - return; + return 0; + } + if (mark_cold(c, a) < 0) { + return -1; } assert(!entry->b_cold); /* First block can't be cold */ basicblock *tail = entry; while (tail->b_next) { - assert(tail->b_nofallthrough || (tail->b_cold == tail->b_next->b_cold)); tail = tail->b_next; } basicblock *origtail = tail; basicblock *b = entry; while(b) { basicblock *next = b->b_next; - if (next == NULL || next == origtail) { + if (next == NULL) { break; } if (next->b_cold) { + //assert(next->b_nofallthrough || (!next->b_next || next->b_next->b_cold)); b->b_next = next->b_next; next->b_next = NULL; tail->b_next = next; @@ -7397,8 +7470,11 @@ push_cold_blocks_to_end(basicblock *entry) { } else { b = next; } + if(next == origtail) { + break; + } } - return; + return 0; } static void @@ -8050,7 +8126,7 @@ makecode(struct compiler *c, struct assembler *a, PyObject *constslist, /* For debugging purposes only */ -#if 0 +#if 1 static void dump_instr(struct instr *i) { @@ -8063,6 +8139,12 @@ dump_instr(struct instr *i) if (HAS_ARG(i->i_opcode)) { sprintf(arg, "arg: %d ", i->i_oparg); } + if (is_jump(i)) { + sprintf(arg, "target: %p ", i->i_target); + } + if (is_block_push(i)) { + sprintf(arg, "except_target: %p ", i->i_target); + } fprintf(stderr, "line: %d, opcode: %d %s%s%s\n", i->i_lineno, i->i_opcode, arg, jabs, jrel); } @@ -8071,8 +8153,8 @@ static void dump_basicblock(const basicblock *b) { const char *b_return = b->b_return ? "return " : ""; - fprintf(stderr, "[%d %p] used: %d, depth: %d, offset: %d %s\n", - b->b_cold, b, b->b_iused, b->b_startdepth, b->b_offset, b_return); + fprintf(stderr, "[%d %d %d %p] used: %d, depth: %d, offset: %d %s\n", + b->b_cold, b->b_warm, b->b_nofallthrough, b, b->b_iused, b->b_startdepth, b->b_offset, b_return); if (b->b_instr) { int i; for (i = 0; i < b->b_iused; i++) { @@ -8359,9 +8441,6 @@ assemble(struct compiler *c, int addNone) PyCodeObject *co = NULL; PyObject *consts = NULL; - /* Check that ENTER_COLD/EXIT_COLD calls are balanced */ - assert(COLD_VALUE(c) == 0); - /* Make sure every block that falls off the end returns None. */ if (!c->u->u_curblock->b_return) { UNSET_LOC(c); @@ -8387,6 +8466,7 @@ assemble(struct compiler *c, int addNone) for (b = c->u->u_blocks; b != NULL; b = b->b_list) { nblocks++; entryblock = b; + assert(b->b_warm == 0 && b->b_cold == 0); } assert(entryblock != NULL); @@ -8464,7 +8544,7 @@ assemble(struct compiler *c, int addNone) } convert_exception_handlers_to_nops(entryblock); - push_cold_blocks_to_end(entryblock); + push_cold_blocks_to_end(c, &a, entryblock); remove_redundant_jumps(entryblock); @@ -9160,7 +9240,7 @@ normalize_basic_block(basicblock *bb) { } static int -mark_reachable(struct assembler *a) { +mark_reachable(struct compiler *c, struct assembler *a) { basicblock **stack, **sp; sp = stack = (basicblock **)PyObject_Malloc(sizeof(basicblock *) * a->a_nblocks); if (stack == NULL) { @@ -9185,6 +9265,11 @@ mark_reachable(struct assembler *a) { *sp++ = target; } target->b_predecessors++; + if (is_block_push(instr)) { + target->b_except_predecessors++; + } + assert(target->b_except_predecessors == 0 || + target->b_except_predecessors == target->b_predecessors); } } } @@ -9290,7 +9375,7 @@ optimize_cfg(struct compiler *c, struct assembler *a, PyObject *consts) return -1; } } - if (mark_reachable(a)) { + if (mark_reachable(c, a)) { return -1; } /* Delete unreachable instructions */ @@ -9304,8 +9389,6 @@ optimize_cfg(struct compiler *c, struct assembler *a, PyObject *consts) for (basicblock *b = a->a_entry; b != NULL; b = b->b_next) { clean_basic_block(b); } - /* Delete jump instructions made redundant by previous step. */ - remove_redundant_jumps(a->a_entry); return 0; } From aabea441c85a981c6ccc21500e6c67bb4893df19 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Thu, 12 May 2022 23:18:35 +0100 Subject: [PATCH 07/26] abort if fallthrough from cold to warm block --- Lib/test/test_code.py | 8 ++++---- Python/compile.c | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_code.py b/Lib/test/test_code.py index d03457d16ad76f..f2f305b9fc388f 100644 --- a/Lib/test/test_code.py +++ b/Lib/test/test_code.py @@ -376,14 +376,14 @@ def test_co_positions_artificial_instructions(self): ], [ ('RESUME', 0), - ("COPY", 3), - ("POP_EXCEPT", None), - ("RERAISE", 1), ("PUSH_EXC_INFO", None), ("LOAD_CONST", None), # artificial 'None' ("STORE_NAME", "e"), # XX: we know the location for this ("DELETE_NAME", "e"), - ("RERAISE", 1) + ("RERAISE", 1), + ("COPY", 3), + ("POP_EXCEPT", None), + ("RERAISE", 1), ] ) diff --git a/Python/compile.c b/Python/compile.c index 2335416b2cae3e..7ac992347fea37 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -7437,6 +7437,22 @@ mark_cold(struct compiler *c, struct assembler *a) { } } PyObject_Free(stack); + + /* If we have a cold block with fallthrough to a warm block, abort */ + /* TODO: handle this better */ + int abort = 0; + for (basicblock *b = c->u->u_blocks; b != NULL; b = b->b_list) { + if (b->b_cold && !b->b_nofallthrough && b->b_next && b->b_next->b_warm) { + abort = 1; + break; + } + } + if (abort) { + for (basicblock *b = c->u->u_blocks; b != NULL; b = b->b_list) { + b->b_cold = 0; + } + } + return 0; } From 521ca2c3ce43b6a74e97d6383daefa382a4a79fe Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Fri, 13 May 2022 10:57:10 +0100 Subject: [PATCH 08/26] exclude generators and coroutines --- Python/compile.c | 40 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index 7ac992347fea37..50efcd1ecf62ea 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -191,9 +191,6 @@ is_jump(struct instr *i) is_bit_set_in_table(_PyOpcode_Jump, i->i_opcode); } -static void -dump_instr(struct instr *i); - static int instr_size(struct instr *instruction) { @@ -273,6 +270,10 @@ typedef struct basicblock_ { unsigned b_warm : 1; } basicblock; +#ifdef DEBUG_COLD_BLOCK_STUFF +static void dump_basicblock(const basicblock *b); +#endif + /* fblockinfo tracks the current frame block. A frame block is used to handle loops, try/except, and try/finally. @@ -7438,6 +7439,13 @@ mark_cold(struct compiler *c, struct assembler *a) { } PyObject_Free(stack); +#ifdef DEBUG_COLD_BLOCK_STUFF + for (basicblock *b = c->u->u_blocks; b != NULL; b = b->b_list) { + if (b->b_iused > 0 && !b->b_cold && !b->b_warm) { + dump_basicblock(b); + } + } +#endif /* If we have a cold block with fallthrough to a warm block, abort */ /* TODO: handle this better */ int abort = 0; @@ -7456,12 +7464,22 @@ mark_cold(struct compiler *c, struct assembler *a) { return 0; } +static int compute_code_flags(struct compiler *c); + static int push_cold_blocks_to_end(struct compiler *c, struct assembler *a, basicblock *entry) { if (entry->b_next == NULL) { /* single basicblock, no need to reorder */ return 0; } + int flags = compute_code_flags(c); + if (flags < 0) { + return -1; + } + if (flags & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR)) { + /* skip generators */ + return 0; + } if (mark_cold(c, a) < 0) { return -1; } @@ -7472,12 +7490,20 @@ push_cold_blocks_to_end(struct compiler *c, struct assembler *a, basicblock *ent } basicblock *origtail = tail; basicblock *b = entry; +#ifdef DEBUG_COLD_BLOCK_STUFF + fprintf(stderr, "<<<<<<<<<<<<<\n"); + dump_basicblock(b); +#endif while(b) { basicblock *next = b->b_next; if (next == NULL) { break; } if (next->b_cold) { +#ifdef DEBUG_COLD_BLOCK_STUFF + dump_basicblock(next); + fprintf(stderr, "*******************************************************************\n"); +#endif //assert(next->b_nofallthrough || (!next->b_next || next->b_next->b_cold)); b->b_next = next->b_next; next->b_next = NULL; @@ -7485,11 +7511,17 @@ push_cold_blocks_to_end(struct compiler *c, struct assembler *a, basicblock *ent tail = next; } else { b = next; +#ifdef DEBUG_COLD_BLOCK_STUFF + dump_basicblock(b); +#endif } if(next == origtail) { break; } } +#ifdef DEBUG_COLD_BLOCK_STUFF + fprintf(stderr, ">>>>>>>>>>>>>\n"); +#endif return 0; } @@ -8142,7 +8174,7 @@ makecode(struct compiler *c, struct assembler *a, PyObject *constslist, /* For debugging purposes only */ -#if 1 +#ifdef DEBUG_COLD_BLOCK_STUFF static void dump_instr(struct instr *i) { From 57a75764868d718b9f95e9eb1ac1c987cd889a99 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Fri, 13 May 2022 11:27:23 +0100 Subject: [PATCH 09/26] minor tidy up --- Python/compile.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index 50efcd1ecf62ea..2ca4f0f226bc04 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -7372,13 +7372,10 @@ label_exception_targets(basicblock *entry) { } static void -mark_warm(struct compiler *c, struct assembler *a, basicblock **stack) { +mark_warm(basicblock *entry, basicblock **stack) { basicblock **sp = stack; - for (basicblock *b = c->u->u_blocks; b != NULL; b = b->b_list) { - b->b_visited = 0; - } - *sp++ = a->a_entry; + *sp++ = entry; while (sp > stack) { basicblock *b = *(--sp); b->b_visited = 1; @@ -7399,12 +7396,19 @@ mark_warm(struct compiler *c, struct assembler *a, basicblock **stack) { static int mark_cold(struct compiler *c, struct assembler *a) { - basicblock **stack = (basicblock **)PyObject_Malloc(sizeof(basicblock *) * a->a_nblocks * 2 /* TODO: remove *2, count again? */); + int nblocks = 0; + for (basicblock *b = c->u->u_blocks; b != NULL; b = b->b_list) { + b->b_visited = 0; + assert(!b->b_cold && !b->b_warm); + nblocks++; + } + + basicblock **stack = (basicblock **)PyObject_Malloc(sizeof(basicblock *) * nblocks); basicblock **sp = stack; if (stack == NULL) { return -1; } - mark_warm(c, a, stack); + mark_warm(a->a_entry, stack); sp = stack; for (basicblock *b = c->u->u_blocks; b != NULL; b = b->b_list) { From fd94d0da0500bcb816c5601f16994839e9b4ca14 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Fri, 13 May 2022 14:41:02 +0100 Subject: [PATCH 10/26] mark cold/warm use block from assembler instead of compiler. code_flags calculated only once. don't pass compiler/assembler around as much --- Python/compile.c | 70 +++++++++++++++++++----------------------------- 1 file changed, 28 insertions(+), 42 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index 2ca4f0f226bc04..efd3cf87b2ceba 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -270,6 +270,9 @@ typedef struct basicblock_ { unsigned b_warm : 1; } basicblock; +#define DEBUG_COLD_BLOCK_STUFF +#undef DEBUG_COLD_BLOCK_STUFF + #ifdef DEBUG_COLD_BLOCK_STUFF static void dump_basicblock(const basicblock *b); #endif @@ -7395,9 +7398,9 @@ mark_warm(basicblock *entry, basicblock **stack) { } static int -mark_cold(struct compiler *c, struct assembler *a) { +mark_cold(basicblock *entry) { int nblocks = 0; - for (basicblock *b = c->u->u_blocks; b != NULL; b = b->b_list) { + for (basicblock *b = entry; b != NULL; b = b->b_next) { b->b_visited = 0; assert(!b->b_cold && !b->b_warm); nblocks++; @@ -7408,10 +7411,10 @@ mark_cold(struct compiler *c, struct assembler *a) { if (stack == NULL) { return -1; } - mark_warm(a->a_entry, stack); + mark_warm(entry, stack); sp = stack; - for (basicblock *b = c->u->u_blocks; b != NULL; b = b->b_list) { + for (basicblock *b = entry; b != NULL; b = b->b_next) { b->b_visited = 0; if (b->b_except_predecessors) { assert(b->b_except_predecessors == b->b_predecessors); @@ -7443,24 +7446,17 @@ mark_cold(struct compiler *c, struct assembler *a) { } PyObject_Free(stack); -#ifdef DEBUG_COLD_BLOCK_STUFF - for (basicblock *b = c->u->u_blocks; b != NULL; b = b->b_list) { - if (b->b_iused > 0 && !b->b_cold && !b->b_warm) { - dump_basicblock(b); - } - } -#endif /* If we have a cold block with fallthrough to a warm block, abort */ /* TODO: handle this better */ int abort = 0; - for (basicblock *b = c->u->u_blocks; b != NULL; b = b->b_list) { + for (basicblock *b = entry; b != NULL; b = b->b_next) { if (b->b_cold && !b->b_nofallthrough && b->b_next && b->b_next->b_warm) { abort = 1; break; } } if (abort) { - for (basicblock *b = c->u->u_blocks; b != NULL; b = b->b_list) { + for (basicblock *b = entry; b != NULL; b = b->b_next) { b->b_cold = 0; } } @@ -7468,23 +7464,17 @@ mark_cold(struct compiler *c, struct assembler *a) { return 0; } -static int compute_code_flags(struct compiler *c); - static int -push_cold_blocks_to_end(struct compiler *c, struct assembler *a, basicblock *entry) { +push_cold_blocks_to_end(basicblock *entry, int code_flags) { if (entry->b_next == NULL) { /* single basicblock, no need to reorder */ return 0; } - int flags = compute_code_flags(c); - if (flags < 0) { - return -1; - } - if (flags & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR)) { + if (code_flags & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR)) { /* skip generators */ return 0; } - if (mark_cold(c, a) < 0) { + if (mark_cold(entry) < 0) { return -1; } assert(!entry->b_cold); /* First block can't be cold */ @@ -8082,7 +8072,7 @@ compute_localsplus_info(struct compiler *c, int nlocalsplus, static PyCodeObject * makecode(struct compiler *c, struct assembler *a, PyObject *constslist, - int maxdepth, int nlocalsplus) + int maxdepth, int nlocalsplus, int code_flags) { PyCodeObject *co = NULL; PyObject *names = NULL; @@ -8098,11 +8088,6 @@ makecode(struct compiler *c, struct assembler *a, PyObject *constslist, goto error; } - int flags = compute_code_flags(c); - if (flags < 0) { - goto error; - } - consts = PyList_AsTuple(constslist); /* PyCode_New requires a tuple */ if (consts == NULL) { goto error; @@ -8133,7 +8118,7 @@ makecode(struct compiler *c, struct assembler *a, PyObject *constslist, .filename = c->c_filename, .name = c->u->u_name, .qualname = c->u->u_qualname ? c->u->u_qualname : c->u->u_name, - .flags = flags, + .flags = code_flags, .code = a->a_bytecode, .firstlineno = c->u->u_firstlineno, @@ -8281,17 +8266,13 @@ insert_instruction(basicblock *block, int pos, struct instr *instr) { static int insert_prefix_instructions(struct compiler *c, basicblock *entryblock, - int *fixed, int nfreevars) + int *fixed, int nfreevars, int code_flags) { - int flags = compute_code_flags(c); - if (flags < 0) { - return -1; - } assert(c->u->u_firstlineno > 0); /* Add the generator prefix instructions. */ - if (flags & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR)) { + if (code_flags & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR)) { struct instr make_gen = { .i_opcode = RETURN_GENERATOR, .i_oparg = 0, @@ -8493,6 +8474,11 @@ assemble(struct compiler *c, int addNone) PyCodeObject *co = NULL; PyObject *consts = NULL; + int code_flags = compute_code_flags(c); + if (code_flags < 0) { + return NULL; + } + /* Make sure every block that falls off the end returns None. */ if (!c->u->u_curblock->b_return) { UNSET_LOC(c); @@ -8547,7 +8533,7 @@ assemble(struct compiler *c, int addNone) } // This must be called before fix_cell_offsets(). - if (insert_prefix_instructions(c, entryblock, cellfixedoffsets, nfreevars)) { + if (insert_prefix_instructions(c, entryblock, cellfixedoffsets, nfreevars, code_flags)) { goto error; } @@ -8596,11 +8582,11 @@ assemble(struct compiler *c, int addNone) } convert_exception_handlers_to_nops(entryblock); - push_cold_blocks_to_end(c, &a, entryblock); + push_cold_blocks_to_end(entryblock, code_flags); remove_redundant_jumps(entryblock); - - for (basicblock *b = a.a_entry; b != NULL; b = b->b_next) { + assert(a.a_entry == entryblock); + for (basicblock *b = entryblock; b != NULL; b = b->b_next) { clean_basic_block(b); } @@ -8649,7 +8635,7 @@ assemble(struct compiler *c, int addNone) goto error; } - co = makecode(c, &a, consts, maxdepth, nlocalsplus); + co = makecode(c, &a, consts, maxdepth, nlocalsplus, code_flags); error: Py_XDECREF(consts); assemble_free(&a); @@ -9292,7 +9278,7 @@ normalize_basic_block(basicblock *bb) { } static int -mark_reachable(struct compiler *c, struct assembler *a) { +mark_reachable(struct assembler *a) { basicblock **stack, **sp; sp = stack = (basicblock **)PyObject_Malloc(sizeof(basicblock *) * a->a_nblocks); if (stack == NULL) { @@ -9427,7 +9413,7 @@ optimize_cfg(struct compiler *c, struct assembler *a, PyObject *consts) return -1; } } - if (mark_reachable(c, a)) { + if (mark_reachable(a)) { return -1; } /* Delete unreachable instructions */ From 4759a4525ffaaa32ee5085a83b875ec9b5d32c69 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Wed, 18 May 2022 19:19:53 +0100 Subject: [PATCH 11/26] move mark_cold/warm to the new traversal style --- Python/compile.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index c0210237b1d247..641e995a831f49 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -7377,8 +7377,12 @@ label_exception_targets(basicblock *entry) { return -1; } -static void -mark_warm(basicblock *entry, basicblock **stack) { +static int +mark_warm(basicblock *entry) { + basicblock **stack = make_cfg_traversal_stack(entry); + if (stack == NULL) { + return -1; + } basicblock **sp = stack; *sp++ = entry; @@ -7398,27 +7402,26 @@ mark_warm(basicblock *entry, basicblock **stack) { } } } + PyMem_Free(stack); + return 0; } static int mark_cold(basicblock *entry) { - int nblocks = 0; for (basicblock *b = entry; b != NULL; b = b->b_next) { - b->b_visited = 0; assert(!b->b_cold && !b->b_warm); - nblocks++; + } + if (mark_warm(entry) < 0) { + return -1; } - basicblock **stack = (basicblock **)PyObject_Malloc(sizeof(basicblock *) * nblocks); - basicblock **sp = stack; + basicblock **stack = make_cfg_traversal_stack(entry); if (stack == NULL) { return -1; } - mark_warm(entry, stack); - sp = stack; + basicblock **sp = stack; for (basicblock *b = entry; b != NULL; b = b->b_next) { - b->b_visited = 0; if (b->b_except_predecessors) { assert(b->b_except_predecessors == b->b_predecessors); assert(!b->b_warm); @@ -7447,7 +7450,7 @@ mark_cold(basicblock *entry) { } } } - PyObject_Free(stack); + PyMem_Free(stack); /* If we have a cold block with fallthrough to a warm block, abort */ /* TODO: handle this better */ From cd644f02cdf5bbe720082b6f14b850a98779c5c2 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Wed, 18 May 2022 21:25:52 +0100 Subject: [PATCH 12/26] fix a silly bug --- Python/compile.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index 641e995a831f49..3c0c2a51f9b85f 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -7476,10 +7476,6 @@ push_cold_blocks_to_end(basicblock *entry, int code_flags) { /* single basicblock, no need to reorder */ return 0; } - if (code_flags & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR)) { - /* skip generators */ - return 0; - } if (mark_cold(entry) < 0) { return -1; } @@ -7494,21 +7490,20 @@ push_cold_blocks_to_end(basicblock *entry, int code_flags) { fprintf(stderr, "<<<<<<<<<<<<<\n"); dump_basicblock(b); #endif - while(b) { + while(b && b->b_next) { basicblock *next = b->b_next; - if (next == NULL) { - break; - } if (next->b_cold) { #ifdef DEBUG_COLD_BLOCK_STUFF dump_basicblock(next); fprintf(stderr, "*******************************************************************\n"); #endif //assert(next->b_nofallthrough || (!next->b_next || next->b_next->b_cold)); - b->b_next = next->b_next; - next->b_next = NULL; - tail->b_next = next; - tail = next; + if (next->b_next) { + b->b_next = next->b_next; + next->b_next = NULL; + tail->b_next = next; + tail = next; + } } else { b = next; #ifdef DEBUG_COLD_BLOCK_STUFF From 3351114940d78391b5bbd8e09d8687dc8177b8c0 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Thu, 19 May 2022 15:32:04 +0100 Subject: [PATCH 13/26] replace cold->warm fallthrough by explicit jump --- Python/compile.c | 44 ++++++++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index 3c0c2a51f9b85f..4c0cf8d3af0e1d 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -7451,27 +7451,11 @@ mark_cold(basicblock *entry) { } } PyMem_Free(stack); - - /* If we have a cold block with fallthrough to a warm block, abort */ - /* TODO: handle this better */ - int abort = 0; - for (basicblock *b = entry; b != NULL; b = b->b_next) { - if (b->b_cold && !b->b_nofallthrough && b->b_next && b->b_next->b_warm) { - abort = 1; - break; - } - } - if (abort) { - for (basicblock *b = entry; b != NULL; b = b->b_next) { - b->b_cold = 0; - } - } - return 0; } static int -push_cold_blocks_to_end(basicblock *entry, int code_flags) { +push_cold_blocks_to_end(struct compiler *c, basicblock *entry, int code_flags) { if (entry->b_next == NULL) { /* single basicblock, no need to reorder */ return 0; @@ -7479,6 +7463,28 @@ push_cold_blocks_to_end(basicblock *entry, int code_flags) { if (mark_cold(entry) < 0) { return -1; } + + /* If we have a cold block with fallthrough to a warm block, add */ + /* and explicit jump instead of fallthrough */ + for (basicblock *b = entry; b != NULL; b = b->b_next) { + if (b->b_cold && !b->b_nofallthrough && b->b_next && b->b_next->b_warm) { + basicblock *explicit_jump = compiler_new_block(c); + int off = compiler_next_instr(explicit_jump); + struct instr *i = &explicit_jump->b_instr[off]; + i->i_opcode = JUMP; + i->i_target = b->b_next; + i->i_lineno = -1; + i->i_end_lineno = 0; + i->i_col_offset = 0; + i->i_end_col_offset = 0; + + explicit_jump->b_cold = 1; + explicit_jump->b_nofallthrough = 1; + explicit_jump->b_next = b->b_next; + b->b_next = explicit_jump; + } + } + assert(!entry->b_cold); /* First block can't be cold */ basicblock *tail = entry; while (tail->b_next) { @@ -8582,7 +8588,9 @@ assemble(struct compiler *c, int addNone) } convert_exception_handlers_to_nops(entryblock); - push_cold_blocks_to_end(entryblock, code_flags); + if (push_cold_blocks_to_end(c, entryblock, code_flags) < 0) { + goto error; + } remove_redundant_jumps(entryblock); assert(a.a_entry == entryblock); From 51f28c6f2f4fc599a5128ecad9dd801bd702b0ed Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Thu, 19 May 2022 18:15:04 +0100 Subject: [PATCH 14/26] remove debug code --- Python/compile.c | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index 4c0cf8d3af0e1d..4a0aeb0a5861e1 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -270,12 +270,6 @@ typedef struct basicblock_ { unsigned b_warm : 1; } basicblock; -#define DEBUG_COLD_BLOCK_STUFF -#undef DEBUG_COLD_BLOCK_STUFF - -#ifdef DEBUG_COLD_BLOCK_STUFF -static void dump_basicblock(const basicblock *b); -#endif /* fblockinfo tracks the current frame block. @@ -7492,18 +7486,9 @@ push_cold_blocks_to_end(struct compiler *c, basicblock *entry, int code_flags) { } basicblock *origtail = tail; basicblock *b = entry; -#ifdef DEBUG_COLD_BLOCK_STUFF - fprintf(stderr, "<<<<<<<<<<<<<\n"); - dump_basicblock(b); -#endif while(b && b->b_next) { basicblock *next = b->b_next; if (next->b_cold) { -#ifdef DEBUG_COLD_BLOCK_STUFF - dump_basicblock(next); - fprintf(stderr, "*******************************************************************\n"); -#endif - //assert(next->b_nofallthrough || (!next->b_next || next->b_next->b_cold)); if (next->b_next) { b->b_next = next->b_next; next->b_next = NULL; @@ -7512,17 +7497,11 @@ push_cold_blocks_to_end(struct compiler *c, basicblock *entry, int code_flags) { } } else { b = next; -#ifdef DEBUG_COLD_BLOCK_STUFF - dump_basicblock(b); -#endif } if(next == origtail) { break; } } -#ifdef DEBUG_COLD_BLOCK_STUFF - fprintf(stderr, ">>>>>>>>>>>>>\n"); -#endif return 0; } @@ -8170,7 +8149,7 @@ makecode(struct compiler *c, struct assembler *a, PyObject *constslist, /* For debugging purposes only */ -#ifdef DEBUG_COLD_BLOCK_STUFF +#if 0 static void dump_instr(struct instr *i) { From 752e9a79cbbdc397967ac53bd8529fc6853d664d Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Sun, 29 May 2022 17:16:57 +0100 Subject: [PATCH 15/26] reverse unnecessary changes --- Lib/test/test_code.py | 2 +- Python/compile.c | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Lib/test/test_code.py b/Lib/test/test_code.py index f2f305b9fc388f..1bb138e7f3243b 100644 --- a/Lib/test/test_code.py +++ b/Lib/test/test_code.py @@ -383,7 +383,7 @@ def test_co_positions_artificial_instructions(self): ("RERAISE", 1), ("COPY", 3), ("POP_EXCEPT", None), - ("RERAISE", 1), + ("RERAISE", 1) ] ) diff --git a/Python/compile.c b/Python/compile.c index 4a0aeb0a5861e1..f9b6e678bfcbdd 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -5660,7 +5660,6 @@ compiler_async_with(struct compiler *c, stmt_ty s, int pos) ADDOP_LOAD_CONST(c, Py_None); ADD_YIELD_FROM(c, 1); compiler_with_except_finish(c, cleanup); - ADDOP_JUMP(c, JUMP, exit); compiler_use_next_block(c, exit); return 1; @@ -5754,7 +5753,6 @@ compiler_with(struct compiler *c, stmt_ty s, int pos) ADDOP(c, PUSH_EXC_INFO); ADDOP(c, WITH_EXCEPT_START); compiler_with_except_finish(c, cleanup); - ADDOP_JUMP(c, JUMP, exit); compiler_use_next_block(c, exit); return 1; From e719b0f2cc4a2ef39f498eb8c0e540a044badf97 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Mon, 30 May 2022 10:23:02 +0100 Subject: [PATCH 16/26] fix merge error --- Python/compile.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/compile.c b/Python/compile.c index 0d550fc66d4d1f..b9751fb87d9915 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -7449,7 +7449,7 @@ push_cold_blocks_to_end(struct compiler *c, basicblock *entry, int code_flags) { for (basicblock *b = entry; b != NULL; b = b->b_next) { if (b->b_cold && !b->b_nofallthrough && b->b_next && b->b_next->b_warm) { basicblock *explicit_jump = compiler_new_block(c); - int off = compiler_next_instr(explicit_jump); + int off = basicblock_next_instr(explicit_jump); struct instr *i = &explicit_jump->b_instr[off]; i->i_opcode = JUMP; i->i_target = b->b_next; From 60b433f68242997f8ef3aee8bcff4adedcda2c53 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Mon, 30 May 2022 10:27:36 +0100 Subject: [PATCH 17/26] use the new basicblock_add_jump --- Python/compile.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index b9751fb87d9915..221ac485a3be41 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -7449,14 +7449,7 @@ push_cold_blocks_to_end(struct compiler *c, basicblock *entry, int code_flags) { for (basicblock *b = entry; b != NULL; b = b->b_next) { if (b->b_cold && !b->b_nofallthrough && b->b_next && b->b_next->b_warm) { basicblock *explicit_jump = compiler_new_block(c); - int off = basicblock_next_instr(explicit_jump); - struct instr *i = &explicit_jump->b_instr[off]; - i->i_opcode = JUMP; - i->i_target = b->b_next; - i->i_lineno = -1; - i->i_end_lineno = 0; - i->i_col_offset = 0; - i->i_end_col_offset = 0; + basicblock_add_jump(explicit_jump, JUMP, -1, 0, 0, 0, b->b_next); explicit_jump->b_cold = 1; explicit_jump->b_nofallthrough = 1; From dc8949aa7add9003cdc2d50aae4e0205548f135c Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Mon, 30 May 2022 10:50:45 +0100 Subject: [PATCH 18/26] fix test_dis again --- Lib/test/test_dis.py | 85 ++++++++++++++++++++++---------------------- 1 file changed, 42 insertions(+), 43 deletions(-) diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index c5b80b72f8395b..1e88ca822fdabe 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -1442,49 +1442,48 @@ def _prepare_test_cases(): Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=260, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL', opcode=171, arg=2, argval=2, argrepr='', offset=262, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=272, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='JUMP_FORWARD', opcode=110, arg=41, argval=358, argrepr='to 358', offset=274, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=276, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='WITH_EXCEPT_START', opcode=49, arg=None, argval=None, argrepr='', offset=278, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_JUMP_FORWARD_IF_TRUE', opcode=115, arg=4, argval=290, argrepr='to 290', offset=280, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=2, argval=2, argrepr='', offset=282, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=284, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=286, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=288, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=290, starts_line=None, is_jump_target=True, positions=None), - Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=292, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=294, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=296, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='JUMP_FORWARD', opcode=110, arg=29, argval=358, argrepr='to 358', offset=298, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=300, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=4, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=302, starts_line=22, is_jump_target=False, positions=None), - Instruction(opname='CHECK_EXC_MATCH', opcode=36, arg=None, argval=None, argrepr='', offset=314, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_JUMP_FORWARD_IF_FALSE', opcode=114, arg=16, argval=350, argrepr='to 350', 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='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=320, starts_line=23, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=9, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=332, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=334, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=344, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=346, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='JUMP_FORWARD', opcode=110, arg=4, argval=358, argrepr='to 358', offset=348, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=350, starts_line=22, is_jump_target=True, positions=None), - Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=352, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=354, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=356, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=358, starts_line=28, is_jump_target=True, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=370, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=372, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=382, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=384, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=386, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=388, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=390, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=402, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=404, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=414, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=416, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=418, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=420, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=422, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=274, starts_line=28, is_jump_target=True, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=286, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=288, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=298, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=300, 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='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='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_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='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), + Instruction(opname='POP_JUMP_FORWARD_IF_FALSE', opcode=114, arg=16, argval=378, argrepr='to 378', offset=344, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=346, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=348, starts_line=23, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=9, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=360, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=362, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=372, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=374, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='JUMP_BACKWARD', opcode=140, arg=52, argval=274, argrepr='to 274', offset=376, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=378, starts_line=22, is_jump_target=True, positions=None), + Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=380, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=382, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=384, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=386, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=388, starts_line=28, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=400, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=402, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=412, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=414, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=416, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=418, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=420, starts_line=None, is_jump_target=False, positions=None), ] # One last piece of inspect fodder to check the default line number handling From 7e5d1fbbd54775cc162b6713315eb7d0a1475422 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Mon, 30 May 2022 15:55:05 +0100 Subject: [PATCH 19/26] revert changes to Lib/importlib/_bootstrap_external.py --- Lib/importlib/_bootstrap_external.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 7939c3fbfe2fda..eac371fdefc782 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -419,8 +419,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 = (4111).to_bytes(2, 'little') + b'\r\n' ->>>>>>> upstream/main +MAGIC_NUMBER = (3501).to_bytes(2, 'little') + b'\r\n' _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c From dcfb8a76a501a7633e92e6ebf69dddebff996cbb Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Mon, 30 May 2022 16:32:43 +0100 Subject: [PATCH 20/26] typo in comment --- Python/compile.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/compile.c b/Python/compile.c index 221ac485a3be41..ef0359134833f0 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -7445,7 +7445,7 @@ push_cold_blocks_to_end(struct compiler *c, basicblock *entry, int code_flags) { } /* If we have a cold block with fallthrough to a warm block, add */ - /* and explicit jump instead of fallthrough */ + /* an explicit jump instead of fallthrough */ for (basicblock *b = entry; b != NULL; b = b->b_next) { if (b->b_cold && !b->b_nofallthrough && b->b_next && b->b_next->b_warm) { basicblock *explicit_jump = compiler_new_block(c); From 0f0f08562ecdd98179a4a4e1fb8b98acad302e4d Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Mon, 30 May 2022 15:51:12 +0000 Subject: [PATCH 21/26] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20b?= =?UTF-8?q?lurb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../2022-05-30-15-51-11.gh-issue-93356.l5wnzW.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-05-30-15-51-11.gh-issue-93356.l5wnzW.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-05-30-15-51-11.gh-issue-93356.l5wnzW.rst b/Misc/NEWS.d/next/Core and Builtins/2022-05-30-15-51-11.gh-issue-93356.l5wnzW.rst new file mode 100644 index 00000000000000..9bb58468197e2d --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-05-30-15-51-11.gh-issue-93356.l5wnzW.rst @@ -0,0 +1 @@ +Code for exception handlers is emitted at the end of the code unit's bytecode. This avoids one jump when no exception is raised. From d1baf48266d62270552231d38f4ef3903dc27c81 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Mon, 30 May 2022 19:51:41 +0100 Subject: [PATCH 22/26] use b_visited for 'pushed to sp' rather than for 'popped from sp' --- Python/compile.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index ef0359134833f0..8d29098ef05242 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -7366,19 +7366,21 @@ mark_warm(basicblock *entry) { basicblock **sp = stack; *sp++ = entry; + entry->b_visited = 1; while (sp > stack) { basicblock *b = *(--sp); - b->b_visited = 1; assert(!b->b_except_predecessors); b->b_warm = 1; basicblock *next = b->b_next; if (next && !b->b_nofallthrough && !next->b_visited) { *sp++ = next; + next->b_visited = 1; } for (int i=0; i < b->b_iused; i++) { struct instr *instr = &b->b_instr[i]; if (is_jump(instr) && !instr->i_target->b_visited) { *sp++ = instr->i_target; + instr->i_target->b_visited = 1; } } } @@ -7406,17 +7408,18 @@ mark_cold(basicblock *entry) { assert(b->b_except_predecessors == b->b_predecessors); assert(!b->b_warm); *sp++ = b; + b->b_visited = 1; } } while (sp > stack) { basicblock *b = *(--sp); b->b_cold = 1; - b->b_visited = 1; basicblock *next = b->b_next; if (next && !b->b_nofallthrough) { if (!next->b_warm && !next->b_visited) { *sp++ = next; + next->b_visited = 1; } } for (int i = 0; i < b->b_iused; i++) { @@ -7426,6 +7429,7 @@ mark_cold(basicblock *entry) { basicblock *target = b->b_instr[i].i_target; if (!target->b_warm && !target->b_visited) { *sp++ = target; + target->b_visited = 1; } } } From aa52363b468b1d03fe4d19678e579efb732de2c2 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Wed, 1 Jun 2022 11:00:25 +0100 Subject: [PATCH 23/26] add missing null check --- Python/compile.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Python/compile.c b/Python/compile.c index 8d29098ef05242..c318edd16e3e2e 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -7453,6 +7453,9 @@ push_cold_blocks_to_end(struct compiler *c, basicblock *entry, int code_flags) { for (basicblock *b = entry; b != NULL; b = b->b_next) { if (b->b_cold && !b->b_nofallthrough && b->b_next && b->b_next->b_warm) { basicblock *explicit_jump = compiler_new_block(c); + if (explicit_jump == NULL) { + return -1; + } basicblock_add_jump(explicit_jump, JUMP, -1, 0, 0, 0, b->b_next); explicit_jump->b_cold = 1; From 848c8b1660121a151670f8758b6fe15d87f7227a Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Wed, 1 Jun 2022 12:42:31 +0100 Subject: [PATCH 24/26] rewrite cold-block-reordering logic (hopefully easier to follow now) --- Python/compile.c | 50 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index c318edd16e3e2e..90ba95dcefcec6 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -7466,28 +7466,44 @@ push_cold_blocks_to_end(struct compiler *c, basicblock *entry, int code_flags) { } assert(!entry->b_cold); /* First block can't be cold */ - basicblock *tail = entry; - while (tail->b_next) { - tail = tail->b_next; - } - basicblock *origtail = tail; + basicblock *cold_blocks = NULL; + basicblock *cold_blocks_tail = NULL; + basicblock *b = entry; - while(b && b->b_next) { - basicblock *next = b->b_next; - if (next->b_cold) { - if (next->b_next) { - b->b_next = next->b_next; - next->b_next = NULL; - tail->b_next = next; - tail = next; - } - } else { - b = next; + while(b->b_next) { + assert(!b->b_cold); + while (b->b_next && !b->b_next->b_cold) { + b = b->b_next; } - if(next == origtail) { + if (b->b_next == NULL) { + /* no more cold blocks */ break; } + + /* b->b_next is the beginning of a cold streak */ + assert(!b->b_cold && b->b_next->b_cold); + + basicblock *b_end = b->b_next; + while (b_end->b_next && b_end->b_next->b_cold) { + b_end = b_end->b_next; + } + + /* b_end is the end of the cold streak */ + assert(b_end && b_end->b_cold); + assert(b_end->b_next == NULL || !b_end->b_next->b_cold); + + if (cold_blocks == NULL) { + cold_blocks = b->b_next; + } + else { + cold_blocks_tail->b_next = b->b_next; + } + cold_blocks_tail = b_end; + b->b_next = b_end->b_next; + b_end->b_next = NULL; } + assert(b != NULL && b->b_next == NULL); + b->b_next = cold_blocks; return 0; } From 44d4093523d4952753f6c5c9a406970fe3ab87e1 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Wed, 1 Jun 2022 15:29:58 +0100 Subject: [PATCH 25/26] make regen --- Python/stdlib_module_names.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/Python/stdlib_module_names.h b/Python/stdlib_module_names.h index 553585a76a394a..0b5554ddf3c3a7 100644 --- a/Python/stdlib_module_names.h +++ b/Python/stdlib_module_names.h @@ -202,7 +202,6 @@ static const char* _Py_stdlib_module_names[] = { "operator", "optparse", "os", -"ossaudiodev", "pathlib", "pdb", "pickle", @@ -247,7 +246,6 @@ static const char* _Py_stdlib_module_names[] = { "sndhdr", "socket", "socketserver", -"spwd", "sqlite3", "sre_compile", "sre_constants", From 6a12c786c748e5dfff90d8e5a33d1fa9826a5183 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Wed, 1 Jun 2022 16:03:20 +0100 Subject: [PATCH 26/26] Revert "make regen" This reverts commit 44d4093523d4952753f6c5c9a406970fe3ab87e1. --- Python/stdlib_module_names.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Python/stdlib_module_names.h b/Python/stdlib_module_names.h index 0b5554ddf3c3a7..553585a76a394a 100644 --- a/Python/stdlib_module_names.h +++ b/Python/stdlib_module_names.h @@ -202,6 +202,7 @@ static const char* _Py_stdlib_module_names[] = { "operator", "optparse", "os", +"ossaudiodev", "pathlib", "pdb", "pickle", @@ -246,6 +247,7 @@ static const char* _Py_stdlib_module_names[] = { "sndhdr", "socket", "socketserver", +"spwd", "sqlite3", "sre_compile", "sre_constants",