mirror of https://github.com/python/cpython
gh-93356: Lay out exception handling code at end of code unit (GH-92769)
This commit is contained in:
parent
af5bb1fba4
commit
94b1586ca5
|
@ -1442,49 +1442,48 @@ expected_opinfo_jumpy = [
|
|||
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
|
||||
|
|
|
@ -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.
|
262
Python/compile.c
262
Python/compile.c
|
@ -248,6 +248,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() */
|
||||
|
@ -262,6 +264,10 @@ 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;
|
||||
/* b_warm is used by the cold-detection algorithm to mark blocks which are definitely not cold */
|
||||
unsigned b_warm : 1;
|
||||
} basicblock;
|
||||
|
||||
|
||||
|
@ -7352,6 +7358,155 @@ error:
|
|||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
mark_warm(basicblock *entry) {
|
||||
basicblock **stack = make_cfg_traversal_stack(entry);
|
||||
if (stack == NULL) {
|
||||
return -1;
|
||||
}
|
||||
basicblock **sp = stack;
|
||||
|
||||
*sp++ = entry;
|
||||
entry->b_visited = 1;
|
||||
while (sp > stack) {
|
||||
basicblock *b = *(--sp);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
PyMem_Free(stack);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mark_cold(basicblock *entry) {
|
||||
for (basicblock *b = entry; b != NULL; b = b->b_next) {
|
||||
assert(!b->b_cold && !b->b_warm);
|
||||
}
|
||||
if (mark_warm(entry) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
basicblock **stack = make_cfg_traversal_stack(entry);
|
||||
if (stack == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
basicblock **sp = stack;
|
||||
for (basicblock *b = entry; b != NULL; b = b->b_next) {
|
||||
if (b->b_except_predecessors) {
|
||||
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;
|
||||
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++) {
|
||||
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;
|
||||
target->b_visited = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
PyMem_Free(stack);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
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;
|
||||
}
|
||||
if (mark_cold(entry) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* If we have a cold block with fallthrough to a warm block, add */
|
||||
/* 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);
|
||||
if (explicit_jump == NULL) {
|
||||
return -1;
|
||||
}
|
||||
basicblock_add_jump(explicit_jump, JUMP, -1, 0, 0, 0, b->b_next);
|
||||
|
||||
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 *cold_blocks = NULL;
|
||||
basicblock *cold_blocks_tail = NULL;
|
||||
|
||||
basicblock *b = entry;
|
||||
while(b->b_next) {
|
||||
assert(!b->b_cold);
|
||||
while (b->b_next && !b->b_next->b_cold) {
|
||||
b = b->b_next;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
static void
|
||||
convert_exception_handlers_to_nops(basicblock *entry) {
|
||||
|
@ -8009,7 +8164,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;
|
||||
|
@ -8025,11 +8180,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;
|
||||
|
@ -8060,7 +8210,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,
|
||||
|
@ -8118,6 +8268,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);
|
||||
}
|
||||
|
@ -8126,8 +8282,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 %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++) {
|
||||
|
@ -8202,17 +8358,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,
|
||||
|
@ -8373,6 +8525,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)
|
||||
{
|
||||
|
@ -8382,6 +8566,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);
|
||||
|
@ -8407,6 +8596,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);
|
||||
|
||||
|
@ -8435,7 +8625,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;
|
||||
}
|
||||
|
||||
|
@ -8482,7 +8672,14 @@ assemble(struct compiler *c, int addNone)
|
|||
goto error;
|
||||
}
|
||||
convert_exception_handlers_to_nops(entryblock);
|
||||
for (basicblock *b = a.a_entry; b != NULL; b = b->b_next) {
|
||||
|
||||
if (push_cold_blocks_to_end(c, entryblock, code_flags) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
remove_redundant_jumps(entryblock);
|
||||
assert(a.a_entry == entryblock);
|
||||
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
|
||||
clean_basic_block(b);
|
||||
}
|
||||
|
||||
|
@ -8535,7 +8732,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);
|
||||
|
@ -9206,6 +9403,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9328,30 +9530,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. 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);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue