From 43df9b3a07cf00f691051c33036e482bac14027f Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Sat, 25 Feb 2023 17:59:08 +0000 Subject: [PATCH 01/23] compiler uses instruction stream to create codeobjects --- Python/compile.c | 321 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 311 insertions(+), 10 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index 2f1130e62ee161..58e495380401e7 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -404,6 +404,22 @@ enum { COMPILER_SCOPE_COMPREHENSION, }; +typedef struct codegen_instr_ { + int ci_opcode; + int ci_oparg; + location ci_loc; +} codegen_instr; + +/* A write-only stream of instructions */ +typedef struct instr_stream_ { + codegen_instr *s_instrs; + int s_allocated; + int s_used; + + int *s_labelmap; + int s_labelmap_size; +} instr_stream; + typedef struct cfg_builder_ { /* The entryblock, at which control flow begins. All blocks of the CFG are reachable through the b_next links */ @@ -417,8 +433,120 @@ typedef struct cfg_builder_ { jump_target_label g_current_label; /* next free label id */ int g_next_free_label; + /* instruction stream */ + instr_stream g_instr_stream; + bool g_build_instr_stream; } cfg_builder; + +#define INITIAL_INSTR_STREAM_SIZE 100 +#define INITIAL_INSTR_STREAM_LABELS_MAP_SIZE 10 + +static int +instr_stream_next_inst(instr_stream *is) { + if (is->s_instrs == NULL) { + assert(is->s_allocated == 0); + assert(is->s_used == 0); + is->s_instrs = (codegen_instr *)PyObject_Calloc( + INITIAL_INSTR_STREAM_SIZE, sizeof(codegen_instr)); + if (is->s_instrs == NULL) { + return ERROR; + } + is->s_allocated = INITIAL_INSTR_STREAM_SIZE; + } + if (is->s_used == is->s_allocated) { + codegen_instr *tmp = (codegen_instr *)PyObject_Realloc( + is->s_instrs, 2 * is->s_allocated * sizeof(codegen_instr)); + if (tmp == NULL) { + return ERROR; + } + is->s_instrs = tmp; + is->s_allocated *= 2; + } + assert(is->s_used < is->s_allocated); + return is->s_used++; +} + +static int +instr_stream_add_label(instr_stream *is, int lbl) { + if (is->s_labelmap_size <= lbl) { + int old_size, new_size; + int *tmp = NULL; + if (is->s_labelmap == NULL) { + old_size = 0; + new_size = INITIAL_INSTR_STREAM_LABELS_MAP_SIZE; + if (new_size < 2 * lbl) { + new_size = 2 * lbl; + } + tmp = (int*)PyObject_Calloc(new_size, sizeof(int)); + } + else { + old_size = is->s_labelmap_size; + new_size = 2 * lbl; + tmp = (int*)PyObject_Realloc(is->s_labelmap, + new_size * sizeof(int)); + } + if (tmp == NULL) { + return ERROR; + } + for(int i = old_size; i < new_size; i++) { + tmp[i] = -111; /* something weird, for debugging */ + } + is->s_labelmap = tmp; + is->s_labelmap_size = new_size; + } + is->s_labelmap[lbl] = is->s_used; /* label refers to the next instruction */ + return SUCCESS; +} + +/* Replace jump target labels by the offset of the target instruction */ +static int +instr_stream_normalize_labels(instr_stream *is) { + /* replace jump target labels by offsets */ + for (int i=0; i < is->s_used; i++) { + if (HAS_TARGET(is->s_instrs[i].ci_opcode)) { + int lbl = is->s_instrs[i].ci_oparg; + assert(lbl >= 0 && lbl <= is->s_labelmap_size); + int offset = is->s_labelmap[lbl]; + assert(offset >= 0 && offset < is->s_used); + is->s_instrs[i].ci_oparg = offset; + } + } + return SUCCESS; +} + + +static int cfg_builder_use_label(cfg_builder *g, jump_target_label lbl); +static int cfg_builder_addop(cfg_builder *g, int opcode, int oparg, location loc); + +static int +instr_stream_to_cfg(instr_stream *is, cfg_builder *g) { + /* Note: there can be more than one label for the same offset */ +bool interesting = false; +for (int i=0; i < is->s_used; i++) { + codegen_instr *instr = &is->s_instrs[i]; + if (instr->ci_opcode == 257) { + //interesting = true; + //fprintf(stderr, "-----------------------\n"); + } +} + for (int i = 0; i < is->s_used; i++) { + for (int j=0; j < is->s_labelmap_size; j++) { + if (is->s_labelmap[j] == i) { + jump_target_label lbl = {j}; + RETURN_IF_ERROR(cfg_builder_use_label(g, lbl)); + } + } + codegen_instr *instr = &is->s_instrs[i]; +if (interesting) { + fprintf(stderr, "[%d] %d %d \n", i, instr->ci_opcode, instr->ci_oparg); +} + RETURN_IF_ERROR(cfg_builder_addop(g, instr->ci_opcode, instr->ci_oparg, instr->ci_loc)); + } + + return SUCCESS; +} + /* The following items change on entry and exit of code blocks. They must be saved and restored when returning to a block. */ @@ -446,6 +574,7 @@ struct compiler_unit { Py_ssize_t u_kwonlyargcount; /* number of keyword only arguments for block */ cfg_builder u_cfg_builder; /* The control flow graph */ + instr_stream u_inst_stream; int u_nfblocks; struct fblockinfo u_fblock[CO_MAXBLOCKS]; @@ -981,6 +1110,9 @@ cfg_builder_use_next_block(cfg_builder *g, basicblock *block) static int cfg_builder_use_label(cfg_builder *g, jump_target_label lbl) { + if (g->g_build_instr_stream) { + RETURN_IF_ERROR(instr_stream_add_label(&g->g_instr_stream, lbl.id)); + } g->g_current_label = lbl; return cfg_builder_maybe_start_new_block(g); } @@ -1200,11 +1332,56 @@ cfg_builder_maybe_start_new_block(cfg_builder *g) return SUCCESS; } +static int +instr_stream_addop(instr_stream *is, int opcode, int oparg, location loc) +{ + assert(IS_WITHIN_OPCODE_RANGE(opcode)); + assert(!IS_ASSEMBLER_OPCODE(opcode)); + assert(HAS_ARG(opcode) || HAS_TARGET(opcode) || oparg == 0); + assert(0 <= oparg && oparg < (1 << 30)); + + int idx = instr_stream_next_inst(is); + RETURN_IF_ERROR(idx); + codegen_instr *ci = &is->s_instrs[idx]; + ci->ci_opcode = opcode; + ci->ci_oparg = oparg; + ci->ci_loc = loc; + return SUCCESS; +} + +static int +instr_stream_insert_instruction(instr_stream *is, int pos, + int opcode, int oparg, location loc) +{ + assert(pos >= 0 && pos <= is->s_used); + int last_idx = instr_stream_next_inst(is); + RETURN_IF_ERROR(last_idx); + for (int i=last_idx-1; i >= pos; i--) { + is->s_instrs[i+1] = is->s_instrs[i]; + } + codegen_instr *ci = &is->s_instrs[pos]; + ci->ci_opcode = opcode; + ci->ci_oparg = oparg; + ci->ci_loc = loc; + + /* fix the labels map */ + for(int lbl=0; lbl < is->s_labelmap_size; lbl++) { + if (is->s_labelmap[lbl] >= pos) { + is->s_labelmap[lbl]++; + } + } + return SUCCESS; +} + static int cfg_builder_addop(cfg_builder *g, int opcode, int oparg, location loc) { + if (g->g_build_instr_stream ) { + RETURN_IF_ERROR(instr_stream_addop(&g->g_instr_stream, opcode, oparg, loc)); + } RETURN_IF_ERROR(cfg_builder_maybe_start_new_block(g)); - return basicblock_addop(g->g_curblock, opcode, oparg, loc); + int res = basicblock_addop(g->g_curblock, opcode, oparg, loc); + return res; } static int @@ -1614,6 +1791,7 @@ compiler_enter_scope(struct compiler *c, identifier name, cfg_builder *g = CFG_BUILDER(c); RETURN_IF_ERROR(cfg_builder_init(g)); + g->g_build_instr_stream = true; if (u->u_scope_type == COMPILER_SCOPE_MODULE) { loc.lineno = 0; @@ -2412,6 +2590,11 @@ wrap_in_stopiteration_handler(struct compiler *c) RETURN_IF_ERROR( insert_instruction(c->u->u_cfg_builder.g_entryblock, 0, &setup)); + RETURN_IF_ERROR( + instr_stream_insert_instruction( + &c->u->u_cfg_builder.g_instr_stream, 0, + SETUP_CLEANUP, handler.id, NO_LOCATION)); + ADDOP_LOAD_CONST(c, NO_LOCATION, Py_None); ADDOP(c, NO_LOCATION, RETURN_VALUE); USE_LABEL(c, handler); @@ -8102,7 +8285,6 @@ makecode(struct compiler *c, struct assembler *a, PyObject *constslist, PyObject *consts = NULL; PyObject *localsplusnames = NULL; PyObject *localspluskinds = NULL; - names = dict_keys_inorder(c->u->u_names, 0); if (!names) { goto error; @@ -8186,7 +8368,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) { @@ -8292,6 +8474,17 @@ insert_prefix_instructions(struct compiler *c, basicblock *entryblock, .i_target = NULL, }; RETURN_IF_ERROR(insert_instruction(entryblock, 1, &pop_top)); + + RETURN_IF_ERROR( + instr_stream_insert_instruction( + &c->u->u_cfg_builder.g_instr_stream, 0, + RETURN_GENERATOR, 0, + LOCATION(c->u->u_firstlineno, c->u->u_firstlineno, -1, -1))); + + RETURN_IF_ERROR( + instr_stream_insert_instruction( + &c->u->u_cfg_builder.g_instr_stream, 1, + POP_TOP, 0, NO_LOCATION)); } /* Set up cells for any variable that escapes, to be put in a closure. */ @@ -8322,6 +8515,11 @@ insert_prefix_instructions(struct compiler *c, basicblock *entryblock, .i_target = NULL, }; RETURN_IF_ERROR(insert_instruction(entryblock, ncellsused, &make_cell)); + RETURN_IF_ERROR( + instr_stream_insert_instruction( + &c->u->u_cfg_builder.g_instr_stream, ncellsused, + MAKE_CELL, oldindex, NO_LOCATION)); + ncellsused += 1; } PyMem_RawFree(sorted); @@ -8335,6 +8533,10 @@ insert_prefix_instructions(struct compiler *c, basicblock *entryblock, .i_target = NULL, }; RETURN_IF_ERROR(insert_instruction(entryblock, 0, ©_frees)); + RETURN_IF_ERROR( + instr_stream_insert_instruction( + &c->u->u_cfg_builder.g_instr_stream, 0, + COPY_FREE_VARS, nfreevars, NO_LOCATION)); } return SUCCESS; @@ -8511,7 +8713,7 @@ remove_redundant_jumps(cfg_builder *g) { } static int -prepare_localsplus(struct compiler* c, int code_flags) +prepare_localsplus(struct compiler* c, int code_flags, cfg_builder *newg) { assert(PyDict_GET_SIZE(c->u->u_varnames) < INT_MAX); assert(PyDict_GET_SIZE(c->u->u_cellvars) < INT_MAX); @@ -8526,6 +8728,10 @@ prepare_localsplus(struct compiler* c, int code_flags) if (cellfixedoffsets == NULL) { return ERROR; } + int* newcellfixedoffsets = build_cellfixedoffsets(c); + if (newcellfixedoffsets == NULL) { + return ERROR; + } cfg_builder* g = CFG_BUILDER(c); @@ -8534,6 +8740,10 @@ prepare_localsplus(struct compiler* c, int code_flags) PyMem_Free(cellfixedoffsets); return ERROR; } + if (insert_prefix_instructions(c, newg->g_entryblock, newcellfixedoffsets, nfreevars, code_flags)) { + PyMem_Free(newcellfixedoffsets); + return ERROR; + } int numdropped = fix_cell_offsets(c, g->g_entryblock, cellfixedoffsets); PyMem_Free(cellfixedoffsets); // At this point we're done with it. @@ -8541,6 +8751,11 @@ prepare_localsplus(struct compiler* c, int code_flags) if (numdropped < 0) { return ERROR; } + int newnumdropped = fix_cell_offsets(c, newg->g_entryblock, newcellfixedoffsets); + PyMem_Free(newcellfixedoffsets); // At this point we're done with it. + newcellfixedoffsets = NULL; + assert(newnumdropped == numdropped); + nlocalsplus -= numdropped; return nlocalsplus; } @@ -8563,6 +8778,8 @@ assemble(struct compiler *c, int addNone) { PyCodeObject *co = NULL; PyObject *consts = NULL; + PyObject *newconsts = NULL; + cfg_builder newg; struct assembler a; memset(&a, 0, sizeof(struct assembler)); @@ -8598,46 +8815,118 @@ assemble(struct compiler *c, int addNone) } /** Preprocessing **/ +// if (instr_stream_normalize_labels(&g->g_instr_stream) < 0) { +// goto error; +// } + memset(&newg, 0, sizeof(cfg_builder)); + if (cfg_builder_init(&newg) < 0) { + goto error; + } + newg.g_build_instr_stream = false; + if (instr_stream_to_cfg(&g->g_instr_stream, &newg) < 0) { + goto error; + } +#if 0 +//fprintf(stderr, "--------------- OLD ---------------\n"); +int is=0, bs = 0; +for(basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { +// dump_basicblock(b); + is += b->b_iused; + bs += 1; +} +//fprintf(stderr, "total: %d @ %d \n", is, bs); +//fprintf(stderr, "--------------- NEW ---------------\n"); +int newis=0, newbs = 0; +for(basicblock *b = newg.g_entryblock; b != NULL; b = b->b_next) { +// dump_basicblock(b); + newis += b->b_iused; + newbs += 1; +} +if (newbs != bs || newis != is) { + fprintf(stderr, "total: %d @ %d (%d @ %d) \n", newis, newbs, is, bs); +fprintf(stderr, "--------------- OLD ---------------\n"); +for(basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) dump_basicblock(b); +fprintf(stderr, "--------------- NEW ---------------\n"); +for(basicblock *b = newg.g_entryblock; b != NULL; b = b->b_next) dump_basicblock(b); + assert(newbs == bs); + assert(newis == is); +} +#endif /* Map labels to targets and mark exception handlers */ - if (translate_jump_labels_to_targets(g->g_entryblock)) { + if (translate_jump_labels_to_targets(g->g_entryblock) < 0) { + goto error; + } + if (translate_jump_labels_to_targets(newg.g_entryblock) < 0) { goto error; } if (mark_except_handlers(g->g_entryblock) < 0) { goto error; } + if (mark_except_handlers(newg.g_entryblock) < 0) { + goto error; + } + if (label_exception_targets(g->g_entryblock)) { goto error; } + if (label_exception_targets(newg.g_entryblock)) { + goto error; + } /** Optimization **/ consts = consts_dict_keys_inorder(c->u->u_consts); if (consts == NULL) { goto error; } + newconsts = consts_dict_keys_inorder(c->u->u_consts); + if (consts == NULL) { + goto error; + } if (optimize_cfg(g, consts, c->c_const_cache)) { goto error; } - if (add_checks_for_loads_of_uninitialized_variables(g->g_entryblock, c) < 0) { + if (optimize_cfg(&newg, newconsts, c->c_const_cache)) { goto error; } + if (remove_unused_consts(g->g_entryblock, consts) < 0) { goto error; } + if (remove_unused_consts(newg.g_entryblock, newconsts) < 0) { + goto error; + } + if (add_checks_for_loads_of_uninitialized_variables(g->g_entryblock, c) < 0) { + goto error; + } + if (add_checks_for_loads_of_uninitialized_variables(newg.g_entryblock, c) < 0) { + goto error; + } /** line numbers (TODO: move this before optimization stage) */ if (duplicate_exits_without_lineno(g) < 0) { goto error; } + + /** line numbers (TODO: move this before optimization stage) */ + if (duplicate_exits_without_lineno(&newg) < 0) { + goto error; + } + propagate_line_numbers(g->g_entryblock); + propagate_line_numbers(newg.g_entryblock); + guarantee_lineno_for_exits(g->g_entryblock, c->u->u_firstlineno); + guarantee_lineno_for_exits(newg.g_entryblock, c->u->u_firstlineno); if (push_cold_blocks_to_end(g, code_flags) < 0) { goto error; } + if (push_cold_blocks_to_end(&newg, code_flags) < 0) { + goto error; + } /** Assembly **/ - - int nlocalsplus = prepare_localsplus(c, code_flags); + int nlocalsplus = prepare_localsplus(c, code_flags, &newg); if (nlocalsplus < 0) { goto error; } @@ -8646,20 +8935,30 @@ assemble(struct compiler *c, int addNone) if (maxdepth < 0) { goto error; } + int newmaxdepth = stackdepth(newg.g_entryblock, code_flags); + assert(maxdepth == newmaxdepth); + /* TO DO -- For 3.12, make sure that `maxdepth <= MAX_ALLOWED_STACK_USE` */ convert_exception_handlers_to_nops(g->g_entryblock); + convert_exception_handlers_to_nops(newg.g_entryblock); /* Order of basic blocks must have been determined by now */ if (normalize_jumps(g) < 0) { goto error; } + if (normalize_jumps(&newg) < 0) { + goto error; + } assert(no_redundant_jumps(g)); assert(opcode_metadata_is_sane(g)); + assert(no_redundant_jumps(&newg)); + assert(opcode_metadata_is_sane(&newg)); /* Can't modify the bytecode after computing jump offsets. */ assemble_jump_offsets(g->g_entryblock); + assemble_jump_offsets(newg.g_entryblock); /* Create assembler */ if (assemble_init(&a, c->u->u_firstlineno) < 0) { @@ -8667,7 +8966,7 @@ assemble(struct compiler *c, int addNone) } /* Emit code. */ - for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { + for (basicblock *b = newg.g_entryblock; b != NULL; b = b->b_next) { for (int j = 0; j < b->b_iused; j++) { if (assemble_emit(&a, &b->b_instr[j]) < 0) { goto error; @@ -8722,6 +9021,8 @@ assemble(struct compiler *c, int addNone) co = makecode(c, &a, consts, maxdepth, nlocalsplus, code_flags); error: Py_XDECREF(consts); + Py_XDECREF(newconsts); + cfg_builder_fini(&newg); assemble_free(&a); return co; } @@ -9882,7 +10183,7 @@ _PyCompile_OptimizeCfg(PyObject *instructions, PyObject *consts) if (const_cache == NULL) { goto error; } - if (translate_jump_labels_to_targets(g.g_entryblock)) { + if (translate_jump_labels_to_targets(g.g_entryblock) < 0) { goto error; } if (optimize_cfg(&g, consts, const_cache) < 0) { From 2b43f88579514427f7f4a49d7996fa3a5d22bacc Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Sun, 26 Feb 2023 11:08:47 +0000 Subject: [PATCH 02/23] remove unused code --- Python/compile.c | 57 ------------------------------------------------ 1 file changed, 57 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index 58e495380401e7..ee2f1506ed9f7b 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -499,37 +499,12 @@ instr_stream_add_label(instr_stream *is, int lbl) { return SUCCESS; } -/* Replace jump target labels by the offset of the target instruction */ -static int -instr_stream_normalize_labels(instr_stream *is) { - /* replace jump target labels by offsets */ - for (int i=0; i < is->s_used; i++) { - if (HAS_TARGET(is->s_instrs[i].ci_opcode)) { - int lbl = is->s_instrs[i].ci_oparg; - assert(lbl >= 0 && lbl <= is->s_labelmap_size); - int offset = is->s_labelmap[lbl]; - assert(offset >= 0 && offset < is->s_used); - is->s_instrs[i].ci_oparg = offset; - } - } - return SUCCESS; -} - - static int cfg_builder_use_label(cfg_builder *g, jump_target_label lbl); static int cfg_builder_addop(cfg_builder *g, int opcode, int oparg, location loc); static int instr_stream_to_cfg(instr_stream *is, cfg_builder *g) { /* Note: there can be more than one label for the same offset */ -bool interesting = false; -for (int i=0; i < is->s_used; i++) { - codegen_instr *instr = &is->s_instrs[i]; - if (instr->ci_opcode == 257) { - //interesting = true; - //fprintf(stderr, "-----------------------\n"); - } -} for (int i = 0; i < is->s_used; i++) { for (int j=0; j < is->s_labelmap_size; j++) { if (is->s_labelmap[j] == i) { @@ -538,9 +513,6 @@ for (int i=0; i < is->s_used; i++) { } } codegen_instr *instr = &is->s_instrs[i]; -if (interesting) { - fprintf(stderr, "[%d] %d %d \n", i, instr->ci_opcode, instr->ci_oparg); -} RETURN_IF_ERROR(cfg_builder_addop(g, instr->ci_opcode, instr->ci_oparg, instr->ci_loc)); } @@ -8815,9 +8787,6 @@ assemble(struct compiler *c, int addNone) } /** Preprocessing **/ -// if (instr_stream_normalize_labels(&g->g_instr_stream) < 0) { -// goto error; -// } memset(&newg, 0, sizeof(cfg_builder)); if (cfg_builder_init(&newg) < 0) { goto error; @@ -8826,32 +8795,6 @@ assemble(struct compiler *c, int addNone) if (instr_stream_to_cfg(&g->g_instr_stream, &newg) < 0) { goto error; } -#if 0 -//fprintf(stderr, "--------------- OLD ---------------\n"); -int is=0, bs = 0; -for(basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { -// dump_basicblock(b); - is += b->b_iused; - bs += 1; -} -//fprintf(stderr, "total: %d @ %d \n", is, bs); -//fprintf(stderr, "--------------- NEW ---------------\n"); -int newis=0, newbs = 0; -for(basicblock *b = newg.g_entryblock; b != NULL; b = b->b_next) { -// dump_basicblock(b); - newis += b->b_iused; - newbs += 1; -} -if (newbs != bs || newis != is) { - fprintf(stderr, "total: %d @ %d (%d @ %d) \n", newis, newbs, is, bs); -fprintf(stderr, "--------------- OLD ---------------\n"); -for(basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) dump_basicblock(b); -fprintf(stderr, "--------------- NEW ---------------\n"); -for(basicblock *b = newg.g_entryblock; b != NULL; b = b->b_next) dump_basicblock(b); - assert(newbs == bs); - assert(newis == is); -} -#endif /* Map labels to targets and mark exception handlers */ if (translate_jump_labels_to_targets(g->g_entryblock) < 0) { goto error; From 52a1d1d089a5c95e964539c582a6df07dae6dddc Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Sun, 26 Feb 2023 11:30:08 +0000 Subject: [PATCH 03/23] use newg all the way --- Python/compile.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index ee2f1506ed9f7b..388b8394afe761 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -8921,7 +8921,7 @@ assemble(struct compiler *c, int addNone) a.a_lineno = c->u->u_firstlineno; location loc = NO_LOCATION; int size = 0; - for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { + for (basicblock *b = newg.g_entryblock; b != NULL; b = b->b_next) { for (int j = 0; j < b->b_iused; j++) { if (!same_location(loc, b->b_instr[j].i_loc)) { if (assemble_emit_location(&a, loc, size)) { @@ -8937,7 +8937,7 @@ assemble(struct compiler *c, int addNone) goto error; } - if (assemble_exception_table(&a, g->g_entryblock) < 0) { + if (assemble_exception_table(&a, newg.g_entryblock) < 0) { goto error; } if (_PyBytes_Resize(&a.a_except_table, a.a_except_table_off) < 0) { From 9b737f1d6e8abbeab6ce5a7db535908cc1d9b96a Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Sun, 26 Feb 2023 13:55:51 +0000 Subject: [PATCH 04/23] remove double processing --- Python/compile.c | 106 ++++++++++++++--------------------------------- 1 file changed, 32 insertions(+), 74 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index 388b8394afe761..ac53b1f2d5a80d 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -8696,37 +8696,37 @@ prepare_localsplus(struct compiler* c, int code_flags, cfg_builder *newg) assert(INT_MAX - nlocals - ncellvars > 0); assert(INT_MAX - nlocals - ncellvars - nfreevars > 0); int nlocalsplus = nlocals + ncellvars + nfreevars; - int* cellfixedoffsets = build_cellfixedoffsets(c); - if (cellfixedoffsets == NULL) { - return ERROR; - } +// int* cellfixedoffsets = build_cellfixedoffsets(c); +// if (cellfixedoffsets == NULL) { +// return ERROR; +// } int* newcellfixedoffsets = build_cellfixedoffsets(c); if (newcellfixedoffsets == NULL) { return ERROR; } - cfg_builder* g = CFG_BUILDER(c); +// cfg_builder* g = CFG_BUILDER(c); // This must be called before fix_cell_offsets(). - if (insert_prefix_instructions(c, g->g_entryblock, cellfixedoffsets, nfreevars, code_flags)) { - PyMem_Free(cellfixedoffsets); - return ERROR; - } +// if (insert_prefix_instructions(c, g->g_entryblock, cellfixedoffsets, nfreevars, code_flags)) { +// PyMem_Free(cellfixedoffsets); +// return ERROR; +// } if (insert_prefix_instructions(c, newg->g_entryblock, newcellfixedoffsets, nfreevars, code_flags)) { PyMem_Free(newcellfixedoffsets); return ERROR; } - int numdropped = fix_cell_offsets(c, g->g_entryblock, cellfixedoffsets); - PyMem_Free(cellfixedoffsets); // At this point we're done with it. - cellfixedoffsets = NULL; - if (numdropped < 0) { - return ERROR; - } +// int numdropped = fix_cell_offsets(c, g->g_entryblock, cellfixedoffsets); +// PyMem_Free(cellfixedoffsets); // At this point we're done with it. +// cellfixedoffsets = NULL; +// if (numdropped < 0) { +// return ERROR; +// } int newnumdropped = fix_cell_offsets(c, newg->g_entryblock, newcellfixedoffsets); PyMem_Free(newcellfixedoffsets); // At this point we're done with it. newcellfixedoffsets = NULL; - assert(newnumdropped == numdropped); + int numdropped = newnumdropped; nlocalsplus -= numdropped; return nlocalsplus; @@ -8764,8 +8764,20 @@ assemble(struct compiler *c, int addNone) return NULL; } + /** Preprocessing **/ + memset(&newg, 0, sizeof(cfg_builder)); + if (cfg_builder_init(&newg) < 0) { + goto error; + } + newg.g_build_instr_stream = false; + if (instr_stream_to_cfg(&CFG_BUILDER(c)->g_instr_stream, &newg) < 0) { + goto error; + } + + cfg_builder *g = &newg; int nblocks = 0; - for (basicblock *b = CFG_BUILDER(c)->g_block_list; b != NULL; b = b->b_list) { + + for (basicblock *b = g->g_block_list; b != NULL; b = b->b_list) { nblocks++; } if ((size_t)nblocks > SIZE_MAX / sizeof(basicblock *)) { @@ -8773,9 +8785,6 @@ assemble(struct compiler *c, int addNone) goto error; } - cfg_builder *g = CFG_BUILDER(c); - assert(g->g_entryblock != NULL); - /* Set firstlineno if it wasn't explicitly set. */ if (!c->u->u_firstlineno) { if (g->g_entryblock->b_instr && g->g_entryblock->b_instr->i_loc.lineno) { @@ -8786,87 +8795,46 @@ assemble(struct compiler *c, int addNone) } } - /** Preprocessing **/ - memset(&newg, 0, sizeof(cfg_builder)); - if (cfg_builder_init(&newg) < 0) { - goto error; - } - newg.g_build_instr_stream = false; - if (instr_stream_to_cfg(&g->g_instr_stream, &newg) < 0) { - goto error; - } /* Map labels to targets and mark exception handlers */ if (translate_jump_labels_to_targets(g->g_entryblock) < 0) { goto error; } - if (translate_jump_labels_to_targets(newg.g_entryblock) < 0) { - goto error; - } if (mark_except_handlers(g->g_entryblock) < 0) { goto error; } - if (mark_except_handlers(newg.g_entryblock) < 0) { - goto error; - } if (label_exception_targets(g->g_entryblock)) { goto error; } - if (label_exception_targets(newg.g_entryblock)) { - goto error; - } /** Optimization **/ consts = consts_dict_keys_inorder(c->u->u_consts); if (consts == NULL) { goto error; } - newconsts = consts_dict_keys_inorder(c->u->u_consts); - if (consts == NULL) { - goto error; - } if (optimize_cfg(g, consts, c->c_const_cache)) { goto error; } - if (optimize_cfg(&newg, newconsts, c->c_const_cache)) { - goto error; - } if (remove_unused_consts(g->g_entryblock, consts) < 0) { goto error; } - if (remove_unused_consts(newg.g_entryblock, newconsts) < 0) { - goto error; - } if (add_checks_for_loads_of_uninitialized_variables(g->g_entryblock, c) < 0) { goto error; } - if (add_checks_for_loads_of_uninitialized_variables(newg.g_entryblock, c) < 0) { - goto error; - } /** line numbers (TODO: move this before optimization stage) */ if (duplicate_exits_without_lineno(g) < 0) { goto error; } - /** line numbers (TODO: move this before optimization stage) */ - if (duplicate_exits_without_lineno(&newg) < 0) { - goto error; - } - propagate_line_numbers(g->g_entryblock); - propagate_line_numbers(newg.g_entryblock); guarantee_lineno_for_exits(g->g_entryblock, c->u->u_firstlineno); - guarantee_lineno_for_exits(newg.g_entryblock, c->u->u_firstlineno); if (push_cold_blocks_to_end(g, code_flags) < 0) { goto error; } - if (push_cold_blocks_to_end(&newg, code_flags) < 0) { - goto error; - } /** Assembly **/ int nlocalsplus = prepare_localsplus(c, code_flags, &newg); @@ -8878,30 +8846,20 @@ assemble(struct compiler *c, int addNone) if (maxdepth < 0) { goto error; } - int newmaxdepth = stackdepth(newg.g_entryblock, code_flags); - assert(maxdepth == newmaxdepth); /* TO DO -- For 3.12, make sure that `maxdepth <= MAX_ALLOWED_STACK_USE` */ convert_exception_handlers_to_nops(g->g_entryblock); - convert_exception_handlers_to_nops(newg.g_entryblock); /* Order of basic blocks must have been determined by now */ if (normalize_jumps(g) < 0) { goto error; } - - if (normalize_jumps(&newg) < 0) { - goto error; - } assert(no_redundant_jumps(g)); assert(opcode_metadata_is_sane(g)); - assert(no_redundant_jumps(&newg)); - assert(opcode_metadata_is_sane(&newg)); /* Can't modify the bytecode after computing jump offsets. */ assemble_jump_offsets(g->g_entryblock); - assemble_jump_offsets(newg.g_entryblock); /* Create assembler */ if (assemble_init(&a, c->u->u_firstlineno) < 0) { @@ -8909,7 +8867,7 @@ assemble(struct compiler *c, int addNone) } /* Emit code. */ - for (basicblock *b = newg.g_entryblock; b != NULL; b = b->b_next) { + for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { for (int j = 0; j < b->b_iused; j++) { if (assemble_emit(&a, &b->b_instr[j]) < 0) { goto error; @@ -8921,7 +8879,7 @@ assemble(struct compiler *c, int addNone) a.a_lineno = c->u->u_firstlineno; location loc = NO_LOCATION; int size = 0; - for (basicblock *b = newg.g_entryblock; b != NULL; b = b->b_next) { + for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { for (int j = 0; j < b->b_iused; j++) { if (!same_location(loc, b->b_instr[j].i_loc)) { if (assemble_emit_location(&a, loc, size)) { @@ -8937,7 +8895,7 @@ assemble(struct compiler *c, int addNone) goto error; } - if (assemble_exception_table(&a, newg.g_entryblock) < 0) { + if (assemble_exception_table(&a, g->g_entryblock) < 0) { goto error; } if (_PyBytes_Resize(&a.a_except_table, a.a_except_table_off) < 0) { From 083b8b17371b7e4246913fb1e93044e17537cfcc Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Sun, 26 Feb 2023 23:43:23 +0000 Subject: [PATCH 05/23] split cfg_builder_use_label/cfg_builder_addop to separate versions for codegen and cfg_builder --- Python/compile.c | 129 +++++++++++++++++++++++------------------------ 1 file changed, 62 insertions(+), 67 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index ac53b1f2d5a80d..2a87b49ffef5d8 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -181,7 +181,7 @@ static struct jump_target_label_ NO_LABEL = {-1}; } #define USE_LABEL(C, LBL) \ - RETURN_IF_ERROR(cfg_builder_use_label(CFG_BUILDER(C), LBL)) + RETURN_IF_ERROR(codegen_use_label(CFG_BUILDER(C), LBL)) struct instr { int i_opcode; @@ -435,7 +435,6 @@ typedef struct cfg_builder_ { int g_next_free_label; /* instruction stream */ instr_stream g_instr_stream; - bool g_build_instr_stream; } cfg_builder; @@ -499,8 +498,24 @@ instr_stream_add_label(instr_stream *is, int lbl) { return SUCCESS; } -static int cfg_builder_use_label(cfg_builder *g, jump_target_label lbl); -static int cfg_builder_addop(cfg_builder *g, int opcode, int oparg, location loc); +static int cfg_builder_maybe_start_new_block(cfg_builder *g); +static int instr_stream_addop(instr_stream *is, int opcode, int oparg, location loc); +static int basicblock_addop(basicblock *b, int opcode, int oparg, location loc); + +static int +cfg_builder_use_label(cfg_builder *g, jump_target_label lbl) +{ + g->g_current_label = lbl; + return cfg_builder_maybe_start_new_block(g); +} + +static int +cfg_builder_addop(cfg_builder *g, int opcode, int oparg, location loc) +{ + RETURN_IF_ERROR(cfg_builder_maybe_start_new_block(g)); + int res = basicblock_addop(g->g_curblock, opcode, oparg, loc); + return res; +} static int instr_stream_to_cfg(instr_stream *is, cfg_builder *g) { @@ -613,8 +628,7 @@ typedef struct { static int basicblock_next_instr(basicblock *); static basicblock *cfg_builder_new_block(cfg_builder *g); -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, location loc); +static int codegen_addop_i(cfg_builder *g, int opcode, Py_ssize_t oparg, location loc); static void compiler_free(struct compiler *); static int compiler_error(struct compiler *, location loc, const char *, ...); @@ -1080,13 +1094,10 @@ cfg_builder_use_next_block(cfg_builder *g, basicblock *block) } static int -cfg_builder_use_label(cfg_builder *g, jump_target_label lbl) +codegen_use_label(cfg_builder *g, jump_target_label lbl) { - if (g->g_build_instr_stream) { - RETURN_IF_ERROR(instr_stream_add_label(&g->g_instr_stream, lbl.id)); - } - g->g_current_label = lbl; - return cfg_builder_maybe_start_new_block(g); + RETURN_IF_ERROR(instr_stream_add_label(&g->g_instr_stream, lbl.id)); + return SUCCESS; } static inline int @@ -1346,21 +1357,17 @@ instr_stream_insert_instruction(instr_stream *is, int pos, } static int -cfg_builder_addop(cfg_builder *g, int opcode, int oparg, location loc) +codegen_addop(cfg_builder *g, int opcode, int oparg, location loc) { - if (g->g_build_instr_stream ) { - RETURN_IF_ERROR(instr_stream_addop(&g->g_instr_stream, opcode, oparg, loc)); - } - RETURN_IF_ERROR(cfg_builder_maybe_start_new_block(g)); - int res = basicblock_addop(g->g_curblock, opcode, oparg, loc); - return res; + RETURN_IF_ERROR(instr_stream_addop(&g->g_instr_stream, opcode, oparg, loc)); + return SUCCESS; } static int -cfg_builder_addop_noarg(cfg_builder *g, int opcode, location loc) +codegen_addop_noarg(cfg_builder *g, int opcode, location loc) { assert(!HAS_ARG(opcode)); - return cfg_builder_addop(g, opcode, 0, loc); + return codegen_addop(g, opcode, 0, loc); } static Py_ssize_t @@ -1518,7 +1525,7 @@ compiler_addop_load_const(struct compiler *c, location loc, PyObject *o) if (arg < 0) { return ERROR; } - return cfg_builder_addop_i(CFG_BUILDER(c), LOAD_CONST, arg, loc); + return codegen_addop_i(CFG_BUILDER(c), LOAD_CONST, arg, loc); } static int @@ -1529,7 +1536,7 @@ compiler_addop_o(struct compiler *c, location loc, if (arg < 0) { return ERROR; } - return cfg_builder_addop_i(CFG_BUILDER(c), opcode, arg, loc); + return codegen_addop_i(CFG_BUILDER(c), opcode, arg, loc); } static int @@ -1555,12 +1562,12 @@ compiler_addop_name(struct compiler *c, location loc, arg <<= 1; arg |= 1; } - return cfg_builder_addop_i(CFG_BUILDER(c), opcode, arg, loc); + return codegen_addop_i(CFG_BUILDER(c), opcode, arg, loc); } /* Add an opcode with an integer argument */ static int -cfg_builder_addop_i(cfg_builder *g, int opcode, Py_ssize_t oparg, location loc) +codegen_addop_i(cfg_builder *g, int opcode, Py_ssize_t oparg, location loc) { /* oparg value is unsigned, but a signed C int is usually used to store it in the C code (like Python/ceval.c). @@ -1571,23 +1578,23 @@ cfg_builder_addop_i(cfg_builder *g, int opcode, Py_ssize_t oparg, location loc) 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_, loc); + return codegen_addop(g, opcode, oparg_, loc); } static int -cfg_builder_addop_j(cfg_builder *g, location loc, +codegen_addop_j(cfg_builder *g, location loc, int opcode, jump_target_label target) { assert(IS_LABEL(target)); assert(IS_JUMP_OPCODE(opcode) || IS_BLOCK_PUSH_OPCODE(opcode)); - return cfg_builder_addop(g, opcode, target.id, loc); + return codegen_addop(g, opcode, target.id, loc); } #define ADDOP(C, LOC, OP) \ - RETURN_IF_ERROR(cfg_builder_addop_noarg(CFG_BUILDER(C), (OP), (LOC))) + RETURN_IF_ERROR(codegen_addop_noarg(CFG_BUILDER(C), (OP), (LOC))) #define ADDOP_IN_SCOPE(C, LOC, OP) { \ - if (cfg_builder_addop_noarg(CFG_BUILDER(C), (OP), (LOC)) < 0) { \ + if (codegen_addop_noarg(CFG_BUILDER(C), (OP), (LOC)) < 0) { \ compiler_exit_scope(C); \ return ERROR; \ } \ @@ -1622,10 +1629,10 @@ cfg_builder_addop_j(cfg_builder *g, location loc, RETURN_IF_ERROR(compiler_addop_name((C), (LOC), (OP), (C)->u->u_ ## TYPE, (O))) #define ADDOP_I(C, LOC, OP, O) \ - RETURN_IF_ERROR(cfg_builder_addop_i(CFG_BUILDER(C), (OP), (O), (LOC))) + RETURN_IF_ERROR(codegen_addop_i(CFG_BUILDER(C), (OP), (O), (LOC))) #define ADDOP_JUMP(C, LOC, OP, O) \ - RETURN_IF_ERROR(cfg_builder_addop_j(CFG_BUILDER(C), (LOC), (OP), (O))) + RETURN_IF_ERROR(codegen_addop_j(CFG_BUILDER(C), (LOC), (OP), (O))) #define ADDOP_COMPARE(C, LOC, CMP) \ RETURN_IF_ERROR(compiler_addcompare((C), (LOC), (cmpop_ty)(CMP))) @@ -1763,7 +1770,6 @@ compiler_enter_scope(struct compiler *c, identifier name, cfg_builder *g = CFG_BUILDER(c); RETURN_IF_ERROR(cfg_builder_init(g)); - g->g_build_instr_stream = true; if (u->u_scope_type == COMPILER_SCOPE_MODULE) { loc.lineno = 0; @@ -4254,7 +4260,7 @@ compiler_nameop(struct compiler *c, location loc, if (op == LOAD_GLOBAL) { arg <<= 1; } - return cfg_builder_addop_i(CFG_BUILDER(c), op, arg, loc); + return codegen_addop_i(CFG_BUILDER(c), op, arg, loc); } static int @@ -6273,7 +6279,7 @@ emit_and_reset_fail_pop(struct compiler *c, location loc, } while (--pc->fail_pop_size) { USE_LABEL(c, pc->fail_pop[pc->fail_pop_size]); - if (cfg_builder_addop_noarg(CFG_BUILDER(c), POP_TOP, loc) < 0) { + if (codegen_addop_noarg(CFG_BUILDER(c), POP_TOP, loc) < 0) { pc->fail_pop_size = 0; PyObject_Free(pc->fail_pop); pc->fail_pop = NULL; @@ -6713,7 +6719,7 @@ compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc) pc->fail_pop = NULL; pc->fail_pop_size = 0; pc->on_top = 0; - if (cfg_builder_addop_i(CFG_BUILDER(c), COPY, 1, LOC(alt)) < 0 || + if (codegen_addop_i(CFG_BUILDER(c), COPY, 1, LOC(alt)) < 0 || compiler_pattern(c, alt, pc) < 0) { goto error; } @@ -6776,7 +6782,7 @@ compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc) } } assert(control); - if (cfg_builder_addop_j(CFG_BUILDER(c), LOC(alt), JUMP, end) < 0 || + if (codegen_addop_j(CFG_BUILDER(c), LOC(alt), JUMP, end) < 0 || emit_and_reset_fail_pop(c, LOC(alt), pc) < 0) { goto error; @@ -6788,7 +6794,7 @@ compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc) // Need to NULL this for the PyObject_Free call in the error block. old_pc.fail_pop = NULL; // No match. Pop the remaining copy of the subject and fail: - if (cfg_builder_addop_noarg(CFG_BUILDER(c), POP_TOP, LOC(p)) < 0 || + if (codegen_addop_noarg(CFG_BUILDER(c), POP_TOP, LOC(p)) < 0 || jump_to_fail_pop(c, LOC(p), pc, JUMP) < 0) { goto error; } @@ -8696,37 +8702,21 @@ prepare_localsplus(struct compiler* c, int code_flags, cfg_builder *newg) assert(INT_MAX - nlocals - ncellvars > 0); assert(INT_MAX - nlocals - ncellvars - nfreevars > 0); int nlocalsplus = nlocals + ncellvars + nfreevars; -// int* cellfixedoffsets = build_cellfixedoffsets(c); -// if (cellfixedoffsets == NULL) { -// return ERROR; -// } - int* newcellfixedoffsets = build_cellfixedoffsets(c); - if (newcellfixedoffsets == NULL) { + int* cellfixedoffsets = build_cellfixedoffsets(c); + if (cellfixedoffsets == NULL) { return ERROR; - } + } -// cfg_builder* g = CFG_BUILDER(c); // This must be called before fix_cell_offsets(). -// if (insert_prefix_instructions(c, g->g_entryblock, cellfixedoffsets, nfreevars, code_flags)) { -// PyMem_Free(cellfixedoffsets); -// return ERROR; -// } - if (insert_prefix_instructions(c, newg->g_entryblock, newcellfixedoffsets, nfreevars, code_flags)) { - PyMem_Free(newcellfixedoffsets); + if (insert_prefix_instructions(c, newg->g_entryblock, cellfixedoffsets, nfreevars, code_flags)) { + PyMem_Free(cellfixedoffsets); return ERROR; } -// int numdropped = fix_cell_offsets(c, g->g_entryblock, cellfixedoffsets); -// PyMem_Free(cellfixedoffsets); // At this point we're done with it. -// cellfixedoffsets = NULL; -// if (numdropped < 0) { -// return ERROR; -// } - int newnumdropped = fix_cell_offsets(c, newg->g_entryblock, newcellfixedoffsets); - PyMem_Free(newcellfixedoffsets); // At this point we're done with it. - newcellfixedoffsets = NULL; - int numdropped = newnumdropped; + int numdropped = fix_cell_offsets(c, newg->g_entryblock, cellfixedoffsets); + PyMem_Free(cellfixedoffsets); // At this point we're done with it. + cellfixedoffsets = NULL; nlocalsplus -= numdropped; return nlocalsplus; @@ -8769,7 +8759,6 @@ assemble(struct compiler *c, int addNone) if (cfg_builder_init(&newg) < 0) { goto error; } - newg.g_build_instr_stream = false; if (instr_stream_to_cfg(&CFG_BUILDER(c)->g_instr_stream, &newg) < 0) { goto error; } @@ -10052,13 +10041,19 @@ _PyCompile_CodeGen(PyObject *ast, PyObject *filename, PyCompilerFlags *pflags, goto finally; } - cfg_builder *g = CFG_BUILDER(c); - - if (translate_jump_labels_to_targets(g->g_entryblock) < 0) { + cfg_builder g; + memset(&g, 0, sizeof(cfg_builder)); + if (cfg_builder_init(&g) < 0) { + goto finally; + } + if (instr_stream_to_cfg(&CFG_BUILDER(c)->g_instr_stream, &g) < 0) { + goto finally; + } + if (translate_jump_labels_to_targets(g.g_entryblock) < 0) { goto finally; } - res = cfg_to_instructions(g); + res = cfg_to_instructions(&g); finally: compiler_exit_scope(c); From a56bafed32cf18778bb03f6ec803a5499c7af08e Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Mon, 27 Feb 2023 11:19:46 +0000 Subject: [PATCH 06/23] codegen functions take an instr_stream --- Python/compile.c | 63 ++++++++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index 2a87b49ffef5d8..2b6a6bf984be58 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -181,7 +181,7 @@ static struct jump_target_label_ NO_LABEL = {-1}; } #define USE_LABEL(C, LBL) \ - RETURN_IF_ERROR(codegen_use_label(CFG_BUILDER(C), LBL)) + RETURN_IF_ERROR(codegen_use_label(INSTR_STREAM(C), LBL)) struct instr { int i_opcode; @@ -598,6 +598,7 @@ struct compiler { }; #define CFG_BUILDER(C) (&((C)->u->u_cfg_builder)) +#define INSTR_STREAM(C) (&((C)->u->u_cfg_builder.g_instr_stream)) typedef struct { @@ -628,7 +629,7 @@ typedef struct { static int basicblock_next_instr(basicblock *); static basicblock *cfg_builder_new_block(cfg_builder *g); -static int codegen_addop_i(cfg_builder *g, int opcode, Py_ssize_t oparg, location loc); +static int codegen_addop_i(instr_stream *is, int opcode, Py_ssize_t oparg, location loc); static void compiler_free(struct compiler *); static int compiler_error(struct compiler *, location loc, const char *, ...); @@ -1094,9 +1095,9 @@ cfg_builder_use_next_block(cfg_builder *g, basicblock *block) } static int -codegen_use_label(cfg_builder *g, jump_target_label lbl) +codegen_use_label(instr_stream *is, jump_target_label lbl) { - RETURN_IF_ERROR(instr_stream_add_label(&g->g_instr_stream, lbl.id)); + RETURN_IF_ERROR(instr_stream_add_label(is, lbl.id)); return SUCCESS; } @@ -1357,17 +1358,17 @@ instr_stream_insert_instruction(instr_stream *is, int pos, } static int -codegen_addop(cfg_builder *g, int opcode, int oparg, location loc) +codegen_addop(instr_stream *is, int opcode, int oparg, location loc) { - RETURN_IF_ERROR(instr_stream_addop(&g->g_instr_stream, opcode, oparg, loc)); + RETURN_IF_ERROR(instr_stream_addop(is, opcode, oparg, loc)); return SUCCESS; } static int -codegen_addop_noarg(cfg_builder *g, int opcode, location loc) +codegen_addop_noarg(instr_stream *is, int opcode, location loc) { assert(!HAS_ARG(opcode)); - return codegen_addop(g, opcode, 0, loc); + return codegen_addop(is, opcode, 0, loc); } static Py_ssize_t @@ -1525,7 +1526,7 @@ compiler_addop_load_const(struct compiler *c, location loc, PyObject *o) if (arg < 0) { return ERROR; } - return codegen_addop_i(CFG_BUILDER(c), LOAD_CONST, arg, loc); + return codegen_addop_i(INSTR_STREAM(c), LOAD_CONST, arg, loc); } static int @@ -1536,7 +1537,7 @@ compiler_addop_o(struct compiler *c, location loc, if (arg < 0) { return ERROR; } - return codegen_addop_i(CFG_BUILDER(c), opcode, arg, loc); + return codegen_addop_i(INSTR_STREAM(c), opcode, arg, loc); } static int @@ -1562,12 +1563,12 @@ compiler_addop_name(struct compiler *c, location loc, arg <<= 1; arg |= 1; } - return codegen_addop_i(CFG_BUILDER(c), opcode, arg, loc); + return codegen_addop_i(INSTR_STREAM(c), opcode, arg, loc); } /* Add an opcode with an integer argument */ static int -codegen_addop_i(cfg_builder *g, int opcode, Py_ssize_t oparg, location loc) +codegen_addop_i(instr_stream *is, int opcode, Py_ssize_t oparg, location loc) { /* oparg value is unsigned, but a signed C int is usually used to store it in the C code (like Python/ceval.c). @@ -1578,23 +1579,23 @@ codegen_addop_i(cfg_builder *g, int opcode, Py_ssize_t oparg, location loc) EXTENDED_ARG is used for 16, 24, and 32-bit arguments. */ int oparg_ = Py_SAFE_DOWNCAST(oparg, Py_ssize_t, int); - return codegen_addop(g, opcode, oparg_, loc); + return codegen_addop(is, opcode, oparg_, loc); } static int -codegen_addop_j(cfg_builder *g, location loc, +codegen_addop_j(instr_stream *is, location loc, int opcode, jump_target_label target) { assert(IS_LABEL(target)); assert(IS_JUMP_OPCODE(opcode) || IS_BLOCK_PUSH_OPCODE(opcode)); - return codegen_addop(g, opcode, target.id, loc); + return codegen_addop(is, opcode, target.id, loc); } #define ADDOP(C, LOC, OP) \ - RETURN_IF_ERROR(codegen_addop_noarg(CFG_BUILDER(C), (OP), (LOC))) + RETURN_IF_ERROR(codegen_addop_noarg(INSTR_STREAM(C), (OP), (LOC))) #define ADDOP_IN_SCOPE(C, LOC, OP) { \ - if (codegen_addop_noarg(CFG_BUILDER(C), (OP), (LOC)) < 0) { \ + if (codegen_addop_noarg(INSTR_STREAM(C), (OP), (LOC)) < 0) { \ compiler_exit_scope(C); \ return ERROR; \ } \ @@ -1629,10 +1630,10 @@ codegen_addop_j(cfg_builder *g, location loc, RETURN_IF_ERROR(compiler_addop_name((C), (LOC), (OP), (C)->u->u_ ## TYPE, (O))) #define ADDOP_I(C, LOC, OP, O) \ - RETURN_IF_ERROR(codegen_addop_i(CFG_BUILDER(C), (OP), (O), (LOC))) + RETURN_IF_ERROR(codegen_addop_i(INSTR_STREAM(C), (OP), (O), (LOC))) #define ADDOP_JUMP(C, LOC, OP, O) \ - RETURN_IF_ERROR(codegen_addop_j(CFG_BUILDER(C), (LOC), (OP), (O))) + RETURN_IF_ERROR(codegen_addop_j(INSTR_STREAM(C), (LOC), (OP), (O))) #define ADDOP_COMPARE(C, LOC, CMP) \ RETURN_IF_ERROR(compiler_addcompare((C), (LOC), (cmpop_ty)(CMP))) @@ -2570,7 +2571,7 @@ wrap_in_stopiteration_handler(struct compiler *c) RETURN_IF_ERROR( instr_stream_insert_instruction( - &c->u->u_cfg_builder.g_instr_stream, 0, + INSTR_STREAM(c), 0, SETUP_CLEANUP, handler.id, NO_LOCATION)); ADDOP_LOAD_CONST(c, NO_LOCATION, Py_None); @@ -4260,7 +4261,7 @@ compiler_nameop(struct compiler *c, location loc, if (op == LOAD_GLOBAL) { arg <<= 1; } - return codegen_addop_i(CFG_BUILDER(c), op, arg, loc); + return codegen_addop_i(INSTR_STREAM(c), op, arg, loc); } static int @@ -6279,7 +6280,7 @@ emit_and_reset_fail_pop(struct compiler *c, location loc, } while (--pc->fail_pop_size) { USE_LABEL(c, pc->fail_pop[pc->fail_pop_size]); - if (codegen_addop_noarg(CFG_BUILDER(c), POP_TOP, loc) < 0) { + if (codegen_addop_noarg(INSTR_STREAM(c), POP_TOP, loc) < 0) { pc->fail_pop_size = 0; PyObject_Free(pc->fail_pop); pc->fail_pop = NULL; @@ -6719,7 +6720,7 @@ compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc) pc->fail_pop = NULL; pc->fail_pop_size = 0; pc->on_top = 0; - if (codegen_addop_i(CFG_BUILDER(c), COPY, 1, LOC(alt)) < 0 || + if (codegen_addop_i(INSTR_STREAM(c), COPY, 1, LOC(alt)) < 0 || compiler_pattern(c, alt, pc) < 0) { goto error; } @@ -6782,7 +6783,7 @@ compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc) } } assert(control); - if (codegen_addop_j(CFG_BUILDER(c), LOC(alt), JUMP, end) < 0 || + if (codegen_addop_j(INSTR_STREAM(c), LOC(alt), JUMP, end) < 0 || emit_and_reset_fail_pop(c, LOC(alt), pc) < 0) { goto error; @@ -6794,7 +6795,7 @@ compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc) // Need to NULL this for the PyObject_Free call in the error block. old_pc.fail_pop = NULL; // No match. Pop the remaining copy of the subject and fail: - if (codegen_addop_noarg(CFG_BUILDER(c), POP_TOP, LOC(p)) < 0 || + if (codegen_addop_noarg(INSTR_STREAM(c), POP_TOP, LOC(p)) < 0 || jump_to_fail_pop(c, LOC(p), pc, JUMP) < 0) { goto error; } @@ -8455,13 +8456,13 @@ insert_prefix_instructions(struct compiler *c, basicblock *entryblock, RETURN_IF_ERROR( instr_stream_insert_instruction( - &c->u->u_cfg_builder.g_instr_stream, 0, + INSTR_STREAM(c), 0, RETURN_GENERATOR, 0, LOCATION(c->u->u_firstlineno, c->u->u_firstlineno, -1, -1))); RETURN_IF_ERROR( instr_stream_insert_instruction( - &c->u->u_cfg_builder.g_instr_stream, 1, + INSTR_STREAM(c), 1, POP_TOP, 0, NO_LOCATION)); } @@ -8495,7 +8496,7 @@ insert_prefix_instructions(struct compiler *c, basicblock *entryblock, RETURN_IF_ERROR(insert_instruction(entryblock, ncellsused, &make_cell)); RETURN_IF_ERROR( instr_stream_insert_instruction( - &c->u->u_cfg_builder.g_instr_stream, ncellsused, + INSTR_STREAM(c), ncellsused, MAKE_CELL, oldindex, NO_LOCATION)); ncellsused += 1; @@ -8513,7 +8514,7 @@ insert_prefix_instructions(struct compiler *c, basicblock *entryblock, RETURN_IF_ERROR(insert_instruction(entryblock, 0, ©_frees)); RETURN_IF_ERROR( instr_stream_insert_instruction( - &c->u->u_cfg_builder.g_instr_stream, 0, + INSTR_STREAM(c), 0, COPY_FREE_VARS, nfreevars, NO_LOCATION)); } @@ -8759,7 +8760,7 @@ assemble(struct compiler *c, int addNone) if (cfg_builder_init(&newg) < 0) { goto error; } - if (instr_stream_to_cfg(&CFG_BUILDER(c)->g_instr_stream, &newg) < 0) { + if (instr_stream_to_cfg(INSTR_STREAM(c), &newg) < 0) { goto error; } @@ -10046,7 +10047,7 @@ _PyCompile_CodeGen(PyObject *ast, PyObject *filename, PyCompilerFlags *pflags, if (cfg_builder_init(&g) < 0) { goto finally; } - if (instr_stream_to_cfg(&CFG_BUILDER(c)->g_instr_stream, &g) < 0) { + if (instr_stream_to_cfg(INSTR_STREAM(c), &g) < 0) { goto finally; } if (translate_jump_labels_to_targets(g.g_entryblock) < 0) { From 8be1b288861acd639514b89f1a2f138ae32240e0 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Mon, 27 Feb 2023 11:54:09 +0000 Subject: [PATCH 07/23] free isntr_stream. Attach it to compiluer_unit (not cfg_builder) --- Python/compile.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index 2b6a6bf984be58..969bfd1b917a6f 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -433,8 +433,6 @@ typedef struct cfg_builder_ { jump_target_label g_current_label; /* next free label id */ int g_next_free_label; - /* instruction stream */ - instr_stream g_instr_stream; } cfg_builder; @@ -517,6 +515,15 @@ cfg_builder_addop(cfg_builder *g, int opcode, int oparg, location loc) return res; } +static void +instr_stream_fini(instr_stream *is) { + PyObject_Free(is->s_labelmap); + is->s_labelmap = NULL; + + PyObject_Free(is->s_instrs); + is->s_instrs = NULL; +} + static int instr_stream_to_cfg(instr_stream *is, cfg_builder *g) { /* Note: there can be more than one label for the same offset */ @@ -560,8 +567,8 @@ struct compiler_unit { Py_ssize_t u_posonlyargcount; /* number of positional only arguments for block */ Py_ssize_t u_kwonlyargcount; /* number of keyword only arguments for block */ + instr_stream u_instr_stream; /* codegen output */ cfg_builder u_cfg_builder; /* The control flow graph */ - instr_stream u_inst_stream; int u_nfblocks; struct fblockinfo u_fblock[CO_MAXBLOCKS]; @@ -598,7 +605,7 @@ struct compiler { }; #define CFG_BUILDER(C) (&((C)->u->u_cfg_builder)) -#define INSTR_STREAM(C) (&((C)->u->u_cfg_builder.g_instr_stream)) +#define INSTR_STREAM(C) (&((C)->u->u_instr_stream)) typedef struct { @@ -974,6 +981,7 @@ cfg_builder_fini(cfg_builder* g) static void compiler_unit_free(struct compiler_unit *u) { + instr_stream_fini(&u->u_instr_stream); cfg_builder_fini(&u->u_cfg_builder); Py_CLEAR(u->u_ste); Py_CLEAR(u->u_name); From 741f77367f0ea1c68fb315ba5754972a27fe1a82 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Mon, 27 Feb 2023 13:46:27 +0000 Subject: [PATCH 08/23] move things around --- Python/compile.c | 164 +++++++++++++++++++++-------------------------- 1 file changed, 73 insertions(+), 91 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index 969bfd1b917a6f..bf6cf24a1488a9 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -181,7 +181,7 @@ static struct jump_target_label_ NO_LABEL = {-1}; } #define USE_LABEL(C, LBL) \ - RETURN_IF_ERROR(codegen_use_label(INSTR_STREAM(C), LBL)) + RETURN_IF_ERROR(instr_stream_add_label(INSTR_STREAM(C), (LBL).id)) struct instr { int i_opcode; @@ -404,22 +404,6 @@ enum { COMPILER_SCOPE_COMPREHENSION, }; -typedef struct codegen_instr_ { - int ci_opcode; - int ci_oparg; - location ci_loc; -} codegen_instr; - -/* A write-only stream of instructions */ -typedef struct instr_stream_ { - codegen_instr *s_instrs; - int s_allocated; - int s_used; - - int *s_labelmap; - int s_labelmap_size; -} instr_stream; - typedef struct cfg_builder_ { /* The entryblock, at which control flow begins. All blocks of the CFG are reachable through the b_next links */ @@ -435,6 +419,21 @@ typedef struct cfg_builder_ { int g_next_free_label; } cfg_builder; +typedef struct codegen_instr_ { + int ci_opcode; + int ci_oparg; + location ci_loc; +} codegen_instr; + +/* A write-only stream of instructions */ +typedef struct instr_stream_ { + codegen_instr *s_instrs; + int s_allocated; + int s_used; + + int *s_labelmap; + int s_labelmap_size; +} instr_stream; #define INITIAL_INSTR_STREAM_SIZE 100 #define INITIAL_INSTR_STREAM_LABELS_MAP_SIZE 10 @@ -496,23 +495,45 @@ instr_stream_add_label(instr_stream *is, int lbl) { return SUCCESS; } -static int cfg_builder_maybe_start_new_block(cfg_builder *g); -static int instr_stream_addop(instr_stream *is, int opcode, int oparg, location loc); -static int basicblock_addop(basicblock *b, int opcode, int oparg, location loc); - static int -cfg_builder_use_label(cfg_builder *g, jump_target_label lbl) +instr_stream_addop(instr_stream *is, int opcode, int oparg, location loc) { - g->g_current_label = lbl; - return cfg_builder_maybe_start_new_block(g); + assert(IS_WITHIN_OPCODE_RANGE(opcode)); + assert(!IS_ASSEMBLER_OPCODE(opcode)); + assert(HAS_ARG(opcode) || HAS_TARGET(opcode) || oparg == 0); + assert(0 <= oparg && oparg < (1 << 30)); + + int idx = instr_stream_next_inst(is); + RETURN_IF_ERROR(idx); + codegen_instr *ci = &is->s_instrs[idx]; + ci->ci_opcode = opcode; + ci->ci_oparg = oparg; + ci->ci_loc = loc; + return SUCCESS; } static int -cfg_builder_addop(cfg_builder *g, int opcode, int oparg, location loc) +instr_stream_insert_instruction(instr_stream *is, int pos, + int opcode, int oparg, location loc) { - RETURN_IF_ERROR(cfg_builder_maybe_start_new_block(g)); - int res = basicblock_addop(g->g_curblock, opcode, oparg, loc); - return res; + assert(pos >= 0 && pos <= is->s_used); + int last_idx = instr_stream_next_inst(is); + RETURN_IF_ERROR(last_idx); + for (int i=last_idx-1; i >= pos; i--) { + is->s_instrs[i+1] = is->s_instrs[i]; + } + codegen_instr *ci = &is->s_instrs[pos]; + ci->ci_opcode = opcode; + ci->ci_oparg = oparg; + ci->ci_loc = loc; + + /* fix the labels map */ + for(int lbl=0; lbl < is->s_labelmap_size; lbl++) { + if (is->s_labelmap[lbl] >= pos) { + is->s_labelmap[lbl]++; + } + } + return SUCCESS; } static void @@ -524,6 +545,23 @@ instr_stream_fini(instr_stream *is) { is->s_instrs = NULL; } +static int basicblock_addop(basicblock *b, int opcode, int oparg, location loc); +static int cfg_builder_maybe_start_new_block(cfg_builder *g); + +static int +cfg_builder_use_label(cfg_builder *g, jump_target_label lbl) +{ + g->g_current_label = lbl; + return cfg_builder_maybe_start_new_block(g); +} + +static int +cfg_builder_addop(cfg_builder *g, int opcode, int oparg, location loc) +{ + RETURN_IF_ERROR(cfg_builder_maybe_start_new_block(g)); + return basicblock_addop(g->g_curblock, opcode, oparg, loc); +} + static int instr_stream_to_cfg(instr_stream *is, cfg_builder *g) { /* Note: there can be more than one label for the same offset */ @@ -537,10 +575,10 @@ instr_stream_to_cfg(instr_stream *is, cfg_builder *g) { codegen_instr *instr = &is->s_instrs[i]; RETURN_IF_ERROR(cfg_builder_addop(g, instr->ci_opcode, instr->ci_oparg, instr->ci_loc)); } - return SUCCESS; } + /* The following items change on entry and exit of code blocks. They must be saved and restored when returning to a block. */ @@ -635,7 +673,6 @@ typedef struct { static int basicblock_next_instr(basicblock *); -static basicblock *cfg_builder_new_block(cfg_builder *g); static int codegen_addop_i(instr_stream *is, int opcode, Py_ssize_t oparg, location loc); static void compiler_free(struct compiler *); @@ -950,6 +987,8 @@ cfg_builder_check(cfg_builder *g) } } +static basicblock *cfg_builder_new_block(cfg_builder *g); + static int cfg_builder_init(cfg_builder *g) { @@ -1102,13 +1141,6 @@ cfg_builder_use_next_block(cfg_builder *g, basicblock *block) return block; } -static int -codegen_use_label(instr_stream *is, jump_target_label lbl) -{ - RETURN_IF_ERROR(instr_stream_add_label(is, lbl.id)); - return SUCCESS; -} - static inline int basicblock_append_instructions(basicblock *target, basicblock *source) { @@ -1324,59 +1356,11 @@ cfg_builder_maybe_start_new_block(cfg_builder *g) return SUCCESS; } -static int -instr_stream_addop(instr_stream *is, int opcode, int oparg, location loc) -{ - assert(IS_WITHIN_OPCODE_RANGE(opcode)); - assert(!IS_ASSEMBLER_OPCODE(opcode)); - assert(HAS_ARG(opcode) || HAS_TARGET(opcode) || oparg == 0); - assert(0 <= oparg && oparg < (1 << 30)); - - int idx = instr_stream_next_inst(is); - RETURN_IF_ERROR(idx); - codegen_instr *ci = &is->s_instrs[idx]; - ci->ci_opcode = opcode; - ci->ci_oparg = oparg; - ci->ci_loc = loc; - return SUCCESS; -} - -static int -instr_stream_insert_instruction(instr_stream *is, int pos, - int opcode, int oparg, location loc) -{ - assert(pos >= 0 && pos <= is->s_used); - int last_idx = instr_stream_next_inst(is); - RETURN_IF_ERROR(last_idx); - for (int i=last_idx-1; i >= pos; i--) { - is->s_instrs[i+1] = is->s_instrs[i]; - } - codegen_instr *ci = &is->s_instrs[pos]; - ci->ci_opcode = opcode; - ci->ci_oparg = oparg; - ci->ci_loc = loc; - - /* fix the labels map */ - for(int lbl=0; lbl < is->s_labelmap_size; lbl++) { - if (is->s_labelmap[lbl] >= pos) { - is->s_labelmap[lbl]++; - } - } - return SUCCESS; -} - -static int -codegen_addop(instr_stream *is, int opcode, int oparg, location loc) -{ - RETURN_IF_ERROR(instr_stream_addop(is, opcode, oparg, loc)); - return SUCCESS; -} - static int codegen_addop_noarg(instr_stream *is, int opcode, location loc) { assert(!HAS_ARG(opcode)); - return codegen_addop(is, opcode, 0, loc); + return instr_stream_addop(is, opcode, 0, loc); } static Py_ssize_t @@ -1587,7 +1571,7 @@ codegen_addop_i(instr_stream *is, int opcode, Py_ssize_t oparg, location loc) EXTENDED_ARG is used for 16, 24, and 32-bit arguments. */ int oparg_ = Py_SAFE_DOWNCAST(oparg, Py_ssize_t, int); - return codegen_addop(is, opcode, oparg_, loc); + return instr_stream_addop(is, opcode, oparg_, loc); } static int @@ -1596,7 +1580,7 @@ codegen_addop_j(instr_stream *is, location loc, { assert(IS_LABEL(target)); assert(IS_JUMP_OPCODE(opcode) || IS_BLOCK_PUSH_OPCODE(opcode)); - return codegen_addop(is, opcode, target.id, loc); + return instr_stream_addop(is, opcode, target.id, loc); } #define ADDOP(C, LOC, OP) \ @@ -8355,7 +8339,7 @@ makecode(struct compiler *c, struct assembler *a, PyObject *constslist, /* For debugging purposes only */ -#if 1 +#if 0 static void dump_instr(struct instr *i) { @@ -8749,7 +8733,6 @@ assemble(struct compiler *c, int addNone) { PyCodeObject *co = NULL; PyObject *consts = NULL; - PyObject *newconsts = NULL; cfg_builder newg; struct assembler a; memset(&a, 0, sizeof(struct assembler)); @@ -8920,7 +8903,6 @@ assemble(struct compiler *c, int addNone) co = makecode(c, &a, consts, maxdepth, nlocalsplus, code_flags); error: Py_XDECREF(consts); - Py_XDECREF(newconsts); cfg_builder_fini(&newg); assemble_free(&a); return co; From fb0752503c25bcd7d2294d034f2adfc16448198c Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Mon, 27 Feb 2023 15:10:17 +0000 Subject: [PATCH 09/23] labels generated by instr_stream instead of cfg_builder --- Python/compile.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index bf6cf24a1488a9..9421a89b145b9b 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -175,13 +175,13 @@ static struct jump_target_label_ NO_LABEL = {-1}; #define IS_LABEL(L) (!SAME_LABEL((L), (NO_LABEL))) #define NEW_JUMP_TARGET_LABEL(C, NAME) \ - jump_target_label NAME = cfg_new_label(CFG_BUILDER(C)); \ + jump_target_label NAME = instr_stream_new_label(INSTR_STREAM(C)); \ if (!IS_LABEL(NAME)) { \ return ERROR; \ } #define USE_LABEL(C, LBL) \ - RETURN_IF_ERROR(instr_stream_add_label(INSTR_STREAM(C), (LBL).id)) + RETURN_IF_ERROR(instr_stream_use_label(INSTR_STREAM(C), (LBL).id)) struct instr { int i_opcode; @@ -415,8 +415,6 @@ typedef struct cfg_builder_ { basicblock *g_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; typedef struct codegen_instr_ { @@ -431,8 +429,10 @@ typedef struct instr_stream_ { int s_allocated; int s_used; - int *s_labelmap; + int *s_labelmap; /* label id --> instr offset */ int s_labelmap_size; + int s_next_free_label; /* next free label id */ + } instr_stream; #define INITIAL_INSTR_STREAM_SIZE 100 @@ -463,8 +463,15 @@ instr_stream_next_inst(instr_stream *is) { return is->s_used++; } +static jump_target_label +instr_stream_new_label(instr_stream *is) +{ + jump_target_label lbl = {is->s_next_free_label++}; + return lbl; +} + static int -instr_stream_add_label(instr_stream *is, int lbl) { +instr_stream_use_label(instr_stream *is, int lbl) { if (is->s_labelmap_size <= lbl) { int old_size, new_size; int *tmp = NULL; @@ -970,7 +977,7 @@ dictbytype(PyObject *src, int scope_type, int flag, Py_ssize_t offset) return dest; } -static void +static int cfg_builder_check(cfg_builder *g) { for (basicblock *block = g->g_block_list; block != NULL; block = block->b_list) { @@ -985,6 +992,7 @@ cfg_builder_check(cfg_builder *g) assert (block->b_ialloc == 0); } } + return SUCCESS; } static basicblock *cfg_builder_new_block(cfg_builder *g); @@ -1107,13 +1115,6 @@ compiler_set_qualname(struct compiler *c) return SUCCESS; } -static jump_target_label -cfg_new_label(cfg_builder *g) -{ - jump_target_label lbl = {g->g_next_free_label++}; - return lbl; -} - /* Allocate a new block and return a pointer to it. Returns NULL on error. */ @@ -8758,6 +8759,8 @@ assemble(struct compiler *c, int addNone) cfg_builder *g = &newg; int nblocks = 0; + //assert(cfg_builder_check(g)); + for (basicblock *b = g->g_block_list; b != NULL; b = b->b_list) { nblocks++; } From 1b06bf873325e476fdb2616a02726119716837d5 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Mon, 27 Feb 2023 20:34:32 +0000 Subject: [PATCH 10/23] add implicit RETURN NONE to the stream --- Python/compile.c | 67 ++++++++++++++++-------------------------------- 1 file changed, 22 insertions(+), 45 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index 9421a89b145b9b..09ecf4c14e19f9 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -352,12 +352,6 @@ basicblock_last_instr(const basicblock *b) { return NULL; } -static inline int -basicblock_returns(const basicblock *b) { - struct instr *last = basicblock_last_instr(b); - return last && (last->i_opcode == RETURN_VALUE || last->i_opcode == RETURN_CONST); -} - static inline int basicblock_exits_scope(const basicblock *b) { struct instr *last = basicblock_last_instr(b); @@ -977,7 +971,7 @@ dictbytype(PyObject *src, int scope_type, int flag, Py_ssize_t offset) return dest; } -static int +static bool cfg_builder_check(cfg_builder *g) { for (basicblock *block = g->g_block_list; block != NULL; block = block->b_list) { @@ -992,7 +986,7 @@ cfg_builder_check(cfg_builder *g) assert (block->b_ialloc == 0); } } - return SUCCESS; + return true; } static basicblock *cfg_builder_new_block(cfg_builder *g); @@ -2553,15 +2547,6 @@ wrap_in_stopiteration_handler(struct compiler *c) NEW_JUMP_TARGET_LABEL(c, handler); /* Insert SETUP_CLEANUP at start */ - struct instr setup = { - .i_opcode = SETUP_CLEANUP, - .i_oparg = handler.id, - .i_loc = NO_LOCATION, - .i_target = NULL, - }; - RETURN_IF_ERROR( - insert_instruction(c->u->u_cfg_builder.g_entryblock, 0, &setup)); - RETURN_IF_ERROR( instr_stream_insert_instruction( INSTR_STREAM(c), 0, @@ -8360,6 +8345,12 @@ dump_instr(struct instr *i) i->i_loc.lineno, i->i_opcode, arg, jabs, jrel); } +static inline int +basicblock_returns(const basicblock *b) { + struct instr *last = basicblock_last_instr(b); + return last && (last->i_opcode == RETURN_VALUE || last->i_opcode == RETURN_CONST); +} + static void dump_basicblock(const basicblock *b) { @@ -8446,17 +8437,6 @@ insert_prefix_instructions(struct compiler *c, basicblock *entryblock, .i_target = NULL, }; RETURN_IF_ERROR(insert_instruction(entryblock, 1, &pop_top)); - - RETURN_IF_ERROR( - instr_stream_insert_instruction( - INSTR_STREAM(c), 0, - RETURN_GENERATOR, 0, - LOCATION(c->u->u_firstlineno, c->u->u_firstlineno, -1, -1))); - - RETURN_IF_ERROR( - instr_stream_insert_instruction( - INSTR_STREAM(c), 1, - POP_TOP, 0, NO_LOCATION)); } /* Set up cells for any variable that escapes, to be put in a closure. */ @@ -8487,11 +8467,6 @@ insert_prefix_instructions(struct compiler *c, basicblock *entryblock, .i_target = NULL, }; RETURN_IF_ERROR(insert_instruction(entryblock, ncellsused, &make_cell)); - RETURN_IF_ERROR( - instr_stream_insert_instruction( - INSTR_STREAM(c), ncellsused, - MAKE_CELL, oldindex, NO_LOCATION)); - ncellsused += 1; } PyMem_RawFree(sorted); @@ -8505,10 +8480,6 @@ insert_prefix_instructions(struct compiler *c, basicblock *entryblock, .i_target = NULL, }; RETURN_IF_ERROR(insert_instruction(entryblock, 0, ©_frees)); - RETURN_IF_ERROR( - instr_stream_insert_instruction( - INSTR_STREAM(c), 0, - COPY_FREE_VARS, nfreevars, NO_LOCATION)); } return SUCCESS; @@ -8717,15 +8688,21 @@ prepare_localsplus(struct compiler* c, int code_flags, cfg_builder *newg) } static int -add_return_at_end_of_block(struct compiler *c, int addNone) +add_return_at_end(struct compiler *c, int addNone) { - /* Make sure every block that falls off the end returns None. */ - if (!basicblock_returns(CFG_BUILDER(c)->g_curblock)) { - if (addNone) { - ADDOP_LOAD_CONST(c, NO_LOCATION, Py_None); + /* Make sure every instruction stream that falls off the end returns None. */ + instr_stream *is = INSTR_STREAM(c); + if (is->s_used > 0) { + codegen_instr *instr = &is->s_instrs[is->s_used]; + int opcode = instr->ci_opcode; + if (opcode == RETURN_VALUE || opcode == RETURN_CONST) { + return SUCCESS; } - ADDOP(c, NO_LOCATION, RETURN_VALUE); } + if (addNone) { + ADDOP_LOAD_CONST(c, NO_LOCATION, Py_None); + } + ADDOP(c, NO_LOCATION, RETURN_VALUE); return SUCCESS; } @@ -8743,7 +8720,7 @@ assemble(struct compiler *c, int addNone) return NULL; } - if (add_return_at_end_of_block(c, addNone) < 0) { + if (add_return_at_end(c, addNone) < 0) { return NULL; } @@ -8759,7 +8736,7 @@ assemble(struct compiler *c, int addNone) cfg_builder *g = &newg; int nblocks = 0; - //assert(cfg_builder_check(g)); + assert(cfg_builder_check(g)); for (basicblock *b = g->g_block_list; b != NULL; b = b->b_list) { nblocks++; From 142a7f14129bb40195bf65f1a1738b8b4f61724d Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Mon, 27 Feb 2023 21:04:41 +0000 Subject: [PATCH 11/23] remove u_cfg_builder --- Python/compile.c | 33 ++++++++++++--------------------- 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index 09ecf4c14e19f9..79fd11658a9013 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -607,7 +607,6 @@ struct compiler_unit { Py_ssize_t u_kwonlyargcount; /* number of keyword only arguments for block */ instr_stream u_instr_stream; /* codegen output */ - cfg_builder u_cfg_builder; /* The control flow graph */ int u_nfblocks; struct fblockinfo u_fblock[CO_MAXBLOCKS]; @@ -643,7 +642,6 @@ struct compiler { PyArena *c_arena; /* pointer to memory allocation arena */ }; -#define CFG_BUILDER(C) (&((C)->u->u_cfg_builder)) #define INSTR_STREAM(C) (&((C)->u->u_instr_stream)) @@ -1007,7 +1005,7 @@ cfg_builder_init(cfg_builder *g) static void cfg_builder_fini(cfg_builder* g) { - cfg_builder_check(g); + assert(cfg_builder_check(g)); basicblock *b = g->g_block_list; while (b != NULL) { if (b->b_instr) { @@ -1023,7 +1021,6 @@ static void compiler_unit_free(struct compiler_unit *u) { instr_stream_fini(&u->u_instr_stream); - cfg_builder_fini(&u->u_cfg_builder); Py_CLEAR(u->u_ste); Py_CLEAR(u->u_name); Py_CLEAR(u->u_qualname); @@ -1756,9 +1753,6 @@ compiler_enter_scope(struct compiler *c, identifier name, c->c_nestlevel++; - cfg_builder *g = CFG_BUILDER(c); - RETURN_IF_ERROR(cfg_builder_init(g)); - if (u->u_scope_type == COMPILER_SCOPE_MODULE) { loc.lineno = 0; } @@ -1793,7 +1787,6 @@ compiler_exit_scope(struct compiler *c) _PyErr_WriteUnraisableMsg("on removing the last compiler " "stack item", NULL); } - cfg_builder_check(CFG_BUILDER(c)); } else { c->u = NULL; @@ -8656,7 +8649,7 @@ remove_redundant_jumps(cfg_builder *g) { } static int -prepare_localsplus(struct compiler* c, int code_flags, cfg_builder *newg) +prepare_localsplus(struct compiler* c, cfg_builder *g, int code_flags) { assert(PyDict_GET_SIZE(c->u->u_varnames) < INT_MAX); assert(PyDict_GET_SIZE(c->u->u_cellvars) < INT_MAX); @@ -8674,12 +8667,12 @@ prepare_localsplus(struct compiler* c, int code_flags, cfg_builder *newg) // This must be called before fix_cell_offsets(). - if (insert_prefix_instructions(c, newg->g_entryblock, cellfixedoffsets, nfreevars, code_flags)) { + if (insert_prefix_instructions(c, g->g_entryblock, cellfixedoffsets, nfreevars, code_flags)) { PyMem_Free(cellfixedoffsets); return ERROR; } - int numdropped = fix_cell_offsets(c, newg->g_entryblock, cellfixedoffsets); + int numdropped = fix_cell_offsets(c, g->g_entryblock, cellfixedoffsets); PyMem_Free(cellfixedoffsets); // At this point we're done with it. cellfixedoffsets = NULL; @@ -8711,7 +8704,8 @@ assemble(struct compiler *c, int addNone) { PyCodeObject *co = NULL; PyObject *consts = NULL; - cfg_builder newg; + cfg_builder g_; + cfg_builder *g = &g_; struct assembler a; memset(&a, 0, sizeof(struct assembler)); @@ -8725,19 +8719,16 @@ assemble(struct compiler *c, int addNone) } /** Preprocessing **/ - memset(&newg, 0, sizeof(cfg_builder)); - if (cfg_builder_init(&newg) < 0) { + memset(g, 0, sizeof(cfg_builder)); + if (cfg_builder_init(g) < 0) { goto error; } - if (instr_stream_to_cfg(INSTR_STREAM(c), &newg) < 0) { + if (instr_stream_to_cfg(INSTR_STREAM(c), g) < 0) { goto error; } - - cfg_builder *g = &newg; - int nblocks = 0; - assert(cfg_builder_check(g)); + int nblocks = 0; for (basicblock *b = g->g_block_list; b != NULL; b = b->b_list) { nblocks++; } @@ -8798,7 +8789,7 @@ assemble(struct compiler *c, int addNone) } /** Assembly **/ - int nlocalsplus = prepare_localsplus(c, code_flags, &newg); + int nlocalsplus = prepare_localsplus(c, g, code_flags); if (nlocalsplus < 0) { goto error; } @@ -8883,7 +8874,7 @@ assemble(struct compiler *c, int addNone) co = makecode(c, &a, consts, maxdepth, nlocalsplus, code_flags); error: Py_XDECREF(consts); - cfg_builder_fini(&newg); + cfg_builder_fini(g); assemble_free(&a); return co; } From f9f844342b87fc00f5a007964dd18950921401e0 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Mon, 27 Feb 2023 21:27:28 +0000 Subject: [PATCH 12/23] init the cfg_builder in instr_stream_to_cfg --- Python/compile.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index 79fd11658a9013..f1dc8457c46f52 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -426,7 +426,6 @@ typedef struct instr_stream_ { int *s_labelmap; /* label id --> instr offset */ int s_labelmap_size; int s_next_free_label; /* next free label id */ - } instr_stream; #define INITIAL_INSTR_STREAM_SIZE 100 @@ -563,8 +562,12 @@ cfg_builder_addop(cfg_builder *g, int opcode, int oparg, location loc) return basicblock_addop(g->g_curblock, opcode, oparg, loc); } +static int cfg_builder_init(cfg_builder *g); + static int instr_stream_to_cfg(instr_stream *is, cfg_builder *g) { + memset(g, 0, sizeof(cfg_builder)); + RETURN_IF_ERROR(cfg_builder_init(g)); /* Note: there can be more than one label for the same offset */ for (int i = 0; i < is->s_used; i++) { for (int j=0; j < is->s_labelmap_size; j++) { @@ -8675,6 +8678,9 @@ prepare_localsplus(struct compiler* c, cfg_builder *g, int code_flags) int numdropped = fix_cell_offsets(c, g->g_entryblock, cellfixedoffsets); PyMem_Free(cellfixedoffsets); // At this point we're done with it. cellfixedoffsets = NULL; + if (numdropped < 0) { + return ERROR; + } nlocalsplus -= numdropped; return nlocalsplus; @@ -8719,10 +8725,6 @@ assemble(struct compiler *c, int addNone) } /** Preprocessing **/ - memset(g, 0, sizeof(cfg_builder)); - if (cfg_builder_init(g) < 0) { - goto error; - } if (instr_stream_to_cfg(INSTR_STREAM(c), g) < 0) { goto error; } @@ -8754,7 +8756,6 @@ assemble(struct compiler *c, int addNone) if (mark_except_handlers(g->g_entryblock) < 0) { goto error; } - if (label_exception_targets(g->g_entryblock)) { goto error; } @@ -8767,7 +8768,6 @@ assemble(struct compiler *c, int addNone) if (optimize_cfg(g, consts, c->c_const_cache)) { goto error; } - if (remove_unused_consts(g->g_entryblock, consts) < 0) { goto error; } @@ -8779,9 +8779,7 @@ assemble(struct compiler *c, int addNone) if (duplicate_exits_without_lineno(g) < 0) { goto error; } - propagate_line_numbers(g->g_entryblock); - guarantee_lineno_for_exits(g->g_entryblock, c->u->u_firstlineno); if (push_cold_blocks_to_end(g, code_flags) < 0) { @@ -8789,6 +8787,7 @@ assemble(struct compiler *c, int addNone) } /** Assembly **/ + int nlocalsplus = prepare_localsplus(c, g, code_flags); if (nlocalsplus < 0) { goto error; @@ -8798,7 +8797,6 @@ assemble(struct compiler *c, int addNone) if (maxdepth < 0) { goto error; } - /* TO DO -- For 3.12, make sure that `maxdepth <= MAX_ALLOWED_STACK_USE` */ convert_exception_handlers_to_nops(g->g_entryblock); @@ -10004,10 +10002,6 @@ _PyCompile_CodeGen(PyObject *ast, PyObject *filename, PyCompilerFlags *pflags, } cfg_builder g; - memset(&g, 0, sizeof(cfg_builder)); - if (cfg_builder_init(&g) < 0) { - goto finally; - } if (instr_stream_to_cfg(INSTR_STREAM(c), &g) < 0) { goto finally; } From f6fcde97e448ddd0ce1b6723cd83f5a230691913 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Tue, 28 Feb 2023 10:30:18 +0000 Subject: [PATCH 13/23] stream->sequence --- Python/compile.c | 126 +++++++++++++++++++++++------------------------ 1 file changed, 63 insertions(+), 63 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index f1dc8457c46f52..4eedc05b91c8c6 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -175,13 +175,13 @@ static struct jump_target_label_ NO_LABEL = {-1}; #define IS_LABEL(L) (!SAME_LABEL((L), (NO_LABEL))) #define NEW_JUMP_TARGET_LABEL(C, NAME) \ - jump_target_label NAME = instr_stream_new_label(INSTR_STREAM(C)); \ + jump_target_label NAME = instr_sequence_new_label(INSTR_STREAM(C)); \ if (!IS_LABEL(NAME)) { \ return ERROR; \ } #define USE_LABEL(C, LBL) \ - RETURN_IF_ERROR(instr_stream_use_label(INSTR_STREAM(C), (LBL).id)) + RETURN_IF_ERROR(instr_sequence_use_label(INSTR_STREAM(C), (LBL).id)) struct instr { int i_opcode; @@ -418,7 +418,7 @@ typedef struct codegen_instr_ { } codegen_instr; /* A write-only stream of instructions */ -typedef struct instr_stream_ { +typedef struct instr_sequence_ { codegen_instr *s_instrs; int s_allocated; int s_used; @@ -426,49 +426,49 @@ typedef struct instr_stream_ { int *s_labelmap; /* label id --> instr offset */ int s_labelmap_size; int s_next_free_label; /* next free label id */ -} instr_stream; +} instr_sequence; #define INITIAL_INSTR_STREAM_SIZE 100 #define INITIAL_INSTR_STREAM_LABELS_MAP_SIZE 10 static int -instr_stream_next_inst(instr_stream *is) { - if (is->s_instrs == NULL) { - assert(is->s_allocated == 0); - assert(is->s_used == 0); - is->s_instrs = (codegen_instr *)PyObject_Calloc( +instr_sequence_next_inst(instr_sequence *seq) { + if (seq->s_instrs == NULL) { + assert(seq->s_allocated == 0); + assert(seq->s_used == 0); + seq->s_instrs = (codegen_instr *)PyObject_Calloc( INITIAL_INSTR_STREAM_SIZE, sizeof(codegen_instr)); - if (is->s_instrs == NULL) { + if (seq->s_instrs == NULL) { return ERROR; } - is->s_allocated = INITIAL_INSTR_STREAM_SIZE; + seq->s_allocated = INITIAL_INSTR_STREAM_SIZE; } - if (is->s_used == is->s_allocated) { + if (seq->s_used == seq->s_allocated) { codegen_instr *tmp = (codegen_instr *)PyObject_Realloc( - is->s_instrs, 2 * is->s_allocated * sizeof(codegen_instr)); + seq->s_instrs, 2 * seq->s_allocated * sizeof(codegen_instr)); if (tmp == NULL) { return ERROR; } - is->s_instrs = tmp; - is->s_allocated *= 2; + seq->s_instrs = tmp; + seq->s_allocated *= 2; } - assert(is->s_used < is->s_allocated); - return is->s_used++; + assert(seq->s_used < seq->s_allocated); + return seq->s_used++; } static jump_target_label -instr_stream_new_label(instr_stream *is) +instr_sequence_new_label(instr_sequence *seq) { - jump_target_label lbl = {is->s_next_free_label++}; + jump_target_label lbl = {seq->s_next_free_label++}; return lbl; } static int -instr_stream_use_label(instr_stream *is, int lbl) { - if (is->s_labelmap_size <= lbl) { +instr_sequence_use_label(instr_sequence *seq, int lbl) { + if (seq->s_labelmap_size <= lbl) { int old_size, new_size; int *tmp = NULL; - if (is->s_labelmap == NULL) { + if (seq->s_labelmap == NULL) { old_size = 0; new_size = INITIAL_INSTR_STREAM_LABELS_MAP_SIZE; if (new_size < 2 * lbl) { @@ -477,9 +477,9 @@ instr_stream_use_label(instr_stream *is, int lbl) { tmp = (int*)PyObject_Calloc(new_size, sizeof(int)); } else { - old_size = is->s_labelmap_size; + old_size = seq->s_labelmap_size; new_size = 2 * lbl; - tmp = (int*)PyObject_Realloc(is->s_labelmap, + tmp = (int*)PyObject_Realloc(seq->s_labelmap, new_size * sizeof(int)); } if (tmp == NULL) { @@ -488,24 +488,24 @@ instr_stream_use_label(instr_stream *is, int lbl) { for(int i = old_size; i < new_size; i++) { tmp[i] = -111; /* something weird, for debugging */ } - is->s_labelmap = tmp; - is->s_labelmap_size = new_size; + seq->s_labelmap = tmp; + seq->s_labelmap_size = new_size; } - is->s_labelmap[lbl] = is->s_used; /* label refers to the next instruction */ + seq->s_labelmap[lbl] = seq->s_used; /* label refers to the next instruction */ return SUCCESS; } static int -instr_stream_addop(instr_stream *is, int opcode, int oparg, location loc) +instr_sequence_addop(instr_sequence *seq, int opcode, int oparg, location loc) { assert(IS_WITHIN_OPCODE_RANGE(opcode)); assert(!IS_ASSEMBLER_OPCODE(opcode)); assert(HAS_ARG(opcode) || HAS_TARGET(opcode) || oparg == 0); assert(0 <= oparg && oparg < (1 << 30)); - int idx = instr_stream_next_inst(is); + int idx = instr_sequence_next_inst(seq); RETURN_IF_ERROR(idx); - codegen_instr *ci = &is->s_instrs[idx]; + codegen_instr *ci = &seq->s_instrs[idx]; ci->ci_opcode = opcode; ci->ci_oparg = oparg; ci->ci_loc = loc; @@ -513,36 +513,36 @@ instr_stream_addop(instr_stream *is, int opcode, int oparg, location loc) } static int -instr_stream_insert_instruction(instr_stream *is, int pos, - int opcode, int oparg, location loc) +instr_sequence_insert_instruction(instr_sequence *seq, int pos, + int opcode, int oparg, location loc) { - assert(pos >= 0 && pos <= is->s_used); - int last_idx = instr_stream_next_inst(is); + assert(pos >= 0 && pos <= seq->s_used); + int last_idx = instr_sequence_next_inst(seq); RETURN_IF_ERROR(last_idx); for (int i=last_idx-1; i >= pos; i--) { - is->s_instrs[i+1] = is->s_instrs[i]; + seq->s_instrs[i+1] = seq->s_instrs[i]; } - codegen_instr *ci = &is->s_instrs[pos]; + codegen_instr *ci = &seq->s_instrs[pos]; ci->ci_opcode = opcode; ci->ci_oparg = oparg; ci->ci_loc = loc; /* fix the labels map */ - for(int lbl=0; lbl < is->s_labelmap_size; lbl++) { - if (is->s_labelmap[lbl] >= pos) { - is->s_labelmap[lbl]++; + for(int lbl=0; lbl < seq->s_labelmap_size; lbl++) { + if (seq->s_labelmap[lbl] >= pos) { + seq->s_labelmap[lbl]++; } } return SUCCESS; } static void -instr_stream_fini(instr_stream *is) { - PyObject_Free(is->s_labelmap); - is->s_labelmap = NULL; +instr_sequence_fini(instr_sequence *seq) { + PyObject_Free(seq->s_labelmap); + seq->s_labelmap = NULL; - PyObject_Free(is->s_instrs); - is->s_instrs = NULL; + PyObject_Free(seq->s_instrs); + seq->s_instrs = NULL; } static int basicblock_addop(basicblock *b, int opcode, int oparg, location loc); @@ -565,18 +565,18 @@ cfg_builder_addop(cfg_builder *g, int opcode, int oparg, location loc) static int cfg_builder_init(cfg_builder *g); static int -instr_stream_to_cfg(instr_stream *is, cfg_builder *g) { +instr_sequence_to_cfg(instr_sequence *seq, cfg_builder *g) { memset(g, 0, sizeof(cfg_builder)); RETURN_IF_ERROR(cfg_builder_init(g)); /* Note: there can be more than one label for the same offset */ - for (int i = 0; i < is->s_used; i++) { - for (int j=0; j < is->s_labelmap_size; j++) { - if (is->s_labelmap[j] == i) { + for (int i = 0; i < seq->s_used; i++) { + for (int j=0; j < seq->s_labelmap_size; j++) { + if (seq->s_labelmap[j] == i) { jump_target_label lbl = {j}; RETURN_IF_ERROR(cfg_builder_use_label(g, lbl)); } } - codegen_instr *instr = &is->s_instrs[i]; + codegen_instr *instr = &seq->s_instrs[i]; RETURN_IF_ERROR(cfg_builder_addop(g, instr->ci_opcode, instr->ci_oparg, instr->ci_loc)); } return SUCCESS; @@ -609,7 +609,7 @@ struct compiler_unit { Py_ssize_t u_posonlyargcount; /* number of positional only arguments for block */ Py_ssize_t u_kwonlyargcount; /* number of keyword only arguments for block */ - instr_stream u_instr_stream; /* codegen output */ + instr_sequence u_instr_sequence; /* codegen output */ int u_nfblocks; struct fblockinfo u_fblock[CO_MAXBLOCKS]; @@ -645,7 +645,7 @@ struct compiler { PyArena *c_arena; /* pointer to memory allocation arena */ }; -#define INSTR_STREAM(C) (&((C)->u->u_instr_stream)) +#define INSTR_STREAM(C) (&((C)->u->u_instr_sequence)) typedef struct { @@ -675,7 +675,7 @@ typedef struct { static int basicblock_next_instr(basicblock *); -static int codegen_addop_i(instr_stream *is, int opcode, Py_ssize_t oparg, location loc); +static int codegen_addop_i(instr_sequence *seq, int opcode, Py_ssize_t oparg, location loc); static void compiler_free(struct compiler *); static int compiler_error(struct compiler *, location loc, const char *, ...); @@ -1023,7 +1023,7 @@ cfg_builder_fini(cfg_builder* g) static void compiler_unit_free(struct compiler_unit *u) { - instr_stream_fini(&u->u_instr_stream); + instr_sequence_fini(&u->u_instr_sequence); Py_CLEAR(u->u_ste); Py_CLEAR(u->u_name); Py_CLEAR(u->u_qualname); @@ -1352,10 +1352,10 @@ cfg_builder_maybe_start_new_block(cfg_builder *g) } static int -codegen_addop_noarg(instr_stream *is, int opcode, location loc) +codegen_addop_noarg(instr_sequence *seq, int opcode, location loc) { assert(!HAS_ARG(opcode)); - return instr_stream_addop(is, opcode, 0, loc); + return instr_sequence_addop(seq, opcode, 0, loc); } static Py_ssize_t @@ -1555,7 +1555,7 @@ compiler_addop_name(struct compiler *c, location loc, /* Add an opcode with an integer argument */ static int -codegen_addop_i(instr_stream *is, int opcode, Py_ssize_t oparg, location loc) +codegen_addop_i(instr_sequence *seq, int opcode, Py_ssize_t oparg, location loc) { /* oparg value is unsigned, but a signed C int is usually used to store it in the C code (like Python/ceval.c). @@ -1566,16 +1566,16 @@ codegen_addop_i(instr_stream *is, int opcode, Py_ssize_t oparg, location loc) EXTENDED_ARG is used for 16, 24, and 32-bit arguments. */ int oparg_ = Py_SAFE_DOWNCAST(oparg, Py_ssize_t, int); - return instr_stream_addop(is, opcode, oparg_, loc); + return instr_sequence_addop(seq, opcode, oparg_, loc); } static int -codegen_addop_j(instr_stream *is, location loc, +codegen_addop_j(instr_sequence *seq, location loc, int opcode, jump_target_label target) { assert(IS_LABEL(target)); assert(IS_JUMP_OPCODE(opcode) || IS_BLOCK_PUSH_OPCODE(opcode)); - return instr_stream_addop(is, opcode, target.id, loc); + return instr_sequence_addop(seq, opcode, target.id, loc); } #define ADDOP(C, LOC, OP) \ @@ -2544,7 +2544,7 @@ wrap_in_stopiteration_handler(struct compiler *c) /* Insert SETUP_CLEANUP at start */ RETURN_IF_ERROR( - instr_stream_insert_instruction( + instr_sequence_insert_instruction( INSTR_STREAM(c), 0, SETUP_CLEANUP, handler.id, NO_LOCATION)); @@ -8690,7 +8690,7 @@ static int add_return_at_end(struct compiler *c, int addNone) { /* Make sure every instruction stream that falls off the end returns None. */ - instr_stream *is = INSTR_STREAM(c); + instr_sequence *is = INSTR_STREAM(c); if (is->s_used > 0) { codegen_instr *instr = &is->s_instrs[is->s_used]; int opcode = instr->ci_opcode; @@ -8725,7 +8725,7 @@ assemble(struct compiler *c, int addNone) } /** Preprocessing **/ - if (instr_stream_to_cfg(INSTR_STREAM(c), g) < 0) { + if (instr_sequence_to_cfg(INSTR_STREAM(c), g) < 0) { goto error; } assert(cfg_builder_check(g)); @@ -10002,7 +10002,7 @@ _PyCompile_CodeGen(PyObject *ast, PyObject *filename, PyCompilerFlags *pflags, } cfg_builder g; - if (instr_stream_to_cfg(INSTR_STREAM(c), &g) < 0) { + if (instr_sequence_to_cfg(INSTR_STREAM(c), &g) < 0) { goto finally; } if (translate_jump_labels_to_targets(g.g_entryblock) < 0) { From 84f5a9d0a0b6409bea0bda698ec7e6ce52096690 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Tue, 28 Feb 2023 11:00:14 +0000 Subject: [PATCH 14/23] instr->cfg_instr, codegen_instr->instr --- Python/compile.c | 170 +++++++++++++++++++++++------------------------ 1 file changed, 85 insertions(+), 85 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index 4eedc05b91c8c6..12c75bbc03754a 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -183,7 +183,7 @@ static struct jump_target_label_ NO_LABEL = {-1}; #define USE_LABEL(C, LBL) \ RETURN_IF_ERROR(instr_sequence_use_label(INSTR_STREAM(C), (LBL).id)) -struct instr { +struct cfg_instr { int i_opcode; int i_oparg; location i_loc; @@ -196,7 +196,7 @@ struct instr { #define INSTR_SET_OP1(I, OP, ARG) \ do { \ assert(HAS_ARG(OP)); \ - struct instr *_instr__ptr_ = (I); \ + struct cfg_instr *_instr__ptr_ = (I); \ _instr__ptr_->i_opcode = (OP); \ _instr__ptr_->i_oparg = (ARG); \ } while (0); @@ -205,7 +205,7 @@ struct instr { #define INSTR_SET_OP0(I, OP) \ do { \ assert(!HAS_ARG(OP)); \ - struct instr *_instr__ptr_ = (I); \ + struct cfg_instr *_instr__ptr_ = (I); \ _instr__ptr_->i_opcode = (OP); \ _instr__ptr_->i_oparg = 0; \ } while (0); @@ -235,25 +235,25 @@ is_bit_set_in_table(const uint32_t *table, int bitindex) { } static inline int -is_relative_jump(struct instr *i) +is_relative_jump(struct cfg_instr *i) { return is_bit_set_in_table(_PyOpcode_RelativeJump, i->i_opcode); } static inline int -is_block_push(struct instr *i) +is_block_push(struct cfg_instr *i) { return IS_BLOCK_PUSH_OPCODE(i->i_opcode); } static inline int -is_jump(struct instr *i) +is_jump(struct cfg_instr *i) { return IS_JUMP_OPCODE(i->i_opcode); } static int -instr_size(struct instr *instruction) +instr_size(struct cfg_instr *instruction) { int opcode = instruction->i_opcode; assert(!IS_PSEUDO_OPCODE(opcode)); @@ -265,7 +265,7 @@ instr_size(struct instr *instruction) } static void -write_instr(_Py_CODEUNIT *codestr, struct instr *instruction, int ilen) +write_instr(_Py_CODEUNIT *codestr, struct cfg_instr *instruction, int ilen) { int opcode = instruction->i_opcode; assert(!IS_PSEUDO_OPCODE(opcode)); @@ -313,7 +313,7 @@ typedef struct basicblock_ { /* 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 */ - struct instr *b_instr; + struct cfg_instr *b_instr; /* If b_next is non-NULL, it is a pointer to the next block reached by normal control flow. */ struct basicblock_ *b_next; @@ -342,7 +342,7 @@ typedef struct basicblock_ { } basicblock; -static struct instr * +static struct cfg_instr * basicblock_last_instr(const basicblock *b) { assert(b->b_iused >= 0); if (b->b_iused > 0) { @@ -354,13 +354,13 @@ basicblock_last_instr(const basicblock *b) { static inline int basicblock_exits_scope(const basicblock *b) { - struct instr *last = basicblock_last_instr(b); + struct cfg_instr *last = basicblock_last_instr(b); return last && IS_SCOPE_EXIT_OPCODE(last->i_opcode); } static inline int basicblock_nofallthrough(const basicblock *b) { - struct instr *last = basicblock_last_instr(b); + struct cfg_instr *last = basicblock_last_instr(b); return (last && (IS_SCOPE_EXIT_OPCODE(last->i_opcode) || IS_UNCONDITIONAL_JUMP_OPCODE(last->i_opcode))); @@ -411,15 +411,15 @@ typedef struct cfg_builder_ { jump_target_label g_current_label; } cfg_builder; -typedef struct codegen_instr_ { - int ci_opcode; - int ci_oparg; - location ci_loc; -} codegen_instr; +typedef struct { + int i_opcode; + int i_oparg; + location i_loc; +} instruction; /* A write-only stream of instructions */ typedef struct instr_sequence_ { - codegen_instr *s_instrs; + instruction *s_instrs; int s_allocated; int s_used; @@ -436,16 +436,16 @@ instr_sequence_next_inst(instr_sequence *seq) { if (seq->s_instrs == NULL) { assert(seq->s_allocated == 0); assert(seq->s_used == 0); - seq->s_instrs = (codegen_instr *)PyObject_Calloc( - INITIAL_INSTR_STREAM_SIZE, sizeof(codegen_instr)); + seq->s_instrs = (instruction *)PyObject_Calloc( + INITIAL_INSTR_STREAM_SIZE, sizeof(instruction)); if (seq->s_instrs == NULL) { return ERROR; } seq->s_allocated = INITIAL_INSTR_STREAM_SIZE; } if (seq->s_used == seq->s_allocated) { - codegen_instr *tmp = (codegen_instr *)PyObject_Realloc( - seq->s_instrs, 2 * seq->s_allocated * sizeof(codegen_instr)); + instruction *tmp = (instruction *)PyObject_Realloc( + seq->s_instrs, 2 * seq->s_allocated * sizeof(instruction)); if (tmp == NULL) { return ERROR; } @@ -505,10 +505,10 @@ instr_sequence_addop(instr_sequence *seq, int opcode, int oparg, location loc) int idx = instr_sequence_next_inst(seq); RETURN_IF_ERROR(idx); - codegen_instr *ci = &seq->s_instrs[idx]; - ci->ci_opcode = opcode; - ci->ci_oparg = oparg; - ci->ci_loc = loc; + instruction *ci = &seq->s_instrs[idx]; + ci->i_opcode = opcode; + ci->i_oparg = oparg; + ci->i_loc = loc; return SUCCESS; } @@ -522,10 +522,10 @@ instr_sequence_insert_instruction(instr_sequence *seq, int pos, for (int i=last_idx-1; i >= pos; i--) { seq->s_instrs[i+1] = seq->s_instrs[i]; } - codegen_instr *ci = &seq->s_instrs[pos]; - ci->ci_opcode = opcode; - ci->ci_oparg = oparg; - ci->ci_loc = loc; + instruction *ci = &seq->s_instrs[pos]; + ci->i_opcode = opcode; + ci->i_oparg = oparg; + ci->i_loc = loc; /* fix the labels map */ for(int lbl=0; lbl < seq->s_labelmap_size; lbl++) { @@ -576,8 +576,8 @@ instr_sequence_to_cfg(instr_sequence *seq, cfg_builder *g) { RETURN_IF_ERROR(cfg_builder_use_label(g, lbl)); } } - codegen_instr *instr = &seq->s_instrs[i]; - RETURN_IF_ERROR(cfg_builder_addop(g, instr->ci_opcode, instr->ci_oparg, instr->ci_loc)); + instruction *instr = &seq->s_instrs[i]; + RETURN_IF_ERROR(cfg_builder_addop(g, instr->i_opcode, instr->i_oparg, instr->i_loc)); } return SUCCESS; } @@ -1176,8 +1176,8 @@ basicblock_next_instr(basicblock *b) { assert(b != NULL); if (b->b_instr == NULL) { - b->b_instr = (struct instr *)PyObject_Calloc( - DEFAULT_BLOCK_SIZE, sizeof(struct instr)); + b->b_instr = (struct cfg_instr *)PyObject_Calloc( + DEFAULT_BLOCK_SIZE, sizeof(struct cfg_instr)); if (b->b_instr == NULL) { PyErr_NoMemory(); return ERROR; @@ -1185,9 +1185,9 @@ basicblock_next_instr(basicblock *b) b->b_ialloc = DEFAULT_BLOCK_SIZE; } else if (b->b_iused == b->b_ialloc) { - struct instr *tmp; + struct cfg_instr *tmp; size_t oldsize, newsize; - oldsize = b->b_ialloc * sizeof(struct instr); + oldsize = b->b_ialloc * sizeof(struct cfg_instr); newsize = oldsize << 1; if (oldsize > (SIZE_MAX >> 1)) { @@ -1200,7 +1200,7 @@ basicblock_next_instr(basicblock *b) return ERROR; } b->b_ialloc <<= 1; - tmp = (struct instr *)PyObject_Realloc( + tmp = (struct cfg_instr *)PyObject_Realloc( (void *)b->b_instr, newsize); if (tmp == NULL) { PyErr_NoMemory(); @@ -1317,7 +1317,7 @@ basicblock_addop(basicblock *b, int opcode, int oparg, location loc) if (off < 0) { return ERROR; } - struct instr *i = &b->b_instr[off]; + struct cfg_instr *i = &b->b_instr[off]; i->i_opcode = opcode; i->i_oparg = oparg; i->i_target = NULL; @@ -1332,7 +1332,7 @@ 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->g_curblock); + struct cfg_instr *last = basicblock_last_instr(g->g_curblock); return last && IS_TERMINATOR_OPCODE(last->i_opcode); } @@ -2528,7 +2528,7 @@ compiler_check_debug_args(struct compiler *c, arguments_ty args) } static inline int -insert_instruction(basicblock *block, int pos, struct instr *instr) { +insert_instruction(basicblock *block, int pos, struct cfg_instr *instr) { RETURN_IF_ERROR(basicblock_next_instr(block)); for (int i = block->b_iused - 1; i > pos; i--) { block->b_instr[i] = block->b_instr[i-1]; @@ -7087,7 +7087,7 @@ stackdepth(basicblock *entryblock, int code_flags) assert(depth >= 0); basicblock *next = b->b_next; for (int i = 0; i < b->b_iused; i++) { - struct instr *instr = &b->b_instr[i]; + struct cfg_instr *instr = &b->b_instr[i]; int effect = stack_effect(instr->i_opcode, instr->i_oparg, 0); if (effect == PY_INVALID_STACK_EFFECT) { PyErr_Format(PyExc_SystemError, @@ -7176,7 +7176,7 @@ blocksize(basicblock *b) } static basicblock * -push_except_block(ExceptStack *stack, struct instr *setup) { +push_except_block(ExceptStack *stack, struct cfg_instr *setup) { assert(is_block_push(setup)); int opcode = setup->i_opcode; basicblock * target = setup->i_target; @@ -7248,7 +7248,7 @@ label_exception_targets(basicblock *entryblock) { b->b_exceptstack = NULL; handler = except_stack_top(except_stack); for (int i = 0; i < b->b_iused; i++) { - struct instr *instr = &b->b_instr[i]; + struct cfg_instr *instr = &b->b_instr[i]; if (is_block_push(instr)) { if (!instr->i_target->b_visited) { ExceptStack *copy = copy_except_stack(except_stack); @@ -7326,7 +7326,7 @@ mark_except_handlers(basicblock *entryblock) { #endif 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]; + struct cfg_instr *instr = &b->b_instr[i]; if (is_block_push(instr)) { instr->i_target->b_except_handler = 1; } @@ -7355,7 +7355,7 @@ mark_warm(basicblock *entryblock) { next->b_visited = 1; } for (int i=0; i < b->b_iused; i++) { - struct instr *instr = &b->b_instr[i]; + struct cfg_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; @@ -7400,7 +7400,7 @@ mark_cold(basicblock *entryblock) { } } for (int i = 0; i < b->b_iused; i++) { - struct instr *instr = &b->b_instr[i]; + struct cfg_instr *instr = &b->b_instr[i]; if (is_jump(instr)) { assert(i == b->b_iused - 1); basicblock *target = b->b_instr[i].i_target; @@ -7441,7 +7441,7 @@ push_cold_blocks_to_end(cfg_builder *g, int code_flags) { b->b_next = explicit_jump; /* set target */ - struct instr *last = basicblock_last_instr(explicit_jump); + struct cfg_instr *last = basicblock_last_instr(explicit_jump); last->i_target = explicit_jump->b_next; } } @@ -7496,7 +7496,7 @@ static void convert_exception_handlers_to_nops(basicblock *entryblock) { 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]; + struct cfg_instr *instr = &b->b_instr[i]; if (is_block_push(instr) || instr->i_opcode == POP_BLOCK) { INSTR_SET_OP0(instr, NOP); } @@ -7575,7 +7575,7 @@ assemble_exception_table(struct assembler *a, basicblock *entryblock) for (b = entryblock; b != NULL; b = b->b_next) { ioffset = b->b_offset; for (int i = 0; i < b->b_iused; i++) { - struct instr *instr = &b->b_instr[i]; + struct cfg_instr *instr = &b->b_instr[i]; if (instr->i_except != handler) { if (handler != NULL) { RETURN_IF_ERROR( @@ -7745,7 +7745,7 @@ assemble_emit_location(struct assembler* a, location loc, int isize) */ static int -assemble_emit(struct assembler *a, struct instr *i) +assemble_emit(struct assembler *a, struct cfg_instr *i) { Py_ssize_t len = PyBytes_GET_SIZE(a->a_bytecode); _Py_CODEUNIT *code; @@ -7765,7 +7765,7 @@ assemble_emit(struct assembler *a, struct instr *i) static int normalize_jumps_in_block(cfg_builder *g, basicblock *b) { - struct instr *last = basicblock_last_instr(b); + struct cfg_instr *last = basicblock_last_instr(b); if (last == NULL || !is_jump(last)) { return SUCCESS; } @@ -7866,7 +7866,7 @@ assemble_jump_offsets(basicblock *entryblock) for (basicblock *b = entryblock; b != NULL; b = b->b_next) { bsize = b->b_offset; for (int i = 0; i < b->b_iused; i++) { - struct instr *instr = &b->b_instr[i]; + struct cfg_instr *instr = &b->b_instr[i]; int isize = instr_size(instr); /* Relative jumps are computed relative to the instruction pointer after fetching @@ -7938,7 +7938,7 @@ scan_block_for_locals(basicblock *b, basicblock ***sp) // bit i is set if local i is potentially uninitialized uint64_t unsafe_mask = b->b_unsafe_locals_mask; for (int i = 0; i < b->b_iused; i++) { - struct instr *instr = &b->b_instr[i]; + struct cfg_instr *instr = &b->b_instr[i]; assert(instr->i_opcode != EXTENDED_ARG); assert(!IS_SUPERINSTRUCTION_OPCODE(instr->i_opcode)); if (instr->i_except != NULL) { @@ -7971,7 +7971,7 @@ scan_block_for_locals(basicblock *b, basicblock ***sp) if (b->b_next && BB_HAS_FALLTHROUGH(b)) { maybe_push(b->b_next, unsafe_mask, sp); } - struct instr *last = basicblock_last_instr(b); + struct cfg_instr *last = basicblock_last_instr(b); if (last && is_jump(last)) { assert(last->i_target != NULL); maybe_push(last->i_target, unsafe_mask, sp); @@ -7994,7 +7994,7 @@ fast_scan_many_locals(basicblock *entryblock, int nlocals) for (basicblock *b = entryblock; b != NULL; b = b->b_next) { blocknum++; for (int i = 0; i < b->b_iused; i++) { - struct instr *instr = &b->b_instr[i]; + struct cfg_instr *instr = &b->b_instr[i]; assert(instr->i_opcode != EXTENDED_ARG); assert(!IS_SUPERINSTRUCTION_OPCODE(instr->i_opcode)); int arg = instr->i_oparg; @@ -8323,7 +8323,7 @@ makecode(struct compiler *c, struct assembler *a, PyObject *constslist, /* For debugging purposes only */ #if 0 static void -dump_instr(struct instr *i) +dump_instr(struct cfg_instr *i) { const char *jrel = (is_relative_jump(i)) ? "jrel " : ""; const char *jabs = (is_jump(i) && !is_relative_jump(i))? "jabs " : ""; @@ -8343,7 +8343,7 @@ dump_instr(struct instr *i) static inline int basicblock_returns(const basicblock *b) { - struct instr *last = basicblock_last_instr(b); + struct cfg_instr *last = basicblock_last_instr(b); return last && (last->i_opcode == RETURN_VALUE || last->i_opcode == RETURN_CONST); } @@ -8419,14 +8419,14 @@ insert_prefix_instructions(struct compiler *c, basicblock *entryblock, /* Add the generator prefix instructions. */ if (code_flags & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR)) { - struct instr make_gen = { + struct cfg_instr make_gen = { .i_opcode = RETURN_GENERATOR, .i_oparg = 0, .i_loc = LOCATION(c->u->u_firstlineno, c->u->u_firstlineno, -1, -1), .i_target = NULL, }; RETURN_IF_ERROR(insert_instruction(entryblock, 0, &make_gen)); - struct instr pop_top = { + struct cfg_instr pop_top = { .i_opcode = POP_TOP, .i_oparg = 0, .i_loc = NO_LOCATION, @@ -8455,7 +8455,7 @@ insert_prefix_instructions(struct compiler *c, basicblock *entryblock, if (oldindex == -1) { continue; } - struct instr make_cell = { + struct cfg_instr make_cell = { .i_opcode = MAKE_CELL, // This will get fixed in offset_derefs(). .i_oparg = oldindex, @@ -8469,7 +8469,7 @@ insert_prefix_instructions(struct compiler *c, basicblock *entryblock, } if (nfreevars) { - struct instr copy_frees = { + struct cfg_instr copy_frees = { .i_opcode = COPY_FREE_VARS, .i_oparg = nfreevars, .i_loc = NO_LOCATION, @@ -8490,7 +8490,7 @@ guarantee_lineno_for_exits(basicblock *entryblock, int firstlineno) { int lineno = firstlineno; assert(lineno > 0); for (basicblock *b = entryblock; b != NULL; b = b->b_next) { - struct instr *last = basicblock_last_instr(b); + struct cfg_instr *last = basicblock_last_instr(b); if (last == NULL) { continue; } @@ -8532,7 +8532,7 @@ fix_cell_offsets(struct compiler *c, basicblock *entryblock, int *fixedmap) // Then update offsets, either relative to locals or by cell2arg. for (basicblock *b = entryblock; b != NULL; b = b->b_next) { for (int i = 0; i < b->b_iused; i++) { - struct instr *inst = &b->b_instr[i]; + struct cfg_instr *inst = &b->b_instr[i]; // This is called before extended args are generated. assert(inst->i_opcode != EXTENDED_ARG); int oldoffset = inst->i_oparg; @@ -8572,7 +8572,7 @@ no_redundant_nops(cfg_builder *g) { static bool no_redundant_jumps(cfg_builder *g) { for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { - struct instr *last = basicblock_last_instr(b); + struct cfg_instr *last = basicblock_last_instr(b); if (last != NULL) { if (IS_UNCONDITIONAL_JUMP_OPCODE(last->i_opcode)) { assert(last->i_target != b->b_next); @@ -8590,7 +8590,7 @@ opcode_metadata_is_sane(cfg_builder *g) { bool result = true; for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { for (int i = 0; i < b->b_iused; i++) { - struct instr *instr = &b->b_instr[i]; + struct cfg_instr *instr = &b->b_instr[i]; int opcode = instr->i_opcode; int oparg = instr->i_oparg; assert(opcode <= MAX_REAL_OPCODE); @@ -8634,7 +8634,7 @@ remove_redundant_jumps(cfg_builder *g) { */ assert(no_empty_basic_blocks(g)); for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { - struct instr *last = basicblock_last_instr(b); + struct cfg_instr *last = basicblock_last_instr(b); assert(last != NULL); assert(!IS_ASSEMBLER_OPCODE(last->i_opcode)); if (IS_UNCONDITIONAL_JUMP_OPCODE(last->i_opcode)) { @@ -8692,8 +8692,8 @@ add_return_at_end(struct compiler *c, int addNone) /* Make sure every instruction stream that falls off the end returns None. */ instr_sequence *is = INSTR_STREAM(c); if (is->s_used > 0) { - codegen_instr *instr = &is->s_instrs[is->s_used]; - int opcode = instr->ci_opcode; + instruction *instr = &is->s_instrs[is->s_used]; + int opcode = instr->i_opcode; if (opcode == RETURN_VALUE || opcode == RETURN_CONST) { return SUCCESS; } @@ -8902,7 +8902,7 @@ get_const_value(int opcode, int oparg, PyObject *co_consts) */ static int fold_tuple_on_constants(PyObject *const_cache, - struct instr *inst, + struct cfg_instr *inst, int n, PyObject *consts) { /* Pre-conditions */ @@ -8971,7 +8971,7 @@ swaptimize(basicblock *block, int *ix) // NOTE: "./python -m test test_patma" serves as a good, quick stress test // for this function. Make sure to blow away cached *.pyc files first! assert(*ix < block->b_iused); - struct instr *instructions = &block->b_instr[*ix]; + struct cfg_instr *instructions = &block->b_instr[*ix]; // Find the length of the current sequence of SWAPs and NOPs, and record the // maximum depth of the stack manipulations: assert(instructions[0].i_opcode == SWAP); @@ -9072,7 +9072,7 @@ static int next_swappable_instruction(basicblock *block, int i, int lineno) { while (++i < block->b_iused) { - struct instr *instruction = &block->b_instr[i]; + struct cfg_instr *instruction = &block->b_instr[i]; if (0 <= lineno && instruction->i_loc.lineno != lineno) { // Optimizing across this instruction could cause user-visible // changes in the names bound between line tracing events! @@ -9098,7 +9098,7 @@ apply_static_swaps(basicblock *block, int i) // SWAPs are to our left, and potential swaperands are to our right: for (; 0 <= i; i--) { assert(i < block->b_iused); - struct instr *swap = &block->b_instr[i]; + struct cfg_instr *swap = &block->b_instr[i]; if (swap->i_opcode != SWAP) { if (swap->i_opcode == NOP || SWAPPABLE(swap->i_opcode)) { // Nope, but we know how to handle these. Keep looking: @@ -9121,7 +9121,7 @@ apply_static_swaps(basicblock *block, int i) } // Success! INSTR_SET_OP0(swap, NOP); - struct instr temp = block->b_instr[j]; + struct cfg_instr temp = block->b_instr[j]; block->b_instr[j] = block->b_instr[k]; block->b_instr[k] = temp; } @@ -9131,7 +9131,7 @@ apply_static_swaps(basicblock *block, int i) // target->i_target using the provided opcode. Return whether or not the // optimization was successful. static bool -jump_thread(struct instr *inst, struct instr *target, int opcode) +jump_thread(struct cfg_instr *inst, struct cfg_instr *target, int opcode) { assert(is_jump(inst)); assert(is_jump(target)); @@ -9156,11 +9156,11 @@ optimize_basic_block(PyObject *const_cache, basicblock *bb, PyObject *consts) { assert(PyDict_CheckExact(const_cache)); assert(PyList_CheckExact(consts)); - struct instr nop; + struct cfg_instr nop; INSTR_SET_OP0(&nop, NOP); - struct instr *target; + struct cfg_instr *target; for (int i = 0; i < bb->b_iused; i++) { - struct instr *inst = &bb->b_instr[i]; + struct cfg_instr *inst = &bb->b_instr[i]; int oparg = inst->i_oparg; int nextop = i+1 < bb->b_iused ? bb->b_instr[i+1].i_opcode : 0; if (HAS_TARGET(inst->i_opcode)) { @@ -9397,7 +9397,7 @@ optimize_basic_block(PyObject *const_cache, basicblock *bb, PyObject *consts) */ static int inline_small_exit_blocks(basicblock *bb) { - struct instr *last = basicblock_last_instr(bb); + struct cfg_instr *last = basicblock_last_instr(bb); if (last == NULL) { return 0; } @@ -9505,7 +9505,7 @@ mark_reachable(basicblock *entryblock) { } for (int i = 0; i < b->b_iused; i++) { basicblock *target; - struct instr *instr = &b->b_instr[i]; + struct cfg_instr *instr = &b->b_instr[i]; if (is_jump(instr) || is_block_push(instr)) { target = instr->i_target; if (!target->b_visited) { @@ -9536,7 +9536,7 @@ eliminate_empty_basic_blocks(cfg_builder *g) { for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { assert(b->b_iused > 0); for (int i = 0; i < b->b_iused; i++) { - struct instr *instr = &b->b_instr[i]; + struct cfg_instr *instr = &b->b_instr[i]; if (HAS_TARGET(instr->i_opcode)) { basicblock *target = instr->i_target; while (target->b_iused == 0) { @@ -9560,7 +9560,7 @@ eliminate_empty_basic_blocks(cfg_builder *g) { static void propagate_line_numbers(basicblock *entryblock) { for (basicblock *b = entryblock; b != NULL; b = b->b_next) { - struct instr *last = basicblock_last_instr(b); + struct cfg_instr *last = basicblock_last_instr(b); if (last == NULL) { continue; } @@ -9616,7 +9616,7 @@ translate_jump_labels_to_targets(basicblock *entryblock) } 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]; + struct cfg_instr *instr = &b->b_instr[i]; assert(instr->i_target == NULL); if (HAS_TARGET(instr->i_opcode)) { int lbl = instr->i_oparg; @@ -9802,7 +9802,7 @@ duplicate_exits_without_lineno(cfg_builder *g) */ basicblock *entryblock = g->g_entryblock; for (basicblock *b = entryblock; b != NULL; b = b->b_next) { - struct instr *last = basicblock_last_instr(b); + struct cfg_instr *last = basicblock_last_instr(b); assert(last != NULL); if (is_jump(last)) { basicblock *target = last->i_target; @@ -9826,7 +9826,7 @@ duplicate_exits_without_lineno(cfg_builder *g) for (basicblock *b = entryblock; b != NULL; b = b->b_next) { if (BB_HAS_FALLTHROUGH(b) && b->b_next && b->b_iused > 0) { if (is_exit_without_lineno(b->b_next)) { - struct instr *last = basicblock_last_instr(b); + struct cfg_instr *last = basicblock_last_instr(b); assert(last != NULL); b->b_next->b_instr[0].i_loc = last->i_loc; } @@ -9942,7 +9942,7 @@ cfg_to_instructions(cfg_builder *g) } for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { for (int i = 0; i < b->b_iused; i++) { - struct instr *instr = &b->b_instr[i]; + struct cfg_instr *instr = &b->b_instr[i]; location loc = instr->i_loc; int arg = HAS_TARGET(instr->i_opcode) ? instr->i_target->b_label : instr->i_oparg; From cd0225d3aefd9023d626dc3c1d9c76a48a2165c2 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Tue, 28 Feb 2023 15:29:11 +0000 Subject: [PATCH 15/23] make sure we always emit something to jump to at the end --- Python/compile.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index 12c75bbc03754a..c8223773cc1a87 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -8689,15 +8689,9 @@ prepare_localsplus(struct compiler* c, cfg_builder *g, int code_flags) static int add_return_at_end(struct compiler *c, int addNone) { - /* Make sure every instruction stream that falls off the end returns None. */ - instr_sequence *is = INSTR_STREAM(c); - if (is->s_used > 0) { - instruction *instr = &is->s_instrs[is->s_used]; - int opcode = instr->i_opcode; - if (opcode == RETURN_VALUE || opcode == RETURN_CONST) { - return SUCCESS; - } - } + /* Make sure every instruction stream that falls off the end returns None. + * This also ensures that no jump target offsets are out of bounds. + */ if (addNone) { ADDOP_LOAD_CONST(c, NO_LOCATION, Py_None); } From b8f4acf3cc01f02d37a895f92e047572d1b742fd Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Tue, 28 Feb 2023 15:35:46 +0000 Subject: [PATCH 16/23] INSTR_STREAM --> INSTR_SEQUENCE --- Python/compile.c | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index c8223773cc1a87..5a4644177e0660 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -175,13 +175,13 @@ static struct jump_target_label_ NO_LABEL = {-1}; #define IS_LABEL(L) (!SAME_LABEL((L), (NO_LABEL))) #define NEW_JUMP_TARGET_LABEL(C, NAME) \ - jump_target_label NAME = instr_sequence_new_label(INSTR_STREAM(C)); \ + jump_target_label NAME = instr_sequence_new_label(INSTR_SEQUENCE(C)); \ if (!IS_LABEL(NAME)) { \ return ERROR; \ } #define USE_LABEL(C, LBL) \ - RETURN_IF_ERROR(instr_sequence_use_label(INSTR_STREAM(C), (LBL).id)) + RETURN_IF_ERROR(instr_sequence_use_label(INSTR_SEQUENCE(C), (LBL).id)) struct cfg_instr { int i_opcode; @@ -428,8 +428,8 @@ typedef struct instr_sequence_ { int s_next_free_label; /* next free label id */ } instr_sequence; -#define INITIAL_INSTR_STREAM_SIZE 100 -#define INITIAL_INSTR_STREAM_LABELS_MAP_SIZE 10 +#define INITIAL_INSTR_SEQUENCE_SIZE 100 +#define INITIAL_INSTR_SEQUENCE_LABELS_MAP_SIZE 10 static int instr_sequence_next_inst(instr_sequence *seq) { @@ -437,11 +437,11 @@ instr_sequence_next_inst(instr_sequence *seq) { assert(seq->s_allocated == 0); assert(seq->s_used == 0); seq->s_instrs = (instruction *)PyObject_Calloc( - INITIAL_INSTR_STREAM_SIZE, sizeof(instruction)); + INITIAL_INSTR_SEQUENCE_SIZE, sizeof(instruction)); if (seq->s_instrs == NULL) { return ERROR; } - seq->s_allocated = INITIAL_INSTR_STREAM_SIZE; + seq->s_allocated = INITIAL_INSTR_SEQUENCE_SIZE; } if (seq->s_used == seq->s_allocated) { instruction *tmp = (instruction *)PyObject_Realloc( @@ -470,7 +470,7 @@ instr_sequence_use_label(instr_sequence *seq, int lbl) { int *tmp = NULL; if (seq->s_labelmap == NULL) { old_size = 0; - new_size = INITIAL_INSTR_STREAM_LABELS_MAP_SIZE; + new_size = INITIAL_INSTR_SEQUENCE_LABELS_MAP_SIZE; if (new_size < 2 * lbl) { new_size = 2 * lbl; } @@ -645,7 +645,7 @@ struct compiler { PyArena *c_arena; /* pointer to memory allocation arena */ }; -#define INSTR_STREAM(C) (&((C)->u->u_instr_sequence)) +#define INSTR_SEQUENCE(C) (&((C)->u->u_instr_sequence)) typedef struct { @@ -1513,7 +1513,7 @@ compiler_addop_load_const(struct compiler *c, location loc, PyObject *o) if (arg < 0) { return ERROR; } - return codegen_addop_i(INSTR_STREAM(c), LOAD_CONST, arg, loc); + return codegen_addop_i(INSTR_SEQUENCE(c), LOAD_CONST, arg, loc); } static int @@ -1524,7 +1524,7 @@ compiler_addop_o(struct compiler *c, location loc, if (arg < 0) { return ERROR; } - return codegen_addop_i(INSTR_STREAM(c), opcode, arg, loc); + return codegen_addop_i(INSTR_SEQUENCE(c), opcode, arg, loc); } static int @@ -1550,7 +1550,7 @@ compiler_addop_name(struct compiler *c, location loc, arg <<= 1; arg |= 1; } - return codegen_addop_i(INSTR_STREAM(c), opcode, arg, loc); + return codegen_addop_i(INSTR_SEQUENCE(c), opcode, arg, loc); } /* Add an opcode with an integer argument */ @@ -1579,10 +1579,10 @@ codegen_addop_j(instr_sequence *seq, location loc, } #define ADDOP(C, LOC, OP) \ - RETURN_IF_ERROR(codegen_addop_noarg(INSTR_STREAM(C), (OP), (LOC))) + RETURN_IF_ERROR(codegen_addop_noarg(INSTR_SEQUENCE(C), (OP), (LOC))) #define ADDOP_IN_SCOPE(C, LOC, OP) { \ - if (codegen_addop_noarg(INSTR_STREAM(C), (OP), (LOC)) < 0) { \ + if (codegen_addop_noarg(INSTR_SEQUENCE(C), (OP), (LOC)) < 0) { \ compiler_exit_scope(C); \ return ERROR; \ } \ @@ -1617,10 +1617,10 @@ codegen_addop_j(instr_sequence *seq, location loc, RETURN_IF_ERROR(compiler_addop_name((C), (LOC), (OP), (C)->u->u_ ## TYPE, (O))) #define ADDOP_I(C, LOC, OP, O) \ - RETURN_IF_ERROR(codegen_addop_i(INSTR_STREAM(C), (OP), (O), (LOC))) + RETURN_IF_ERROR(codegen_addop_i(INSTR_SEQUENCE(C), (OP), (O), (LOC))) #define ADDOP_JUMP(C, LOC, OP, O) \ - RETURN_IF_ERROR(codegen_addop_j(INSTR_STREAM(C), (LOC), (OP), (O))) + RETURN_IF_ERROR(codegen_addop_j(INSTR_SEQUENCE(C), (LOC), (OP), (O))) #define ADDOP_COMPARE(C, LOC, CMP) \ RETURN_IF_ERROR(compiler_addcompare((C), (LOC), (cmpop_ty)(CMP))) @@ -2545,7 +2545,7 @@ wrap_in_stopiteration_handler(struct compiler *c) /* Insert SETUP_CLEANUP at start */ RETURN_IF_ERROR( instr_sequence_insert_instruction( - INSTR_STREAM(c), 0, + INSTR_SEQUENCE(c), 0, SETUP_CLEANUP, handler.id, NO_LOCATION)); ADDOP_LOAD_CONST(c, NO_LOCATION, Py_None); @@ -4235,7 +4235,7 @@ compiler_nameop(struct compiler *c, location loc, if (op == LOAD_GLOBAL) { arg <<= 1; } - return codegen_addop_i(INSTR_STREAM(c), op, arg, loc); + return codegen_addop_i(INSTR_SEQUENCE(c), op, arg, loc); } static int @@ -6254,7 +6254,7 @@ emit_and_reset_fail_pop(struct compiler *c, location loc, } while (--pc->fail_pop_size) { USE_LABEL(c, pc->fail_pop[pc->fail_pop_size]); - if (codegen_addop_noarg(INSTR_STREAM(c), POP_TOP, loc) < 0) { + if (codegen_addop_noarg(INSTR_SEQUENCE(c), POP_TOP, loc) < 0) { pc->fail_pop_size = 0; PyObject_Free(pc->fail_pop); pc->fail_pop = NULL; @@ -6694,7 +6694,7 @@ compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc) pc->fail_pop = NULL; pc->fail_pop_size = 0; pc->on_top = 0; - if (codegen_addop_i(INSTR_STREAM(c), COPY, 1, LOC(alt)) < 0 || + if (codegen_addop_i(INSTR_SEQUENCE(c), COPY, 1, LOC(alt)) < 0 || compiler_pattern(c, alt, pc) < 0) { goto error; } @@ -6757,7 +6757,7 @@ compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc) } } assert(control); - if (codegen_addop_j(INSTR_STREAM(c), LOC(alt), JUMP, end) < 0 || + if (codegen_addop_j(INSTR_SEQUENCE(c), LOC(alt), JUMP, end) < 0 || emit_and_reset_fail_pop(c, LOC(alt), pc) < 0) { goto error; @@ -6769,7 +6769,7 @@ compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc) // Need to NULL this for the PyObject_Free call in the error block. old_pc.fail_pop = NULL; // No match. Pop the remaining copy of the subject and fail: - if (codegen_addop_noarg(INSTR_STREAM(c), POP_TOP, LOC(p)) < 0 || + if (codegen_addop_noarg(INSTR_SEQUENCE(c), POP_TOP, LOC(p)) < 0 || jump_to_fail_pop(c, LOC(p), pc, JUMP) < 0) { goto error; } @@ -8719,7 +8719,7 @@ assemble(struct compiler *c, int addNone) } /** Preprocessing **/ - if (instr_sequence_to_cfg(INSTR_STREAM(c), g) < 0) { + if (instr_sequence_to_cfg(INSTR_SEQUENCE(c), g) < 0) { goto error; } assert(cfg_builder_check(g)); @@ -9996,7 +9996,7 @@ _PyCompile_CodeGen(PyObject *ast, PyObject *filename, PyCompilerFlags *pflags, } cfg_builder g; - if (instr_sequence_to_cfg(INSTR_STREAM(c), &g) < 0) { + if (instr_sequence_to_cfg(INSTR_SEQUENCE(c), &g) < 0) { goto finally; } if (translate_jump_labels_to_targets(g.g_entryblock) < 0) { From 258f14203c141f214c4c5bd3ff54c7529139e3ce Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Wed, 1 Mar 2023 18:15:30 +0000 Subject: [PATCH 17/23] free the cfg_builder in the test harness --- Python/compile.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Python/compile.c b/Python/compile.c index 5a4644177e0660..f18b35f74b2683 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -10007,6 +10007,7 @@ _PyCompile_CodeGen(PyObject *ast, PyObject *filename, PyCompilerFlags *pflags, finally: compiler_exit_scope(c); + cfg_builder_fini(&g); compiler_free(c); _PyArena_Free(arena); return res; From fd7f2b3a4e3237fa502e28f6abc6f1209f27dae2 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Thu, 2 Mar 2023 19:08:24 +0000 Subject: [PATCH 18/23] #ifndef NDEBUG around cfg_builder_check --- Python/compile.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Python/compile.c b/Python/compile.c index 0fb93259ea1f55..f02805effe80f6 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -972,6 +972,7 @@ dictbytype(PyObject *src, int scope_type, int flag, Py_ssize_t offset) return dest; } +#ifndef NDEBUG static bool cfg_builder_check(cfg_builder *g) { @@ -989,6 +990,7 @@ cfg_builder_check(cfg_builder *g) } return true; } +#endif static basicblock *cfg_builder_new_block(cfg_builder *g); From 57fbe36db1cecf27762698cdb280b493f170ddc4 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Fri, 3 Mar 2023 16:30:01 +0000 Subject: [PATCH 19/23] create shared helper function for resizing arrays --- Python/compile.c | 146 ++++++++++++++++++++++++----------------------- 1 file changed, 76 insertions(+), 70 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index f02805effe80f6..b5068aa361fd25 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -431,27 +431,73 @@ typedef struct instr_sequence_ { #define INITIAL_INSTR_SEQUENCE_SIZE 100 #define INITIAL_INSTR_SEQUENCE_LABELS_MAP_SIZE 10 +/* + * Resize the array if index is out of range. + * + * index: the index we want to access + * arr pointer to the array + * alloc: pointer to the capacity of the array + * default_alloc: initial number of items + * item_size: size of each item + * + */ static int -instr_sequence_next_inst(instr_sequence *seq) { - if (seq->s_instrs == NULL) { - assert(seq->s_allocated == 0); - assert(seq->s_used == 0); - seq->s_instrs = (instruction *)PyObject_Calloc( - INITIAL_INSTR_SEQUENCE_SIZE, sizeof(instruction)); - if (seq->s_instrs == NULL) { +ensure_array_large_enough(int index, void **arr_, int *alloc, int default_alloc, size_t item_size) +{ + void *arr = *arr_; + if (arr == NULL) { + int new_alloc = default_alloc; + if (index >= new_alloc) { + new_alloc = index + default_alloc; + } + arr = PyObject_Calloc(new_alloc, item_size); + if (arr == NULL) { + PyErr_NoMemory(); return ERROR; } - seq->s_allocated = INITIAL_INSTR_SEQUENCE_SIZE; + *alloc = new_alloc; } - if (seq->s_used == seq->s_allocated) { - instruction *tmp = (instruction *)PyObject_Realloc( - seq->s_instrs, 2 * seq->s_allocated * sizeof(instruction)); + else if (index >= *alloc) { + size_t oldsize = *alloc * item_size; + int new_alloc = *alloc << 1; + if (index >= new_alloc) { + new_alloc = index + default_alloc; + } + size_t newsize = new_alloc * item_size; + + if (oldsize > (SIZE_MAX >> 1)) { + PyErr_NoMemory(); + return ERROR; + } + + if (newsize == 0) { + PyErr_NoMemory(); + return ERROR; + } + void *tmp = PyObject_Realloc(arr, newsize); if (tmp == NULL) { + PyErr_NoMemory(); return ERROR; } - seq->s_instrs = tmp; - seq->s_allocated *= 2; + *alloc = new_alloc; + arr = tmp; + memset((char *)arr + oldsize, 0, newsize - oldsize); } + + *arr_ = arr; + return SUCCESS; +} + +static int +instr_sequence_next_inst(instr_sequence *seq) { + assert(seq->s_instrs != NULL || seq->s_used == 0); + + RETURN_IF_ERROR( + ensure_array_large_enough(seq->s_used + 1, + (void**)&seq->s_instrs, + &seq->s_allocated, + INITIAL_INSTR_SEQUENCE_SIZE, + sizeof(instruction))); assert(seq->s_used < seq->s_allocated); return seq->s_used++; } @@ -465,31 +511,16 @@ instr_sequence_new_label(instr_sequence *seq) static int instr_sequence_use_label(instr_sequence *seq, int lbl) { - if (seq->s_labelmap_size <= lbl) { - int old_size, new_size; - int *tmp = NULL; - if (seq->s_labelmap == NULL) { - old_size = 0; - new_size = INITIAL_INSTR_SEQUENCE_LABELS_MAP_SIZE; - if (new_size < 2 * lbl) { - new_size = 2 * lbl; - } - tmp = (int*)PyObject_Calloc(new_size, sizeof(int)); - } - else { - old_size = seq->s_labelmap_size; - new_size = 2 * lbl; - tmp = (int*)PyObject_Realloc(seq->s_labelmap, - new_size * sizeof(int)); - } - if (tmp == NULL) { - return ERROR; - } - for(int i = old_size; i < new_size; i++) { - tmp[i] = -111; /* something weird, for debugging */ - } - seq->s_labelmap = tmp; - seq->s_labelmap_size = new_size; + int old_size = seq->s_labelmap_size; + RETURN_IF_ERROR( + ensure_array_large_enough(lbl, + (void**)&seq->s_labelmap, + &seq->s_labelmap_size, + INITIAL_INSTR_SEQUENCE_LABELS_MAP_SIZE, + sizeof(int))); + + for(int i = old_size; i < seq->s_labelmap_size; i++) { + seq->s_labelmap[i] = -111; /* something weird, for debugging */ } seq->s_labelmap[lbl] = seq->s_used; /* label refers to the next instruction */ return SUCCESS; @@ -1177,40 +1208,15 @@ static int basicblock_next_instr(basicblock *b) { assert(b != NULL); - if (b->b_instr == NULL) { - b->b_instr = (struct cfg_instr *)PyObject_Calloc( - DEFAULT_BLOCK_SIZE, sizeof(struct cfg_instr)); - if (b->b_instr == NULL) { - PyErr_NoMemory(); - return ERROR; - } - b->b_ialloc = DEFAULT_BLOCK_SIZE; - } - else if (b->b_iused == b->b_ialloc) { - struct cfg_instr *tmp; - size_t oldsize, newsize; - oldsize = b->b_ialloc * sizeof(struct cfg_instr); - newsize = oldsize << 1; - if (oldsize > (SIZE_MAX >> 1)) { - PyErr_NoMemory(); - return ERROR; - } + RETURN_IF_ERROR( + ensure_array_large_enough( + b->b_iused + 1, + (void**)&b->b_instr, + &b->b_ialloc, + DEFAULT_BLOCK_SIZE, + sizeof(struct cfg_instr))); - if (newsize == 0) { - PyErr_NoMemory(); - return ERROR; - } - b->b_ialloc <<= 1; - tmp = (struct cfg_instr *)PyObject_Realloc( - (void *)b->b_instr, newsize); - if (tmp == NULL) { - PyErr_NoMemory(); - return ERROR; - } - b->b_instr = tmp; - memset((char *)b->b_instr + oldsize, 0, newsize - oldsize); - } return b->b_iused++; } From dc9f1f51e927e3833848b9d4e52fd6d4f0d695e9 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Fri, 3 Mar 2023 16:36:15 +0000 Subject: [PATCH 20/23] remove obsolete comment --- Python/compile.c | 1 - 1 file changed, 1 deletion(-) diff --git a/Python/compile.c b/Python/compile.c index b5068aa361fd25..6ec7e9f495e9b9 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -187,7 +187,6 @@ struct cfg_instr { int i_opcode; int i_oparg; location i_loc; - /* The following fields should not be set by the front-end: */ struct basicblock_ *i_target; /* target block (if jump instruction) */ struct basicblock_ *i_except; /* target block when exception is raised */ }; From fa1c66ab7b7805fd6bb035c352808371d00186f6 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Tue, 7 Mar 2023 12:08:45 +0000 Subject: [PATCH 21/23] address code review --- Python/compile.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index 4e10e0a8e3cb89..e5c01ea1cb5b06 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -469,10 +469,7 @@ ensure_array_large_enough(int index, void **arr_, int *alloc, int default_alloc, return ERROR; } - if (newsize == 0) { - PyErr_NoMemory(); - return ERROR; - } + assert(newsize > 0); void *tmp = PyObject_Realloc(arr, newsize); if (tmp == NULL) { PyErr_NoMemory(); From 3528176db14f5ea8480d91b3c12eeb1a1f8121da Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Tue, 7 Mar 2023 12:10:21 +0000 Subject: [PATCH 22/23] tweak comments --- Python/compile.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index e5c01ea1cb5b06..cb5dd2c40ae9eb 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -416,7 +416,7 @@ typedef struct { location i_loc; } instruction; -/* A write-only stream of instructions */ + typedef struct instr_sequence_ { instruction *s_instrs; int s_allocated; @@ -434,7 +434,7 @@ typedef struct instr_sequence_ { * Resize the array if index is out of range. * * index: the index we want to access - * arr pointer to the array + * arr: pointer to the array * alloc: pointer to the capacity of the array * default_alloc: initial number of items * item_size: size of each item From fb13e36fbed8c66236ab6bdf584b5f421c23223b Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Tue, 7 Mar 2023 12:13:34 +0000 Subject: [PATCH 23/23] index -> idx to avoid github's hilighting --- Python/compile.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index cb5dd2c40ae9eb..45c97b4f8ef0e6 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -433,7 +433,7 @@ typedef struct instr_sequence_ { /* * Resize the array if index is out of range. * - * index: the index we want to access + * idx: the index we want to access * arr: pointer to the array * alloc: pointer to the capacity of the array * default_alloc: initial number of items @@ -441,13 +441,13 @@ typedef struct instr_sequence_ { * */ static int -ensure_array_large_enough(int index, void **arr_, int *alloc, int default_alloc, size_t item_size) +ensure_array_large_enough(int idx, void **arr_, int *alloc, int default_alloc, size_t item_size) { void *arr = *arr_; if (arr == NULL) { int new_alloc = default_alloc; - if (index >= new_alloc) { - new_alloc = index + default_alloc; + if (idx >= new_alloc) { + new_alloc = idx + default_alloc; } arr = PyObject_Calloc(new_alloc, item_size); if (arr == NULL) { @@ -456,11 +456,11 @@ ensure_array_large_enough(int index, void **arr_, int *alloc, int default_alloc, } *alloc = new_alloc; } - else if (index >= *alloc) { + else if (idx >= *alloc) { size_t oldsize = *alloc * item_size; int new_alloc = *alloc << 1; - if (index >= new_alloc) { - new_alloc = index + default_alloc; + if (idx >= new_alloc) { + new_alloc = idx + default_alloc; } size_t newsize = new_alloc * item_size;