From f2c72548ea2846f28ef290a7d60535b9ad31b78c Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Thu, 3 Aug 2023 23:19:24 +0100 Subject: [PATCH 1/9] move code that manipulates CFG to flowgraph.c --- Include/internal/pycore_flowgraph.h | 9 + Python/compile.c | 251 +--------------------------- Python/flowgraph.c | 250 +++++++++++++++++++++++++++ 3 files changed, 268 insertions(+), 242 deletions(-) diff --git a/Include/internal/pycore_flowgraph.h b/Include/internal/pycore_flowgraph.h index cb55f8712e7ad6..ce3860e0d3901c 100644 --- a/Include/internal/pycore_flowgraph.h +++ b/Include/internal/pycore_flowgraph.h @@ -90,6 +90,15 @@ void _PyCfgBuilder_Fini(_PyCfgBuilder *g); int _PyCfg_OptimizeCodeUnit(_PyCfgBuilder *g, PyObject *consts, PyObject *const_cache, int nlocals, int nparams, int firstlineno); + +int _PyCfg_OptimizedCfgToInstructionList(_PyCfgBuilder *g, _PyCompile_CodeUnitMetadata *umd, + int code_flags, int *stackdepth, int *nlocalsplus); + +int _PyCfg_ToOptimizedInstructionList(_PyCfgBuilder *g, _PyCompile_CodeUnitMetadata *umd, + PyObject *consts, PyObject *const_cache, + int nparams, int firstlineno, int code_flags, + int *stackdepth, int *nlocalsplus); + int _PyCfg_Stackdepth(_PyCfgBuilder *g); void _PyCfg_ConvertPseudoOps(_PyCfgBasicblock *entryblock); int _PyCfg_ResolveJumps(_PyCfgBuilder *g); diff --git a/Python/compile.c b/Python/compile.c index b673e3ac6c1cc5..f33d6655b63030 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -7493,201 +7493,6 @@ _PyCompile_ConstCacheMergeOne(PyObject *const_cache, PyObject **obj) return SUCCESS; } - -static int * -build_cellfixedoffsets(_PyCompile_CodeUnitMetadata *umd) -{ - int nlocals = (int)PyDict_GET_SIZE(umd->u_varnames); - int ncellvars = (int)PyDict_GET_SIZE(umd->u_cellvars); - int nfreevars = (int)PyDict_GET_SIZE(umd->u_freevars); - - int noffsets = ncellvars + nfreevars; - int *fixed = PyMem_New(int, noffsets); - if (fixed == NULL) { - PyErr_NoMemory(); - return NULL; - } - for (int i = 0; i < noffsets; i++) { - fixed[i] = nlocals + i; - } - - PyObject *varname, *cellindex; - Py_ssize_t pos = 0; - while (PyDict_Next(umd->u_cellvars, &pos, &varname, &cellindex)) { - PyObject *varindex = PyDict_GetItem(umd->u_varnames, varname); - if (varindex != NULL) { - assert(PyLong_AS_LONG(cellindex) < INT_MAX); - assert(PyLong_AS_LONG(varindex) < INT_MAX); - int oldindex = (int)PyLong_AS_LONG(cellindex); - int argoffset = (int)PyLong_AS_LONG(varindex); - fixed[oldindex] = argoffset; - } - } - - return fixed; -} - -#define IS_GENERATOR(CF) \ - ((CF) & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR)) - -static int -insert_prefix_instructions(_PyCompile_CodeUnitMetadata *umd, basicblock *entryblock, - int *fixed, int nfreevars, int code_flags) -{ - assert(umd->u_firstlineno > 0); - - /* Add the generator prefix instructions. */ - if (IS_GENERATOR(code_flags)) { - /* Note that RETURN_GENERATOR + POP_TOP have a net stack effect - * of 0. This is because RETURN_GENERATOR pushes an element - * with _PyFrame_StackPush before switching stacks. - */ - cfg_instr make_gen = { - .i_opcode = RETURN_GENERATOR, - .i_oparg = 0, - .i_loc = LOCATION(umd->u_firstlineno, umd->u_firstlineno, -1, -1), - .i_target = NULL, - }; - RETURN_IF_ERROR(_PyBasicblock_InsertInstruction(entryblock, 0, &make_gen)); - cfg_instr pop_top = { - .i_opcode = POP_TOP, - .i_oparg = 0, - .i_loc = NO_LOCATION, - .i_target = NULL, - }; - RETURN_IF_ERROR(_PyBasicblock_InsertInstruction(entryblock, 1, &pop_top)); - } - - /* Set up cells for any variable that escapes, to be put in a closure. */ - const int ncellvars = (int)PyDict_GET_SIZE(umd->u_cellvars); - if (ncellvars) { - // umd->u_cellvars has the cells out of order so we sort them - // before adding the MAKE_CELL instructions. Note that we - // adjust for arg cells, which come first. - const int nvars = ncellvars + (int)PyDict_GET_SIZE(umd->u_varnames); - int *sorted = PyMem_RawCalloc(nvars, sizeof(int)); - if (sorted == NULL) { - PyErr_NoMemory(); - return ERROR; - } - for (int i = 0; i < ncellvars; i++) { - sorted[fixed[i]] = i + 1; - } - for (int i = 0, ncellsused = 0; ncellsused < ncellvars; i++) { - int oldindex = sorted[i] - 1; - if (oldindex == -1) { - continue; - } - cfg_instr make_cell = { - .i_opcode = MAKE_CELL, - // This will get fixed in offset_derefs(). - .i_oparg = oldindex, - .i_loc = NO_LOCATION, - .i_target = NULL, - }; - if (_PyBasicblock_InsertInstruction(entryblock, ncellsused, &make_cell) < 0) { - PyMem_RawFree(sorted); - return ERROR; - } - ncellsused += 1; - } - PyMem_RawFree(sorted); - } - - if (nfreevars) { - cfg_instr copy_frees = { - .i_opcode = COPY_FREE_VARS, - .i_oparg = nfreevars, - .i_loc = NO_LOCATION, - .i_target = NULL, - }; - RETURN_IF_ERROR(_PyBasicblock_InsertInstruction(entryblock, 0, ©_frees)); - } - - return SUCCESS; -} - -static int -fix_cell_offsets(_PyCompile_CodeUnitMetadata *umd, basicblock *entryblock, int *fixedmap) -{ - int nlocals = (int)PyDict_GET_SIZE(umd->u_varnames); - int ncellvars = (int)PyDict_GET_SIZE(umd->u_cellvars); - int nfreevars = (int)PyDict_GET_SIZE(umd->u_freevars); - int noffsets = ncellvars + nfreevars; - - // First deal with duplicates (arg cells). - int numdropped = 0; - for (int i = 0; i < noffsets ; i++) { - if (fixedmap[i] == i + nlocals) { - fixedmap[i] -= numdropped; - } - else { - // It was a duplicate (cell/arg). - numdropped += 1; - } - } - - // 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++) { - 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; - switch(inst->i_opcode) { - case MAKE_CELL: - case LOAD_CLOSURE: - case LOAD_DEREF: - case STORE_DEREF: - case DELETE_DEREF: - case LOAD_FROM_DICT_OR_DEREF: - assert(oldoffset >= 0); - assert(oldoffset < noffsets); - assert(fixedmap[oldoffset] >= 0); - inst->i_oparg = fixedmap[oldoffset]; - } - } - } - - return numdropped; -} - - -static int -prepare_localsplus(_PyCompile_CodeUnitMetadata *umd, cfg_builder *g, int code_flags) -{ - assert(PyDict_GET_SIZE(umd->u_varnames) < INT_MAX); - assert(PyDict_GET_SIZE(umd->u_cellvars) < INT_MAX); - assert(PyDict_GET_SIZE(umd->u_freevars) < INT_MAX); - int nlocals = (int)PyDict_GET_SIZE(umd->u_varnames); - int ncellvars = (int)PyDict_GET_SIZE(umd->u_cellvars); - int nfreevars = (int)PyDict_GET_SIZE(umd->u_freevars); - assert(INT_MAX - nlocals - ncellvars > 0); - assert(INT_MAX - nlocals - ncellvars - nfreevars > 0); - int nlocalsplus = nlocals + ncellvars + nfreevars; - int* cellfixedoffsets = build_cellfixedoffsets(umd); - if (cellfixedoffsets == NULL) { - return ERROR; - } - - - // This must be called before fix_cell_offsets(). - if (insert_prefix_instructions(umd, g->g_entryblock, cellfixedoffsets, nfreevars, code_flags)) { - PyMem_Free(cellfixedoffsets); - return ERROR; - } - - int numdropped = fix_cell_offsets(umd, 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; -} - static int add_return_at_end(struct compiler *c, int addNone) { @@ -7720,42 +7525,18 @@ optimize_and_assemble_code_unit(struct compiler_unit *u, PyObject *const_cache, goto error; } int nparams = (int)PyList_GET_SIZE(u->u_ste->ste_varnames); - int nlocals = (int)PyDict_GET_SIZE(u->u_metadata.u_varnames); assert(u->u_metadata.u_firstlineno); - if (_PyCfg_OptimizeCodeUnit(&g, consts, const_cache, nlocals, - nparams, u->u_metadata.u_firstlineno) < 0) { - goto error; - } - int stackdepth = _PyCfg_Stackdepth(&g); - if (stackdepth < 0) { + int stackdepth; + int nlocalsplus; + if (_PyCfg_ToOptimizedInstructionList(&g, &u->u_metadata, + consts, const_cache, nparams, + u->u_metadata.u_firstlineno, code_flags, + &stackdepth, &nlocalsplus) < 0) { goto error; } - /* prepare_localsplus adds instructions for generators that push - * and pop an item on the stack. This assertion makes sure there - * is space on the stack for that. - * It should always be true, because a generator must have at - * least one expression or call to INTRINSIC_STOPITERATION_ERROR, - * which requires stackspace. - */ - assert(!(IS_GENERATOR(code_flags) && stackdepth == 0)); - /** Assembly **/ - int nlocalsplus = prepare_localsplus(&u->u_metadata, &g, code_flags); - if (nlocalsplus < 0) { - goto error; - } - - _PyCfg_ConvertPseudoOps(g.g_entryblock); - - /* Order of basic blocks must have been determined by now */ - - if (_PyCfg_ResolveJumps(&g) < 0) { - goto error; - } - - /* Can't modify the bytecode after computing jump offsets. */ if (cfg_to_instr_sequence(&g, &optimized_instrs) < 0) { goto error; @@ -8242,27 +8023,13 @@ _PyCompile_Assemble(_PyCompile_CodeUnitMetadata *umd, PyObject *filename, goto error; } - int stackdepth = _PyCfg_Stackdepth(&g); - if (stackdepth < 0) { - goto error; - } - int code_flags = 0; - int nlocalsplus = prepare_localsplus(umd, &g, code_flags); - if (nlocalsplus < 0) { + int stackdepth, nlocalsplus; + if (_PyCfg_OptimizedCfgToInstructionList(&g, umd, code_flags, + &stackdepth, &nlocalsplus) < 0) { goto error; } - _PyCfg_ConvertPseudoOps(g.g_entryblock); - - /* Order of basic blocks must have been determined by now */ - - if (_PyCfg_ResolveJumps(&g) < 0) { - goto error; - } - - /* Can't modify the bytecode after computing jump offsets. */ - if (cfg_to_instr_sequence(&g, &optimized_instrs) < 0) { goto error; } diff --git a/Python/flowgraph.c b/Python/flowgraph.c index a72b85d45aa27d..ad4ff83b0507e4 100644 --- a/Python/flowgraph.c +++ b/Python/flowgraph.c @@ -33,6 +33,8 @@ static const jump_target_label NO_LABEL = {-1}; #define SAME_LABEL(L1, L2) ((L1).id == (L2).id) #define IS_LABEL(L) (!SAME_LABEL((L), (NO_LABEL))) +#define LOCATION(LNO, END_LNO, COL, END_COL) \ + ((const _PyCompilerSrcLocation){(LNO), (END_LNO), (COL), (END_COL)}) static inline int is_block_push(cfg_instr *i) @@ -2293,3 +2295,251 @@ _PyCfg_OptimizeCodeUnit(cfg_builder *g, PyObject *consts, PyObject *const_cache, RETURN_IF_ERROR(resolve_line_numbers(g, firstlineno)); return SUCCESS; } + +static int * +build_cellfixedoffsets(_PyCompile_CodeUnitMetadata *umd) +{ + int nlocals = (int)PyDict_GET_SIZE(umd->u_varnames); + int ncellvars = (int)PyDict_GET_SIZE(umd->u_cellvars); + int nfreevars = (int)PyDict_GET_SIZE(umd->u_freevars); + + int noffsets = ncellvars + nfreevars; + int *fixed = PyMem_New(int, noffsets); + if (fixed == NULL) { + PyErr_NoMemory(); + return NULL; + } + for (int i = 0; i < noffsets; i++) { + fixed[i] = nlocals + i; + } + + PyObject *varname, *cellindex; + Py_ssize_t pos = 0; + while (PyDict_Next(umd->u_cellvars, &pos, &varname, &cellindex)) { + PyObject *varindex = PyDict_GetItem(umd->u_varnames, varname); + if (varindex != NULL) { + assert(PyLong_AS_LONG(cellindex) < INT_MAX); + assert(PyLong_AS_LONG(varindex) < INT_MAX); + int oldindex = (int)PyLong_AS_LONG(cellindex); + int argoffset = (int)PyLong_AS_LONG(varindex); + fixed[oldindex] = argoffset; + } + } + + return fixed; +} + +#define IS_GENERATOR(CF) \ + ((CF) & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR)) + +static int +insert_prefix_instructions(_PyCompile_CodeUnitMetadata *umd, basicblock *entryblock, + int *fixed, int nfreevars, int code_flags) +{ + assert(umd->u_firstlineno > 0); + + /* Add the generator prefix instructions. */ + if (IS_GENERATOR(code_flags)) { + /* Note that RETURN_GENERATOR + POP_TOP have a net stack effect + * of 0. This is because RETURN_GENERATOR pushes an element + * with _PyFrame_StackPush before switching stacks. + */ + cfg_instr make_gen = { + .i_opcode = RETURN_GENERATOR, + .i_oparg = 0, + .i_loc = LOCATION(umd->u_firstlineno, umd->u_firstlineno, -1, -1), + .i_target = NULL, + }; + RETURN_IF_ERROR(_PyBasicblock_InsertInstruction(entryblock, 0, &make_gen)); + cfg_instr pop_top = { + .i_opcode = POP_TOP, + .i_oparg = 0, + .i_loc = NO_LOCATION, + .i_target = NULL, + }; + RETURN_IF_ERROR(_PyBasicblock_InsertInstruction(entryblock, 1, &pop_top)); + } + + /* Set up cells for any variable that escapes, to be put in a closure. */ + const int ncellvars = (int)PyDict_GET_SIZE(umd->u_cellvars); + if (ncellvars) { + // umd->u_cellvars has the cells out of order so we sort them + // before adding the MAKE_CELL instructions. Note that we + // adjust for arg cells, which come first. + const int nvars = ncellvars + (int)PyDict_GET_SIZE(umd->u_varnames); + int *sorted = PyMem_RawCalloc(nvars, sizeof(int)); + if (sorted == NULL) { + PyErr_NoMemory(); + return ERROR; + } + for (int i = 0; i < ncellvars; i++) { + sorted[fixed[i]] = i + 1; + } + for (int i = 0, ncellsused = 0; ncellsused < ncellvars; i++) { + int oldindex = sorted[i] - 1; + if (oldindex == -1) { + continue; + } + cfg_instr make_cell = { + .i_opcode = MAKE_CELL, + // This will get fixed in offset_derefs(). + .i_oparg = oldindex, + .i_loc = NO_LOCATION, + .i_target = NULL, + }; + if (_PyBasicblock_InsertInstruction(entryblock, ncellsused, &make_cell) < 0) { + PyMem_RawFree(sorted); + return ERROR; + } + ncellsused += 1; + } + PyMem_RawFree(sorted); + } + + if (nfreevars) { + cfg_instr copy_frees = { + .i_opcode = COPY_FREE_VARS, + .i_oparg = nfreevars, + .i_loc = NO_LOCATION, + .i_target = NULL, + }; + RETURN_IF_ERROR(_PyBasicblock_InsertInstruction(entryblock, 0, ©_frees)); + } + + return SUCCESS; +} + +static int +fix_cell_offsets(_PyCompile_CodeUnitMetadata *umd, basicblock *entryblock, int *fixedmap) +{ + int nlocals = (int)PyDict_GET_SIZE(umd->u_varnames); + int ncellvars = (int)PyDict_GET_SIZE(umd->u_cellvars); + int nfreevars = (int)PyDict_GET_SIZE(umd->u_freevars); + int noffsets = ncellvars + nfreevars; + + // First deal with duplicates (arg cells). + int numdropped = 0; + for (int i = 0; i < noffsets ; i++) { + if (fixedmap[i] == i + nlocals) { + fixedmap[i] -= numdropped; + } + else { + // It was a duplicate (cell/arg). + numdropped += 1; + } + } + + // 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++) { + 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; + switch(inst->i_opcode) { + case MAKE_CELL: + case LOAD_CLOSURE: + case LOAD_DEREF: + case STORE_DEREF: + case DELETE_DEREF: + case LOAD_FROM_DICT_OR_DEREF: + assert(oldoffset >= 0); + assert(oldoffset < noffsets); + assert(fixedmap[oldoffset] >= 0); + inst->i_oparg = fixedmap[oldoffset]; + } + } + } + + return numdropped; +} + +static int +prepare_localsplus(_PyCompile_CodeUnitMetadata *umd, cfg_builder *g, int code_flags) +{ + assert(PyDict_GET_SIZE(umd->u_varnames) < INT_MAX); + assert(PyDict_GET_SIZE(umd->u_cellvars) < INT_MAX); + assert(PyDict_GET_SIZE(umd->u_freevars) < INT_MAX); + int nlocals = (int)PyDict_GET_SIZE(umd->u_varnames); + int ncellvars = (int)PyDict_GET_SIZE(umd->u_cellvars); + int nfreevars = (int)PyDict_GET_SIZE(umd->u_freevars); + assert(INT_MAX - nlocals - ncellvars > 0); + assert(INT_MAX - nlocals - ncellvars - nfreevars > 0); + int nlocalsplus = nlocals + ncellvars + nfreevars; + int* cellfixedoffsets = build_cellfixedoffsets(umd); + if (cellfixedoffsets == NULL) { + return ERROR; + } + + // This must be called before fix_cell_offsets(). + if (insert_prefix_instructions(umd, g->g_entryblock, cellfixedoffsets, nfreevars, code_flags)) { + PyMem_Free(cellfixedoffsets); + return ERROR; + } + + int numdropped = fix_cell_offsets(umd, 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; +} + +int +_PyCfg_OptimizedCfgToInstructionList(_PyCfgBuilder *g, + _PyCompile_CodeUnitMetadata *umd, int code_flags, + int *stackdepth, int *nlocalsplus) +{ + *stackdepth = _PyCfg_Stackdepth(g); + if (*stackdepth < 0) { + return ERROR; + } + + /* prepare_localsplus adds instructions for generators that push + * and pop an item on the stack. This assertion makes sure there + * is space on the stack for that. + * It should always be true, because a generator must have at + * least one expression or call to INTRINSIC_STOPITERATION_ERROR, + * which requires stackspace. + */ + assert(!(IS_GENERATOR(code_flags) && *stackdepth == 0)); + + *nlocalsplus = prepare_localsplus(umd, g, code_flags); + if (*nlocalsplus < 0) { + return ERROR; + } + + _PyCfg_ConvertPseudoOps(g->g_entryblock); + + /* Order of basic blocks must have been determined by now */ + + if (_PyCfg_ResolveJumps(g) < 0) { + return ERROR; + } + + /* Can't modify the bytecode after computing jump offsets. */ + + return SUCCESS; + +} + +int +_PyCfg_ToOptimizedInstructionList(_PyCfgBuilder *g, _PyCompile_CodeUnitMetadata *umd, + PyObject *consts, PyObject *const_cache, + int nparams, int firstlineno, int code_flags, + int *stackdepth, int *nlocalsplus) +{ + int nlocals = (int)PyDict_GET_SIZE(umd->u_varnames); + RETURN_IF_ERROR(_PyCfg_OptimizeCodeUnit(g, consts, const_cache, nlocals, + nparams, firstlineno)); + + RETURN_IF_ERROR(_PyCfg_OptimizedCfgToInstructionList( + g, umd, code_flags, + stackdepth, nlocalsplus)); + + return SUCCESS; +} + From 313e9f2d952443aa5635e3015a2076f8e62e41dd Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Thu, 3 Aug 2023 23:38:30 +0100 Subject: [PATCH 2/9] f --- Include/internal/pycore_flowgraph.h | 5 ----- Python/compile.c | 12 ++++++++---- Python/flowgraph.c | 16 ---------------- 3 files changed, 8 insertions(+), 25 deletions(-) diff --git a/Include/internal/pycore_flowgraph.h b/Include/internal/pycore_flowgraph.h index ce3860e0d3901c..ca10bc3a49934e 100644 --- a/Include/internal/pycore_flowgraph.h +++ b/Include/internal/pycore_flowgraph.h @@ -94,11 +94,6 @@ int _PyCfg_OptimizeCodeUnit(_PyCfgBuilder *g, PyObject *consts, PyObject *const_ int _PyCfg_OptimizedCfgToInstructionList(_PyCfgBuilder *g, _PyCompile_CodeUnitMetadata *umd, int code_flags, int *stackdepth, int *nlocalsplus); -int _PyCfg_ToOptimizedInstructionList(_PyCfgBuilder *g, _PyCompile_CodeUnitMetadata *umd, - PyObject *consts, PyObject *const_cache, - int nparams, int firstlineno, int code_flags, - int *stackdepth, int *nlocalsplus); - int _PyCfg_Stackdepth(_PyCfgBuilder *g); void _PyCfg_ConvertPseudoOps(_PyCfgBasicblock *entryblock); int _PyCfg_ResolveJumps(_PyCfgBuilder *g); diff --git a/Python/compile.c b/Python/compile.c index f33d6655b63030..c68e78c33126a6 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -7524,15 +7524,19 @@ optimize_and_assemble_code_unit(struct compiler_unit *u, PyObject *const_cache, if (instr_sequence_to_cfg(&u->u_instr_sequence, &g) < 0) { goto error; } + int nlocals = (int)PyDict_GET_SIZE(u->u_metadata.u_varnames); int nparams = (int)PyList_GET_SIZE(u->u_ste->ste_varnames); assert(u->u_metadata.u_firstlineno); + if (_PyCfg_OptimizeCodeUnit(&g, consts, const_cache, nlocals, + nparams, u->u_metadata.u_firstlineno) < 0) { + goto error; + } + int stackdepth; int nlocalsplus; - if (_PyCfg_ToOptimizedInstructionList(&g, &u->u_metadata, - consts, const_cache, nparams, - u->u_metadata.u_firstlineno, code_flags, - &stackdepth, &nlocalsplus) < 0) { + if (_PyCfg_OptimizedCfgToInstructionList(&g, &u->u_metadata, code_flags, + &stackdepth, &nlocalsplus) < 0) { goto error; } diff --git a/Python/flowgraph.c b/Python/flowgraph.c index ad4ff83b0507e4..9428c084d33784 100644 --- a/Python/flowgraph.c +++ b/Python/flowgraph.c @@ -2526,20 +2526,4 @@ _PyCfg_OptimizedCfgToInstructionList(_PyCfgBuilder *g, } -int -_PyCfg_ToOptimizedInstructionList(_PyCfgBuilder *g, _PyCompile_CodeUnitMetadata *umd, - PyObject *consts, PyObject *const_cache, - int nparams, int firstlineno, int code_flags, - int *stackdepth, int *nlocalsplus) -{ - int nlocals = (int)PyDict_GET_SIZE(umd->u_varnames); - RETURN_IF_ERROR(_PyCfg_OptimizeCodeUnit(g, consts, const_cache, nlocals, - nparams, firstlineno)); - - RETURN_IF_ERROR(_PyCfg_OptimizedCfgToInstructionList( - g, umd, code_flags, - stackdepth, nlocalsplus)); - - return SUCCESS; -} From 4e42adc52cbeb7c5a003c4fd05eb2c70c99925c7 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Fri, 4 Aug 2023 11:11:23 +0100 Subject: [PATCH 3/9] _PyCfgBuilder_Init --> _PyCfgBuilder_New --- Include/internal/pycore_flowgraph.h | 4 +- Python/compile.c | 69 ++++++++++++++++------------- Python/flowgraph.c | 26 +++++++++-- 3 files changed, 64 insertions(+), 35 deletions(-) diff --git a/Include/internal/pycore_flowgraph.h b/Include/internal/pycore_flowgraph.h index ca10bc3a49934e..088a808158a96c 100644 --- a/Include/internal/pycore_flowgraph.h +++ b/Include/internal/pycore_flowgraph.h @@ -85,8 +85,8 @@ typedef struct cfg_builder_ { int _PyCfgBuilder_UseLabel(_PyCfgBuilder *g, _PyCfgJumpTargetLabel lbl); int _PyCfgBuilder_Addop(_PyCfgBuilder *g, int opcode, int oparg, _PyCompilerSrcLocation loc); -int _PyCfgBuilder_Init(_PyCfgBuilder *g); -void _PyCfgBuilder_Fini(_PyCfgBuilder *g); +_PyCfgBuilder* _PyCfgBuilder_New(void); +void _PyCfgBuilder_Free(_PyCfgBuilder *g); int _PyCfg_OptimizeCodeUnit(_PyCfgBuilder *g, PyObject *consts, PyObject *const_cache, int nlocals, int nparams, int firstlineno); diff --git a/Python/compile.c b/Python/compile.c index c68e78c33126a6..9c102f0f79672b 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -288,10 +288,12 @@ instr_sequence_fini(instr_sequence *seq) { seq->s_instrs = NULL; } -static int -instr_sequence_to_cfg(instr_sequence *seq, cfg_builder *g) { - memset(g, 0, sizeof(cfg_builder)); - RETURN_IF_ERROR(_PyCfgBuilder_Init(g)); +static cfg_builder* +instr_sequence_to_cfg(instr_sequence *seq) { + cfg_builder *g = _PyCfgBuilder_New(); + if (g == NULL) { + return NULL; + } /* There can be more than one label for the same offset. The * offset2lbl maping selects one of them which we use consistently. @@ -300,7 +302,7 @@ instr_sequence_to_cfg(instr_sequence *seq, cfg_builder *g) { int *offset2lbl = PyMem_Malloc(seq->s_used * sizeof(int)); if (offset2lbl == NULL) { PyErr_NoMemory(); - return ERROR; + goto error; } for (int i = 0; i < seq->s_used; i++) { offset2lbl[i] = -1; @@ -344,12 +346,13 @@ instr_sequence_to_cfg(instr_sequence *seq, cfg_builder *g) { } if ((size_t)nblocks > SIZE_MAX / sizeof(basicblock *)) { PyErr_NoMemory(); - return ERROR; + goto error; } - return SUCCESS; + return g; error: PyMem_Free(offset2lbl); - return ERROR; + _PyCfgBuilder_Free(g); + return NULL; } @@ -7512,6 +7515,7 @@ static PyCodeObject * optimize_and_assemble_code_unit(struct compiler_unit *u, PyObject *const_cache, int code_flags, PyObject *filename) { + cfg_builder *g = NULL; instr_sequence optimized_instrs; memset(&optimized_instrs, 0, sizeof(instr_sequence)); @@ -7520,29 +7524,29 @@ optimize_and_assemble_code_unit(struct compiler_unit *u, PyObject *const_cache, if (consts == NULL) { goto error; } - cfg_builder g; - if (instr_sequence_to_cfg(&u->u_instr_sequence, &g) < 0) { + g = instr_sequence_to_cfg(&u->u_instr_sequence); + if (g == NULL) { goto error; } int nlocals = (int)PyDict_GET_SIZE(u->u_metadata.u_varnames); int nparams = (int)PyList_GET_SIZE(u->u_ste->ste_varnames); assert(u->u_metadata.u_firstlineno); - if (_PyCfg_OptimizeCodeUnit(&g, consts, const_cache, nlocals, + if (_PyCfg_OptimizeCodeUnit(g, consts, const_cache, nlocals, nparams, u->u_metadata.u_firstlineno) < 0) { goto error; } int stackdepth; int nlocalsplus; - if (_PyCfg_OptimizedCfgToInstructionList(&g, &u->u_metadata, code_flags, + if (_PyCfg_OptimizedCfgToInstructionList(g, &u->u_metadata, code_flags, &stackdepth, &nlocalsplus) < 0) { goto error; } /** Assembly **/ - if (cfg_to_instr_sequence(&g, &optimized_instrs) < 0) { + if (cfg_to_instr_sequence(g, &optimized_instrs) < 0) { goto error; } @@ -7553,7 +7557,7 @@ optimize_and_assemble_code_unit(struct compiler_unit *u, PyObject *const_cache, error: Py_XDECREF(consts); instr_sequence_fini(&optimized_instrs); - _PyCfgBuilder_Fini(&g); + _PyCfgBuilder_Free(g); return co; } @@ -7709,23 +7713,26 @@ instructions_to_instr_sequence(PyObject *instructions, instr_sequence *seq) return ERROR; } -static int -instructions_to_cfg(PyObject *instructions, cfg_builder *g) +static cfg_builder* +instructions_to_cfg(PyObject *instructions) { + cfg_builder *g = NULL; instr_sequence seq; memset(&seq, 0, sizeof(instr_sequence)); if (instructions_to_instr_sequence(instructions, &seq) < 0) { goto error; } - if (instr_sequence_to_cfg(&seq, g) < 0) { + g = instr_sequence_to_cfg(&seq); + if (g == NULL) { goto error; } instr_sequence_fini(&seq); - return SUCCESS; + return g; error: + _PyCfgBuilder_Free(g); instr_sequence_fini(&seq); - return ERROR; + return NULL; } static PyObject * @@ -7981,25 +7988,26 @@ _PyCompile_CodeGen(PyObject *ast, PyObject *filename, PyCompilerFlags *pflags, PyObject * _PyCompile_OptimizeCfg(PyObject *instructions, PyObject *consts, int nlocals) { + cfg_builder *g = NULL; PyObject *res = NULL; PyObject *const_cache = PyDict_New(); if (const_cache == NULL) { return NULL; } - cfg_builder g; - if (instructions_to_cfg(instructions, &g) < 0) { + g = instructions_to_cfg(instructions); + if (g == NULL) { goto error; } int nparams = 0, firstlineno = 1; - if (_PyCfg_OptimizeCodeUnit(&g, consts, const_cache, nlocals, + if (_PyCfg_OptimizeCodeUnit(g, consts, const_cache, nlocals, nparams, firstlineno) < 0) { goto error; } - res = cfg_to_instructions(&g); + res = cfg_to_instructions(g); error: Py_DECREF(const_cache); - _PyCfgBuilder_Fini(&g); + _PyCfgBuilder_Free(g); return res; } @@ -8009,6 +8017,7 @@ PyCodeObject * _PyCompile_Assemble(_PyCompile_CodeUnitMetadata *umd, PyObject *filename, PyObject *instructions) { + cfg_builder *g = NULL; PyCodeObject *co = NULL; instr_sequence optimized_instrs; memset(&optimized_instrs, 0, sizeof(instr_sequence)); @@ -8018,23 +8027,23 @@ _PyCompile_Assemble(_PyCompile_CodeUnitMetadata *umd, PyObject *filename, return NULL; } - cfg_builder g; - if (instructions_to_cfg(instructions, &g) < 0) { + g = instructions_to_cfg(instructions); + if (g == NULL) { goto error; } - if (_PyCfg_JumpLabelsToTargets(g.g_entryblock) < 0) { + if (_PyCfg_JumpLabelsToTargets(g->g_entryblock) < 0) { goto error; } int code_flags = 0; int stackdepth, nlocalsplus; - if (_PyCfg_OptimizedCfgToInstructionList(&g, umd, code_flags, + if (_PyCfg_OptimizedCfgToInstructionList(g, umd, code_flags, &stackdepth, &nlocalsplus) < 0) { goto error; } - if (cfg_to_instr_sequence(&g, &optimized_instrs) < 0) { + if (cfg_to_instr_sequence(g, &optimized_instrs) < 0) { goto error; } @@ -8049,7 +8058,7 @@ _PyCompile_Assemble(_PyCompile_CodeUnitMetadata *umd, PyObject *filename, error: Py_DECREF(const_cache); - _PyCfgBuilder_Fini(&g); + _PyCfgBuilder_Free(g); instr_sequence_fini(&optimized_instrs); return co; } diff --git a/Python/flowgraph.c b/Python/flowgraph.c index 9428c084d33784..f405f44318e8b2 100644 --- a/Python/flowgraph.c +++ b/Python/flowgraph.c @@ -313,8 +313,8 @@ cfg_builder_check(cfg_builder *g) } #endif -int -_PyCfgBuilder_Init(cfg_builder *g) +static int +init_cfg_builder(cfg_builder *g) { g->g_block_list = NULL; basicblock *block = cfg_builder_new_block(g); @@ -326,9 +326,28 @@ _PyCfgBuilder_Init(cfg_builder *g) return SUCCESS; } +cfg_builder * +_PyCfgBuilder_New(void) +{ + cfg_builder *g = PyMem_Malloc(sizeof(cfg_builder)); + if (g == NULL) { + PyErr_NoMemory(); + return NULL; + } + memset(g, 0, sizeof(cfg_builder)); + if (init_cfg_builder(g) < 0) { + PyMem_Free(g); + return NULL; + } + return g; +} + void -_PyCfgBuilder_Fini(cfg_builder* g) +_PyCfgBuilder_Free(cfg_builder* g) { + if (g == NULL) { + return; + } assert(cfg_builder_check(g)); basicblock *b = g->g_block_list; while (b != NULL) { @@ -339,6 +358,7 @@ _PyCfgBuilder_Fini(cfg_builder* g) PyObject_Free((void *)b); b = next; } + PyMem_Free(g); } int From 265706906f73bfb5e749ab1642dd6d99962ea050 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Fri, 4 Aug 2023 12:05:12 +0100 Subject: [PATCH 4/9] move _PyCfgBuilder_CheckSize to flowgraph.c --- Include/internal/pycore_flowgraph.h | 5 +++-- Python/compile.c | 21 +++++++-------------- Python/flowgraph.c | 16 +++++++++++++++- 3 files changed, 25 insertions(+), 17 deletions(-) diff --git a/Include/internal/pycore_flowgraph.h b/Include/internal/pycore_flowgraph.h index 088a808158a96c..b16949940ee051 100644 --- a/Include/internal/pycore_flowgraph.h +++ b/Include/internal/pycore_flowgraph.h @@ -87,12 +87,13 @@ int _PyCfgBuilder_Addop(_PyCfgBuilder *g, int opcode, int oparg, _PyCompilerSrcL _PyCfgBuilder* _PyCfgBuilder_New(void); void _PyCfgBuilder_Free(_PyCfgBuilder *g); +int _PyCfgBuilder_CheckSize(_PyCfgBuilder* g); int _PyCfg_OptimizeCodeUnit(_PyCfgBuilder *g, PyObject *consts, PyObject *const_cache, int nlocals, int nparams, int firstlineno); -int _PyCfg_OptimizedCfgToInstructionList(_PyCfgBuilder *g, _PyCompile_CodeUnitMetadata *umd, - int code_flags, int *stackdepth, int *nlocalsplus); +int _PyCfg_OptimizedCfgToInstructionSequence(_PyCfgBuilder *g, _PyCompile_CodeUnitMetadata *umd, + int code_flags, int *stackdepth, int *nlocalsplus); int _PyCfg_Stackdepth(_PyCfgBuilder *g); void _PyCfg_ConvertPseudoOps(_PyCfgBasicblock *entryblock); diff --git a/Python/compile.c b/Python/compile.c index 9c102f0f79672b..7f785aab415906 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -338,24 +338,17 @@ instr_sequence_to_cfg(instr_sequence *seq) { goto error; } } - PyMem_Free(offset2lbl); - - int nblocks = 0; - for (basicblock *b = g->g_block_list; b != NULL; b = b->b_list) { - nblocks++; - } - if ((size_t)nblocks > SIZE_MAX / sizeof(basicblock *)) { - PyErr_NoMemory(); + if (_PyCfgBuilder_CheckSize(g) < 0) { goto error; } + PyMem_Free(offset2lbl); return g; error: - PyMem_Free(offset2lbl); _PyCfgBuilder_Free(g); + PyMem_Free(offset2lbl); return NULL; } - /* The following items change on entry and exit of code blocks. They must be saved and restored when returning to a block. */ @@ -7539,8 +7532,8 @@ optimize_and_assemble_code_unit(struct compiler_unit *u, PyObject *const_cache, int stackdepth; int nlocalsplus; - if (_PyCfg_OptimizedCfgToInstructionList(g, &u->u_metadata, code_flags, - &stackdepth, &nlocalsplus) < 0) { + if (_PyCfg_OptimizedCfgToInstructionSequence(g, &u->u_metadata, code_flags, + &stackdepth, &nlocalsplus) < 0) { goto error; } @@ -8038,8 +8031,8 @@ _PyCompile_Assemble(_PyCompile_CodeUnitMetadata *umd, PyObject *filename, int code_flags = 0; int stackdepth, nlocalsplus; - if (_PyCfg_OptimizedCfgToInstructionList(g, umd, code_flags, - &stackdepth, &nlocalsplus) < 0) { + if (_PyCfg_OptimizedCfgToInstructionSequence(g, umd, code_flags, + &stackdepth, &nlocalsplus) < 0) { goto error; } diff --git a/Python/flowgraph.c b/Python/flowgraph.c index f405f44318e8b2..94e8579ffa9ed1 100644 --- a/Python/flowgraph.c +++ b/Python/flowgraph.c @@ -361,6 +361,20 @@ _PyCfgBuilder_Free(cfg_builder* g) PyMem_Free(g); } +int +_PyCfgBuilder_CheckSize(cfg_builder* g) +{ + int nblocks = 0; + for (basicblock *b = g->g_block_list; b != NULL; b = b->b_list) { + nblocks++; + } + if ((size_t)nblocks > SIZE_MAX / sizeof(basicblock *)) { + PyErr_NoMemory(); + return ERROR; + } + return SUCCESS; +} + int _PyCfgBuilder_UseLabel(cfg_builder *g, jump_target_label lbl) { @@ -2509,7 +2523,7 @@ prepare_localsplus(_PyCompile_CodeUnitMetadata *umd, cfg_builder *g, int code_fl } int -_PyCfg_OptimizedCfgToInstructionList(_PyCfgBuilder *g, +_PyCfg_OptimizedCfgToInstructionSequence(_PyCfgBuilder *g, _PyCompile_CodeUnitMetadata *umd, int code_flags, int *stackdepth, int *nlocalsplus) { From 3c6afe772413be1569305ff5a6c62d9be2f2f553 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Fri, 4 Aug 2023 16:42:23 +0100 Subject: [PATCH 5/9] move cfg_to_instr_sequence to flowgraph.c --- Include/internal/pycore_compile.h | 5 ++ Include/internal/pycore_flowgraph.h | 3 +- Python/compile.c | 75 +++++++---------------------- Python/flowgraph.c | 46 ++++++++++++++++-- 4 files changed, 68 insertions(+), 61 deletions(-) diff --git a/Include/internal/pycore_compile.h b/Include/internal/pycore_compile.h index fa2f64021e73c9..ad657c0f0fcedc 100644 --- a/Include/internal/pycore_compile.h +++ b/Include/internal/pycore_compile.h @@ -54,6 +54,11 @@ typedef struct { int s_next_free_label; /* next free label id */ } _PyCompile_InstructionSequence; +int _PyCompile_InstructionSequence_UseLabel(_PyCompile_InstructionSequence *seq, int lbl); +int _PyCompile_InstructionSequence_Addop(_PyCompile_InstructionSequence *seq, + int opcode, int oparg, + _PyCompilerSrcLocation loc); + typedef struct { PyObject *u_name; PyObject *u_qualname; /* dot-separated qualified name (lazy) */ diff --git a/Include/internal/pycore_flowgraph.h b/Include/internal/pycore_flowgraph.h index b16949940ee051..479b4b0ac1be77 100644 --- a/Include/internal/pycore_flowgraph.h +++ b/Include/internal/pycore_flowgraph.h @@ -93,7 +93,8 @@ int _PyCfg_OptimizeCodeUnit(_PyCfgBuilder *g, PyObject *consts, PyObject *const_ int nlocals, int nparams, int firstlineno); int _PyCfg_OptimizedCfgToInstructionSequence(_PyCfgBuilder *g, _PyCompile_CodeUnitMetadata *umd, - int code_flags, int *stackdepth, int *nlocalsplus); + int code_flags, int *stackdepth, int *nlocalsplus, + _PyCompile_InstructionSequence *seq); int _PyCfg_Stackdepth(_PyCfgBuilder *g); void _PyCfg_ConvertPseudoOps(_PyCfgBasicblock *entryblock); diff --git a/Python/compile.c b/Python/compile.c index 7f785aab415906..36b3ebb6a88c09 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -101,7 +101,7 @@ static jump_target_label NO_LABEL = {-1}; } #define USE_LABEL(C, LBL) \ - RETURN_IF_ERROR(instr_sequence_use_label(INSTR_SEQUENCE(C), (LBL).id)) + RETURN_IF_ERROR(_PyCompile_InstructionSequence_UseLabel(INSTR_SEQUENCE(C), (LBL).id)) /* fblockinfo tracks the current frame block. @@ -218,8 +218,9 @@ instr_sequence_new_label(instr_sequence *seq) return lbl; } -static int -instr_sequence_use_label(instr_sequence *seq, int lbl) { +int +_PyCompile_InstructionSequence_UseLabel(instr_sequence *seq, int lbl) +{ int old_size = seq->s_labelmap_size; RETURN_IF_ERROR( _PyCompile_EnsureArrayLargeEnough(lbl, @@ -238,8 +239,9 @@ instr_sequence_use_label(instr_sequence *seq, int lbl) { #define MAX_OPCODE 511 -static int -instr_sequence_addop(instr_sequence *seq, int opcode, int oparg, location loc) +int +_PyCompile_InstructionSequence_Addop(instr_sequence *seq, int opcode, int oparg, + location loc) { assert(0 <= opcode && opcode <= MAX_OPCODE); assert(IS_WITHIN_OPCODE_RANGE(opcode)); @@ -916,7 +918,7 @@ codegen_addop_noarg(instr_sequence *seq, int opcode, location loc) { assert(!OPCODE_HAS_ARG(opcode)); assert(!IS_ASSEMBLER_OPCODE(opcode)); - return instr_sequence_addop(seq, opcode, 0, loc); + return _PyCompile_InstructionSequence_Addop(seq, opcode, 0, loc); } static Py_ssize_t @@ -1149,7 +1151,7 @@ codegen_addop_i(instr_sequence *seq, int opcode, Py_ssize_t oparg, location loc) int oparg_ = Py_SAFE_DOWNCAST(oparg, Py_ssize_t, int); assert(!IS_ASSEMBLER_OPCODE(opcode)); - return instr_sequence_addop(seq, opcode, oparg_, loc); + return _PyCompile_InstructionSequence_Addop(seq, opcode, oparg_, loc); } static int @@ -1159,7 +1161,7 @@ codegen_addop_j(instr_sequence *seq, location loc, assert(IS_LABEL(target)); assert(OPCODE_HAS_JUMP(opcode) || IS_BLOCK_PUSH_OPCODE(opcode)); assert(!IS_ASSEMBLER_OPCODE(opcode)); - return instr_sequence_addop(seq, opcode, target.id, loc); + return _PyCompile_InstructionSequence_Addop(seq, opcode, target.id, loc); } #define RETURN_IF_ERROR_IN_SCOPE(C, CALL) { \ @@ -7502,8 +7504,6 @@ add_return_at_end(struct compiler *c, int addNone) return SUCCESS; } -static int cfg_to_instr_sequence(cfg_builder *g, instr_sequence *seq); - static PyCodeObject * optimize_and_assemble_code_unit(struct compiler_unit *u, PyObject *const_cache, int code_flags, PyObject *filename) @@ -7533,16 +7533,13 @@ optimize_and_assemble_code_unit(struct compiler_unit *u, PyObject *const_cache, int stackdepth; int nlocalsplus; if (_PyCfg_OptimizedCfgToInstructionSequence(g, &u->u_metadata, code_flags, - &stackdepth, &nlocalsplus) < 0) { + &stackdepth, &nlocalsplus, + &optimized_instrs) < 0) { goto error; } /** Assembly **/ - if (cfg_to_instr_sequence(g, &optimized_instrs) < 0) { - goto error; - } - co = _PyAssemble_MakeCodeObject(&u->u_metadata, const_cache, consts, stackdepth, &optimized_instrs, nlocalsplus, code_flags, filename); @@ -7573,39 +7570,6 @@ optimize_and_assemble(struct compiler *c, int addNone) return optimize_and_assemble_code_unit(u, const_cache, code_flags, filename); } -static int -cfg_to_instr_sequence(cfg_builder *g, instr_sequence *seq) -{ - int lbl = 0; - for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { - b->b_label = (jump_target_label){lbl}; - lbl += b->b_iused; - } - for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { - RETURN_IF_ERROR(instr_sequence_use_label(seq, b->b_label.id)); - for (int i = 0; i < b->b_iused; i++) { - cfg_instr *instr = &b->b_instr[i]; - if (OPCODE_HAS_JUMP(instr->i_opcode)) { - instr->i_oparg = instr->i_target->b_label.id; - } - RETURN_IF_ERROR( - instr_sequence_addop(seq, instr->i_opcode, instr->i_oparg, instr->i_loc)); - - _PyCompile_ExceptHandlerInfo *hi = &seq->s_instrs[seq->s_used-1].i_except_handler_info; - if (instr->i_except != NULL) { - hi->h_label = instr->i_except->b_label.id; - hi->h_startdepth = instr->i_except->b_startdepth; - hi->h_preserve_lasti = instr->i_except->b_preserve_lasti; - } - else { - hi->h_label = -1; - } - } - } - return SUCCESS; -} - - /* Access to compiler optimizations for unit tests. * * _PyCompile_CodeGen takes and AST, applies code-gen and @@ -7655,7 +7619,7 @@ instructions_to_instr_sequence(PyObject *instructions, instr_sequence *seq) for (int i = 0; i < num_insts; i++) { if (is_target[i]) { - if (instr_sequence_use_label(seq, i) < 0) { + if (_PyCompile_InstructionSequence_UseLabel(seq, i) < 0) { goto error; } } @@ -7695,7 +7659,7 @@ instructions_to_instr_sequence(PyObject *instructions, instr_sequence *seq) if (PyErr_Occurred()) { goto error; } - if (instr_sequence_addop(seq, opcode, oparg, loc) < 0) { + if (_PyCompile_InstructionSequence_Addop(seq, opcode, oparg, loc) < 0) { goto error; } } @@ -8004,7 +7968,7 @@ _PyCompile_OptimizeCfg(PyObject *instructions, PyObject *consts, int nlocals) return res; } -int _PyCfg_JumpLabelsToTargets(basicblock *entryblock); +int _PyCfg_JumpLabelsToTargets(cfg_builder *g); PyCodeObject * _PyCompile_Assemble(_PyCompile_CodeUnitMetadata *umd, PyObject *filename, @@ -8025,18 +7989,15 @@ _PyCompile_Assemble(_PyCompile_CodeUnitMetadata *umd, PyObject *filename, goto error; } - if (_PyCfg_JumpLabelsToTargets(g->g_entryblock) < 0) { + if (_PyCfg_JumpLabelsToTargets(g) < 0) { goto error; } int code_flags = 0; int stackdepth, nlocalsplus; if (_PyCfg_OptimizedCfgToInstructionSequence(g, umd, code_flags, - &stackdepth, &nlocalsplus) < 0) { - goto error; - } - - if (cfg_to_instr_sequence(g, &optimized_instrs) < 0) { + &stackdepth, &nlocalsplus, + &optimized_instrs) < 0) { goto error; } diff --git a/Python/flowgraph.c b/Python/flowgraph.c index 94e8579ffa9ed1..5f33e0b4aca5d2 100644 --- a/Python/flowgraph.c +++ b/Python/flowgraph.c @@ -565,9 +565,9 @@ translate_jump_labels_to_targets(basicblock *entryblock) } int -_PyCfg_JumpLabelsToTargets(basicblock *entryblock) +_PyCfg_JumpLabelsToTargets(_PyCfgBuilder *g) { - return translate_jump_labels_to_targets(entryblock); + return translate_jump_labels_to_targets(g->g_entryblock); } static int @@ -2522,10 +2522,47 @@ prepare_localsplus(_PyCompile_CodeUnitMetadata *umd, cfg_builder *g, int code_fl return nlocalsplus; } +typedef _PyCompile_InstructionSequence instr_sequence; + +static int +cfg_to_instr_sequence(cfg_builder *g, instr_sequence *seq) +{ + int lbl = 0; + for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { + b->b_label = (jump_target_label){lbl}; + lbl += b->b_iused; + } + for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { + RETURN_IF_ERROR(_PyCompile_InstructionSequence_UseLabel(seq, b->b_label.id)); + for (int i = 0; i < b->b_iused; i++) { + cfg_instr *instr = &b->b_instr[i]; + if (OPCODE_HAS_JUMP(instr->i_opcode)) { + instr->i_oparg = instr->i_target->b_label.id; + } + RETURN_IF_ERROR( + _PyCompile_InstructionSequence_Addop( + seq, instr->i_opcode, instr->i_oparg, instr->i_loc)); + + _PyCompile_ExceptHandlerInfo *hi = &seq->s_instrs[seq->s_used-1].i_except_handler_info; + if (instr->i_except != NULL) { + hi->h_label = instr->i_except->b_label.id; + hi->h_startdepth = instr->i_except->b_startdepth; + hi->h_preserve_lasti = instr->i_except->b_preserve_lasti; + } + else { + hi->h_label = -1; + } + } + } + return SUCCESS; +} + + int _PyCfg_OptimizedCfgToInstructionSequence(_PyCfgBuilder *g, _PyCompile_CodeUnitMetadata *umd, int code_flags, - int *stackdepth, int *nlocalsplus) + int *stackdepth, int *nlocalsplus, + instr_sequence *seq) { *stackdepth = _PyCfg_Stackdepth(g); if (*stackdepth < 0) { @@ -2555,6 +2592,9 @@ _PyCfg_OptimizedCfgToInstructionSequence(_PyCfgBuilder *g, } /* Can't modify the bytecode after computing jump offsets. */ + if (cfg_to_instr_sequence(g, seq) < 0) { + return ERROR; + } return SUCCESS; From 0197e0b6e18cad28a2d806b51179914ce96c8348 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Fri, 4 Aug 2023 17:30:25 +0100 Subject: [PATCH 6/9] some functions became static --- Include/internal/pycore_flowgraph.h | 6 +--- Python/compile.c | 42 ++++--------------------- Python/flowgraph.c | 49 +++++++++++------------------ 3 files changed, 25 insertions(+), 72 deletions(-) diff --git a/Include/internal/pycore_flowgraph.h b/Include/internal/pycore_flowgraph.h index 479b4b0ac1be77..42d6b9e821c3de 100644 --- a/Include/internal/pycore_flowgraph.h +++ b/Include/internal/pycore_flowgraph.h @@ -67,7 +67,6 @@ typedef struct _PyCfgBasicblock_ { unsigned b_warm : 1; } _PyCfgBasicblock; -int _PyBasicblock_InsertInstruction(_PyCfgBasicblock *block, int pos, _PyCfgInstruction *instr); typedef struct cfg_builder_ { /* The entryblock, at which control flow begins. All blocks of the @@ -92,14 +91,11 @@ int _PyCfgBuilder_CheckSize(_PyCfgBuilder* g); int _PyCfg_OptimizeCodeUnit(_PyCfgBuilder *g, PyObject *consts, PyObject *const_cache, int nlocals, int nparams, int firstlineno); +int _PyCfg_ToInstructionSequence(_PyCfgBuilder *g, _PyCompile_InstructionSequence *seq); int _PyCfg_OptimizedCfgToInstructionSequence(_PyCfgBuilder *g, _PyCompile_CodeUnitMetadata *umd, int code_flags, int *stackdepth, int *nlocalsplus, _PyCompile_InstructionSequence *seq); -int _PyCfg_Stackdepth(_PyCfgBuilder *g); -void _PyCfg_ConvertPseudoOps(_PyCfgBasicblock *entryblock); -int _PyCfg_ResolveJumps(_PyCfgBuilder *g); - PyCodeObject * _PyAssemble_MakeCodeObject(_PyCompile_CodeUnitMetadata *u, PyObject *const_cache, PyObject *consts, int maxdepth, _PyCompile_InstructionSequence *instrs, diff --git a/Python/compile.c b/Python/compile.c index 36b3ebb6a88c09..0bd995aa0b92d2 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -70,8 +70,6 @@ && ((C)->u->u_ste->ste_type == ModuleBlock)) typedef _PyCompilerSrcLocation location; -typedef _PyCfgInstruction cfg_instr; -typedef _PyCfgBasicblock basicblock; typedef _PyCfgBuilder cfg_builder; #define LOCATION(LNO, END_LNO, COL, END_COL) \ @@ -7728,42 +7726,14 @@ instr_sequence_to_instructions(instr_sequence *seq) static PyObject * cfg_to_instructions(cfg_builder *g) { - PyObject *instructions = PyList_New(0); - if (instructions == NULL) { + instr_sequence seq; + memset(&seq, 0, sizeof(seq)); + if (_PyCfg_ToInstructionSequence(g, &seq) < 0) { return NULL; } - int lbl = 0; - for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { - b->b_label = (jump_target_label){lbl}; - lbl += b->b_iused; - } - for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { - for (int i = 0; i < b->b_iused; i++) { - cfg_instr *instr = &b->b_instr[i]; - location loc = instr->i_loc; - int arg = HAS_TARGET(instr->i_opcode) ? - instr->i_target->b_label.id : instr->i_oparg; - - PyObject *inst_tuple = Py_BuildValue( - "(iiiiii)", instr->i_opcode, arg, - loc.lineno, loc.end_lineno, - loc.col_offset, loc.end_col_offset); - if (inst_tuple == NULL) { - goto error; - } - - if (PyList_Append(instructions, inst_tuple) != 0) { - Py_DECREF(inst_tuple); - goto error; - } - Py_DECREF(inst_tuple); - } - } - - return instructions; -error: - Py_DECREF(instructions); - return NULL; + PyObject *res = instr_sequence_to_instructions(&seq); + instr_sequence_fini(&seq); + return res; } // C implementation of inspect.cleandoc() diff --git a/Python/flowgraph.c b/Python/flowgraph.c index 5f33e0b4aca5d2..89640c5d4460fc 100644 --- a/Python/flowgraph.c +++ b/Python/flowgraph.c @@ -177,8 +177,8 @@ copy_basicblock(cfg_builder *g, basicblock *block) return result; } -int -_PyBasicblock_InsertInstruction(basicblock *block, int pos, cfg_instr *instr) { +static int +basicblock_insert_instruction(basicblock *block, int pos, 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]; @@ -499,14 +499,6 @@ normalize_jumps(_PyCfgBuilder *g) return SUCCESS; } -int -_PyCfg_ResolveJumps(_PyCfgBuilder *g) -{ - RETURN_IF_ERROR(normalize_jumps(g)); - assert(no_redundant_jumps(g)); - return SUCCESS; -} - static int check_cfg(cfg_builder *g) { for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { @@ -669,8 +661,8 @@ stackdepth_push(basicblock ***sp, basicblock *b, int depth) /* Find the flow path that needs the largest stack. We assume that * cycles in the flow graph have no net effect on the stack depth. */ -int -_PyCfg_Stackdepth(cfg_builder *g) +static int +calculate_stackdepth(cfg_builder *g) { basicblock *entryblock = g->g_entryblock; for (basicblock *b = entryblock; b != NULL; b = b->b_next) { @@ -2139,8 +2131,8 @@ push_cold_blocks_to_end(cfg_builder *g) { return SUCCESS; } -void -_PyCfg_ConvertPseudoOps(basicblock *entryblock) +static void +convert_pseudo_ops(basicblock *entryblock) { for (basicblock *b = entryblock; b != NULL; b = b->b_next) { for (int i = 0; i < b->b_iused; i++) { @@ -2384,14 +2376,14 @@ insert_prefix_instructions(_PyCompile_CodeUnitMetadata *umd, basicblock *entrybl .i_loc = LOCATION(umd->u_firstlineno, umd->u_firstlineno, -1, -1), .i_target = NULL, }; - RETURN_IF_ERROR(_PyBasicblock_InsertInstruction(entryblock, 0, &make_gen)); + RETURN_IF_ERROR(basicblock_insert_instruction(entryblock, 0, &make_gen)); cfg_instr pop_top = { .i_opcode = POP_TOP, .i_oparg = 0, .i_loc = NO_LOCATION, .i_target = NULL, }; - RETURN_IF_ERROR(_PyBasicblock_InsertInstruction(entryblock, 1, &pop_top)); + RETURN_IF_ERROR(basicblock_insert_instruction(entryblock, 1, &pop_top)); } /* Set up cells for any variable that escapes, to be put in a closure. */ @@ -2421,7 +2413,7 @@ insert_prefix_instructions(_PyCompile_CodeUnitMetadata *umd, basicblock *entrybl .i_loc = NO_LOCATION, .i_target = NULL, }; - if (_PyBasicblock_InsertInstruction(entryblock, ncellsused, &make_cell) < 0) { + if (basicblock_insert_instruction(entryblock, ncellsused, &make_cell) < 0) { PyMem_RawFree(sorted); return ERROR; } @@ -2437,7 +2429,7 @@ insert_prefix_instructions(_PyCompile_CodeUnitMetadata *umd, basicblock *entrybl .i_loc = NO_LOCATION, .i_target = NULL, }; - RETURN_IF_ERROR(_PyBasicblock_InsertInstruction(entryblock, 0, ©_frees)); + RETURN_IF_ERROR(basicblock_insert_instruction(entryblock, 0, ©_frees)); } return SUCCESS; @@ -2522,10 +2514,8 @@ prepare_localsplus(_PyCompile_CodeUnitMetadata *umd, cfg_builder *g, int code_fl return nlocalsplus; } -typedef _PyCompile_InstructionSequence instr_sequence; - -static int -cfg_to_instr_sequence(cfg_builder *g, instr_sequence *seq) +int +_PyCfg_ToInstructionSequence(cfg_builder *g, _PyCompile_InstructionSequence *seq) { int lbl = 0; for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { @@ -2562,9 +2552,9 @@ int _PyCfg_OptimizedCfgToInstructionSequence(_PyCfgBuilder *g, _PyCompile_CodeUnitMetadata *umd, int code_flags, int *stackdepth, int *nlocalsplus, - instr_sequence *seq) + _PyCompile_InstructionSequence *seq) { - *stackdepth = _PyCfg_Stackdepth(g); + *stackdepth = calculate_stackdepth(g); if (*stackdepth < 0) { return ERROR; } @@ -2583,21 +2573,18 @@ _PyCfg_OptimizedCfgToInstructionSequence(_PyCfgBuilder *g, return ERROR; } - _PyCfg_ConvertPseudoOps(g->g_entryblock); + convert_pseudo_ops(g->g_entryblock); /* Order of basic blocks must have been determined by now */ - if (_PyCfg_ResolveJumps(g) < 0) { - return ERROR; - } + RETURN_IF_ERROR(normalize_jumps(g)); + assert(no_redundant_jumps(g)); /* Can't modify the bytecode after computing jump offsets. */ - if (cfg_to_instr_sequence(g, seq) < 0) { + if (_PyCfg_ToInstructionSequence(g, seq) < 0) { return ERROR; } return SUCCESS; - } - From 3994c3a19ab9b9affc641e811595a00453683b8a Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Fri, 4 Aug 2023 17:49:01 +0100 Subject: [PATCH 7/9] make _PyCfgInstruction and _PyCfgExceptStack opaque --- Include/internal/pycore_flowgraph.h | 18 ++--------- Python/flowgraph.c | 46 ++++++++++++++++++----------- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/Include/internal/pycore_flowgraph.h b/Include/internal/pycore_flowgraph.h index 42d6b9e821c3de..184b6daced576d 100644 --- a/Include/internal/pycore_flowgraph.h +++ b/Include/internal/pycore_flowgraph.h @@ -12,23 +12,11 @@ extern "C" { #include "pycore_compile.h" -typedef struct { - int i_opcode; - int i_oparg; - _PyCompilerSrcLocation i_loc; - struct _PyCfgBasicblock_ *i_target; /* target block (if jump instruction) */ - struct _PyCfgBasicblock_ *i_except; /* target block when exception is raised */ -} _PyCfgInstruction; - typedef struct { int id; } _PyCfgJumpTargetLabel; - -typedef struct { - struct _PyCfgBasicblock_ *handlers[CO_MAXBLOCKS+1]; - int depth; -} _PyCfgExceptStack; +struct _PyCfgExceptStack; typedef struct _PyCfgBasicblock_ { /* Each basicblock in a compilation unit is linked via b_list in the @@ -39,9 +27,9 @@ typedef struct _PyCfgBasicblock_ { /* The label of this block if it is a jump target, -1 otherwise */ _PyCfgJumpTargetLabel b_label; /* Exception stack at start of block, used by assembler to create the exception handling table */ - _PyCfgExceptStack *b_exceptstack; + struct PyCfgExceptStack *b_exceptstack; /* pointer to an array of instructions, initially NULL */ - _PyCfgInstruction *b_instr; + struct _PyCfgInstruction *b_instr; /* If b_next is non-NULL, it is a pointer to the next block reached by normal control flow. */ struct _PyCfgBasicblock_ *b_next; diff --git a/Python/flowgraph.c b/Python/flowgraph.c index 89640c5d4460fc..01e39436e297f5 100644 --- a/Python/flowgraph.c +++ b/Python/flowgraph.c @@ -26,7 +26,15 @@ typedef _PyCompilerSrcLocation location; typedef _PyCfgJumpTargetLabel jump_target_label; typedef _PyCfgBasicblock basicblock; typedef _PyCfgBuilder cfg_builder; -typedef _PyCfgInstruction cfg_instr; + +typedef struct _PyCfgInstruction { + int i_opcode; + int i_oparg; + _PyCompilerSrcLocation i_loc; + struct _PyCfgBasicblock_ *i_target; /* target block (if jump instruction) */ + struct _PyCfgBasicblock_ *i_except; /* target block when exception is raised */ +} cfg_instr; + static const jump_target_label NO_LABEL = {-1}; @@ -52,7 +60,7 @@ is_jump(cfg_instr *i) #define INSTR_SET_OP1(I, OP, ARG) \ do { \ assert(OPCODE_HAS_ARG(OP)); \ - _PyCfgInstruction *_instr__ptr_ = (I); \ + struct _PyCfgInstruction *_instr__ptr_ = (I); \ _instr__ptr_->i_opcode = (OP); \ _instr__ptr_->i_oparg = (ARG); \ } while (0); @@ -61,7 +69,7 @@ is_jump(cfg_instr *i) #define INSTR_SET_OP0(I, OP) \ do { \ assert(!OPCODE_HAS_ARG(OP)); \ - _PyCfgInstruction *_instr__ptr_ = (I); \ + struct _PyCfgInstruction *_instr__ptr_ = (I); \ _instr__ptr_->i_opcode = (OP); \ _instr__ptr_->i_oparg = 0; \ } while (0); @@ -151,7 +159,7 @@ basicblock_last_instr(const basicblock *b) { static inline int basicblock_nofallthrough(const _PyCfgBasicblock *b) { - _PyCfgInstruction *last = basicblock_last_instr(b); + struct _PyCfgInstruction *last = basicblock_last_instr(b); return (last && (IS_SCOPE_EXIT_OPCODE(last->i_opcode) || IS_UNCONDITIONAL_JUMP_OPCODE(last->i_opcode))); @@ -581,10 +589,14 @@ mark_except_handlers(basicblock *entryblock) { } -typedef _PyCfgExceptStack ExceptStack; +struct _PyCfgExceptStack { + struct _PyCfgBasicblock_ *handlers[CO_MAXBLOCKS+1]; + int depth; +}; + static basicblock * -push_except_block(ExceptStack *stack, cfg_instr *setup) { +push_except_block(struct _PyCfgExceptStack *stack, cfg_instr *setup) { assert(is_block_push(setup)); int opcode = setup->i_opcode; basicblock * target = setup->i_target; @@ -596,19 +608,19 @@ push_except_block(ExceptStack *stack, cfg_instr *setup) { } static basicblock * -pop_except_block(ExceptStack *stack) { +pop_except_block(struct _PyCfgExceptStack *stack) { assert(stack->depth > 0); return stack->handlers[--stack->depth]; } static basicblock * -except_stack_top(ExceptStack *stack) { +except_stack_top(struct _PyCfgExceptStack *stack) { return stack->handlers[stack->depth]; } -static ExceptStack * +static struct _PyCfgExceptStack * make_except_stack(void) { - ExceptStack *new = PyMem_Malloc(sizeof(ExceptStack)); + struct _PyCfgExceptStack *new = PyMem_Malloc(sizeof(struct _PyCfgExceptStack)); if (new == NULL) { PyErr_NoMemory(); return NULL; @@ -618,14 +630,14 @@ make_except_stack(void) { return new; } -static ExceptStack * -copy_except_stack(ExceptStack *stack) { - ExceptStack *copy = PyMem_Malloc(sizeof(ExceptStack)); +static struct _PyCfgExceptStack * +copy_except_stack(struct _PyCfgExceptStack *stack) { + struct _PyCfgExceptStack *copy = PyMem_Malloc(sizeof(struct _PyCfgExceptStack)); if (copy == NULL) { PyErr_NoMemory(); return NULL; } - memcpy(copy, stack, sizeof(ExceptStack)); + memcpy(copy, stack, sizeof(struct _PyCfgExceptStack)); return copy; } @@ -751,7 +763,7 @@ label_exception_targets(basicblock *entryblock) { if (todo_stack == NULL) { return ERROR; } - ExceptStack *except_stack = make_except_stack(); + struct _PyCfgExceptStack *except_stack = make_except_stack(); if (except_stack == NULL) { PyMem_Free(todo_stack); PyErr_NoMemory(); @@ -775,7 +787,7 @@ label_exception_targets(basicblock *entryblock) { 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); + struct _PyCfgExceptStack *copy = copy_except_stack(except_stack); if (copy == NULL) { goto error; } @@ -794,7 +806,7 @@ label_exception_targets(basicblock *entryblock) { assert(i == b->b_iused -1); if (!instr->i_target->b_visited) { if (BB_HAS_FALLTHROUGH(b)) { - ExceptStack *copy = copy_except_stack(except_stack); + struct _PyCfgExceptStack *copy = copy_except_stack(except_stack); if (copy == NULL) { goto error; } From 3001f903b39548459e47f13fb8105262d8e099f7 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Fri, 4 Aug 2023 18:04:35 +0100 Subject: [PATCH 8/9] basicblock is local to flowgraph and cfg_builder is opaque --- Include/internal/pycore_flowgraph.h | 70 ++++------------------------ Python/compile.c | 2 +- Python/flowgraph.c | 72 ++++++++++++++++++++++++----- 3 files changed, 70 insertions(+), 74 deletions(-) diff --git a/Include/internal/pycore_flowgraph.h b/Include/internal/pycore_flowgraph.h index 184b6daced576d..58fed46886ea45 100644 --- a/Include/internal/pycore_flowgraph.h +++ b/Include/internal/pycore_flowgraph.h @@ -11,76 +11,24 @@ extern "C" { #include "pycore_opcode_utils.h" #include "pycore_compile.h" - typedef struct { int id; } _PyCfgJumpTargetLabel; -struct _PyCfgExceptStack; - -typedef struct _PyCfgBasicblock_ { - /* Each basicblock in a compilation unit is linked via b_list in the - reverse order that the block are allocated. b_list points to the next - block in this list, not to be confused with b_next, which is next by - control flow. */ - struct _PyCfgBasicblock_ *b_list; - /* The label of this block if it is a jump target, -1 otherwise */ - _PyCfgJumpTargetLabel b_label; - /* Exception stack at start of block, used by assembler to create the exception handling table */ - struct PyCfgExceptStack *b_exceptstack; - /* pointer to an array of instructions, initially NULL */ - struct _PyCfgInstruction *b_instr; - /* If b_next is non-NULL, it is a pointer to the next - block reached by normal control flow. */ - struct _PyCfgBasicblock_ *b_next; - /* number of instructions used */ - int b_iused; - /* length of instruction array (b_instr) */ - int b_ialloc; - /* Used by add_checks_for_loads_of_unknown_variables */ - uint64_t b_unsafe_locals_mask; - /* Number of predecessors that a block has. */ - int b_predecessors; - /* depth of stack upon entry of block, computed by stackdepth() */ - int b_startdepth; - /* Basic block is an exception handler that preserves lasti */ - unsigned b_preserve_lasti : 1; - /* Used by compiler passes to mark whether they have visited a basic block. */ - unsigned b_visited : 1; - /* b_except_handler is used by the cold-detection algorithm to mark exception targets */ - unsigned b_except_handler : 1; - /* b_cold is true if this block is not perf critical (like an exception handler) */ - unsigned b_cold : 1; - /* b_warm is used by the cold-detection algorithm to mark blocks which are definitely not cold */ - unsigned b_warm : 1; -} _PyCfgBasicblock; - - -typedef struct cfg_builder_ { - /* The entryblock, at which control flow begins. All blocks of the - CFG are reachable through the b_next links */ - _PyCfgBasicblock *g_entryblock; - /* Pointer to the most recently allocated block. By following - b_list links, you can reach all allocated blocks. */ - _PyCfgBasicblock *g_block_list; - /* pointer to the block currently being constructed */ - _PyCfgBasicblock *g_curblock; - /* label for the next instruction to be placed */ - _PyCfgJumpTargetLabel g_current_label; -} _PyCfgBuilder; +struct _PyCfgBuilder; -int _PyCfgBuilder_UseLabel(_PyCfgBuilder *g, _PyCfgJumpTargetLabel lbl); -int _PyCfgBuilder_Addop(_PyCfgBuilder *g, int opcode, int oparg, _PyCompilerSrcLocation loc); +int _PyCfgBuilder_UseLabel(struct _PyCfgBuilder *g, _PyCfgJumpTargetLabel lbl); +int _PyCfgBuilder_Addop(struct _PyCfgBuilder *g, int opcode, int oparg, _PyCompilerSrcLocation loc); -_PyCfgBuilder* _PyCfgBuilder_New(void); -void _PyCfgBuilder_Free(_PyCfgBuilder *g); -int _PyCfgBuilder_CheckSize(_PyCfgBuilder* g); +struct _PyCfgBuilder* _PyCfgBuilder_New(void); +void _PyCfgBuilder_Free(struct _PyCfgBuilder *g); +int _PyCfgBuilder_CheckSize(struct _PyCfgBuilder* g); -int _PyCfg_OptimizeCodeUnit(_PyCfgBuilder *g, PyObject *consts, PyObject *const_cache, +int _PyCfg_OptimizeCodeUnit(struct _PyCfgBuilder *g, PyObject *consts, PyObject *const_cache, int nlocals, int nparams, int firstlineno); -int _PyCfg_ToInstructionSequence(_PyCfgBuilder *g, _PyCompile_InstructionSequence *seq); -int _PyCfg_OptimizedCfgToInstructionSequence(_PyCfgBuilder *g, _PyCompile_CodeUnitMetadata *umd, +int _PyCfg_ToInstructionSequence(struct _PyCfgBuilder *g, _PyCompile_InstructionSequence *seq); +int _PyCfg_OptimizedCfgToInstructionSequence(struct _PyCfgBuilder *g, _PyCompile_CodeUnitMetadata *umd, int code_flags, int *stackdepth, int *nlocalsplus, _PyCompile_InstructionSequence *seq); diff --git a/Python/compile.c b/Python/compile.c index 0bd995aa0b92d2..ac554570e36673 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -70,7 +70,7 @@ && ((C)->u->u_ste->ste_type == ModuleBlock)) typedef _PyCompilerSrcLocation location; -typedef _PyCfgBuilder cfg_builder; +typedef struct _PyCfgBuilder cfg_builder; #define LOCATION(LNO, END_LNO, COL, END_COL) \ ((const _PyCompilerSrcLocation){(LNO), (END_LNO), (COL), (END_COL)}) diff --git a/Python/flowgraph.c b/Python/flowgraph.c index 01e39436e297f5..430203cc20f472 100644 --- a/Python/flowgraph.c +++ b/Python/flowgraph.c @@ -24,17 +24,65 @@ typedef _PyCompilerSrcLocation location; typedef _PyCfgJumpTargetLabel jump_target_label; -typedef _PyCfgBasicblock basicblock; -typedef _PyCfgBuilder cfg_builder; typedef struct _PyCfgInstruction { int i_opcode; int i_oparg; _PyCompilerSrcLocation i_loc; - struct _PyCfgBasicblock_ *i_target; /* target block (if jump instruction) */ - struct _PyCfgBasicblock_ *i_except; /* target block when exception is raised */ + struct _PyCfgBasicblock *i_target; /* target block (if jump instruction) */ + struct _PyCfgBasicblock *i_except; /* target block when exception is raised */ } cfg_instr; +typedef struct _PyCfgBasicblock { + /* Each basicblock in a compilation unit is linked via b_list in the + reverse order that the block are allocated. b_list points to the next + block in this list, not to be confused with b_next, which is next by + control flow. */ + struct _PyCfgBasicblock *b_list; + /* The label of this block if it is a jump target, -1 otherwise */ + _PyCfgJumpTargetLabel b_label; + /* Exception stack at start of block, used by assembler to create the exception handling table */ + struct PyCfgExceptStack *b_exceptstack; + /* pointer to an array of instructions, initially NULL */ + cfg_instr *b_instr; + /* If b_next is non-NULL, it is a pointer to the next + block reached by normal control flow. */ + struct _PyCfgBasicblock *b_next; + /* number of instructions used */ + int b_iused; + /* length of instruction array (b_instr) */ + int b_ialloc; + /* Used by add_checks_for_loads_of_unknown_variables */ + uint64_t b_unsafe_locals_mask; + /* Number of predecessors that a block has. */ + int b_predecessors; + /* depth of stack upon entry of block, computed by stackdepth() */ + int b_startdepth; + /* Basic block is an exception handler that preserves lasti */ + unsigned b_preserve_lasti : 1; + /* Used by compiler passes to mark whether they have visited a basic block. */ + unsigned b_visited : 1; + /* b_except_handler is used by the cold-detection algorithm to mark exception targets */ + unsigned b_except_handler : 1; + /* b_cold is true if this block is not perf critical (like an exception handler) */ + unsigned b_cold : 1; + /* b_warm is used by the cold-detection algorithm to mark blocks which are definitely not cold */ + unsigned b_warm : 1; +} basicblock; + + +typedef struct _PyCfgBuilder { + /* The entryblock, at which control flow begins. All blocks of the + CFG are reachable through the b_next links */ + struct _PyCfgBasicblock *g_entryblock; + /* Pointer to the most recently allocated block. By following + b_list links, you can reach all allocated blocks. */ + struct _PyCfgBasicblock *g_block_list; + /* pointer to the block currently being constructed */ + struct _PyCfgBasicblock *g_curblock; + /* label for the next instruction to be placed */ + _PyCfgJumpTargetLabel g_current_label; +} cfg_builder; static const jump_target_label NO_LABEL = {-1}; @@ -60,7 +108,7 @@ is_jump(cfg_instr *i) #define INSTR_SET_OP1(I, OP, ARG) \ do { \ assert(OPCODE_HAS_ARG(OP)); \ - struct _PyCfgInstruction *_instr__ptr_ = (I); \ + cfg_instr *_instr__ptr_ = (I); \ _instr__ptr_->i_opcode = (OP); \ _instr__ptr_->i_oparg = (ARG); \ } while (0); @@ -69,7 +117,7 @@ is_jump(cfg_instr *i) #define INSTR_SET_OP0(I, OP) \ do { \ assert(!OPCODE_HAS_ARG(OP)); \ - struct _PyCfgInstruction *_instr__ptr_ = (I); \ + cfg_instr *_instr__ptr_ = (I); \ _instr__ptr_->i_opcode = (OP); \ _instr__ptr_->i_oparg = 0; \ } while (0); @@ -158,8 +206,8 @@ basicblock_last_instr(const basicblock *b) { } static inline int -basicblock_nofallthrough(const _PyCfgBasicblock *b) { - struct _PyCfgInstruction *last = basicblock_last_instr(b); +basicblock_nofallthrough(const basicblock *b) { + cfg_instr *last = basicblock_last_instr(b); return (last && (IS_SCOPE_EXIT_OPCODE(last->i_opcode) || IS_UNCONDITIONAL_JUMP_OPCODE(last->i_opcode))); @@ -494,7 +542,7 @@ normalize_jumps_in_block(cfg_builder *g, basicblock *b) { static int -normalize_jumps(_PyCfgBuilder *g) +normalize_jumps(cfg_builder *g) { basicblock *entryblock = g->g_entryblock; for (basicblock *b = entryblock; b != NULL; b = b->b_next) { @@ -565,7 +613,7 @@ translate_jump_labels_to_targets(basicblock *entryblock) } int -_PyCfg_JumpLabelsToTargets(_PyCfgBuilder *g) +_PyCfg_JumpLabelsToTargets(cfg_builder *g) { return translate_jump_labels_to_targets(g->g_entryblock); } @@ -590,7 +638,7 @@ mark_except_handlers(basicblock *entryblock) { struct _PyCfgExceptStack { - struct _PyCfgBasicblock_ *handlers[CO_MAXBLOCKS+1]; + basicblock *handlers[CO_MAXBLOCKS+1]; int depth; }; @@ -2561,7 +2609,7 @@ _PyCfg_ToInstructionSequence(cfg_builder *g, _PyCompile_InstructionSequence *seq int -_PyCfg_OptimizedCfgToInstructionSequence(_PyCfgBuilder *g, +_PyCfg_OptimizedCfgToInstructionSequence(cfg_builder *g, _PyCompile_CodeUnitMetadata *umd, int code_flags, int *stackdepth, int *nlocalsplus, _PyCompile_InstructionSequence *seq) From c05fa8e0614bd2fa6e8653e326de9e44565b4e4c Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Fri, 4 Aug 2023 18:25:11 +0100 Subject: [PATCH 9/9] fix typedef --- Python/flowgraph.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Python/flowgraph.c b/Python/flowgraph.c index 430203cc20f472..8858f76f1e7880 100644 --- a/Python/flowgraph.c +++ b/Python/flowgraph.c @@ -42,7 +42,7 @@ typedef struct _PyCfgBasicblock { /* The label of this block if it is a jump target, -1 otherwise */ _PyCfgJumpTargetLabel b_label; /* Exception stack at start of block, used by assembler to create the exception handling table */ - struct PyCfgExceptStack *b_exceptstack; + struct _PyCfgExceptStack *b_exceptstack; /* pointer to an array of instructions, initially NULL */ cfg_instr *b_instr; /* If b_next is non-NULL, it is a pointer to the next @@ -71,7 +71,7 @@ typedef struct _PyCfgBasicblock { } basicblock; -typedef struct _PyCfgBuilder { +struct _PyCfgBuilder { /* The entryblock, at which control flow begins. All blocks of the CFG are reachable through the b_next links */ struct _PyCfgBasicblock *g_entryblock; @@ -82,7 +82,9 @@ typedef struct _PyCfgBuilder { struct _PyCfgBasicblock *g_curblock; /* label for the next instruction to be placed */ _PyCfgJumpTargetLabel g_current_label; -} cfg_builder; +}; + +typedef struct _PyCfgBuilder cfg_builder; static const jump_target_label NO_LABEL = {-1}; @@ -399,7 +401,7 @@ _PyCfgBuilder_New(void) } void -_PyCfgBuilder_Free(cfg_builder* g) +_PyCfgBuilder_Free(cfg_builder *g) { if (g == NULL) { return; @@ -418,7 +420,7 @@ _PyCfgBuilder_Free(cfg_builder* g) } int -_PyCfgBuilder_CheckSize(cfg_builder* g) +_PyCfgBuilder_CheckSize(cfg_builder *g) { int nblocks = 0; for (basicblock *b = g->g_block_list; b != NULL; b = b->b_list) {