diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index e6194460b787d3..11940bec492d89 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -108,7 +108,6 @@ def __getitem__(self, key): exec('z = a', g, d) self.assertEqual(d['z'], 12) - @unittest.skipIf(support.is_wasi, "exhausts limited stack on WASI") def test_extended_arg(self): # default: 1000 * 2.5 = 2500 repetitions repeat = int(sys.getrecursionlimit() * 2.5) @@ -543,7 +542,6 @@ def test_yet_more_evil_still_undecodable(self): self.assertIn(b"Non-UTF-8", res.err) @support.cpython_only - @unittest.skipIf(support.is_wasi, "exhausts limited stack on WASI") def test_compiler_recursion_limit(self): # Expected limit is sys.getrecursionlimit() * the scaling factor # in symtable.c (currently 3) diff --git a/Python/compile.c b/Python/compile.c index 975efa7e23ecdf..bb0cbc92149164 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -134,11 +134,15 @@ struct location { int end_col_offset; }; + #define LOCATION(LNO, END_LNO, COL, END_COL) \ ((const struct location){(LNO), (END_LNO), (COL), (END_COL)}) static struct location NO_LOCATION = {-1, -1, -1, -1}; +#define NO_OPARG -1 +#define NO_TARGET NULL + struct instr { int i_opcode; int i_oparg; @@ -429,8 +433,6 @@ typedef struct { static int basicblock_next_instr(basicblock *); -static int cfg_builder_addop_i(cfg_builder *g, int opcode, Py_ssize_t oparg, struct location loc); - static void compiler_free(struct compiler *); static int compiler_error(struct compiler *, const char *, ...); static int compiler_warn(struct compiler *, const char *, ...); @@ -866,13 +868,13 @@ cfg_builder_use_next_block(cfg_builder *g, basicblock *block) return block; } -static basicblock * +static inline basicblock * compiler_new_block(struct compiler *c) { return cfg_builder_new_block(CFG_BUILDER(c)); } -static basicblock * +static inline basicblock * compiler_use_next_block(struct compiler *c, basicblock *block) { return cfg_builder_use_next_block(CFG_BUILDER(c), block); @@ -1248,23 +1250,34 @@ PyCompile_OpcodeStackEffect(int opcode, int oparg) return stack_effect(opcode, oparg, -1); } -/* Add an opcode with no argument. - Returns 0 on failure, 1 on success. -*/ +#define HAS_TARGET(opcode) \ + (IS_JUMP_OPCODE(opcode) || IS_BLOCK_PUSH_OPCODE(opcode)) -static int +/* Append an instruction. Returns 0 on failure, 1 on success. */ +static inline int basicblock_addop(basicblock *b, int opcode, int oparg, basicblock *target, struct location loc) { assert(IS_WITHIN_OPCODE_RANGE(opcode)); assert(!IS_ASSEMBLER_OPCODE(opcode)); - assert(HAS_ARG(opcode) || oparg == 0); - assert(0 <= oparg && oparg < (1 << 30)); - assert((target == NULL) || - IS_JUMP_OPCODE(opcode) || - IS_BLOCK_PUSH_OPCODE(opcode)); - assert(oparg == 0 || target == NULL); + assert(oparg == NO_OPARG || (0 <= oparg && oparg < (1 << 30))); + assert((HAS_ARG(opcode) && !HAS_TARGET(opcode) && oparg != NO_OPARG) || + (!(HAS_ARG(opcode) && !HAS_TARGET(opcode)) && oparg == NO_OPARG)); + assert((HAS_TARGET(opcode) && target != NO_TARGET) || + (!HAS_TARGET(opcode) && target == NO_TARGET)); + assert(!(oparg != NO_OPARG && target != NO_TARGET)); + if (oparg != NO_OPARG) { + /* oparg value is unsigned, but a signed C int is usually used to store + it in the C code (like Python/ceval.c). + + Limit to 32-bit signed C int (rather than INT_MAX) for portability. + + The argument of a concrete bytecode instruction is limited to 8-bit. + EXTENDED_ARG is used for 16, 24, and 32-bit arguments. */ + + oparg = Py_SAFE_DOWNCAST(oparg, Py_ssize_t, int); + } int off = basicblock_next_instr(b); if (off < 0) { return 0; @@ -1278,7 +1291,7 @@ basicblock_addop(basicblock *b, int opcode, int oparg, return 1; } -static int +static inline int cfg_builder_addop(cfg_builder *g, int opcode, int oparg, basicblock *target, struct location loc) { @@ -1293,12 +1306,17 @@ cfg_builder_addop(cfg_builder *g, int opcode, int oparg, basicblock *target, return basicblock_addop(g->curblock, opcode, oparg, target, loc); } -static int -cfg_builder_addop_noarg(cfg_builder *g, int opcode, struct location loc) -{ - assert(!HAS_ARG(opcode)); - return cfg_builder_addop(g, opcode, 0, NULL, loc); -} +/* Add an instruction with no arg. Returns 0 on failure, 1 on success. */ +#define CFG_BUILDER_ADDOP_NOARG(G, OP, LOC) \ + cfg_builder_addop(G, OP, NO_OPARG, NO_TARGET, LOC) + +/* Add an instruction with an integer arg. Returns 0 on failure, 1 on success. */ +#define CFG_BUILDER_ADDOP_I(G, OP, ARG, LOC) \ + cfg_builder_addop(G, OP, ARG, NO_TARGET, LOC) + +/* Add a jump instruction. Returns 0 on faiure, 1 on success. */ +#define CFG_BUILDER_ADDOP_J(G, OP, T, LOC) \ + cfg_builder_addop(G, OP, NO_OPARG, T, LOC) static Py_ssize_t dict_add_o(PyObject *dict, PyObject *o) @@ -1457,7 +1475,7 @@ compiler_addop_load_const(struct compiler *c, PyObject *o) Py_ssize_t arg = compiler_add_const(c, o); if (arg < 0) return 0; - return cfg_builder_addop_i(CFG_BUILDER(c), LOAD_CONST, arg, COMPILER_LOC(c)); + return CFG_BUILDER_ADDOP_I(CFG_BUILDER(c), LOAD_CONST, arg, COMPILER_LOC(c)); } static int @@ -1467,7 +1485,8 @@ compiler_addop_o(struct compiler *c, int opcode, PyObject *dict, Py_ssize_t arg = dict_add_o(dict, o); if (arg < 0) return 0; - return cfg_builder_addop_i(CFG_BUILDER(c), opcode, arg, COMPILER_LOC(c)); + assert(HAS_ARG(opcode)); + return CFG_BUILDER_ADDOP_I(CFG_BUILDER(c), opcode, arg, COMPILER_LOC(c)); } static int @@ -1491,48 +1510,21 @@ compiler_addop_name(struct compiler *c, int opcode, PyObject *dict, arg <<= 1; arg |= 1; } - return cfg_builder_addop_i(CFG_BUILDER(c), opcode, arg, COMPILER_LOC(c)); -} - -/* Add an opcode with an integer argument. - Returns 0 on failure, 1 on success. -*/ -static int -cfg_builder_addop_i(cfg_builder *g, int opcode, Py_ssize_t oparg, struct 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). - - Limit to 32-bit signed C int (rather than INT_MAX) for portability. - - The argument of a concrete bytecode instruction is limited to 8-bit. - EXTENDED_ARG is used for 16, 24, and 32-bit arguments. */ - - int oparg_ = Py_SAFE_DOWNCAST(oparg, Py_ssize_t, int); - return cfg_builder_addop(g, opcode, oparg_, NULL, loc); -} - -static int -cfg_builder_addop_j(cfg_builder *g, int opcode, basicblock *target, struct location loc) -{ - assert(target != NULL); - assert(IS_JUMP_OPCODE(opcode) || IS_BLOCK_PUSH_OPCODE(opcode)); - return cfg_builder_addop(g, opcode, 0, target, loc); + return CFG_BUILDER_ADDOP_I(CFG_BUILDER(c), opcode, arg, COMPILER_LOC(c)); } - #define ADDOP(C, OP) { \ - if (!cfg_builder_addop_noarg(CFG_BUILDER(C), (OP), COMPILER_LOC(C))) \ + if (!CFG_BUILDER_ADDOP_NOARG(CFG_BUILDER(C), (OP), COMPILER_LOC(C))) \ return 0; \ } #define ADDOP_NOLINE(C, OP) { \ - if (!cfg_builder_addop_noarg(CFG_BUILDER(C), (OP), NO_LOCATION)) \ + if (!CFG_BUILDER_ADDOP_NOARG(CFG_BUILDER(C), (OP), NO_LOCATION)) \ return 0; \ } #define ADDOP_IN_SCOPE(C, OP) { \ - if (!cfg_builder_addop_noarg(CFG_BUILDER(C), (OP), COMPILER_LOC(C))) { \ + if (!CFG_BUILDER_ADDOP_NOARG(CFG_BUILDER(C), (OP), COMPILER_LOC(C))) { \ compiler_exit_scope(c); \ return 0; \ } \ @@ -1571,17 +1563,20 @@ cfg_builder_addop_j(cfg_builder *g, int opcode, basicblock *target, struct locat } #define ADDOP_I(C, OP, O) { \ - if (!cfg_builder_addop_i(CFG_BUILDER(C), (OP), (O), COMPILER_LOC(C))) \ + assert(HAS_ARG(OP)); \ + if (!CFG_BUILDER_ADDOP_I(CFG_BUILDER(C), (OP), (O), COMPILER_LOC(C))) \ return 0; \ } #define ADDOP_I_NOLINE(C, OP, O) { \ - if (!cfg_builder_addop_i(CFG_BUILDER(C), (OP), (O), NO_LOCATION)) \ + assert(HAS_ARG(OP)); \ + if (!CFG_BUILDER_ADDOP_I(CFG_BUILDER(C), (OP), (O), NO_LOCATION)) \ return 0; \ } #define ADDOP_JUMP(C, OP, O) { \ - if (!cfg_builder_addop_j(CFG_BUILDER(C), (OP), (O), COMPILER_LOC(C))) \ + assert(HAS_TARGET(OP) && (O) != NO_TARGET); \ + if (!CFG_BUILDER_ADDOP_J(CFG_BUILDER(C), (OP), (O), COMPILER_LOC(C))) \ return 0; \ } @@ -1589,7 +1584,8 @@ cfg_builder_addop_j(cfg_builder *g, int opcode, basicblock *target, struct locat * Used for artificial jumps that have no corresponding * token in the source code. */ #define ADDOP_JUMP_NOLINE(C, OP, O) { \ - if (!cfg_builder_addop_j(CFG_BUILDER(C), (OP), (O), NO_LOCATION)) \ + assert(HAS_TARGET(OP) && (O) != NO_TARGET); \ + if (!CFG_BUILDER_ADDOP_J(CFG_BUILDER(C), (OP), (O), NO_LOCATION)) \ return 0; \ } @@ -4237,7 +4233,8 @@ compiler_nameop(struct compiler *c, identifier name, expr_context_ty ctx) if (op == LOAD_GLOBAL) { arg <<= 1; } - return cfg_builder_addop_i(CFG_BUILDER(c), op, arg, COMPILER_LOC(c)); + assert(HAS_ARG(op)); + return CFG_BUILDER_ADDOP_I(CFG_BUILDER(c), op, arg, COMPILER_LOC(c)); } static int @@ -6280,7 +6277,7 @@ emit_and_reset_fail_pop(struct compiler *c, pattern_context *pc) } while (--pc->fail_pop_size) { compiler_use_next_block(c, pc->fail_pop[pc->fail_pop_size]); - if (!cfg_builder_addop_noarg(CFG_BUILDER(c), POP_TOP, COMPILER_LOC(c))) { + if (!CFG_BUILDER_ADDOP_NOARG(CFG_BUILDER(c), POP_TOP, COMPILER_LOC(c))) { pc->fail_pop_size = 0; PyObject_Free(pc->fail_pop); pc->fail_pop = NULL; @@ -6714,7 +6711,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, COMPILER_LOC(c)) || + if (!CFG_BUILDER_ADDOP_I(CFG_BUILDER(c), COPY, 1, COMPILER_LOC(c)) || !compiler_pattern(c, alt, pc)) { goto error; } @@ -6778,7 +6775,8 @@ compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc) } } assert(control); - if (!cfg_builder_addop_j(CFG_BUILDER(c), JUMP, end, COMPILER_LOC(c)) || + assert(end); + if (!CFG_BUILDER_ADDOP_J(CFG_BUILDER(c), JUMP, end, COMPILER_LOC(c)) || !emit_and_reset_fail_pop(c, pc)) { goto error; @@ -6790,7 +6788,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, COMPILER_LOC(c)) || !jump_to_fail_pop(c, pc, JUMP)) { + if (!CFG_BUILDER_ADDOP_NOARG(CFG_BUILDER(c), POP_TOP, COMPILER_LOC(c)) || !jump_to_fail_pop(c, pc, JUMP)) { goto error; } compiler_use_next_block(c, end); @@ -7438,7 +7436,7 @@ push_cold_blocks_to_end(cfg_builder *g, int code_flags) { if (explicit_jump == NULL) { return -1; } - basicblock_addop(explicit_jump, JUMP, 0, b->b_next, NO_LOCATION); + basicblock_addop(explicit_jump, JUMP, NO_OPARG, b->b_next, NO_LOCATION); explicit_jump->b_cold = 1; explicit_jump->b_next = b->b_next;