mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 05:31:20 +00:00 
			
		
		
		
	gh-107901: add the HAS_EVAL_BREAK instruction flag (#108375)
This commit is contained in:
		
							parent
							
								
									5a25daa512
								
							
						
					
					
						commit
						5f41376e93
					
				
					 3 changed files with 28 additions and 21 deletions
				
			
		
							
								
								
									
										36
									
								
								Include/internal/pycore_opcode_metadata.h
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										36
									
								
								Include/internal/pycore_opcode_metadata.h
									
										
									
										generated
									
									
									
								
							|  | @ -1158,12 +1158,14 @@ enum InstructionFormat { | ||||||
| #define HAS_JUMP_FLAG (8) | #define HAS_JUMP_FLAG (8) | ||||||
| #define HAS_FREE_FLAG (16) | #define HAS_FREE_FLAG (16) | ||||||
| #define HAS_LOCAL_FLAG (32) | #define HAS_LOCAL_FLAG (32) | ||||||
|  | #define HAS_EVAL_BREAK_FLAG (64) | ||||||
| #define OPCODE_HAS_ARG(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_ARG_FLAG)) | #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_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_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_HAS_JUMP(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_JUMP_FLAG)) | ||||||
| #define OPCODE_HAS_FREE(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_FREE_FLAG)) | #define OPCODE_HAS_FREE(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_FREE_FLAG)) | ||||||
| #define OPCODE_HAS_LOCAL(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_LOCAL_FLAG)) | #define OPCODE_HAS_LOCAL(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_LOCAL_FLAG)) | ||||||
|  | #define OPCODE_HAS_EVAL_BREAK(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_EVAL_BREAK_FLAG)) | ||||||
| 
 | 
 | ||||||
| struct opcode_metadata { | struct opcode_metadata { | ||||||
|     bool valid_entry; |     bool valid_entry; | ||||||
|  | @ -1196,8 +1198,8 @@ extern const struct opcode_metadata _PyOpcode_opcode_metadata[OPCODE_METADATA_SI | ||||||
| #ifdef NEED_OPCODE_METADATA | #ifdef NEED_OPCODE_METADATA | ||||||
| const struct opcode_metadata _PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE] = { | const struct opcode_metadata _PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE] = { | ||||||
|     [NOP] = { true, INSTR_FMT_IX, 0 }, |     [NOP] = { true, INSTR_FMT_IX, 0 }, | ||||||
|     [RESUME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, |     [RESUME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG }, | ||||||
|     [INSTRUMENTED_RESUME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, |     [INSTRUMENTED_RESUME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG }, | ||||||
|     [LOAD_CLOSURE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG }, |     [LOAD_CLOSURE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG }, | ||||||
|     [LOAD_FAST_CHECK] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG }, |     [LOAD_FAST_CHECK] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG }, | ||||||
|     [LOAD_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG }, |     [LOAD_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG }, | ||||||
|  | @ -1333,10 +1335,10 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE] = { | ||||||
|     [IMPORT_NAME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NAME_FLAG }, |     [IMPORT_NAME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NAME_FLAG }, | ||||||
|     [IMPORT_FROM] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NAME_FLAG }, |     [IMPORT_FROM] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NAME_FLAG }, | ||||||
|     [JUMP_FORWARD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG }, |     [JUMP_FORWARD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG }, | ||||||
|     [JUMP_BACKWARD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG }, |     [JUMP_BACKWARD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EVAL_BREAK_FLAG }, | ||||||
|     [JUMP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG }, |     [JUMP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG }, | ||||||
|     [JUMP_NO_INTERRUPT] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG }, |     [JUMP_NO_INTERRUPT] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG }, | ||||||
|     [ENTER_EXECUTOR] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG }, |     [ENTER_EXECUTOR] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EVAL_BREAK_FLAG }, | ||||||
|     [POP_JUMP_IF_FALSE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG }, |     [POP_JUMP_IF_FALSE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG }, | ||||||
|     [POP_JUMP_IF_TRUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG }, |     [POP_JUMP_IF_TRUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG }, | ||||||
|     [POP_JUMP_IF_NONE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG }, |     [POP_JUMP_IF_NONE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG }, | ||||||
|  | @ -1370,28 +1372,28 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE] = { | ||||||
|     [LOAD_ATTR_METHOD_LAZY_DICT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG }, |     [LOAD_ATTR_METHOD_LAZY_DICT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG }, | ||||||
|     [KW_NAMES] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_CONST_FLAG }, |     [KW_NAMES] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_CONST_FLAG }, | ||||||
|     [INSTRUMENTED_CALL] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, |     [INSTRUMENTED_CALL] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, | ||||||
|     [CALL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, |     [CALL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG }, | ||||||
|     [CALL_BOUND_METHOD_EXACT_ARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, |     [CALL_BOUND_METHOD_EXACT_ARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, | ||||||
|     [CALL_PY_EXACT_ARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, |     [CALL_PY_EXACT_ARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, | ||||||
|     [CALL_PY_WITH_DEFAULTS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, |     [CALL_PY_WITH_DEFAULTS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, | ||||||
|     [CALL_NO_KW_TYPE_1] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, |     [CALL_NO_KW_TYPE_1] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, | ||||||
|     [CALL_NO_KW_STR_1] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, |     [CALL_NO_KW_STR_1] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG }, | ||||||
|     [CALL_NO_KW_TUPLE_1] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, |     [CALL_NO_KW_TUPLE_1] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG }, | ||||||
|     [CALL_NO_KW_ALLOC_AND_ENTER_INIT] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, |     [CALL_NO_KW_ALLOC_AND_ENTER_INIT] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, | ||||||
|     [EXIT_INIT_CHECK] = { true, INSTR_FMT_IX, 0 }, |     [EXIT_INIT_CHECK] = { true, INSTR_FMT_IX, 0 }, | ||||||
|     [CALL_BUILTIN_CLASS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, |     [CALL_BUILTIN_CLASS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG }, | ||||||
|     [CALL_NO_KW_BUILTIN_O] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, |     [CALL_NO_KW_BUILTIN_O] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG }, | ||||||
|     [CALL_NO_KW_BUILTIN_FAST] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, |     [CALL_NO_KW_BUILTIN_FAST] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG }, | ||||||
|     [CALL_BUILTIN_FAST_WITH_KEYWORDS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, |     [CALL_BUILTIN_FAST_WITH_KEYWORDS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG }, | ||||||
|     [CALL_NO_KW_LEN] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, |     [CALL_NO_KW_LEN] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, | ||||||
|     [CALL_NO_KW_ISINSTANCE] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, |     [CALL_NO_KW_ISINSTANCE] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, | ||||||
|     [CALL_NO_KW_LIST_APPEND] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, |     [CALL_NO_KW_LIST_APPEND] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, | ||||||
|     [CALL_NO_KW_METHOD_DESCRIPTOR_O] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, |     [CALL_NO_KW_METHOD_DESCRIPTOR_O] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG }, | ||||||
|     [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, |     [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG }, | ||||||
|     [CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, |     [CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG }, | ||||||
|     [CALL_NO_KW_METHOD_DESCRIPTOR_FAST] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, |     [CALL_NO_KW_METHOD_DESCRIPTOR_FAST] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG }, | ||||||
|     [INSTRUMENTED_CALL_FUNCTION_EX] = { true, INSTR_FMT_IX, 0 }, |     [INSTRUMENTED_CALL_FUNCTION_EX] = { true, INSTR_FMT_IX, 0 }, | ||||||
|     [CALL_FUNCTION_EX] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, |     [CALL_FUNCTION_EX] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG }, | ||||||
|     [MAKE_FUNCTION] = { true, INSTR_FMT_IX, 0 }, |     [MAKE_FUNCTION] = { true, INSTR_FMT_IX, 0 }, | ||||||
|     [SET_FUNCTION_ATTRIBUTE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, |     [SET_FUNCTION_ATTRIBUTE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, | ||||||
|     [RETURN_GENERATOR] = { true, INSTR_FMT_IX, 0 }, |     [RETURN_GENERATOR] = { true, INSTR_FMT_IX, 0 }, | ||||||
|  | @ -1404,7 +1406,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE] = { | ||||||
|     [SWAP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, |     [SWAP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, | ||||||
|     [INSTRUMENTED_INSTRUCTION] = { true, INSTR_FMT_IX, 0 }, |     [INSTRUMENTED_INSTRUCTION] = { true, INSTR_FMT_IX, 0 }, | ||||||
|     [INSTRUMENTED_JUMP_FORWARD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, |     [INSTRUMENTED_JUMP_FORWARD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, | ||||||
|     [INSTRUMENTED_JUMP_BACKWARD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, |     [INSTRUMENTED_JUMP_BACKWARD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG }, | ||||||
|     [INSTRUMENTED_POP_JUMP_IF_TRUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, |     [INSTRUMENTED_POP_JUMP_IF_TRUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, | ||||||
|     [INSTRUMENTED_POP_JUMP_IF_FALSE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, |     [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_NONE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, | ||||||
|  |  | ||||||
|  | @ -381,7 +381,8 @@ def analyze_pseudo(self, pseudo: parsing.Pseudo) -> PseudoInstruction: | ||||||
|         # Make sure the targets have the same fmt |         # Make sure the targets have the same fmt | ||||||
|         fmts = list(set([t.instr_fmt for t in targets])) |         fmts = list(set([t.instr_fmt for t in targets])) | ||||||
|         assert len(fmts) == 1 |         assert len(fmts) == 1 | ||||||
|         assert len(list(set([t.instr_flags.bitmap() for t in targets]))) == 1 |         ignored_flags = {'HAS_EVAL_BREAK_FLAG'} | ||||||
|  |         assert len({t.instr_flags.bitmap(ignore=ignored_flags) for t in targets}) == 1 | ||||||
|         return PseudoInstruction(pseudo.name, targets, fmts[0], targets[0].instr_flags) |         return PseudoInstruction(pseudo.name, targets, fmts[0], targets[0].instr_flags) | ||||||
| 
 | 
 | ||||||
|     def analyze_instruction( |     def analyze_instruction( | ||||||
|  |  | ||||||
|  | @ -3,6 +3,7 @@ | ||||||
| from formatting import Formatter | from formatting import Formatter | ||||||
| import lexer as lx | import lexer as lx | ||||||
| import parsing | import parsing | ||||||
|  | from typing import AbstractSet | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @dataclasses.dataclass | @dataclasses.dataclass | ||||||
|  | @ -15,6 +16,7 @@ class InstructionFlags: | ||||||
|     HAS_JUMP_FLAG: bool |     HAS_JUMP_FLAG: bool | ||||||
|     HAS_FREE_FLAG: bool |     HAS_FREE_FLAG: bool | ||||||
|     HAS_LOCAL_FLAG: bool |     HAS_LOCAL_FLAG: bool | ||||||
|  |     HAS_EVAL_BREAK_FLAG: bool | ||||||
| 
 | 
 | ||||||
|     def __post_init__(self) -> None: |     def __post_init__(self) -> None: | ||||||
|         self.bitmask = {name: (1 << i) for i, name in enumerate(self.names())} |         self.bitmask = {name: (1 << i) for i, name in enumerate(self.names())} | ||||||
|  | @ -37,11 +39,12 @@ def fromInstruction(instr: parsing.Node) -> "InstructionFlags": | ||||||
|                 variable_used(instr, "GETLOCAL") or variable_used(instr, "SETLOCAL") |                 variable_used(instr, "GETLOCAL") or variable_used(instr, "SETLOCAL") | ||||||
|             ) |             ) | ||||||
|             and not has_free, |             and not has_free, | ||||||
|  |             HAS_EVAL_BREAK_FLAG=variable_used(instr, "CHECK_EVAL_BREAKER"), | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|     @staticmethod |     @staticmethod | ||||||
|     def newEmpty() -> "InstructionFlags": |     def newEmpty() -> "InstructionFlags": | ||||||
|         return InstructionFlags(False, False, False, False, False, False) |         return InstructionFlags(False, False, False, False, False, False, False) | ||||||
| 
 | 
 | ||||||
|     def add(self, other: "InstructionFlags") -> None: |     def add(self, other: "InstructionFlags") -> None: | ||||||
|         for name, value in dataclasses.asdict(other).items(): |         for name, value in dataclasses.asdict(other).items(): | ||||||
|  | @ -53,10 +56,11 @@ def names(self, value: bool | None = None) -> list[str]: | ||||||
|             return list(dataclasses.asdict(self).keys()) |             return list(dataclasses.asdict(self).keys()) | ||||||
|         return [n for n, v in dataclasses.asdict(self).items() if v == value] |         return [n for n, v in dataclasses.asdict(self).items() if v == value] | ||||||
| 
 | 
 | ||||||
|     def bitmap(self) -> int: |     def bitmap(self, ignore: AbstractSet[str] = frozenset()) -> int: | ||||||
|         flags = 0 |         flags = 0 | ||||||
|  |         assert all(hasattr(self, name) for name in ignore) | ||||||
|         for name in self.names(): |         for name in self.names(): | ||||||
|             if getattr(self, name): |             if getattr(self, name) and name not in ignore: | ||||||
|                 flags |= self.bitmask[name] |                 flags |= self.bitmask[name] | ||||||
|         return flags |         return flags | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Irit Katriel
						Irit Katriel