diff --git a/Python/flowgraph.c b/Python/flowgraph.c index 213c993bb863a34..aa330e9ce184cf5 100644 --- a/Python/flowgraph.c +++ b/Python/flowgraph.c @@ -1495,6 +1495,8 @@ optimize_basic_block(PyObject *const_cache, basicblock *bb, PyObject *consts) if (opcode == nextop && oparg == bb->b_instr[i+1].i_oparg && bb->b_instr[i].i_loc.lineno == bb->b_instr[i+1].i_loc.lineno) { + assert(OPCODE_NO_EXCEPTION(opcode)); + assert(OPCODE_NO_EXCEPTION(nextop)); bb->b_instr[i].i_opcode = POP_TOP; bb->b_instr[i].i_oparg = 0; } diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index 6a42775e0912080..ef3a67545474ac6 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -919,10 +919,12 @@ enum InstructionFormat { INSTR_FMT_IB, INSTR_FMT_IBC, INSTR_FMT_IBC00, INSTR_FMT #define HAS_CONST_FLAG (2) #define HAS_NAME_FLAG (4) #define HAS_JUMP_FLAG (8) +#define NO_EXCEPTION_FLAG (16) #define OPCODE_HAS_ARG(OP) (_PyOpcode_opcode_metadata[(OP)].flags & (HAS_ARG_FLAG)) #define OPCODE_HAS_CONST(OP) (_PyOpcode_opcode_metadata[(OP)].flags & (HAS_CONST_FLAG)) #define OPCODE_HAS_NAME(OP) (_PyOpcode_opcode_metadata[(OP)].flags & (HAS_NAME_FLAG)) #define OPCODE_HAS_JUMP(OP) (_PyOpcode_opcode_metadata[(OP)].flags & (HAS_JUMP_FLAG)) +#define OPCODE_NO_EXCEPTION(OP) (_PyOpcode_opcode_metadata[(OP)].flags & (NO_EXCEPTION_FLAG)) struct opcode_metadata { bool valid_entry; enum InstructionFormat instr_format; @@ -947,22 +949,22 @@ extern const char * const _PyOpcode_uop_name[512]; #endif #else const struct opcode_metadata _PyOpcode_opcode_metadata[512] = { - [NOP] = { true, INSTR_FMT_IX, 0 }, + [NOP] = { true, INSTR_FMT_IX, NO_EXCEPTION_FLAG }, [RESUME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, [INSTRUMENTED_RESUME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, [LOAD_CLOSURE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, [LOAD_FAST_CHECK] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, [LOAD_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, - [LOAD_FAST_AND_CLEAR] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [LOAD_FAST_AND_CLEAR] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | NO_EXCEPTION_FLAG }, [LOAD_FAST_LOAD_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, [LOAD_CONST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_CONST_FLAG }, - [STORE_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, - [STORE_FAST_MAYBE_NULL] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [STORE_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | NO_EXCEPTION_FLAG }, + [STORE_FAST_MAYBE_NULL] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | NO_EXCEPTION_FLAG }, [STORE_FAST_LOAD_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, - [STORE_FAST_STORE_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, - [POP_TOP] = { true, INSTR_FMT_IX, 0 }, - [PUSH_NULL] = { true, INSTR_FMT_IX, 0 }, - [END_FOR] = { true, INSTR_FMT_IB, 0 }, + [STORE_FAST_STORE_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | NO_EXCEPTION_FLAG }, + [POP_TOP] = { true, INSTR_FMT_IX, NO_EXCEPTION_FLAG }, + [PUSH_NULL] = { true, INSTR_FMT_IX, NO_EXCEPTION_FLAG }, + [END_FOR] = { true, INSTR_FMT_IB, NO_EXCEPTION_FLAG }, [INSTRUMENTED_END_FOR] = { true, INSTR_FMT_IX, 0 }, [END_SEND] = { true, INSTR_FMT_IX, 0 }, [INSTRUMENTED_END_SEND] = { true, INSTR_FMT_IX, 0 }, @@ -1109,10 +1111,10 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[512] = { [BEFORE_ASYNC_WITH] = { true, INSTR_FMT_IX, 0 }, [BEFORE_WITH] = { true, INSTR_FMT_IX, 0 }, [WITH_EXCEPT_START] = { true, INSTR_FMT_IX, 0 }, - [SETUP_FINALLY] = { true, INSTR_FMT_IX, 0 }, - [SETUP_CLEANUP] = { true, INSTR_FMT_IX, 0 }, - [SETUP_WITH] = { true, INSTR_FMT_IX, 0 }, - [POP_BLOCK] = { true, INSTR_FMT_IX, 0 }, + [SETUP_FINALLY] = { true, INSTR_FMT_IX, NO_EXCEPTION_FLAG }, + [SETUP_CLEANUP] = { true, INSTR_FMT_IX, NO_EXCEPTION_FLAG }, + [SETUP_WITH] = { true, INSTR_FMT_IX, NO_EXCEPTION_FLAG }, + [POP_BLOCK] = { true, INSTR_FMT_IX, NO_EXCEPTION_FLAG }, [PUSH_EXC_INFO] = { true, INSTR_FMT_IX, 0 }, [LOAD_ATTR_METHOD_WITH_VALUES] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG }, [LOAD_ATTR_METHOD_NO_DICT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG }, @@ -1139,7 +1141,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[512] = { [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, [CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, [CALL_NO_KW_METHOD_DESCRIPTOR_FAST] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, - [INSTRUMENTED_CALL_FUNCTION_EX] = { true, INSTR_FMT_IX, 0 }, + [INSTRUMENTED_CALL_FUNCTION_EX] = { true, INSTR_FMT_IX, NO_EXCEPTION_FLAG }, [CALL_FUNCTION_EX] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, [MAKE_FUNCTION] = { true, INSTR_FMT_IX, 0 }, [SET_FUNCTION_ATTRIBUTE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, @@ -1150,7 +1152,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[512] = { [FORMAT_WITH_SPEC] = { true, INSTR_FMT_IX, 0 }, [COPY] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, [BINARY_OP] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG }, - [SWAP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [SWAP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | NO_EXCEPTION_FLAG }, [INSTRUMENTED_INSTRUCTION] = { true, INSTR_FMT_IX, 0 }, [INSTRUMENTED_JUMP_FORWARD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, [INSTRUMENTED_JUMP_BACKWARD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, @@ -1158,7 +1160,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[512] = { [INSTRUMENTED_POP_JUMP_IF_FALSE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, [INSTRUMENTED_POP_JUMP_IF_NONE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, - [EXTENDED_ARG] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [EXTENDED_ARG] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | NO_EXCEPTION_FLAG }, [CACHE] = { true, INSTR_FMT_IX, 0 }, [RESERVED] = { true, INSTR_FMT_IX, 0 }, }; diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 38be98034e0d83a..23f1741859d9777 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -252,6 +252,7 @@ class InstructionFlags: HAS_CONST_FLAG: bool HAS_NAME_FLAG: bool HAS_JUMP_FLAG: bool + NO_EXCEPTION_FLAG: bool def __post_init__(self): self.bitmask = { @@ -265,11 +266,12 @@ def fromInstruction(instr: "AnyInstruction"): HAS_CONST_FLAG=variable_used(instr, "FRAME_CO_CONSTS"), HAS_NAME_FLAG=variable_used(instr, "FRAME_CO_NAMES"), HAS_JUMP_FLAG=variable_used(instr, "JUMPBY"), + NO_EXCEPTION_FLAG=no_exception(instr), ) @staticmethod def newEmpty(): - return InstructionFlags(False, False, False, False) + return InstructionFlags(False, False, False, False, False) def add(self, other: "InstructionFlags") -> None: for name, value in dataclasses.asdict(other).items(): @@ -1585,6 +1587,19 @@ def variable_used(node: parser.Node, name: str) -> bool: ) +def no_exception(node: parser.Node) -> bool: + if node.name.startswith("JUMP"): + return False + for token in node.tokens: + token_text = token.text.lower() + if token.kind == "IDENTIFIER": + if token_text == "error_if": + return False + if token_text.startswith("py") or token_text.startswith("_py"): + return False + return True + + def main(): """Parse command line, parse input, analyze, write output.""" args = arg_parser.parse_args() # Prints message and sys.exit(2) on error