diff options
author | Irit Katriel <1055913+iritkatriel@users.noreply.github.com> | 2022-08-04 13:59:32 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-08-04 13:59:32 (GMT) |
commit | 000c3874bfa63507293c22249881f6cfc61af311 (patch) | |
tree | bc6746e73891ec181462204bf44f1ceeec19a9e8 /Python/compile.c | |
parent | 2fef27589e44c91042c2598b5cad6c6ad0516d93 (diff) | |
download | cpython-000c3874bfa63507293c22249881f6cfc61af311.zip cpython-000c3874bfa63507293c22249881f6cfc61af311.tar.gz cpython-000c3874bfa63507293c22249881f6cfc61af311.tar.bz2 |
gh-87092: create a 'jump target label' abstraction so that the compiler's codegen stage does not work directly with basic blocks (GH-95398)
Diffstat (limited to 'Python/compile.c')
-rw-r--r-- | Python/compile.c | 739 |
1 files changed, 385 insertions, 354 deletions
diff --git a/Python/compile.c b/Python/compile.c index 975efa7..3c4dd56 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -139,10 +139,31 @@ struct location { static struct location NO_LOCATION = {-1, -1, -1, -1}; +typedef struct jump_target_label_ { + int id; + struct basicblock_ *block; +} jump_target_label; + +static struct jump_target_label_ NO_LABEL = {-1, NULL}; + +#define SAME_LABEL(L1, L2) ((L1).id == (L2).id) +#define IS_LABEL(L) (!SAME_LABEL((L), (NO_LABEL))) + +#define NEW_JUMP_TARGET_LABEL(C, NAME) \ + jump_target_label NAME = {cfg_new_label_id(CFG_BUILDER(C)), cfg_builder_new_block(CFG_BUILDER(C))}; \ + if (!IS_LABEL(NAME)) { \ + return 0; \ + } + +#define USE_LABEL(C, LBL) cfg_builder_use_label(CFG_BUILDER(C), LBL) + struct instr { int i_opcode; int i_oparg; - /* target block (if jump instruction) */ + /* target block (if jump instruction) -- we temporarily have both the label + and the block in the instr. The label is set by front end, and the block + is calculated by backend. */ + jump_target_label i_target_label; struct basicblock_ *i_target; /* target block when exception is raised, should not be set by front-end. */ struct basicblock_ *i_except; @@ -235,6 +256,8 @@ typedef struct basicblock_ { reverse order that the block are allocated. b_list points to the next block, not to be confused with b_next, which is next by control flow. */ struct basicblock_ *b_list; + /* The label of this block if it is a jump target, -1 otherwise */ + int b_label; /* Exception stack at start of block, used by assembler to create the exception handling table */ ExceptStack *b_exceptstack; /* pointer to an array of instructions, initially NULL */ @@ -309,9 +332,9 @@ enum fblocktype { WHILE_LOOP, FOR_LOOP, TRY_EXCEPT, FINALLY_TRY, FINALLY_END, struct fblockinfo { enum fblocktype fb_type; - basicblock *fb_block; + jump_target_label fb_block; /* (optional) type-specific exit or cleanup block */ - basicblock *fb_exit; + jump_target_label fb_exit; /* (optional) additional information required for unwinding */ void *fb_datum; }; @@ -334,6 +357,10 @@ typedef struct cfg_builder_ { basicblock *block_list; /* pointer to the block currently being constructed */ basicblock *curblock; + /* label for the next instruction to be placed */ + jump_target_label g_current_label; + /* next free label id */ + int g_next_free_label; } cfg_builder; /* The following items change on entry and exit of code blocks. @@ -418,7 +445,7 @@ typedef struct { // fail_pop[2]: POP_TOP // fail_pop[1]: POP_TOP // fail_pop[0]: NOP - basicblock **fail_pop; + jump_target_label *fail_pop; // The current length of fail_pop. Py_ssize_t fail_pop_size; // The number of items on top of the stack that need to *stay* on top of the @@ -429,6 +456,7 @@ typedef struct { static int basicblock_next_instr(basicblock *); +static int cfg_builder_maybe_start_new_block(cfg_builder *g); static int cfg_builder_addop_i(cfg_builder *g, int opcode, Py_ssize_t oparg, struct location loc); static void compiler_free(struct compiler *); @@ -839,6 +867,11 @@ compiler_set_qualname(struct compiler *c) return 1; } +static int +cfg_new_label_id(cfg_builder *g) +{ + return g->g_next_free_label++; +} /* Allocate a new block and return a pointer to it. Returns NULL on error. @@ -854,6 +887,7 @@ cfg_builder_new_block(cfg_builder *g) /* Extend the singly linked list of blocks with new block. */ b->b_list = g->block_list; g->block_list = b; + b->b_label = -1; return b; } @@ -866,16 +900,11 @@ cfg_builder_use_next_block(cfg_builder *g, basicblock *block) return block; } -static basicblock * -compiler_new_block(struct compiler *c) -{ - return cfg_builder_new_block(CFG_BUILDER(c)); -} - -static basicblock * -compiler_use_next_block(struct compiler *c, basicblock *block) +static int +cfg_builder_use_label(cfg_builder *g, jump_target_label lbl) { - return cfg_builder_use_next_block(CFG_BUILDER(c), block); + g->g_current_label = lbl; + return cfg_builder_maybe_start_new_block(g); } static basicblock * @@ -1254,16 +1283,16 @@ PyCompile_OpcodeStackEffect(int opcode, int oparg) static int basicblock_addop(basicblock *b, int opcode, int oparg, - basicblock *target, struct location loc) + jump_target_label target, struct location loc) { assert(IS_WITHIN_OPCODE_RANGE(opcode)); assert(!IS_ASSEMBLER_OPCODE(opcode)); assert(HAS_ARG(opcode) || oparg == 0); assert(0 <= oparg && oparg < (1 << 30)); - assert((target == NULL) || + assert(!IS_LABEL(target) || IS_JUMP_OPCODE(opcode) || IS_BLOCK_PUSH_OPCODE(opcode)); - assert(oparg == 0 || target == NULL); + assert(oparg == 0 || !IS_LABEL(target)); int off = basicblock_next_instr(b); if (off < 0) { @@ -1272,24 +1301,51 @@ basicblock_addop(basicblock *b, int opcode, int oparg, struct instr *i = &b->b_instr[off]; i->i_opcode = opcode; i->i_oparg = oparg; - i->i_target = target; + i->i_target_label = target; + i->i_target = NULL; i->i_loc = loc; return 1; } -static int -cfg_builder_addop(cfg_builder *g, int opcode, int oparg, basicblock *target, - struct location loc) +static bool +cfg_builder_current_block_is_terminated(cfg_builder *g) { + if (IS_LABEL(g->g_current_label)) { + return true; + } struct instr *last = basicblock_last_instr(g->curblock); - if (last && IS_TERMINATOR_OPCODE(last->i_opcode)) { - basicblock *b = cfg_builder_new_block(g); + return last && IS_TERMINATOR_OPCODE(last->i_opcode); +} + +static int +cfg_builder_maybe_start_new_block(cfg_builder *g) +{ + if (cfg_builder_current_block_is_terminated(g)) { + basicblock *b; + if (IS_LABEL(g->g_current_label)) { + b = g->g_current_label.block; + b->b_label = g->g_current_label.id; + g->g_current_label = NO_LABEL; + } + else { + b = cfg_builder_new_block(g); + } if (b == NULL) { return -1; } cfg_builder_use_next_block(g, b); } + return 0; +} + +static int +cfg_builder_addop(cfg_builder *g, int opcode, int oparg, jump_target_label target, + struct location loc) +{ + if (cfg_builder_maybe_start_new_block(g) != 0) { + return -1; + } return basicblock_addop(g->curblock, opcode, oparg, target, loc); } @@ -1297,7 +1353,7 @@ static int cfg_builder_addop_noarg(cfg_builder *g, int opcode, struct location loc) { assert(!HAS_ARG(opcode)); - return cfg_builder_addop(g, opcode, 0, NULL, loc); + return cfg_builder_addop(g, opcode, 0, NO_LABEL, loc); } static Py_ssize_t @@ -1509,13 +1565,13 @@ cfg_builder_addop_i(cfg_builder *g, int opcode, Py_ssize_t oparg, struct locatio EXTENDED_ARG is used for 16, 24, and 32-bit arguments. */ int oparg_ = Py_SAFE_DOWNCAST(oparg, Py_ssize_t, int); - return cfg_builder_addop(g, opcode, oparg_, NULL, loc); + return cfg_builder_addop(g, opcode, oparg_, NO_LABEL, loc); } static int -cfg_builder_addop_j(cfg_builder *g, int opcode, basicblock *target, struct location loc) +cfg_builder_addop_j(cfg_builder *g, int opcode, jump_target_label target, struct location loc) { - assert(target != NULL); + assert(IS_LABEL(target)); assert(IS_JUMP_OPCODE(opcode) || IS_BLOCK_PUSH_OPCODE(opcode)); return cfg_builder_addop(g, opcode, 0, target, loc); } @@ -1744,6 +1800,7 @@ compiler_enter_scope(struct compiler *c, identifier name, if (block == NULL) return 0; g->curblock = g->cfg_entryblock = block; + g->g_current_label = NO_LABEL; if (u->u_scope_type == COMPILER_SCOPE_MODULE) { c->u->u_loc.lineno = 0; @@ -1863,8 +1920,8 @@ find_ann(asdl_stmt_seq *stmts) */ static int -compiler_push_fblock(struct compiler *c, enum fblocktype t, basicblock *b, - basicblock *exit, void *datum) +compiler_push_fblock(struct compiler *c, enum fblocktype t, jump_target_label block_label, + jump_target_label exit, void *datum) { struct fblockinfo *f; if (c->u->u_nfblocks >= CO_MAXBLOCKS) { @@ -1872,20 +1929,20 @@ compiler_push_fblock(struct compiler *c, enum fblocktype t, basicblock *b, } f = &c->u->u_fblock[c->u->u_nfblocks++]; f->fb_type = t; - f->fb_block = b; + f->fb_block = block_label; f->fb_exit = exit; f->fb_datum = datum; return 1; } static void -compiler_pop_fblock(struct compiler *c, enum fblocktype t, basicblock *b) +compiler_pop_fblock(struct compiler *c, enum fblocktype t, jump_target_label block_label) { struct compiler_unit *u = c->u; assert(u->u_nfblocks > 0); u->u_nfblocks--; assert(u->u_fblock[u->u_nfblocks].fb_type == t); - assert(u->u_fblock[u->u_nfblocks].fb_block == b); + assert(SAME_LABEL(u->u_fblock[u->u_nfblocks].fb_block, block_label)); } static int @@ -1900,20 +1957,19 @@ compiler_call_exit_with_nones(struct compiler *c) { static int compiler_add_yield_from(struct compiler *c, int await) { - basicblock *start, *resume, *exit; - start = compiler_new_block(c); - resume = compiler_new_block(c); - exit = compiler_new_block(c); - if (start == NULL || resume == NULL || exit == NULL) { - return 0; - } - compiler_use_next_block(c, start); + NEW_JUMP_TARGET_LABEL(c, start); + NEW_JUMP_TARGET_LABEL(c, resume); + NEW_JUMP_TARGET_LABEL(c, exit); + + USE_LABEL(c, start); ADDOP_JUMP(c, SEND, exit); - compiler_use_next_block(c, resume); + + USE_LABEL(c, resume); ADDOP_I(c, YIELD_VALUE, 0); ADDOP_I(c, RESUME, await ? 3 : 2); ADDOP_JUMP(c, JUMP_NO_INTERRUPT, start); - compiler_use_next_block(c, exit); + + USE_LABEL(c, exit); return 1; } @@ -1965,14 +2021,14 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info, /* This POP_BLOCK gets the line number of the unwinding statement */ ADDOP(c, POP_BLOCK); if (preserve_tos) { - if (!compiler_push_fblock(c, POP_VALUE, NULL, NULL, NULL)) { + if (!compiler_push_fblock(c, POP_VALUE, NO_LABEL, NO_LABEL, NULL)) { return 0; } } /* Emit the finally block */ VISIT_SEQ(c, stmt, info->fb_datum); if (preserve_tos) { - compiler_pop_fblock(c, POP_VALUE, NULL); + compiler_pop_fblock(c, POP_VALUE, NO_LABEL); } /* The finally block should appear to execute after the * statement causing the unwinding, so make the unwinding @@ -2816,7 +2872,7 @@ static int compiler_addcompare(struct compiler *c, cmpop_ty op) static int -compiler_jump_if(struct compiler *c, expr_ty e, basicblock *next, int cond) +compiler_jump_if(struct compiler *c, expr_ty e, jump_target_label next, int cond) { switch (e->kind) { case UnaryOp_kind: @@ -2829,11 +2885,10 @@ compiler_jump_if(struct compiler *c, expr_ty e, basicblock *next, int cond) Py_ssize_t i, n = asdl_seq_LEN(s) - 1; assert(n >= 0); int cond2 = e->v.BoolOp.op == Or; - basicblock *next2 = next; + jump_target_label next2 = next; if (!cond2 != !cond) { - next2 = compiler_new_block(c); - if (next2 == NULL) - return 0; + NEW_JUMP_TARGET_LABEL(c, new_next2); + next2 = new_next2; } for (i = 0; i < n; ++i) { if (!compiler_jump_if(c, (expr_ty)asdl_seq_GET(s, i), next2, cond2)) @@ -2841,27 +2896,25 @@ compiler_jump_if(struct compiler *c, expr_ty e, basicblock *next, int cond) } if (!compiler_jump_if(c, (expr_ty)asdl_seq_GET(s, n), next, cond)) return 0; - if (next2 != next) - compiler_use_next_block(c, next2); + if (!SAME_LABEL(next2, next)) { + USE_LABEL(c, next2); + } return 1; } case IfExp_kind: { - basicblock *end, *next2; - end = compiler_new_block(c); - if (end == NULL) - return 0; - next2 = compiler_new_block(c); - if (next2 == NULL) - return 0; + NEW_JUMP_TARGET_LABEL(c, end); + NEW_JUMP_TARGET_LABEL(c, next2); if (!compiler_jump_if(c, e->v.IfExp.test, next2, 0)) return 0; if (!compiler_jump_if(c, e->v.IfExp.body, next, cond)) return 0; ADDOP_JUMP_NOLINE(c, JUMP, end); - compiler_use_next_block(c, next2); + + USE_LABEL(c, next2); if (!compiler_jump_if(c, e->v.IfExp.orelse, next, cond)) return 0; - compiler_use_next_block(c, end); + + USE_LABEL(c, end); return 1; } case Compare_kind: { @@ -2870,9 +2923,7 @@ compiler_jump_if(struct compiler *c, expr_ty e, basicblock *next, int cond) if (!check_compare(c, e)) { return 0; } - basicblock *cleanup = compiler_new_block(c); - if (cleanup == NULL) - return 0; + NEW_JUMP_TARGET_LABEL(c, cleanup); VISIT(c, expr, e->v.Compare.left); for (i = 0; i < n; i++) { VISIT(c, expr, @@ -2885,16 +2936,16 @@ compiler_jump_if(struct compiler *c, expr_ty e, basicblock *next, int cond) VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Compare.comparators, n)); ADDOP_COMPARE(c, asdl_seq_GET(e->v.Compare.ops, n)); ADDOP_JUMP(c, cond ? POP_JUMP_IF_TRUE : POP_JUMP_IF_FALSE, next); - basicblock *end = compiler_new_block(c); - if (end == NULL) - return 0; + NEW_JUMP_TARGET_LABEL(c, end); ADDOP_JUMP_NOLINE(c, JUMP, end); - compiler_use_next_block(c, cleanup); + + USE_LABEL(c, cleanup); ADDOP(c, POP_TOP); if (!cond) { ADDOP_JUMP_NOLINE(c, JUMP, next); } - compiler_use_next_block(c, end); + + USE_LABEL(c, end); return 1; } /* fallback to general implementation */ @@ -2914,22 +2965,19 @@ compiler_jump_if(struct compiler *c, expr_ty e, basicblock *next, int cond) static int compiler_ifexp(struct compiler *c, expr_ty e) { - basicblock *end, *next; - assert(e->kind == IfExp_kind); - end = compiler_new_block(c); - if (end == NULL) - return 0; - next = compiler_new_block(c); - if (next == NULL) - return 0; + NEW_JUMP_TARGET_LABEL(c, end); + NEW_JUMP_TARGET_LABEL(c, next); + if (!compiler_jump_if(c, e->v.IfExp.test, next, 0)) return 0; VISIT(c, expr, e->v.IfExp.body); ADDOP_JUMP_NOLINE(c, JUMP, end); - compiler_use_next_block(c, next); + + USE_LABEL(c, next); VISIT(c, expr, e->v.IfExp.orelse); - compiler_use_next_block(c, end); + + USE_LABEL(c, end); return 1; } @@ -2993,17 +3041,12 @@ compiler_lambda(struct compiler *c, expr_ty e) static int compiler_if(struct compiler *c, stmt_ty s) { - basicblock *end, *next; + jump_target_label next; assert(s->kind == If_kind); - end = compiler_new_block(c); - if (end == NULL) { - return 0; - } + NEW_JUMP_TARGET_LABEL(c, end); if (asdl_seq_LEN(s->v.If.orelse)) { - next = compiler_new_block(c); - if (next == NULL) { - return 0; - } + NEW_JUMP_TARGET_LABEL(c, orelse); + next = orelse; } else { next = end; @@ -3014,44 +3057,46 @@ compiler_if(struct compiler *c, stmt_ty s) VISIT_SEQ(c, stmt, s->v.If.body); if (asdl_seq_LEN(s->v.If.orelse)) { ADDOP_JUMP_NOLINE(c, JUMP, end); - compiler_use_next_block(c, next); + + USE_LABEL(c, next); VISIT_SEQ(c, stmt, s->v.If.orelse); } - compiler_use_next_block(c, end); + + USE_LABEL(c, end); return 1; } static int compiler_for(struct compiler *c, stmt_ty s) { - basicblock *start, *body, *cleanup, *end; + NEW_JUMP_TARGET_LABEL(c, start); + NEW_JUMP_TARGET_LABEL(c, body); + NEW_JUMP_TARGET_LABEL(c, cleanup); + NEW_JUMP_TARGET_LABEL(c, end); - start = compiler_new_block(c); - body = compiler_new_block(c); - cleanup = compiler_new_block(c); - end = compiler_new_block(c); - if (start == NULL || body == NULL || end == NULL || cleanup == NULL) { - return 0; - } if (!compiler_push_fblock(c, FOR_LOOP, start, end, NULL)) { return 0; } VISIT(c, expr, s->v.For.iter); ADDOP(c, GET_ITER); - compiler_use_next_block(c, start); + + USE_LABEL(c, start); ADDOP_JUMP(c, FOR_ITER, cleanup); - compiler_use_next_block(c, body); + + USE_LABEL(c, body); VISIT(c, expr, s->v.For.target); VISIT_SEQ(c, stmt, s->v.For.body); /* Mark jump as artificial */ UNSET_LOC(c); ADDOP_JUMP(c, JUMP, start); - compiler_use_next_block(c, cleanup); + + USE_LABEL(c, cleanup); compiler_pop_fblock(c, FOR_LOOP, start); VISIT_SEQ(c, stmt, s->v.For.orelse); - compiler_use_next_block(c, end); + + USE_LABEL(c, end); return 1; } @@ -3059,24 +3104,20 @@ compiler_for(struct compiler *c, stmt_ty s) static int compiler_async_for(struct compiler *c, stmt_ty s) { - basicblock *start, *except, *end; if (IS_TOP_LEVEL_AWAIT(c)){ c->u->u_ste->ste_coroutine = 1; } else if (c->u->u_scope_type != COMPILER_SCOPE_ASYNC_FUNCTION) { return compiler_error(c, "'async for' outside async function"); } - start = compiler_new_block(c); - except = compiler_new_block(c); - end = compiler_new_block(c); + NEW_JUMP_TARGET_LABEL(c, start); + NEW_JUMP_TARGET_LABEL(c, except); + NEW_JUMP_TARGET_LABEL(c, end); - if (start == NULL || except == NULL || end == NULL) { - return 0; - } VISIT(c, expr, s->v.AsyncFor.iter); ADDOP(c, GET_AITER); - compiler_use_next_block(c, start); + USE_LABEL(c, start); if (!compiler_push_fblock(c, FOR_LOOP, start, end, NULL)) { return 0; } @@ -3097,7 +3138,7 @@ compiler_async_for(struct compiler *c, stmt_ty s) compiler_pop_fblock(c, FOR_LOOP, start); /* Except block for __anext__ */ - compiler_use_next_block(c, except); + USE_LABEL(c, except); /* Use same line number as the iterator, * as the END_ASYNC_FOR succeeds the `for`, not the body. */ @@ -3107,23 +3148,19 @@ compiler_async_for(struct compiler *c, stmt_ty s) /* `else` block */ VISIT_SEQ(c, stmt, s->v.For.orelse); - compiler_use_next_block(c, end); - + USE_LABEL(c, end); return 1; } static int compiler_while(struct compiler *c, stmt_ty s) { - basicblock *loop, *body, *end, *anchor = NULL; - loop = compiler_new_block(c); - body = compiler_new_block(c); - anchor = compiler_new_block(c); - end = compiler_new_block(c); - if (loop == NULL || body == NULL || anchor == NULL || end == NULL) { - return 0; - } - compiler_use_next_block(c, loop); + NEW_JUMP_TARGET_LABEL(c, loop); + NEW_JUMP_TARGET_LABEL(c, body); + NEW_JUMP_TARGET_LABEL(c, end); + NEW_JUMP_TARGET_LABEL(c, anchor); + + USE_LABEL(c, loop); if (!compiler_push_fblock(c, WHILE_LOOP, loop, end, NULL)) { return 0; } @@ -3131,7 +3168,7 @@ compiler_while(struct compiler *c, stmt_ty s) return 0; } - compiler_use_next_block(c, body); + USE_LABEL(c, body); VISIT_SEQ(c, stmt, s->v.While.body); SET_LOC(c, s); if (!compiler_jump_if(c, s->v.While.test, body, 1)) { @@ -3140,12 +3177,12 @@ compiler_while(struct compiler *c, stmt_ty s) compiler_pop_fblock(c, WHILE_LOOP, loop); - compiler_use_next_block(c, anchor); + USE_LABEL(c, anchor); if (s->v.While.orelse) { VISIT_SEQ(c, stmt, s->v.While.orelse); } - compiler_use_next_block(c, end); + USE_LABEL(c, end); return 1; } @@ -3257,18 +3294,15 @@ compiler_continue(struct compiler *c) static int compiler_try_finally(struct compiler *c, stmt_ty s) { - basicblock *body, *end, *exit, *cleanup; + NEW_JUMP_TARGET_LABEL(c, body); + NEW_JUMP_TARGET_LABEL(c, end); + NEW_JUMP_TARGET_LABEL(c, exit); + NEW_JUMP_TARGET_LABEL(c, cleanup); - body = compiler_new_block(c); - end = compiler_new_block(c); - exit = compiler_new_block(c); - cleanup = compiler_new_block(c); - if (body == NULL || end == NULL || exit == NULL || cleanup == NULL) { - return 0; - } /* `try` block */ ADDOP_JUMP(c, SETUP_FINALLY, end); - compiler_use_next_block(c, body); + + USE_LABEL(c, body); if (!compiler_push_fblock(c, FINALLY_TRY, body, end, s->v.Try.finalbody)) return 0; if (s->v.Try.handlers && asdl_seq_LEN(s->v.Try.handlers)) { @@ -3283,44 +3317,36 @@ compiler_try_finally(struct compiler *c, stmt_ty s) VISIT_SEQ(c, stmt, s->v.Try.finalbody); ADDOP_JUMP_NOLINE(c, JUMP, exit); /* `finally` block */ - compiler_use_next_block(c, end); + + USE_LABEL(c, end); UNSET_LOC(c); ADDOP_JUMP(c, SETUP_CLEANUP, cleanup); ADDOP(c, PUSH_EXC_INFO); - if (!compiler_push_fblock(c, FINALLY_END, end, NULL, NULL)) + if (!compiler_push_fblock(c, FINALLY_END, end, NO_LABEL, NULL)) return 0; VISIT_SEQ(c, stmt, s->v.Try.finalbody); compiler_pop_fblock(c, FINALLY_END, end); ADDOP_I(c, RERAISE, 0); - compiler_use_next_block(c, cleanup); + + USE_LABEL(c, cleanup); POP_EXCEPT_AND_RERAISE(c); - compiler_use_next_block(c, exit); + + USE_LABEL(c, exit); return 1; } static int compiler_try_star_finally(struct compiler *c, stmt_ty s) { - basicblock *body = compiler_new_block(c); - if (body == NULL) { - return 0; - } - basicblock *end = compiler_new_block(c); - if (!end) { - return 0; - } - basicblock *exit = compiler_new_block(c); - if (!exit) { - return 0; - } - basicblock *cleanup = compiler_new_block(c); - if (!cleanup) { - return 0; - } + NEW_JUMP_TARGET_LABEL(c, body); + NEW_JUMP_TARGET_LABEL(c, end); + NEW_JUMP_TARGET_LABEL(c, exit); + NEW_JUMP_TARGET_LABEL(c, cleanup); /* `try` block */ ADDOP_JUMP(c, SETUP_FINALLY, end); - compiler_use_next_block(c, body); + + USE_LABEL(c, body); if (!compiler_push_fblock(c, FINALLY_TRY, body, end, s->v.TryStar.finalbody)) { return 0; } @@ -3336,21 +3362,24 @@ compiler_try_star_finally(struct compiler *c, stmt_ty s) compiler_pop_fblock(c, FINALLY_TRY, body); VISIT_SEQ(c, stmt, s->v.TryStar.finalbody); ADDOP_JUMP_NOLINE(c, JUMP, exit); + /* `finally` block */ - compiler_use_next_block(c, end); + USE_LABEL(c, end); UNSET_LOC(c); ADDOP_JUMP(c, SETUP_CLEANUP, cleanup); ADDOP(c, PUSH_EXC_INFO); - if (!compiler_push_fblock(c, FINALLY_END, end, NULL, NULL)) { + if (!compiler_push_fblock(c, FINALLY_END, end, NO_LABEL, NULL)) { return 0; } VISIT_SEQ(c, stmt, s->v.TryStar.finalbody); compiler_pop_fblock(c, FINALLY_END, end); ADDOP_I(c, RERAISE, 0); - compiler_use_next_block(c, cleanup); + + USE_LABEL(c, cleanup); POP_EXCEPT_AND_RERAISE(c); - compiler_use_next_block(c, exit); + + USE_LABEL(c, exit); return 1; } @@ -3386,18 +3415,17 @@ compiler_try_star_finally(struct compiler *c, stmt_ty s) static int compiler_try_except(struct compiler *c, stmt_ty s) { - basicblock *body, *except, *end, *cleanup; Py_ssize_t i, n; - body = compiler_new_block(c); - except = compiler_new_block(c); - end = compiler_new_block(c); - cleanup = compiler_new_block(c); - if (body == NULL || except == NULL || end == NULL || cleanup == NULL) - return 0; + NEW_JUMP_TARGET_LABEL(c, body); + NEW_JUMP_TARGET_LABEL(c, except); + NEW_JUMP_TARGET_LABEL(c, end); + NEW_JUMP_TARGET_LABEL(c, cleanup); + ADDOP_JUMP(c, SETUP_FINALLY, except); - compiler_use_next_block(c, body); - if (!compiler_push_fblock(c, TRY_EXCEPT, body, NULL, NULL)) + + USE_LABEL(c, body); + if (!compiler_push_fblock(c, TRY_EXCEPT, body, NO_LABEL, NULL)) return 0; VISIT_SEQ(c, stmt, s->v.Try.body); compiler_pop_fblock(c, TRY_EXCEPT, body); @@ -3407,13 +3435,14 @@ compiler_try_except(struct compiler *c, stmt_ty s) } ADDOP_JUMP_NOLINE(c, JUMP, end); n = asdl_seq_LEN(s->v.Try.handlers); - compiler_use_next_block(c, except); + + USE_LABEL(c, except); UNSET_LOC(c); ADDOP_JUMP(c, SETUP_CLEANUP, cleanup); ADDOP(c, PUSH_EXC_INFO); /* Runtime will push a block here, so we need to account for that */ - if (!compiler_push_fblock(c, EXCEPTION_HANDLER, NULL, NULL, NULL)) + if (!compiler_push_fblock(c, EXCEPTION_HANDLER, NO_LABEL, NO_LABEL, NULL)) return 0; for (i = 0; i < n; i++) { excepthandler_ty handler = (excepthandler_ty)asdl_seq_GET( @@ -3422,22 +3451,16 @@ compiler_try_except(struct compiler *c, stmt_ty s) if (!handler->v.ExceptHandler.type && i < n-1) { return compiler_error(c, "default 'except:' must be last"); } - except = compiler_new_block(c); - if (except == NULL) - return 0; + NEW_JUMP_TARGET_LABEL(c, next_except); + except = next_except; if (handler->v.ExceptHandler.type) { VISIT(c, expr, handler->v.ExceptHandler.type); ADDOP(c, CHECK_EXC_MATCH); ADDOP_JUMP(c, POP_JUMP_IF_FALSE, except); } if (handler->v.ExceptHandler.name) { - basicblock *cleanup_end, *cleanup_body; - - cleanup_end = compiler_new_block(c); - cleanup_body = compiler_new_block(c); - if (cleanup_end == NULL || cleanup_body == NULL) { - return 0; - } + NEW_JUMP_TARGET_LABEL(c, cleanup_end); + NEW_JUMP_TARGET_LABEL(c, cleanup_body); compiler_nameop(c, handler->v.ExceptHandler.name, Store); @@ -3454,8 +3477,9 @@ compiler_try_except(struct compiler *c, stmt_ty s) /* second try: */ ADDOP_JUMP(c, SETUP_CLEANUP, cleanup_end); - compiler_use_next_block(c, cleanup_body); - if (!compiler_push_fblock(c, HANDLER_CLEANUP, cleanup_body, NULL, handler->v.ExceptHandler.name)) + + USE_LABEL(c, cleanup_body); + if (!compiler_push_fblock(c, HANDLER_CLEANUP, cleanup_body, NO_LABEL, handler->v.ExceptHandler.name)) return 0; /* second # body */ @@ -3472,7 +3496,7 @@ compiler_try_except(struct compiler *c, stmt_ty s) ADDOP_JUMP(c, JUMP, end); /* except: */ - compiler_use_next_block(c, cleanup_end); + USE_LABEL(c, cleanup_end); /* name = None; del name; # Mark as artificial */ UNSET_LOC(c); @@ -3484,15 +3508,12 @@ compiler_try_except(struct compiler *c, stmt_ty s) ADDOP_I(c, RERAISE, 1); } else { - basicblock *cleanup_body; - - cleanup_body = compiler_new_block(c); - if (!cleanup_body) - return 0; + NEW_JUMP_TARGET_LABEL(c, cleanup_body); ADDOP(c, POP_TOP); /* exc_value */ - compiler_use_next_block(c, cleanup_body); - if (!compiler_push_fblock(c, HANDLER_CLEANUP, cleanup_body, NULL, NULL)) + + USE_LABEL(c, cleanup_body); + if (!compiler_push_fblock(c, HANDLER_CLEANUP, cleanup_body, NO_LABEL, NULL)) return 0; VISIT_SEQ(c, stmt, handler->v.ExceptHandler.body); compiler_pop_fblock(c, HANDLER_CLEANUP, cleanup_body); @@ -3501,15 +3522,18 @@ compiler_try_except(struct compiler *c, stmt_ty s) ADDOP(c, POP_EXCEPT); ADDOP_JUMP(c, JUMP, end); } - compiler_use_next_block(c, except); + + USE_LABEL(c, except); } /* Mark as artificial */ UNSET_LOC(c); - compiler_pop_fblock(c, EXCEPTION_HANDLER, NULL); + compiler_pop_fblock(c, EXCEPTION_HANDLER, NO_LABEL); ADDOP_I(c, RERAISE, 0); - compiler_use_next_block(c, cleanup); + + USE_LABEL(c, cleanup); POP_EXCEPT_AND_RERAISE(c); - compiler_use_next_block(c, end); + + USE_LABEL(c, end); return 1; } @@ -3565,34 +3589,17 @@ compiler_try_except(struct compiler *c, stmt_ty s) static int compiler_try_star_except(struct compiler *c, stmt_ty s) { - basicblock *body = compiler_new_block(c); - if (body == NULL) { - return 0; - } - basicblock *except = compiler_new_block(c); - if (except == NULL) { - return 0; - } - basicblock *orelse = compiler_new_block(c); - if (orelse == NULL) { - return 0; - } - basicblock *end = compiler_new_block(c); - if (end == NULL) { - return 0; - } - basicblock *cleanup = compiler_new_block(c); - if (cleanup == NULL) { - return 0; - } - basicblock *reraise_star = compiler_new_block(c); - if (reraise_star == NULL) { - return 0; - } + NEW_JUMP_TARGET_LABEL(c, body); + NEW_JUMP_TARGET_LABEL(c, except); + NEW_JUMP_TARGET_LABEL(c, orelse); + NEW_JUMP_TARGET_LABEL(c, end); + NEW_JUMP_TARGET_LABEL(c, cleanup); + NEW_JUMP_TARGET_LABEL(c, reraise_star); ADDOP_JUMP(c, SETUP_FINALLY, except); - compiler_use_next_block(c, body); - if (!compiler_push_fblock(c, TRY_EXCEPT, body, NULL, NULL)) { + + USE_LABEL(c, body); + if (!compiler_push_fblock(c, TRY_EXCEPT, body, NO_LABEL, NULL)) { return 0; } VISIT_SEQ(c, stmt, s->v.TryStar.body); @@ -3600,28 +3607,24 @@ compiler_try_star_except(struct compiler *c, stmt_ty s) ADDOP_NOLINE(c, POP_BLOCK); ADDOP_JUMP_NOLINE(c, JUMP, orelse); Py_ssize_t n = asdl_seq_LEN(s->v.TryStar.handlers); - compiler_use_next_block(c, except); + + USE_LABEL(c, except); UNSET_LOC(c); ADDOP_JUMP(c, SETUP_CLEANUP, cleanup); ADDOP(c, PUSH_EXC_INFO); /* Runtime will push a block here, so we need to account for that */ if (!compiler_push_fblock(c, EXCEPTION_GROUP_HANDLER, - NULL, NULL, "except handler")) { + NO_LABEL, NO_LABEL, "except handler")) { return 0; } for (Py_ssize_t i = 0; i < n; i++) { excepthandler_ty handler = (excepthandler_ty)asdl_seq_GET( s->v.TryStar.handlers, i); SET_LOC(c, handler); - except = compiler_new_block(c); - if (except == NULL) { - return 0; - } - basicblock *handle_match = compiler_new_block(c); - if (handle_match == NULL) { - return 0; - } + NEW_JUMP_TARGET_LABEL(c, next_except); + except = next_except; + NEW_JUMP_TARGET_LABEL(c, handle_match); if (i == 0) { /* Push the original EG into the stack */ /* @@ -3648,16 +3651,10 @@ compiler_try_star_except(struct compiler *c, stmt_ty s) ADDOP_JUMP(c, JUMP, except); } - compiler_use_next_block(c, handle_match); + USE_LABEL(c, handle_match); - basicblock *cleanup_end = compiler_new_block(c); - if (cleanup_end == NULL) { - return 0; - } - basicblock *cleanup_body = compiler_new_block(c); - if (cleanup_body == NULL) { - return 0; - } + NEW_JUMP_TARGET_LABEL(c, cleanup_end); + NEW_JUMP_TARGET_LABEL(c, cleanup_body); if (handler->v.ExceptHandler.name) { compiler_nameop(c, handler->v.ExceptHandler.name, Store); @@ -3678,8 +3675,9 @@ compiler_try_star_except(struct compiler *c, stmt_ty s) */ /* second try: */ ADDOP_JUMP(c, SETUP_CLEANUP, cleanup_end); - compiler_use_next_block(c, cleanup_body); - if (!compiler_push_fblock(c, HANDLER_CLEANUP, cleanup_body, NULL, handler->v.ExceptHandler.name)) + + USE_LABEL(c, cleanup_body); + if (!compiler_push_fblock(c, HANDLER_CLEANUP, cleanup_body, NO_LABEL, handler->v.ExceptHandler.name)) return 0; /* second # body */ @@ -3696,7 +3694,7 @@ compiler_try_star_except(struct compiler *c, stmt_ty s) ADDOP_JUMP(c, JUMP, except); /* except: */ - compiler_use_next_block(c, cleanup_end); + USE_LABEL(c, cleanup_end); /* name = None; del name; # Mark as artificial */ UNSET_LOC(c); @@ -3710,9 +3708,9 @@ compiler_try_star_except(struct compiler *c, stmt_ty s) /* add exception raised to the res list */ ADDOP_I(c, LIST_APPEND, 3); // exc ADDOP(c, POP_TOP); // lasti - ADDOP_JUMP(c, JUMP, except); - compiler_use_next_block(c, except); + + USE_LABEL(c, except); if (i == n - 1) { /* Add exc to the list (if not None it's the unhandled part of the EG) */ @@ -3722,13 +3720,10 @@ compiler_try_star_except(struct compiler *c, stmt_ty s) } /* Mark as artificial */ UNSET_LOC(c); - compiler_pop_fblock(c, EXCEPTION_GROUP_HANDLER, NULL); - basicblock *reraise = compiler_new_block(c); - if (!reraise) { - return 0; - } + compiler_pop_fblock(c, EXCEPTION_GROUP_HANDLER, NO_LABEL); + NEW_JUMP_TARGET_LABEL(c, reraise); - compiler_use_next_block(c, reraise_star); + USE_LABEL(c, reraise_star); ADDOP(c, PREP_RERAISE_STAR); ADDOP_I(c, COPY, 1); ADDOP_JUMP(c, POP_JUMP_IF_NOT_NONE, reraise); @@ -3738,16 +3733,20 @@ compiler_try_star_except(struct compiler *c, stmt_ty s) ADDOP(c, POP_BLOCK); ADDOP(c, POP_EXCEPT); ADDOP_JUMP(c, JUMP, end); - compiler_use_next_block(c, reraise); + + USE_LABEL(c, reraise); ADDOP(c, POP_BLOCK); ADDOP_I(c, SWAP, 2); ADDOP(c, POP_EXCEPT); ADDOP_I(c, RERAISE, 0); - compiler_use_next_block(c, cleanup); + + USE_LABEL(c, cleanup); POP_EXCEPT_AND_RERAISE(c); - compiler_use_next_block(c, orelse); + + USE_LABEL(c, orelse); VISIT_SEQ(c, stmt, s->v.TryStar.orelse); - compiler_use_next_block(c, end); + + USE_LABEL(c, end); return 1; } @@ -3917,8 +3916,6 @@ compiler_from_import(struct compiler *c, stmt_ty s) static int compiler_assert(struct compiler *c, stmt_ty s) { - basicblock *end; - /* Always emit a warning if the test is a non-zero length tuple */ if ((s->v.Assert.test->kind == Tuple_kind && asdl_seq_LEN(s->v.Assert.test->v.Tuple.elts) > 0) || @@ -3934,9 +3931,7 @@ compiler_assert(struct compiler *c, stmt_ty s) } if (c->c_optimize) return 1; - end = compiler_new_block(c); - if (end == NULL) - return 0; + NEW_JUMP_TARGET_LABEL(c, end); if (!compiler_jump_if(c, s->v.Assert.test, end, 1)) return 0; ADDOP(c, LOAD_ASSERTION_ERROR); @@ -3945,7 +3940,8 @@ compiler_assert(struct compiler *c, stmt_ty s) ADDOP_I(c, CALL, 0); } ADDOP_I(c, RAISE_VARARGS, 1); - compiler_use_next_block(c, end); + + USE_LABEL(c, end); return 1; } @@ -4243,7 +4239,6 @@ compiler_nameop(struct compiler *c, identifier name, expr_context_ty ctx) static int compiler_boolop(struct compiler *c, expr_ty e) { - basicblock *end; int jumpi; Py_ssize_t i, n; asdl_expr_seq *s; @@ -4253,23 +4248,20 @@ compiler_boolop(struct compiler *c, expr_ty e) jumpi = JUMP_IF_FALSE_OR_POP; else jumpi = JUMP_IF_TRUE_OR_POP; - end = compiler_new_block(c); - if (end == NULL) - return 0; + NEW_JUMP_TARGET_LABEL(c, end); s = e->v.BoolOp.values; n = asdl_seq_LEN(s) - 1; assert(n >= 0); for (i = 0; i < n; ++i) { VISIT(c, expr, (expr_ty)asdl_seq_GET(s, i)); ADDOP_JUMP(c, jumpi, end); - basicblock *next = compiler_new_block(c); - if (next == NULL) { - return 0; - } - compiler_use_next_block(c, next); + NEW_JUMP_TARGET_LABEL(c, next); + + USE_LABEL(c, next); } VISIT(c, expr, (expr_ty)asdl_seq_GET(s, n)); - compiler_use_next_block(c, end); + + USE_LABEL(c, end); return 1; } @@ -4563,9 +4555,7 @@ compiler_compare(struct compiler *c, expr_ty e) ADDOP_COMPARE(c, asdl_seq_GET(e->v.Compare.ops, 0)); } else { - basicblock *cleanup = compiler_new_block(c); - if (cleanup == NULL) - return 0; + NEW_JUMP_TARGET_LABEL(c, cleanup); for (i = 0; i < n; i++) { VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Compare.comparators, i)); @@ -4576,14 +4566,14 @@ compiler_compare(struct compiler *c, expr_ty e) } VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Compare.comparators, n)); ADDOP_COMPARE(c, asdl_seq_GET(e->v.Compare.ops, n)); - basicblock *end = compiler_new_block(c); - if (end == NULL) - return 0; + NEW_JUMP_TARGET_LABEL(c, end); ADDOP_JUMP_NOLINE(c, JUMP, end); - compiler_use_next_block(c, cleanup); + + USE_LABEL(c, cleanup); ADDOP_I(c, SWAP, 2); ADDOP(c, POP_TOP); - compiler_use_next_block(c, end); + + USE_LABEL(c, end); } return 1; } @@ -5138,16 +5128,11 @@ compiler_sync_comprehension_generator(struct compiler *c, and then write to the element */ comprehension_ty gen; - basicblock *start, *anchor, *if_cleanup; Py_ssize_t i, n; - start = compiler_new_block(c); - if_cleanup = compiler_new_block(c); - anchor = compiler_new_block(c); - - if (start == NULL || if_cleanup == NULL || anchor == NULL) { - return 0; - } + NEW_JUMP_TARGET_LABEL(c, start); + NEW_JUMP_TARGET_LABEL(c, if_cleanup); + NEW_JUMP_TARGET_LABEL(c, anchor); gen = (comprehension_ty)asdl_seq_GET(generators, gen_index); @@ -5176,17 +5161,17 @@ compiler_sync_comprehension_generator(struct compiler *c, expr_ty elt = asdl_seq_GET(elts, 0); if (elt->kind != Starred_kind) { VISIT(c, expr, elt); - start = NULL; + start = NO_LABEL; } } - if (start) { + if (IS_LABEL(start)) { VISIT(c, expr, gen->iter); ADDOP(c, GET_ITER); } } - if (start) { + if (IS_LABEL(start)) { depth++; - compiler_use_next_block(c, start); + USE_LABEL(c, start); ADDOP_JUMP(c, FOR_ITER, anchor); } VISIT(c, expr, gen->target); @@ -5233,10 +5218,12 @@ compiler_sync_comprehension_generator(struct compiler *c, return 0; } } - compiler_use_next_block(c, if_cleanup); - if (start) { + + USE_LABEL(c, if_cleanup); + if (IS_LABEL(start)) { ADDOP_JUMP(c, JUMP, start); - compiler_use_next_block(c, anchor); + + USE_LABEL(c, anchor); } return 1; @@ -5249,15 +5236,10 @@ compiler_async_comprehension_generator(struct compiler *c, expr_ty elt, expr_ty val, int type) { comprehension_ty gen; - basicblock *start, *if_cleanup, *except; Py_ssize_t i, n; - start = compiler_new_block(c); - except = compiler_new_block(c); - if_cleanup = compiler_new_block(c); - - if (start == NULL || if_cleanup == NULL || except == NULL) { - return 0; - } + NEW_JUMP_TARGET_LABEL(c, start); + NEW_JUMP_TARGET_LABEL(c, except); + NEW_JUMP_TARGET_LABEL(c, if_cleanup); gen = (comprehension_ty)asdl_seq_GET(generators, gen_index); @@ -5272,10 +5254,10 @@ compiler_async_comprehension_generator(struct compiler *c, ADDOP(c, GET_AITER); } - compiler_use_next_block(c, start); + USE_LABEL(c, start); /* Runtime will push a block here, so we need to account for that */ if (!compiler_push_fblock(c, ASYNC_COMPREHENSION_GENERATOR, start, - NULL, NULL)) { + NO_LABEL, NULL)) { return 0; } @@ -5328,12 +5310,13 @@ compiler_async_comprehension_generator(struct compiler *c, return 0; } } - compiler_use_next_block(c, if_cleanup); + + USE_LABEL(c, if_cleanup); ADDOP_JUMP(c, JUMP, start); compiler_pop_fblock(c, ASYNC_COMPREHENSION_GENERATOR, start); - compiler_use_next_block(c, except); + USE_LABEL(c, except); //UNSET_LOC(c); ADDOP(c, END_ASYNC_FOR); @@ -5494,28 +5477,25 @@ compiler_visit_keyword(struct compiler *c, keyword_ty k) static int -compiler_with_except_finish(struct compiler *c, basicblock * cleanup) { +compiler_with_except_finish(struct compiler *c, jump_target_label cleanup) { UNSET_LOC(c); - basicblock *suppress = compiler_new_block(c); - if (suppress == NULL) { - return 0; - } + NEW_JUMP_TARGET_LABEL(c, suppress); ADDOP_JUMP(c, POP_JUMP_IF_TRUE, suppress); ADDOP_I(c, RERAISE, 2); - compiler_use_next_block(c, suppress); + + USE_LABEL(c, suppress); ADDOP(c, POP_TOP); /* exc_value */ ADDOP(c, POP_BLOCK); ADDOP(c, POP_EXCEPT); ADDOP(c, POP_TOP); ADDOP(c, POP_TOP); - basicblock *exit = compiler_new_block(c); - if (exit == NULL) { - return 0; - } + NEW_JUMP_TARGET_LABEL(c, exit); ADDOP_JUMP(c, JUMP, exit); - compiler_use_next_block(c, cleanup); + + USE_LABEL(c, cleanup); POP_EXCEPT_AND_RERAISE(c); - compiler_use_next_block(c, exit); + + USE_LABEL(c, exit); return 1; } @@ -5546,7 +5526,6 @@ compiler_with_except_finish(struct compiler *c, basicblock * cleanup) { static int compiler_async_with(struct compiler *c, stmt_ty s, int pos) { - basicblock *block, *final, *exit, *cleanup; withitem_ty item = asdl_seq_GET(s->v.AsyncWith.items, pos); assert(s->kind == AsyncWith_kind); @@ -5556,12 +5535,10 @@ compiler_async_with(struct compiler *c, stmt_ty s, int pos) return compiler_error(c, "'async with' outside async function"); } - block = compiler_new_block(c); - final = compiler_new_block(c); - exit = compiler_new_block(c); - cleanup = compiler_new_block(c); - if (!block || !final || !exit || !cleanup) - return 0; + NEW_JUMP_TARGET_LABEL(c, block); + NEW_JUMP_TARGET_LABEL(c, final); + NEW_JUMP_TARGET_LABEL(c, exit); + NEW_JUMP_TARGET_LABEL(c, cleanup); /* Evaluate EXPR */ VISIT(c, expr, item->context_expr); @@ -5574,7 +5551,7 @@ compiler_async_with(struct compiler *c, stmt_ty s, int pos) ADDOP_JUMP(c, SETUP_WITH, final); /* SETUP_WITH pushes a finally block. */ - compiler_use_next_block(c, block); + USE_LABEL(c, block); if (!compiler_push_fblock(c, ASYNC_WITH, block, final, s)) { return 0; } @@ -5613,7 +5590,7 @@ compiler_async_with(struct compiler *c, stmt_ty s, int pos) ADDOP_JUMP(c, JUMP, exit); /* For exceptional outcome: */ - compiler_use_next_block(c, final); + USE_LABEL(c, final); ADDOP_JUMP(c, SETUP_CLEANUP, cleanup); ADDOP(c, PUSH_EXC_INFO); @@ -5623,7 +5600,7 @@ compiler_async_with(struct compiler *c, stmt_ty s, int pos) ADD_YIELD_FROM(c, 1); compiler_with_except_finish(c, cleanup); - compiler_use_next_block(c, exit); + USE_LABEL(c, exit); return 1; } @@ -5652,17 +5629,14 @@ compiler_async_with(struct compiler *c, stmt_ty s, int pos) static int compiler_with(struct compiler *c, stmt_ty s, int pos) { - basicblock *block, *final, *exit, *cleanup; withitem_ty item = asdl_seq_GET(s->v.With.items, pos); assert(s->kind == With_kind); - block = compiler_new_block(c); - final = compiler_new_block(c); - exit = compiler_new_block(c); - cleanup = compiler_new_block(c); - if (!block || !final || !exit || !cleanup) - return 0; + NEW_JUMP_TARGET_LABEL(c, block); + NEW_JUMP_TARGET_LABEL(c, final); + NEW_JUMP_TARGET_LABEL(c, exit); + NEW_JUMP_TARGET_LABEL(c, cleanup); /* Evaluate EXPR */ VISIT(c, expr, item->context_expr); @@ -5671,7 +5645,7 @@ compiler_with(struct compiler *c, stmt_ty s, int pos) ADDOP_JUMP(c, SETUP_WITH, final); /* SETUP_WITH pushes a finally block. */ - compiler_use_next_block(c, block); + USE_LABEL(c, block); if (!compiler_push_fblock(c, WITH, block, final, s)) { return 0; } @@ -5709,14 +5683,14 @@ compiler_with(struct compiler *c, stmt_ty s, int pos) ADDOP_JUMP(c, JUMP, exit); /* For exceptional outcome: */ - compiler_use_next_block(c, final); + USE_LABEL(c, final); ADDOP_JUMP(c, SETUP_CLEANUP, cleanup); ADDOP(c, PUSH_EXC_INFO); ADDOP(c, WITH_EXCEPT_START); compiler_with_except_finish(c, cleanup); - compiler_use_next_block(c, exit); + USE_LABEL(c, exit); return 1; } @@ -6243,16 +6217,15 @@ ensure_fail_pop(struct compiler *c, pattern_context *pc, Py_ssize_t n) if (size <= pc->fail_pop_size) { return 1; } - Py_ssize_t needed = sizeof(basicblock*) * size; - basicblock **resized = PyObject_Realloc(pc->fail_pop, needed); + Py_ssize_t needed = sizeof(jump_target_label) * size; + jump_target_label *resized = PyObject_Realloc(pc->fail_pop, needed); if (resized == NULL) { PyErr_NoMemory(); return 0; } pc->fail_pop = resized; while (pc->fail_pop_size < size) { - basicblock *new_block; - RETURN_IF_FALSE(new_block = compiler_new_block(c)); + NEW_JUMP_TARGET_LABEL(c, new_block); pc->fail_pop[pc->fail_pop_size++] = new_block; } return 1; @@ -6279,7 +6252,7 @@ emit_and_reset_fail_pop(struct compiler *c, pattern_context *pc) return 1; } while (--pc->fail_pop_size) { - compiler_use_next_block(c, pc->fail_pop[pc->fail_pop_size]); + USE_LABEL(c, pc->fail_pop[pc->fail_pop_size]); if (!cfg_builder_addop_noarg(CFG_BUILDER(c), POP_TOP, COMPILER_LOC(c))) { pc->fail_pop_size = 0; PyObject_Free(pc->fail_pop); @@ -6287,7 +6260,7 @@ emit_and_reset_fail_pop(struct compiler *c, pattern_context *pc) return 0; } } - compiler_use_next_block(c, pc->fail_pop[0]); + USE_LABEL(c, pc->fail_pop[0]); PyObject_Free(pc->fail_pop); pc->fail_pop = NULL; return 1; @@ -6689,8 +6662,7 @@ static int compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc) { assert(p->kind == MatchOr_kind); - basicblock *end; - RETURN_IF_FALSE(end = compiler_new_block(c)); + NEW_JUMP_TARGET_LABEL(c, end); Py_ssize_t size = asdl_seq_LEN(p->v.MatchOr.patterns); assert(size > 1); // We're going to be messing with pc. Keep the original info handy: @@ -6793,7 +6765,8 @@ compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc) if (!cfg_builder_addop_noarg(CFG_BUILDER(c), POP_TOP, COMPILER_LOC(c)) || !jump_to_fail_pop(c, pc, JUMP)) { goto error; } - compiler_use_next_block(c, end); + + USE_LABEL(c, end); Py_ssize_t nstores = PyList_GET_SIZE(control); // There's a bunch of stuff on the stack between where the new stores // are and where they need to be: @@ -6952,8 +6925,7 @@ static int compiler_match_inner(struct compiler *c, stmt_ty s, pattern_context *pc) { VISIT(c, expr, s->v.Match.subject); - basicblock *end; - RETURN_IF_FALSE(end = compiler_new_block(c)); + NEW_JUMP_TARGET_LABEL(c, end); Py_ssize_t cases = asdl_seq_LEN(s->v.Match.cases); assert(cases > 0); match_case_ty m = asdl_seq_GET(s->v.Match.cases, cases - 1); @@ -7022,7 +6994,7 @@ compiler_match_inner(struct compiler *c, stmt_ty s, pattern_context *pc) } VISIT_SEQ(c, stmt, m->body); } - compiler_use_next_block(c, end); + USE_LABEL(c, end); return 1; } @@ -7438,11 +7410,17 @@ push_cold_blocks_to_end(cfg_builder *g, int code_flags) { if (explicit_jump == NULL) { return -1; } - basicblock_addop(explicit_jump, JUMP, 0, b->b_next, NO_LOCATION); - + jump_target_label next_label = {b->b_next->b_label, b->b_next}; + basicblock_addop(explicit_jump, JUMP, 0, next_label, NO_LOCATION); explicit_jump->b_cold = 1; explicit_jump->b_next = b->b_next; b->b_next = explicit_jump; + + /* calculate target from target_label */ + /* TODO: formalize an API for adding jumps in the backend */ + struct instr *last = basicblock_last_instr(explicit_jump); + last->i_target = last->i_target_label.block; + last->i_target_label = NO_LABEL; } } @@ -8262,8 +8240,8 @@ static void dump_basicblock(const basicblock *b) { const char *b_return = basicblock_returns(b) ? "return " : ""; - fprintf(stderr, "[%d %d %d %p] used: %d, depth: %d, offset: %d %s\n", - b->b_cold, b->b_warm, BB_NO_FALLTHROUGH(b), b, b->b_iused, + fprintf(stderr, "%d: [%d %d %d %p] used: %d, depth: %d, offset: %d %s\n", + b->b_label, b->b_cold, b->b_warm, BB_NO_FALLTHROUGH(b), b, b->b_iused, b->b_startdepth, b->b_offset, b_return); if (b->b_instr) { int i; @@ -8280,6 +8258,9 @@ static int normalize_basic_block(basicblock *bb); static int +calculate_jump_targets(basicblock *entryblock); + +static int optimize_cfg(basicblock *entryblock, PyObject *consts, PyObject *const_cache); static int @@ -8497,7 +8478,7 @@ static void eliminate_empty_basic_blocks(basicblock *entryblock); -static void +static int remove_redundant_jumps(basicblock *entryblock) { /* 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 @@ -8511,6 +8492,10 @@ remove_redundant_jumps(basicblock *entryblock) { 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 == NULL) { + PyErr_SetString(PyExc_SystemError, "jump with NULL target"); + return -1; + } if (b_last_instr->i_target == b->b_next) { assert(b->b_next->b_iused); b_last_instr->i_opcode = NOP; @@ -8522,6 +8507,7 @@ remove_redundant_jumps(basicblock *entryblock) { if (removed) { eliminate_empty_basic_blocks(entryblock); } + return 0; } static PyCodeObject * @@ -8599,7 +8585,9 @@ assemble(struct compiler *c, int addNone) if (consts == NULL) { goto error; } - + if (calculate_jump_targets(entryblock)) { + goto error; + } if (optimize_cfg(entryblock, consts, c->c_const_cache)) { goto error; } @@ -8627,7 +8615,9 @@ assemble(struct compiler *c, int addNone) goto error; } - remove_redundant_jumps(entryblock); + if (remove_redundant_jumps(entryblock) < 0) { + goto error; + } for (basicblock *b = entryblock; b != NULL; b = b->b_next) { clean_basic_block(b); } @@ -9441,6 +9431,47 @@ propagate_line_numbers(basicblock *entryblock) { } } + +/* Calculate the actual jump target from the target_label */ +static int +calculate_jump_targets(basicblock *entryblock) +{ + int max_label = -1; + for (basicblock *b = entryblock; b != NULL; b = b->b_next) { + if (b->b_label > max_label) { + max_label = b->b_label; + } + } + size_t mapsize = sizeof(basicblock *) * (max_label + 1); + basicblock **label2block = (basicblock **)PyMem_Malloc(mapsize); + if (!label2block) { + PyErr_NoMemory(); + return -1; + } + memset(label2block, 0, mapsize); + for (basicblock *b = entryblock; b != NULL; b = b->b_next) { + if (b->b_label >= 0) { + label2block[b->b_label] = b; + } + } + for (basicblock *b = entryblock; b != NULL; b = b->b_next) { + for (int i = 0; i < b->b_iused; i++) { + struct instr *instr = &b->b_instr[i]; + assert(instr->i_target == NULL); + if (is_jump(instr) || is_block_push(instr)) { + int lbl = instr->i_target_label.id; + assert(lbl >= 0 && lbl <= max_label); + instr->i_target = label2block[lbl]; + assert(instr->i_target != NULL); + assert(instr->i_target->b_label == lbl); + } + instr->i_target_label = NO_LABEL; + } + } + PyMem_Free(label2block); + return 0; +} + /* Perform optimizations on a control flow graph. The consts object should still be in list form to allow new constants to be appended. |