From 2ca26bb68e4645136168e85d77e38935f30d8f8e Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 26 Sep 2023 17:43:21 -0700 Subject: [PATCH 1/9] Print non-viable uops --- Tools/cases_generator/analysis.py | 32 +++++++++++++++++++++++++ Tools/cases_generator/generate_cases.py | 10 ++++++++ 2 files changed, 42 insertions(+) diff --git a/Tools/cases_generator/analysis.py b/Tools/cases_generator/analysis.py index b920c0aa8c1c8a..2a933d2253e051 100644 --- a/Tools/cases_generator/analysis.py +++ b/Tools/cases_generator/analysis.py @@ -414,3 +414,35 @@ def check_macro_components( case _: assert_never(uop) return components + + def report_non_viable_uops(self): + print("The following ops are not viable uops:") + skips = { + "CACHE", + "RESERVED", + "ENTER_EXECUTOR", + "LOAD_FAST_LOAD_FAST", + "LOAD_FAST_LOAD_CONST", + "LOAD_CONST_LOAD_FAST", + "_BINARY_OP_INPLACE_ADD_UNICODE", + "POP_JUMP_IF_TRUE", + "POP_JUMP_IF_FALSE", + "_ITER_JUMP_LIST", + "_ITER_JUMP_TUPLE", + "_ITER_JUMP_SET", + } + non_viable = [ + instr + for instr in self.instrs.values() + if not instr.is_viable_uop() + and instr.name not in skips + and not instr.name.startswith("INSTRUMENTED_") + ] + non_viable.sort(key=lambda instr: instr.name) + for instr in non_viable: + print(f" {instr.name:<35}", end="") + if instr.name in self.families: + print(" (unspecialized)", end="") + elif instr.family is not None: + print(f" (specialization of {instr.family.name})", end="") + print() diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 898736248a98f9..ea017966c8756a 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -92,6 +92,13 @@ description="Generate the code for the interpreter switch.", formatter_class=argparse.ArgumentDefaultsHelpFormatter, ) + +arg_parser.add_argument( + "-v", + "--verbose", + help="Print list of non-viable uops and exit", + action="store_true", +) arg_parser.add_argument( "-o", "--output", type=str, help="Generated code", default=DEFAULT_OUTPUT ) @@ -865,6 +872,9 @@ def main() -> None: a.analyze() # Prints messages and sets a.errors on failure if a.errors: sys.exit(f"Found {a.errors} errors") + if args.verbose: + a.report_non_viable_uops() + return # These raise OSError if output can't be written a.write_instructions(args.output, args.emit_line_directives) From e19517c7f6cbd7d588fb3aea8654bca07ec7f440 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 26 Sep 2023 18:41:58 -0700 Subject: [PATCH 2/9] Sort non-viable opcodes by execution count --- Tools/cases_generator/analysis.py | 42 ++++++++++++++++++++----- Tools/cases_generator/generate_cases.py | 3 +- 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/Tools/cases_generator/analysis.py b/Tools/cases_generator/analysis.py index 2a933d2253e051..91dcba8ceee13d 100644 --- a/Tools/cases_generator/analysis.py +++ b/Tools/cases_generator/analysis.py @@ -415,34 +415,60 @@ def check_macro_components( assert_never(uop) return components - def report_non_viable_uops(self): + def report_non_viable_uops(self, jsonfile: str) -> None: print("The following ops are not viable uops:") skips = { "CACHE", "RESERVED", - "ENTER_EXECUTOR", + "INTERPRETER_EXIT", + "JUMP_BACKWARD", "LOAD_FAST_LOAD_FAST", - "LOAD_FAST_LOAD_CONST", "LOAD_CONST_LOAD_FAST", + "STORE_FAST_STORE_FAST", "_BINARY_OP_INPLACE_ADD_UNICODE", "POP_JUMP_IF_TRUE", "POP_JUMP_IF_FALSE", "_ITER_JUMP_LIST", "_ITER_JUMP_TUPLE", - "_ITER_JUMP_SET", + "_ITER_JUMP_RANGE", } + try: + # Secret feature: if bmraw.json exists, print and sort by execution count + counts = load_execution_counts(jsonfile) + except FileNotFoundError as err: + counts = {} non_viable = [ instr for instr in self.instrs.values() - if not instr.is_viable_uop() - and instr.name not in skips + if instr.name not in skips and not instr.name.startswith("INSTRUMENTED_") + and not instr.is_viable_uop() ] - non_viable.sort(key=lambda instr: instr.name) + non_viable.sort(key=lambda instr: (-counts.get(instr.name, 0), instr.name)) for instr in non_viable: - print(f" {instr.name:<35}", end="") + if instr.name in counts: + scount = f"{counts[instr.name]:,}" + else: + scount = "" + print(f" {scount:>15} {instr.name:<35}", end="") if instr.name in self.families: print(" (unspecialized)", end="") elif instr.family is not None: print(f" (specialization of {instr.family.name})", end="") print() + + +def load_execution_counts(jsonfile: str) -> dict[str, int]: + import json + + with open(jsonfile) as f: + jsondata = json.load(f) + + # Look for keys like "opcode[LOAD_FAST].execution_count" + prefix = "opcode[" + suffix = "].execution_count" + res: dict[str, int] = {} + for key, value in jsondata.items(): + if key.startswith(prefix) and key.endswith(suffix): + res[key[len(prefix) : -len(suffix)]] = value + return res diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index ea017966c8756a..9192d1038ab7d6 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -873,7 +873,8 @@ def main() -> None: if a.errors: sys.exit(f"Found {a.errors} errors") if args.verbose: - a.report_non_viable_uops() + # Load execution counts from bmraw.json, if it exists + a.report_non_viable_uops("bmraw.json") return # These raise OSError if output can't be written From 8d1a856b6ec7f86a82f1f6515e3aaa72a2e24ad3 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 26 Sep 2023 18:03:00 -0700 Subject: [PATCH 3/9] Double _Py_UOP_MAX_TRACE_LENGTH to 128 --- Include/internal/pycore_uops.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Include/internal/pycore_uops.h b/Include/internal/pycore_uops.h index 249f5c010e0092..d8a7d978f1304e 100644 --- a/Include/internal/pycore_uops.h +++ b/Include/internal/pycore_uops.h @@ -10,7 +10,7 @@ extern "C" { #include "pycore_frame.h" // _PyInterpreterFrame -#define _Py_UOP_MAX_TRACE_LENGTH 64 +#define _Py_UOP_MAX_TRACE_LENGTH 128 typedef struct { uint32_t opcode; From 3796e89b7159e0bddb175e3554c14c61d63c3ae2 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 26 Sep 2023 17:44:19 -0700 Subject: [PATCH 4/9] Split LOAD_ATTR_METHOD_WITH_VALUES --- Include/internal/pycore_opcode_metadata.h | 39 +++++++++++++------ Python/abstract_interp_cases.c.h | 11 ++++++ Python/bytecodes.c | 22 ++++++----- Python/executor_cases.c.h | 30 +++++++++++++++ Python/generated_cases.c.h | 47 +++++++++++++---------- 5 files changed, 106 insertions(+), 43 deletions(-) diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index bb37e9a1d1b6b6..6c418225bce034 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -59,18 +59,20 @@ #define _ITER_JUMP_RANGE 331 #define _IS_ITER_EXHAUSTED_RANGE 332 #define _ITER_NEXT_RANGE 333 -#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS 334 -#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 335 -#define _CHECK_PEP_523 336 -#define _CHECK_FUNCTION_EXACT_ARGS 337 -#define _CHECK_STACK_SPACE 338 -#define _INIT_CALL_PY_EXACT_ARGS 339 -#define _PUSH_FRAME 340 -#define _POP_JUMP_IF_FALSE 341 -#define _POP_JUMP_IF_TRUE 342 -#define _JUMP_TO_TOP 343 -#define _SAVE_CURRENT_IP 344 -#define _INSERT 345 +#define _GUARD_KEYS_VERSION 334 +#define _LOAD_ATTR_METHOD_WITH_VALUES 335 +#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS 336 +#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 337 +#define _CHECK_PEP_523 338 +#define _CHECK_FUNCTION_EXACT_ARGS 339 +#define _CHECK_STACK_SPACE 340 +#define _INIT_CALL_PY_EXACT_ARGS 341 +#define _PUSH_FRAME 342 +#define _POP_JUMP_IF_FALSE 343 +#define _POP_JUMP_IF_TRUE 344 +#define _JUMP_TO_TOP 345 +#define _SAVE_CURRENT_IP 346 +#define _INSERT 347 extern int _PyOpcode_num_popped(int opcode, int oparg, bool jump); #ifdef NEED_OPCODE_METADATA @@ -478,6 +480,10 @@ int _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return 0; case PUSH_EXC_INFO: return 1; + case _GUARD_KEYS_VERSION: + return 1; + case _LOAD_ATTR_METHOD_WITH_VALUES: + return 1; case LOAD_ATTR_METHOD_WITH_VALUES: return 1; case LOAD_ATTR_METHOD_NO_DICT: @@ -1018,6 +1024,10 @@ int _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return 0; case PUSH_EXC_INFO: return 2; + case _GUARD_KEYS_VERSION: + return 1; + case _LOAD_ATTR_METHOD_WITH_VALUES: + return 2; case LOAD_ATTR_METHOD_WITH_VALUES: return 2; case LOAD_ATTR_METHOD_NO_DICT: @@ -1420,6 +1430,8 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE] = { [SETUP_WITH] = { true, INSTR_FMT_IX, 0 }, [POP_BLOCK] = { true, INSTR_FMT_IX, 0 }, [PUSH_EXC_INFO] = { true, INSTR_FMT_IX, 0 }, + [_GUARD_KEYS_VERSION] = { true, INSTR_FMT_IXC0, HAS_DEOPT_FLAG }, + [_LOAD_ATTR_METHOD_WITH_VALUES] = { true, INSTR_FMT_IBC000, HAS_ARG_FLAG }, [LOAD_ATTR_METHOD_WITH_VALUES] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG }, [LOAD_ATTR_METHOD_NO_DICT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG }, [LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG }, @@ -1600,6 +1612,7 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[OPCODE_MACRO_EXPAN [GET_YIELD_FROM_ITER] = { .nuops = 1, .uops = { { GET_YIELD_FROM_ITER, 0, 0 } } }, [WITH_EXCEPT_START] = { .nuops = 1, .uops = { { WITH_EXCEPT_START, 0, 0 } } }, [PUSH_EXC_INFO] = { .nuops = 1, .uops = { { PUSH_EXC_INFO, 0, 0 } } }, + [LOAD_ATTR_METHOD_WITH_VALUES] = { .nuops = 3, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _GUARD_KEYS_VERSION, 2, 3 }, { _LOAD_ATTR_METHOD_WITH_VALUES, 4, 5 } } }, [CALL_BOUND_METHOD_EXACT_ARGS] = { .nuops = 9, .uops = { { _CHECK_PEP_523, 0, 0 }, { _CHECK_CALL_BOUND_METHOD_EXACT_ARGS, 0, 0 }, { _INIT_CALL_BOUND_METHOD_EXACT_ARGS, 0, 0 }, { _CHECK_FUNCTION_EXACT_ARGS, 2, 1 }, { _CHECK_STACK_SPACE, 0, 0 }, { _INIT_CALL_PY_EXACT_ARGS, 0, 0 }, { _SET_IP, 7, 3 }, { _SAVE_CURRENT_IP, 0, 0 }, { _PUSH_FRAME, 0, 0 } } }, [CALL_PY_EXACT_ARGS] = { .nuops = 7, .uops = { { _CHECK_PEP_523, 0, 0 }, { _CHECK_FUNCTION_EXACT_ARGS, 2, 1 }, { _CHECK_STACK_SPACE, 0, 0 }, { _INIT_CALL_PY_EXACT_ARGS, 0, 0 }, { _SET_IP, 7, 3 }, { _SAVE_CURRENT_IP, 0, 0 }, { _PUSH_FRAME, 0, 0 } } }, [CALL_TYPE_1] = { .nuops = 1, .uops = { { CALL_TYPE_1, 0, 0 } } }, @@ -1665,6 +1678,8 @@ const char * const _PyOpcode_uop_name[OPCODE_UOP_NAME_SIZE] = { [_ITER_JUMP_RANGE] = "_ITER_JUMP_RANGE", [_IS_ITER_EXHAUSTED_RANGE] = "_IS_ITER_EXHAUSTED_RANGE", [_ITER_NEXT_RANGE] = "_ITER_NEXT_RANGE", + [_GUARD_KEYS_VERSION] = "_GUARD_KEYS_VERSION", + [_LOAD_ATTR_METHOD_WITH_VALUES] = "_LOAD_ATTR_METHOD_WITH_VALUES", [_CHECK_CALL_BOUND_METHOD_EXACT_ARGS] = "_CHECK_CALL_BOUND_METHOD_EXACT_ARGS", [_INIT_CALL_BOUND_METHOD_EXACT_ARGS] = "_INIT_CALL_BOUND_METHOD_EXACT_ARGS", [_CHECK_PEP_523] = "_CHECK_PEP_523", diff --git a/Python/abstract_interp_cases.c.h b/Python/abstract_interp_cases.c.h index 5a3848cd726245..4547d929e44527 100644 --- a/Python/abstract_interp_cases.c.h +++ b/Python/abstract_interp_cases.c.h @@ -627,6 +627,17 @@ break; } + case _GUARD_KEYS_VERSION: { + break; + } + + case _LOAD_ATTR_METHOD_WITH_VALUES: { + STACK_GROW(1); + PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-2)), true); + PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true); + break; + } + case _CHECK_CALL_BOUND_METHOD_EXACT_ARGS: { break; } diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 402b27101dbdb6..e24306f461d3ec 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2769,20 +2769,16 @@ dummy_func( exc_info->exc_value = Py_NewRef(new_exc); } - inst(LOAD_ATTR_METHOD_WITH_VALUES, (unused/1, type_version/2, keys_version/2, descr/4, owner -- attr, self if (1))) { - assert(oparg & 1); - /* Cached method object */ + op(_GUARD_KEYS_VERSION, (keys_version/2, owner -- owner)) { PyTypeObject *owner_cls = Py_TYPE(owner); - assert(type_version != 0); - DEOPT_IF(owner_cls->tp_version_tag != type_version, LOAD_ATTR); - assert(owner_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT); - PyDictOrValues *dorv = _PyObject_DictOrValuesPointer(owner); - DEOPT_IF(!_PyDictOrValues_IsValues(*dorv) && - !_PyObject_MakeInstanceAttributesFromDict(owner, dorv), - LOAD_ATTR); PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls; DEOPT_IF(owner_heap_type->ht_cached_keys->dk_version != keys_version, LOAD_ATTR); + } + + op(_LOAD_ATTR_METHOD_WITH_VALUES, (descr/4, owner -- attr, self if (1))) { + assert(oparg & 1); + /* Cached method object */ STAT_INC(LOAD_ATTR, hit); assert(descr != NULL); attr = Py_NewRef(descr); @@ -2790,6 +2786,12 @@ dummy_func( self = owner; } + macro(LOAD_ATTR_METHOD_WITH_VALUES) = + unused/1 + + _GUARD_TYPE_VERSION + + _GUARD_KEYS_VERSION + + _LOAD_ATTR_METHOD_WITH_VALUES; + inst(LOAD_ATTR_METHOD_NO_DICT, (unused/1, type_version/2, unused/2, descr/4, owner -- attr, self if (1))) { assert(oparg & 1); PyTypeObject *owner_cls = Py_TYPE(owner); diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index befb972f1e90f5..a50d2fe5d4a823 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -2219,6 +2219,36 @@ break; } + case _GUARD_KEYS_VERSION: { + PyObject *owner; + owner = stack_pointer[-1]; + uint32_t keys_version = (uint32_t)operand; + PyTypeObject *owner_cls = Py_TYPE(owner); + PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls; + DEOPT_IF(owner_heap_type->ht_cached_keys->dk_version != + keys_version, LOAD_ATTR); + break; + } + + case _LOAD_ATTR_METHOD_WITH_VALUES: { + PyObject *owner; + PyObject *attr; + PyObject *self; + owner = stack_pointer[-1]; + PyObject *descr = (PyObject *)operand; + assert(oparg & 1); + /* Cached method object */ + STAT_INC(LOAD_ATTR, hit); + assert(descr != NULL); + attr = Py_NewRef(descr); + assert(_PyType_HasFeature(Py_TYPE(attr), Py_TPFLAGS_METHOD_DESCRIPTOR)); + self = owner; + STACK_GROW(1); + stack_pointer[-2] = attr; + stack_pointer[-1] = self; + break; + } + case _CHECK_CALL_BOUND_METHOD_EXACT_ARGS: { PyObject *null; PyObject *callable; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index ebb87a86de432e..03e495512fc6c0 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -3557,28 +3557,33 @@ PyObject *owner; PyObject *attr; PyObject *self; + // _GUARD_TYPE_VERSION owner = stack_pointer[-1]; - uint32_t type_version = read_u32(&next_instr[1].cache); - uint32_t keys_version = read_u32(&next_instr[3].cache); - PyObject *descr = read_obj(&next_instr[5].cache); - assert(oparg & 1); - /* Cached method object */ - PyTypeObject *owner_cls = Py_TYPE(owner); - assert(type_version != 0); - DEOPT_IF(owner_cls->tp_version_tag != type_version, LOAD_ATTR); - assert(owner_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT); - PyDictOrValues *dorv = _PyObject_DictOrValuesPointer(owner); - DEOPT_IF(!_PyDictOrValues_IsValues(*dorv) && - !_PyObject_MakeInstanceAttributesFromDict(owner, dorv), - LOAD_ATTR); - PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls; - DEOPT_IF(owner_heap_type->ht_cached_keys->dk_version != - keys_version, LOAD_ATTR); - STAT_INC(LOAD_ATTR, hit); - assert(descr != NULL); - attr = Py_NewRef(descr); - assert(_PyType_HasFeature(Py_TYPE(attr), Py_TPFLAGS_METHOD_DESCRIPTOR)); - self = owner; + { + uint32_t type_version = read_u32(&next_instr[1].cache); + PyTypeObject *tp = Py_TYPE(owner); + assert(type_version != 0); + DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); + } + // _GUARD_KEYS_VERSION + { + uint32_t keys_version = read_u32(&next_instr[3].cache); + PyTypeObject *owner_cls = Py_TYPE(owner); + PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls; + DEOPT_IF(owner_heap_type->ht_cached_keys->dk_version != + keys_version, LOAD_ATTR); + } + // _LOAD_ATTR_METHOD_WITH_VALUES + { + PyObject *descr = read_obj(&next_instr[5].cache); + assert(oparg & 1); + /* Cached method object */ + STAT_INC(LOAD_ATTR, hit); + assert(descr != NULL); + attr = Py_NewRef(descr); + assert(_PyType_HasFeature(Py_TYPE(attr), Py_TPFLAGS_METHOD_DESCRIPTOR)); + self = owner; + } STACK_GROW(1); stack_pointer[-2] = attr; stack_pointer[-1] = self; From 6d816ed491ff8d1234a4d27f4f9005d95c6c3dfb Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 26 Sep 2023 17:52:25 -0700 Subject: [PATCH 5/9] Split LOAD_ATTR_METHOD_NO_DICT --- Include/internal/pycore_opcode_metadata.h | 32 ++++++++++++++--------- Python/abstract_interp_cases.c.h | 7 +++++ Python/bytecodes.c | 9 +++++-- Python/executor_cases.c.h | 20 ++++++++++++++ Python/generated_cases.c.h | 30 +++++++++++++-------- 5 files changed, 73 insertions(+), 25 deletions(-) diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index 6c418225bce034..dc5ce7e80c3dda 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -61,18 +61,19 @@ #define _ITER_NEXT_RANGE 333 #define _GUARD_KEYS_VERSION 334 #define _LOAD_ATTR_METHOD_WITH_VALUES 335 -#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS 336 -#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 337 -#define _CHECK_PEP_523 338 -#define _CHECK_FUNCTION_EXACT_ARGS 339 -#define _CHECK_STACK_SPACE 340 -#define _INIT_CALL_PY_EXACT_ARGS 341 -#define _PUSH_FRAME 342 -#define _POP_JUMP_IF_FALSE 343 -#define _POP_JUMP_IF_TRUE 344 -#define _JUMP_TO_TOP 345 -#define _SAVE_CURRENT_IP 346 -#define _INSERT 347 +#define _LOAD_ATTR_METHOD_NO_DICT 336 +#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS 337 +#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 338 +#define _CHECK_PEP_523 339 +#define _CHECK_FUNCTION_EXACT_ARGS 340 +#define _CHECK_STACK_SPACE 341 +#define _INIT_CALL_PY_EXACT_ARGS 342 +#define _PUSH_FRAME 343 +#define _POP_JUMP_IF_FALSE 344 +#define _POP_JUMP_IF_TRUE 345 +#define _JUMP_TO_TOP 346 +#define _SAVE_CURRENT_IP 347 +#define _INSERT 348 extern int _PyOpcode_num_popped(int opcode, int oparg, bool jump); #ifdef NEED_OPCODE_METADATA @@ -486,6 +487,8 @@ int _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return 1; case LOAD_ATTR_METHOD_WITH_VALUES: return 1; + case _LOAD_ATTR_METHOD_NO_DICT: + return 1; case LOAD_ATTR_METHOD_NO_DICT: return 1; case LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES: @@ -1030,6 +1033,8 @@ int _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return 2; case LOAD_ATTR_METHOD_WITH_VALUES: return 2; + case _LOAD_ATTR_METHOD_NO_DICT: + return 2; case LOAD_ATTR_METHOD_NO_DICT: return 2; case LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES: @@ -1433,6 +1438,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE] = { [_GUARD_KEYS_VERSION] = { true, INSTR_FMT_IXC0, HAS_DEOPT_FLAG }, [_LOAD_ATTR_METHOD_WITH_VALUES] = { true, INSTR_FMT_IBC000, HAS_ARG_FLAG }, [LOAD_ATTR_METHOD_WITH_VALUES] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG }, + [_LOAD_ATTR_METHOD_NO_DICT] = { true, INSTR_FMT_IBC000, HAS_ARG_FLAG }, [LOAD_ATTR_METHOD_NO_DICT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG }, [LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG }, [LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG }, @@ -1613,6 +1619,7 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[OPCODE_MACRO_EXPAN [WITH_EXCEPT_START] = { .nuops = 1, .uops = { { WITH_EXCEPT_START, 0, 0 } } }, [PUSH_EXC_INFO] = { .nuops = 1, .uops = { { PUSH_EXC_INFO, 0, 0 } } }, [LOAD_ATTR_METHOD_WITH_VALUES] = { .nuops = 3, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _GUARD_KEYS_VERSION, 2, 3 }, { _LOAD_ATTR_METHOD_WITH_VALUES, 4, 5 } } }, + [LOAD_ATTR_METHOD_NO_DICT] = { .nuops = 2, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_METHOD_NO_DICT, 4, 5 } } }, [CALL_BOUND_METHOD_EXACT_ARGS] = { .nuops = 9, .uops = { { _CHECK_PEP_523, 0, 0 }, { _CHECK_CALL_BOUND_METHOD_EXACT_ARGS, 0, 0 }, { _INIT_CALL_BOUND_METHOD_EXACT_ARGS, 0, 0 }, { _CHECK_FUNCTION_EXACT_ARGS, 2, 1 }, { _CHECK_STACK_SPACE, 0, 0 }, { _INIT_CALL_PY_EXACT_ARGS, 0, 0 }, { _SET_IP, 7, 3 }, { _SAVE_CURRENT_IP, 0, 0 }, { _PUSH_FRAME, 0, 0 } } }, [CALL_PY_EXACT_ARGS] = { .nuops = 7, .uops = { { _CHECK_PEP_523, 0, 0 }, { _CHECK_FUNCTION_EXACT_ARGS, 2, 1 }, { _CHECK_STACK_SPACE, 0, 0 }, { _INIT_CALL_PY_EXACT_ARGS, 0, 0 }, { _SET_IP, 7, 3 }, { _SAVE_CURRENT_IP, 0, 0 }, { _PUSH_FRAME, 0, 0 } } }, [CALL_TYPE_1] = { .nuops = 1, .uops = { { CALL_TYPE_1, 0, 0 } } }, @@ -1680,6 +1687,7 @@ const char * const _PyOpcode_uop_name[OPCODE_UOP_NAME_SIZE] = { [_ITER_NEXT_RANGE] = "_ITER_NEXT_RANGE", [_GUARD_KEYS_VERSION] = "_GUARD_KEYS_VERSION", [_LOAD_ATTR_METHOD_WITH_VALUES] = "_LOAD_ATTR_METHOD_WITH_VALUES", + [_LOAD_ATTR_METHOD_NO_DICT] = "_LOAD_ATTR_METHOD_NO_DICT", [_CHECK_CALL_BOUND_METHOD_EXACT_ARGS] = "_CHECK_CALL_BOUND_METHOD_EXACT_ARGS", [_INIT_CALL_BOUND_METHOD_EXACT_ARGS] = "_INIT_CALL_BOUND_METHOD_EXACT_ARGS", [_CHECK_PEP_523] = "_CHECK_PEP_523", diff --git a/Python/abstract_interp_cases.c.h b/Python/abstract_interp_cases.c.h index 4547d929e44527..afa8bc96cec966 100644 --- a/Python/abstract_interp_cases.c.h +++ b/Python/abstract_interp_cases.c.h @@ -638,6 +638,13 @@ break; } + case _LOAD_ATTR_METHOD_NO_DICT: { + STACK_GROW(1); + PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-2)), true); + PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true); + break; + } + case _CHECK_CALL_BOUND_METHOD_EXACT_ARGS: { break; } diff --git a/Python/bytecodes.c b/Python/bytecodes.c index e24306f461d3ec..3afb577b5cf0e8 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2792,10 +2792,9 @@ dummy_func( _GUARD_KEYS_VERSION + _LOAD_ATTR_METHOD_WITH_VALUES; - inst(LOAD_ATTR_METHOD_NO_DICT, (unused/1, type_version/2, unused/2, descr/4, owner -- attr, self if (1))) { + op(_LOAD_ATTR_METHOD_NO_DICT, (descr/4, owner -- attr, self if (1))) { assert(oparg & 1); PyTypeObject *owner_cls = Py_TYPE(owner); - DEOPT_IF(owner_cls->tp_version_tag != type_version, LOAD_ATTR); assert(owner_cls->tp_dictoffset == 0); STAT_INC(LOAD_ATTR, hit); assert(descr != NULL); @@ -2804,6 +2803,12 @@ dummy_func( self = owner; } + macro(LOAD_ATTR_METHOD_NO_DICT) = + unused/1 + + _GUARD_TYPE_VERSION + + unused/2 + + _LOAD_ATTR_METHOD_NO_DICT; + inst(LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES, (unused/1, type_version/2, keys_version/2, descr/4, owner -- attr, unused if (0))) { assert((oparg & 1) == 0); PyTypeObject *owner_cls = Py_TYPE(owner); diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index a50d2fe5d4a823..b35f16fb99fe2d 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -2249,6 +2249,26 @@ break; } + case _LOAD_ATTR_METHOD_NO_DICT: { + PyObject *owner; + PyObject *attr; + PyObject *self; + owner = stack_pointer[-1]; + PyObject *descr = (PyObject *)operand; + assert(oparg & 1); + PyTypeObject *owner_cls = Py_TYPE(owner); + assert(owner_cls->tp_dictoffset == 0); + STAT_INC(LOAD_ATTR, hit); + assert(descr != NULL); + assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); + attr = Py_NewRef(descr); + self = owner; + STACK_GROW(1); + stack_pointer[-2] = attr; + stack_pointer[-1] = self; + break; + } + case _CHECK_CALL_BOUND_METHOD_EXACT_ARGS: { PyObject *null; PyObject *callable; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 03e495512fc6c0..d5491509a85240 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -3595,18 +3595,26 @@ PyObject *owner; PyObject *attr; PyObject *self; + // _GUARD_TYPE_VERSION owner = stack_pointer[-1]; - uint32_t type_version = read_u32(&next_instr[1].cache); - PyObject *descr = read_obj(&next_instr[5].cache); - assert(oparg & 1); - PyTypeObject *owner_cls = Py_TYPE(owner); - DEOPT_IF(owner_cls->tp_version_tag != type_version, LOAD_ATTR); - assert(owner_cls->tp_dictoffset == 0); - STAT_INC(LOAD_ATTR, hit); - assert(descr != NULL); - assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); - attr = Py_NewRef(descr); - self = owner; + { + uint32_t type_version = read_u32(&next_instr[1].cache); + PyTypeObject *tp = Py_TYPE(owner); + assert(type_version != 0); + DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); + } + // _LOAD_ATTR_METHOD_NO_DICT + { + PyObject *descr = read_obj(&next_instr[5].cache); + assert(oparg & 1); + PyTypeObject *owner_cls = Py_TYPE(owner); + assert(owner_cls->tp_dictoffset == 0); + STAT_INC(LOAD_ATTR, hit); + assert(descr != NULL); + assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); + attr = Py_NewRef(descr); + self = owner; + } STACK_GROW(1); stack_pointer[-2] = attr; stack_pointer[-1] = self; From 5ba03d1d8a2daecd5e6d9243e561ac176ccfffc9 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 26 Sep 2023 17:59:22 -0700 Subject: [PATCH 6/9] Split LOAD_ATTR_SLOT (weird: action may deopt) --- Include/internal/pycore_opcode_metadata.h | 66 +++++++++++++---------- Python/abstract_interp_cases.c.h | 7 +++ Python/bytecodes.c | 11 ++-- Python/executor_cases.c.h | 19 +++++++ Python/generated_cases.c.h | 30 ++++++----- 5 files changed, 88 insertions(+), 45 deletions(-) diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index dc5ce7e80c3dda..d2ea6c8bcecaed 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -46,34 +46,35 @@ #define _GUARD_TYPE_VERSION 318 #define _CHECK_MANAGED_OBJECT_HAS_VALUES 319 #define _LOAD_ATTR_INSTANCE_VALUE 320 -#define _IS_NONE 321 -#define _ITER_CHECK_LIST 322 -#define _ITER_JUMP_LIST 323 -#define _IS_ITER_EXHAUSTED_LIST 324 -#define _ITER_NEXT_LIST 325 -#define _ITER_CHECK_TUPLE 326 -#define _ITER_JUMP_TUPLE 327 -#define _IS_ITER_EXHAUSTED_TUPLE 328 -#define _ITER_NEXT_TUPLE 329 -#define _ITER_CHECK_RANGE 330 -#define _ITER_JUMP_RANGE 331 -#define _IS_ITER_EXHAUSTED_RANGE 332 -#define _ITER_NEXT_RANGE 333 -#define _GUARD_KEYS_VERSION 334 -#define _LOAD_ATTR_METHOD_WITH_VALUES 335 -#define _LOAD_ATTR_METHOD_NO_DICT 336 -#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS 337 -#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 338 -#define _CHECK_PEP_523 339 -#define _CHECK_FUNCTION_EXACT_ARGS 340 -#define _CHECK_STACK_SPACE 341 -#define _INIT_CALL_PY_EXACT_ARGS 342 -#define _PUSH_FRAME 343 -#define _POP_JUMP_IF_FALSE 344 -#define _POP_JUMP_IF_TRUE 345 -#define _JUMP_TO_TOP 346 -#define _SAVE_CURRENT_IP 347 -#define _INSERT 348 +#define _LOAD_ATTR_SLOT 321 +#define _IS_NONE 322 +#define _ITER_CHECK_LIST 323 +#define _ITER_JUMP_LIST 324 +#define _IS_ITER_EXHAUSTED_LIST 325 +#define _ITER_NEXT_LIST 326 +#define _ITER_CHECK_TUPLE 327 +#define _ITER_JUMP_TUPLE 328 +#define _IS_ITER_EXHAUSTED_TUPLE 329 +#define _ITER_NEXT_TUPLE 330 +#define _ITER_CHECK_RANGE 331 +#define _ITER_JUMP_RANGE 332 +#define _IS_ITER_EXHAUSTED_RANGE 333 +#define _ITER_NEXT_RANGE 334 +#define _GUARD_KEYS_VERSION 335 +#define _LOAD_ATTR_METHOD_WITH_VALUES 336 +#define _LOAD_ATTR_METHOD_NO_DICT 337 +#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS 338 +#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 339 +#define _CHECK_PEP_523 340 +#define _CHECK_FUNCTION_EXACT_ARGS 341 +#define _CHECK_STACK_SPACE 342 +#define _INIT_CALL_PY_EXACT_ARGS 343 +#define _PUSH_FRAME 344 +#define _POP_JUMP_IF_FALSE 345 +#define _POP_JUMP_IF_TRUE 346 +#define _JUMP_TO_TOP 347 +#define _SAVE_CURRENT_IP 348 +#define _INSERT 349 extern int _PyOpcode_num_popped(int opcode, int oparg, bool jump); #ifdef NEED_OPCODE_METADATA @@ -359,6 +360,8 @@ int _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return 1; case LOAD_ATTR_WITH_HINT: return 1; + case _LOAD_ATTR_SLOT: + return 1; case LOAD_ATTR_SLOT: return 1; case LOAD_ATTR_CLASS: @@ -905,8 +908,10 @@ int _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return ((oparg & 1) ? 1 : 0) + 1; case LOAD_ATTR_WITH_HINT: return ((oparg & 1) ? 1 : 0) + 1; - case LOAD_ATTR_SLOT: + case _LOAD_ATTR_SLOT: return ((oparg & 1) ? 1 : 0) + 1; + case LOAD_ATTR_SLOT: + return (oparg & 1 ? 1 : 0) + 1; case LOAD_ATTR_CLASS: return ((oparg & 1) ? 1 : 0) + 1; case LOAD_ATTR_PROPERTY: @@ -1374,6 +1379,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE] = { [LOAD_ATTR_INSTANCE_VALUE] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG }, [LOAD_ATTR_MODULE] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG }, [LOAD_ATTR_WITH_HINT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG }, + [_LOAD_ATTR_SLOT] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG }, [LOAD_ATTR_SLOT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG }, [LOAD_ATTR_CLASS] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG }, [LOAD_ATTR_PROPERTY] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG }, @@ -1601,6 +1607,7 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[OPCODE_MACRO_EXPAN [LOAD_SUPER_ATTR_METHOD] = { .nuops = 1, .uops = { { LOAD_SUPER_ATTR_METHOD, 0, 0 } } }, [LOAD_ATTR] = { .nuops = 1, .uops = { { LOAD_ATTR, 0, 0 } } }, [LOAD_ATTR_INSTANCE_VALUE] = { .nuops = 3, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_MANAGED_OBJECT_HAS_VALUES, 0, 0 }, { _LOAD_ATTR_INSTANCE_VALUE, 1, 3 } } }, + [LOAD_ATTR_SLOT] = { .nuops = 2, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_SLOT, 1, 3 } } }, [COMPARE_OP] = { .nuops = 1, .uops = { { COMPARE_OP, 0, 0 } } }, [COMPARE_OP_FLOAT] = { .nuops = 1, .uops = { { COMPARE_OP_FLOAT, 0, 0 } } }, [COMPARE_OP_INT] = { .nuops = 1, .uops = { { COMPARE_OP_INT, 0, 0 } } }, @@ -1672,6 +1679,7 @@ const char * const _PyOpcode_uop_name[OPCODE_UOP_NAME_SIZE] = { [_GUARD_TYPE_VERSION] = "_GUARD_TYPE_VERSION", [_CHECK_MANAGED_OBJECT_HAS_VALUES] = "_CHECK_MANAGED_OBJECT_HAS_VALUES", [_LOAD_ATTR_INSTANCE_VALUE] = "_LOAD_ATTR_INSTANCE_VALUE", + [_LOAD_ATTR_SLOT] = "_LOAD_ATTR_SLOT", [_IS_NONE] = "_IS_NONE", [_ITER_CHECK_LIST] = "_ITER_CHECK_LIST", [_ITER_JUMP_LIST] = "_ITER_JUMP_LIST", diff --git a/Python/abstract_interp_cases.c.h b/Python/abstract_interp_cases.c.h index afa8bc96cec966..47118c84e2d85f 100644 --- a/Python/abstract_interp_cases.c.h +++ b/Python/abstract_interp_cases.c.h @@ -474,6 +474,13 @@ break; } + case _LOAD_ATTR_SLOT: { + STACK_GROW(((oparg & 1) ? 1 : 0)); + PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1 - (oparg & 1 ? 1 : 0))), true); + PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-(oparg & 1 ? 1 : 0))), true); + break; + } + case COMPARE_OP: { STACK_SHRINK(1); PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true); diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 3afb577b5cf0e8..6b6e595cb656e9 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1939,10 +1939,7 @@ dummy_func( DECREF_INPUTS(); } - inst(LOAD_ATTR_SLOT, (unused/1, type_version/2, index/1, unused/5, owner -- attr, null if (oparg & 1))) { - PyTypeObject *tp = Py_TYPE(owner); - assert(type_version != 0); - DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); + op(_LOAD_ATTR_SLOT, (index/1, owner -- attr, null if (oparg & 1))) { char *addr = (char *)owner + index; attr = *(PyObject **)addr; DEOPT_IF(attr == NULL, LOAD_ATTR); @@ -1952,6 +1949,12 @@ dummy_func( DECREF_INPUTS(); } + macro(LOAD_ATTR_SLOT) = + unused/1 + + _GUARD_TYPE_VERSION + + _LOAD_ATTR_SLOT + // NOTE: This action may also deopt + unused/5; + inst(LOAD_ATTR_CLASS, (unused/1, type_version/2, unused/2, descr/4, owner -- attr, null if (oparg & 1))) { DEOPT_IF(!PyType_Check(owner), LOAD_ATTR); diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index b35f16fb99fe2d..bd56a6d2cab803 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -1714,6 +1714,25 @@ break; } + case _LOAD_ATTR_SLOT: { + PyObject *owner; + PyObject *attr; + PyObject *null = NULL; + owner = stack_pointer[-1]; + uint16_t index = (uint16_t)operand; + char *addr = (char *)owner + index; + attr = *(PyObject **)addr; + DEOPT_IF(attr == NULL, LOAD_ATTR); + STAT_INC(LOAD_ATTR, hit); + Py_INCREF(attr); + null = NULL; + Py_DECREF(owner); + STACK_GROW(((oparg & 1) ? 1 : 0)); + stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = attr; + if (oparg & 1) { stack_pointer[-(oparg & 1 ? 1 : 0)] = null; } + break; + } + case COMPARE_OP: { PyObject *right; PyObject *left; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index d5491509a85240..826ada8933b1a4 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2504,19 +2504,25 @@ PyObject *owner; PyObject *attr; PyObject *null = NULL; + // _GUARD_TYPE_VERSION owner = stack_pointer[-1]; - uint32_t type_version = read_u32(&next_instr[1].cache); - uint16_t index = read_u16(&next_instr[3].cache); - PyTypeObject *tp = Py_TYPE(owner); - assert(type_version != 0); - DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); - char *addr = (char *)owner + index; - attr = *(PyObject **)addr; - DEOPT_IF(attr == NULL, LOAD_ATTR); - STAT_INC(LOAD_ATTR, hit); - Py_INCREF(attr); - null = NULL; - Py_DECREF(owner); + { + uint32_t type_version = read_u32(&next_instr[1].cache); + PyTypeObject *tp = Py_TYPE(owner); + assert(type_version != 0); + DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); + } + // _LOAD_ATTR_SLOT + { + uint16_t index = read_u16(&next_instr[3].cache); + char *addr = (char *)owner + index; + attr = *(PyObject **)addr; + DEOPT_IF(attr == NULL, LOAD_ATTR); + STAT_INC(LOAD_ATTR, hit); + Py_INCREF(attr); + null = NULL; + Py_DECREF(owner); + } STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = attr; if (oparg & 1) { stack_pointer[-(oparg & 1 ? 1 : 0)] = null; } From 5d0fa92929342e25f2ef81b8079b1ec25c8ee96c Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 26 Sep 2023 18:49:10 -0700 Subject: [PATCH 7/9] Split STORE_ATTR_SLOT --- Include/internal/pycore_opcode_metadata.h | 71 ++++++++++++++--------- Python/abstract_interp_cases.c.h | 9 +++ Python/bytecodes.c | 10 +++- Python/executor_cases.c.h | 26 +++++++++ Python/generated_cases.c.h | 28 +++++---- 5 files changed, 104 insertions(+), 40 deletions(-) diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index d2ea6c8bcecaed..a2edc95f300634 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -47,34 +47,36 @@ #define _CHECK_MANAGED_OBJECT_HAS_VALUES 319 #define _LOAD_ATTR_INSTANCE_VALUE 320 #define _LOAD_ATTR_SLOT 321 -#define _IS_NONE 322 -#define _ITER_CHECK_LIST 323 -#define _ITER_JUMP_LIST 324 -#define _IS_ITER_EXHAUSTED_LIST 325 -#define _ITER_NEXT_LIST 326 -#define _ITER_CHECK_TUPLE 327 -#define _ITER_JUMP_TUPLE 328 -#define _IS_ITER_EXHAUSTED_TUPLE 329 -#define _ITER_NEXT_TUPLE 330 -#define _ITER_CHECK_RANGE 331 -#define _ITER_JUMP_RANGE 332 -#define _IS_ITER_EXHAUSTED_RANGE 333 -#define _ITER_NEXT_RANGE 334 -#define _GUARD_KEYS_VERSION 335 -#define _LOAD_ATTR_METHOD_WITH_VALUES 336 -#define _LOAD_ATTR_METHOD_NO_DICT 337 -#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS 338 -#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 339 -#define _CHECK_PEP_523 340 -#define _CHECK_FUNCTION_EXACT_ARGS 341 -#define _CHECK_STACK_SPACE 342 -#define _INIT_CALL_PY_EXACT_ARGS 343 -#define _PUSH_FRAME 344 -#define _POP_JUMP_IF_FALSE 345 -#define _POP_JUMP_IF_TRUE 346 -#define _JUMP_TO_TOP 347 -#define _SAVE_CURRENT_IP 348 -#define _INSERT 349 +#define _GUARD_TYPE_VERSION_STORE 322 +#define _STORE_ATTR_SLOT 323 +#define _IS_NONE 324 +#define _ITER_CHECK_LIST 325 +#define _ITER_JUMP_LIST 326 +#define _IS_ITER_EXHAUSTED_LIST 327 +#define _ITER_NEXT_LIST 328 +#define _ITER_CHECK_TUPLE 329 +#define _ITER_JUMP_TUPLE 330 +#define _IS_ITER_EXHAUSTED_TUPLE 331 +#define _ITER_NEXT_TUPLE 332 +#define _ITER_CHECK_RANGE 333 +#define _ITER_JUMP_RANGE 334 +#define _IS_ITER_EXHAUSTED_RANGE 335 +#define _ITER_NEXT_RANGE 336 +#define _GUARD_KEYS_VERSION 337 +#define _LOAD_ATTR_METHOD_WITH_VALUES 338 +#define _LOAD_ATTR_METHOD_NO_DICT 339 +#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS 340 +#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 341 +#define _CHECK_PEP_523 342 +#define _CHECK_FUNCTION_EXACT_ARGS 343 +#define _CHECK_STACK_SPACE 344 +#define _INIT_CALL_PY_EXACT_ARGS 345 +#define _PUSH_FRAME 346 +#define _POP_JUMP_IF_FALSE 347 +#define _POP_JUMP_IF_TRUE 348 +#define _JUMP_TO_TOP 349 +#define _SAVE_CURRENT_IP 350 +#define _INSERT 351 extern int _PyOpcode_num_popped(int opcode, int oparg, bool jump); #ifdef NEED_OPCODE_METADATA @@ -374,6 +376,10 @@ int _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return 2; case STORE_ATTR_WITH_HINT: return 2; + case _GUARD_TYPE_VERSION_STORE: + return 1; + case _STORE_ATTR_SLOT: + return 2; case STORE_ATTR_SLOT: return 2; case COMPARE_OP: @@ -922,6 +928,10 @@ int _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return 0; case STORE_ATTR_WITH_HINT: return 0; + case _GUARD_TYPE_VERSION_STORE: + return 1; + case _STORE_ATTR_SLOT: + return 0; case STORE_ATTR_SLOT: return 0; case COMPARE_OP: @@ -1386,6 +1396,8 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE] = { [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG }, [STORE_ATTR_INSTANCE_VALUE] = { true, INSTR_FMT_IXC000, HAS_DEOPT_FLAG }, [STORE_ATTR_WITH_HINT] = { true, INSTR_FMT_IBC000, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG }, + [_GUARD_TYPE_VERSION_STORE] = { true, INSTR_FMT_IXC0, HAS_DEOPT_FLAG }, + [_STORE_ATTR_SLOT] = { true, INSTR_FMT_IXC, 0 }, [STORE_ATTR_SLOT] = { true, INSTR_FMT_IXC000, HAS_DEOPT_FLAG }, [COMPARE_OP] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_ERROR_FLAG }, [COMPARE_OP_FLOAT] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG }, @@ -1608,6 +1620,7 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[OPCODE_MACRO_EXPAN [LOAD_ATTR] = { .nuops = 1, .uops = { { LOAD_ATTR, 0, 0 } } }, [LOAD_ATTR_INSTANCE_VALUE] = { .nuops = 3, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_MANAGED_OBJECT_HAS_VALUES, 0, 0 }, { _LOAD_ATTR_INSTANCE_VALUE, 1, 3 } } }, [LOAD_ATTR_SLOT] = { .nuops = 2, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_SLOT, 1, 3 } } }, + [STORE_ATTR_SLOT] = { .nuops = 2, .uops = { { _GUARD_TYPE_VERSION_STORE, 2, 1 }, { _STORE_ATTR_SLOT, 1, 3 } } }, [COMPARE_OP] = { .nuops = 1, .uops = { { COMPARE_OP, 0, 0 } } }, [COMPARE_OP_FLOAT] = { .nuops = 1, .uops = { { COMPARE_OP_FLOAT, 0, 0 } } }, [COMPARE_OP_INT] = { .nuops = 1, .uops = { { COMPARE_OP_INT, 0, 0 } } }, @@ -1680,6 +1693,8 @@ const char * const _PyOpcode_uop_name[OPCODE_UOP_NAME_SIZE] = { [_CHECK_MANAGED_OBJECT_HAS_VALUES] = "_CHECK_MANAGED_OBJECT_HAS_VALUES", [_LOAD_ATTR_INSTANCE_VALUE] = "_LOAD_ATTR_INSTANCE_VALUE", [_LOAD_ATTR_SLOT] = "_LOAD_ATTR_SLOT", + [_GUARD_TYPE_VERSION_STORE] = "_GUARD_TYPE_VERSION_STORE", + [_STORE_ATTR_SLOT] = "_STORE_ATTR_SLOT", [_IS_NONE] = "_IS_NONE", [_ITER_CHECK_LIST] = "_ITER_CHECK_LIST", [_ITER_JUMP_LIST] = "_ITER_JUMP_LIST", diff --git a/Python/abstract_interp_cases.c.h b/Python/abstract_interp_cases.c.h index 47118c84e2d85f..ef1cc5edeea240 100644 --- a/Python/abstract_interp_cases.c.h +++ b/Python/abstract_interp_cases.c.h @@ -481,6 +481,15 @@ break; } + case _GUARD_TYPE_VERSION_STORE: { + break; + } + + case _STORE_ATTR_SLOT: { + STACK_SHRINK(2); + break; + } + case COMPARE_OP: { STACK_SHRINK(1); PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true); diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 6b6e595cb656e9..afc095c4e72647 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2083,10 +2083,13 @@ dummy_func( Py_DECREF(owner); } - inst(STORE_ATTR_SLOT, (unused/1, type_version/2, index/1, value, owner --)) { + op(_GUARD_TYPE_VERSION_STORE, (type_version/2, owner -- owner)) { PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); + } + + op(_STORE_ATTR_SLOT, (index/1, value, owner --)) { char *addr = (char *)owner + index; STAT_INC(STORE_ATTR, hit); PyObject *old_value = *(PyObject **)addr; @@ -2095,6 +2098,11 @@ dummy_func( Py_DECREF(owner); } + macro(STORE_ATTR_SLOT) = + unused/1 + + _GUARD_TYPE_VERSION_STORE + + _STORE_ATTR_SLOT; + family(COMPARE_OP, INLINE_CACHE_ENTRIES_COMPARE_OP) = { COMPARE_OP_FLOAT, COMPARE_OP_INT, diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index bd56a6d2cab803..d7eb215557d022 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -1733,6 +1733,32 @@ break; } + case _GUARD_TYPE_VERSION_STORE: { + PyObject *owner; + owner = stack_pointer[-1]; + uint32_t type_version = (uint32_t)operand; + PyTypeObject *tp = Py_TYPE(owner); + assert(type_version != 0); + DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); + break; + } + + case _STORE_ATTR_SLOT: { + PyObject *owner; + PyObject *value; + owner = stack_pointer[-1]; + value = stack_pointer[-2]; + uint16_t index = (uint16_t)operand; + char *addr = (char *)owner + index; + STAT_INC(STORE_ATTR, hit); + PyObject *old_value = *(PyObject **)addr; + *(PyObject **)addr = value; + Py_XDECREF(old_value); + Py_DECREF(owner); + STACK_SHRINK(2); + break; + } + case COMPARE_OP: { PyObject *right; PyObject *left; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 826ada8933b1a4..9b8d6234515dce 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2700,19 +2700,25 @@ TARGET(STORE_ATTR_SLOT) { PyObject *owner; PyObject *value; + // _GUARD_TYPE_VERSION_STORE owner = stack_pointer[-1]; + { + uint32_t type_version = read_u32(&next_instr[1].cache); + PyTypeObject *tp = Py_TYPE(owner); + assert(type_version != 0); + DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); + } + // _STORE_ATTR_SLOT value = stack_pointer[-2]; - uint32_t type_version = read_u32(&next_instr[1].cache); - uint16_t index = read_u16(&next_instr[3].cache); - PyTypeObject *tp = Py_TYPE(owner); - assert(type_version != 0); - DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); - char *addr = (char *)owner + index; - STAT_INC(STORE_ATTR, hit); - PyObject *old_value = *(PyObject **)addr; - *(PyObject **)addr = value; - Py_XDECREF(old_value); - Py_DECREF(owner); + { + uint16_t index = read_u16(&next_instr[3].cache); + char *addr = (char *)owner + index; + STAT_INC(STORE_ATTR, hit); + PyObject *old_value = *(PyObject **)addr; + *(PyObject **)addr = value; + Py_XDECREF(old_value); + Py_DECREF(owner); + } STACK_SHRINK(2); next_instr += 4; DISPATCH(); From b54eee3d757832ae5c5a3093e487600f1019ced4 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 26 Sep 2023 20:57:32 -0700 Subject: [PATCH 8/9] Split STORE_ATTR_INSTANCE_VALUE --- Include/internal/pycore_opcode_metadata.h | 75 ++++++++++++++--------- Python/abstract_interp_cases.c.h | 9 +++ Python/bytecodes.c | 14 ++++- Python/executor_cases.c.h | 32 ++++++++++ Python/generated_cases.c.h | 47 ++++++++------ 5 files changed, 126 insertions(+), 51 deletions(-) diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index a2edc95f300634..e661f968920080 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -47,36 +47,38 @@ #define _CHECK_MANAGED_OBJECT_HAS_VALUES 319 #define _LOAD_ATTR_INSTANCE_VALUE 320 #define _LOAD_ATTR_SLOT 321 -#define _GUARD_TYPE_VERSION_STORE 322 -#define _STORE_ATTR_SLOT 323 -#define _IS_NONE 324 -#define _ITER_CHECK_LIST 325 -#define _ITER_JUMP_LIST 326 -#define _IS_ITER_EXHAUSTED_LIST 327 -#define _ITER_NEXT_LIST 328 -#define _ITER_CHECK_TUPLE 329 -#define _ITER_JUMP_TUPLE 330 -#define _IS_ITER_EXHAUSTED_TUPLE 331 -#define _ITER_NEXT_TUPLE 332 -#define _ITER_CHECK_RANGE 333 -#define _ITER_JUMP_RANGE 334 -#define _IS_ITER_EXHAUSTED_RANGE 335 -#define _ITER_NEXT_RANGE 336 -#define _GUARD_KEYS_VERSION 337 -#define _LOAD_ATTR_METHOD_WITH_VALUES 338 -#define _LOAD_ATTR_METHOD_NO_DICT 339 -#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS 340 -#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 341 -#define _CHECK_PEP_523 342 -#define _CHECK_FUNCTION_EXACT_ARGS 343 -#define _CHECK_STACK_SPACE 344 -#define _INIT_CALL_PY_EXACT_ARGS 345 -#define _PUSH_FRAME 346 -#define _POP_JUMP_IF_FALSE 347 -#define _POP_JUMP_IF_TRUE 348 -#define _JUMP_TO_TOP 349 -#define _SAVE_CURRENT_IP 350 -#define _INSERT 351 +#define _GUARD_DORV_VALUES 322 +#define _STORE_ATTR_INSTANCE_VALUE 323 +#define _GUARD_TYPE_VERSION_STORE 324 +#define _STORE_ATTR_SLOT 325 +#define _IS_NONE 326 +#define _ITER_CHECK_LIST 327 +#define _ITER_JUMP_LIST 328 +#define _IS_ITER_EXHAUSTED_LIST 329 +#define _ITER_NEXT_LIST 330 +#define _ITER_CHECK_TUPLE 331 +#define _ITER_JUMP_TUPLE 332 +#define _IS_ITER_EXHAUSTED_TUPLE 333 +#define _ITER_NEXT_TUPLE 334 +#define _ITER_CHECK_RANGE 335 +#define _ITER_JUMP_RANGE 336 +#define _IS_ITER_EXHAUSTED_RANGE 337 +#define _ITER_NEXT_RANGE 338 +#define _GUARD_KEYS_VERSION 339 +#define _LOAD_ATTR_METHOD_WITH_VALUES 340 +#define _LOAD_ATTR_METHOD_NO_DICT 341 +#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS 342 +#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 343 +#define _CHECK_PEP_523 344 +#define _CHECK_FUNCTION_EXACT_ARGS 345 +#define _CHECK_STACK_SPACE 346 +#define _INIT_CALL_PY_EXACT_ARGS 347 +#define _PUSH_FRAME 348 +#define _POP_JUMP_IF_FALSE 349 +#define _POP_JUMP_IF_TRUE 350 +#define _JUMP_TO_TOP 351 +#define _SAVE_CURRENT_IP 352 +#define _INSERT 353 extern int _PyOpcode_num_popped(int opcode, int oparg, bool jump); #ifdef NEED_OPCODE_METADATA @@ -372,6 +374,10 @@ int _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return 1; case LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN: return 1; + case _GUARD_DORV_VALUES: + return 1; + case _STORE_ATTR_INSTANCE_VALUE: + return 2; case STORE_ATTR_INSTANCE_VALUE: return 2; case STORE_ATTR_WITH_HINT: @@ -924,6 +930,10 @@ int _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return 1; case LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN: return 1; + case _GUARD_DORV_VALUES: + return 1; + case _STORE_ATTR_INSTANCE_VALUE: + return 0; case STORE_ATTR_INSTANCE_VALUE: return 0; case STORE_ATTR_WITH_HINT: @@ -1394,6 +1404,8 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE] = { [LOAD_ATTR_CLASS] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG }, [LOAD_ATTR_PROPERTY] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG }, [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG }, + [_GUARD_DORV_VALUES] = { true, INSTR_FMT_IX, HAS_DEOPT_FLAG }, + [_STORE_ATTR_INSTANCE_VALUE] = { true, INSTR_FMT_IXC, 0 }, [STORE_ATTR_INSTANCE_VALUE] = { true, INSTR_FMT_IXC000, HAS_DEOPT_FLAG }, [STORE_ATTR_WITH_HINT] = { true, INSTR_FMT_IBC000, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG }, [_GUARD_TYPE_VERSION_STORE] = { true, INSTR_FMT_IXC0, HAS_DEOPT_FLAG }, @@ -1620,6 +1632,7 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[OPCODE_MACRO_EXPAN [LOAD_ATTR] = { .nuops = 1, .uops = { { LOAD_ATTR, 0, 0 } } }, [LOAD_ATTR_INSTANCE_VALUE] = { .nuops = 3, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_MANAGED_OBJECT_HAS_VALUES, 0, 0 }, { _LOAD_ATTR_INSTANCE_VALUE, 1, 3 } } }, [LOAD_ATTR_SLOT] = { .nuops = 2, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_SLOT, 1, 3 } } }, + [STORE_ATTR_INSTANCE_VALUE] = { .nuops = 3, .uops = { { _GUARD_TYPE_VERSION_STORE, 2, 1 }, { _GUARD_DORV_VALUES, 0, 0 }, { _STORE_ATTR_INSTANCE_VALUE, 1, 3 } } }, [STORE_ATTR_SLOT] = { .nuops = 2, .uops = { { _GUARD_TYPE_VERSION_STORE, 2, 1 }, { _STORE_ATTR_SLOT, 1, 3 } } }, [COMPARE_OP] = { .nuops = 1, .uops = { { COMPARE_OP, 0, 0 } } }, [COMPARE_OP_FLOAT] = { .nuops = 1, .uops = { { COMPARE_OP_FLOAT, 0, 0 } } }, @@ -1693,6 +1706,8 @@ const char * const _PyOpcode_uop_name[OPCODE_UOP_NAME_SIZE] = { [_CHECK_MANAGED_OBJECT_HAS_VALUES] = "_CHECK_MANAGED_OBJECT_HAS_VALUES", [_LOAD_ATTR_INSTANCE_VALUE] = "_LOAD_ATTR_INSTANCE_VALUE", [_LOAD_ATTR_SLOT] = "_LOAD_ATTR_SLOT", + [_GUARD_DORV_VALUES] = "_GUARD_DORV_VALUES", + [_STORE_ATTR_INSTANCE_VALUE] = "_STORE_ATTR_INSTANCE_VALUE", [_GUARD_TYPE_VERSION_STORE] = "_GUARD_TYPE_VERSION_STORE", [_STORE_ATTR_SLOT] = "_STORE_ATTR_SLOT", [_IS_NONE] = "_IS_NONE", diff --git a/Python/abstract_interp_cases.c.h b/Python/abstract_interp_cases.c.h index ef1cc5edeea240..a810881a756c63 100644 --- a/Python/abstract_interp_cases.c.h +++ b/Python/abstract_interp_cases.c.h @@ -481,6 +481,15 @@ break; } + case _GUARD_DORV_VALUES: { + break; + } + + case _STORE_ATTR_INSTANCE_VALUE: { + STACK_SHRINK(2); + break; + } + case _GUARD_TYPE_VERSION_STORE: { break; } diff --git a/Python/bytecodes.c b/Python/bytecodes.c index afc095c4e72647..36d81fefc9bfe0 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2022,13 +2022,15 @@ dummy_func( DISPATCH_INLINED(new_frame); } - inst(STORE_ATTR_INSTANCE_VALUE, (unused/1, type_version/2, index/1, value, owner --)) { + op(_GUARD_DORV_VALUES, (owner -- owner)) { PyTypeObject *tp = Py_TYPE(owner); - assert(type_version != 0); - DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT); PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); DEOPT_IF(!_PyDictOrValues_IsValues(dorv), STORE_ATTR); + } + + op(_STORE_ATTR_INSTANCE_VALUE, (index/1, value, owner --)) { + PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); STAT_INC(STORE_ATTR, hit); PyDictValues *values = _PyDictOrValues_GetValues(dorv); PyObject *old_value = values->values[index]; @@ -2042,6 +2044,12 @@ dummy_func( Py_DECREF(owner); } + macro(STORE_ATTR_INSTANCE_VALUE) = + unused/1 + + _GUARD_TYPE_VERSION_STORE + + _GUARD_DORV_VALUES + + _STORE_ATTR_INSTANCE_VALUE; + inst(STORE_ATTR_WITH_HINT, (unused/1, type_version/2, hint/1, value, owner --)) { PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index d7eb215557d022..78eb70877b53d3 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -1733,6 +1733,38 @@ break; } + case _GUARD_DORV_VALUES: { + PyObject *owner; + owner = stack_pointer[-1]; + PyTypeObject *tp = Py_TYPE(owner); + assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT); + PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); + DEOPT_IF(!_PyDictOrValues_IsValues(dorv), STORE_ATTR); + break; + } + + case _STORE_ATTR_INSTANCE_VALUE: { + PyObject *owner; + PyObject *value; + owner = stack_pointer[-1]; + value = stack_pointer[-2]; + uint16_t index = (uint16_t)operand; + PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); + STAT_INC(STORE_ATTR, hit); + PyDictValues *values = _PyDictOrValues_GetValues(dorv); + PyObject *old_value = values->values[index]; + values->values[index] = value; + if (old_value == NULL) { + _PyDictValues_AddToInsertionOrder(values, index); + } + else { + Py_DECREF(old_value); + } + Py_DECREF(owner); + STACK_SHRINK(2); + break; + } + case _GUARD_TYPE_VERSION_STORE: { PyObject *owner; owner = stack_pointer[-1]; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 9b8d6234515dce..7b73b97b514987 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2621,27 +2621,38 @@ TARGET(STORE_ATTR_INSTANCE_VALUE) { PyObject *owner; PyObject *value; + // _GUARD_TYPE_VERSION_STORE owner = stack_pointer[-1]; - value = stack_pointer[-2]; - uint32_t type_version = read_u32(&next_instr[1].cache); - uint16_t index = read_u16(&next_instr[3].cache); - PyTypeObject *tp = Py_TYPE(owner); - assert(type_version != 0); - DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); - assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT); - PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); - DEOPT_IF(!_PyDictOrValues_IsValues(dorv), STORE_ATTR); - STAT_INC(STORE_ATTR, hit); - PyDictValues *values = _PyDictOrValues_GetValues(dorv); - PyObject *old_value = values->values[index]; - values->values[index] = value; - if (old_value == NULL) { - _PyDictValues_AddToInsertionOrder(values, index); + { + uint32_t type_version = read_u32(&next_instr[1].cache); + PyTypeObject *tp = Py_TYPE(owner); + assert(type_version != 0); + DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); } - else { - Py_DECREF(old_value); + // _GUARD_DORV_VALUES + { + PyTypeObject *tp = Py_TYPE(owner); + assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT); + PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); + DEOPT_IF(!_PyDictOrValues_IsValues(dorv), STORE_ATTR); + } + // _STORE_ATTR_INSTANCE_VALUE + value = stack_pointer[-2]; + { + uint16_t index = read_u16(&next_instr[3].cache); + PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); + STAT_INC(STORE_ATTR, hit); + PyDictValues *values = _PyDictOrValues_GetValues(dorv); + PyObject *old_value = values->values[index]; + values->values[index] = value; + if (old_value == NULL) { + _PyDictValues_AddToInsertionOrder(values, index); + } + else { + Py_DECREF(old_value); + } + Py_DECREF(owner); } - Py_DECREF(owner); STACK_SHRINK(2); next_instr += 4; DISPATCH(); From 85fb1e72177d21e22214793561c1c922cdfa5258 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Wed, 27 Sep 2023 13:58:04 -0700 Subject: [PATCH 9/9] Fix LOAD_ATTR_METHOD_WITH_VALUES I had dropped one of the DEOPT_IF() calls! :-( --- Include/internal/pycore_opcode_metadata.h | 39 +++++++++++++---------- Python/abstract_interp_cases.c.h | 4 +++ Python/bytecodes.c | 10 ++++++ Python/executor_cases.c.h | 12 +++++++ Python/generated_cases.c.h | 9 ++++++ 5 files changed, 58 insertions(+), 16 deletions(-) diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index e661f968920080..16c1637e496033 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -64,21 +64,22 @@ #define _ITER_JUMP_RANGE 336 #define _IS_ITER_EXHAUSTED_RANGE 337 #define _ITER_NEXT_RANGE 338 -#define _GUARD_KEYS_VERSION 339 -#define _LOAD_ATTR_METHOD_WITH_VALUES 340 -#define _LOAD_ATTR_METHOD_NO_DICT 341 -#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS 342 -#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 343 -#define _CHECK_PEP_523 344 -#define _CHECK_FUNCTION_EXACT_ARGS 345 -#define _CHECK_STACK_SPACE 346 -#define _INIT_CALL_PY_EXACT_ARGS 347 -#define _PUSH_FRAME 348 -#define _POP_JUMP_IF_FALSE 349 -#define _POP_JUMP_IF_TRUE 350 -#define _JUMP_TO_TOP 351 -#define _SAVE_CURRENT_IP 352 -#define _INSERT 353 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT 339 +#define _GUARD_KEYS_VERSION 340 +#define _LOAD_ATTR_METHOD_WITH_VALUES 341 +#define _LOAD_ATTR_METHOD_NO_DICT 342 +#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS 343 +#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 344 +#define _CHECK_PEP_523 345 +#define _CHECK_FUNCTION_EXACT_ARGS 346 +#define _CHECK_STACK_SPACE 347 +#define _INIT_CALL_PY_EXACT_ARGS 348 +#define _PUSH_FRAME 349 +#define _POP_JUMP_IF_FALSE 350 +#define _POP_JUMP_IF_TRUE 351 +#define _JUMP_TO_TOP 352 +#define _SAVE_CURRENT_IP 353 +#define _INSERT 354 extern int _PyOpcode_num_popped(int opcode, int oparg, bool jump); #ifdef NEED_OPCODE_METADATA @@ -496,6 +497,8 @@ int _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return 0; case PUSH_EXC_INFO: return 1; + case _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT: + return 1; case _GUARD_KEYS_VERSION: return 1; case _LOAD_ATTR_METHOD_WITH_VALUES: @@ -1052,6 +1055,8 @@ int _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return 0; case PUSH_EXC_INFO: return 2; + case _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT: + return 1; case _GUARD_KEYS_VERSION: return 1; case _LOAD_ATTR_METHOD_WITH_VALUES: @@ -1465,6 +1470,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE] = { [SETUP_WITH] = { true, INSTR_FMT_IX, 0 }, [POP_BLOCK] = { true, INSTR_FMT_IX, 0 }, [PUSH_EXC_INFO] = { true, INSTR_FMT_IX, 0 }, + [_GUARD_DORV_VALUES_INST_ATTR_FROM_DICT] = { true, INSTR_FMT_IX, HAS_DEOPT_FLAG }, [_GUARD_KEYS_VERSION] = { true, INSTR_FMT_IXC0, HAS_DEOPT_FLAG }, [_LOAD_ATTR_METHOD_WITH_VALUES] = { true, INSTR_FMT_IBC000, HAS_ARG_FLAG }, [LOAD_ATTR_METHOD_WITH_VALUES] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG }, @@ -1651,7 +1657,7 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[OPCODE_MACRO_EXPAN [GET_YIELD_FROM_ITER] = { .nuops = 1, .uops = { { GET_YIELD_FROM_ITER, 0, 0 } } }, [WITH_EXCEPT_START] = { .nuops = 1, .uops = { { WITH_EXCEPT_START, 0, 0 } } }, [PUSH_EXC_INFO] = { .nuops = 1, .uops = { { PUSH_EXC_INFO, 0, 0 } } }, - [LOAD_ATTR_METHOD_WITH_VALUES] = { .nuops = 3, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _GUARD_KEYS_VERSION, 2, 3 }, { _LOAD_ATTR_METHOD_WITH_VALUES, 4, 5 } } }, + [LOAD_ATTR_METHOD_WITH_VALUES] = { .nuops = 4, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT, 0, 0 }, { _GUARD_KEYS_VERSION, 2, 3 }, { _LOAD_ATTR_METHOD_WITH_VALUES, 4, 5 } } }, [LOAD_ATTR_METHOD_NO_DICT] = { .nuops = 2, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_METHOD_NO_DICT, 4, 5 } } }, [CALL_BOUND_METHOD_EXACT_ARGS] = { .nuops = 9, .uops = { { _CHECK_PEP_523, 0, 0 }, { _CHECK_CALL_BOUND_METHOD_EXACT_ARGS, 0, 0 }, { _INIT_CALL_BOUND_METHOD_EXACT_ARGS, 0, 0 }, { _CHECK_FUNCTION_EXACT_ARGS, 2, 1 }, { _CHECK_STACK_SPACE, 0, 0 }, { _INIT_CALL_PY_EXACT_ARGS, 0, 0 }, { _SET_IP, 7, 3 }, { _SAVE_CURRENT_IP, 0, 0 }, { _PUSH_FRAME, 0, 0 } } }, [CALL_PY_EXACT_ARGS] = { .nuops = 7, .uops = { { _CHECK_PEP_523, 0, 0 }, { _CHECK_FUNCTION_EXACT_ARGS, 2, 1 }, { _CHECK_STACK_SPACE, 0, 0 }, { _INIT_CALL_PY_EXACT_ARGS, 0, 0 }, { _SET_IP, 7, 3 }, { _SAVE_CURRENT_IP, 0, 0 }, { _PUSH_FRAME, 0, 0 } } }, @@ -1723,6 +1729,7 @@ const char * const _PyOpcode_uop_name[OPCODE_UOP_NAME_SIZE] = { [_ITER_JUMP_RANGE] = "_ITER_JUMP_RANGE", [_IS_ITER_EXHAUSTED_RANGE] = "_IS_ITER_EXHAUSTED_RANGE", [_ITER_NEXT_RANGE] = "_ITER_NEXT_RANGE", + [_GUARD_DORV_VALUES_INST_ATTR_FROM_DICT] = "_GUARD_DORV_VALUES_INST_ATTR_FROM_DICT", [_GUARD_KEYS_VERSION] = "_GUARD_KEYS_VERSION", [_LOAD_ATTR_METHOD_WITH_VALUES] = "_LOAD_ATTR_METHOD_WITH_VALUES", [_LOAD_ATTR_METHOD_NO_DICT] = "_LOAD_ATTR_METHOD_NO_DICT", diff --git a/Python/abstract_interp_cases.c.h b/Python/abstract_interp_cases.c.h index a810881a756c63..61b1db9e5a1543 100644 --- a/Python/abstract_interp_cases.c.h +++ b/Python/abstract_interp_cases.c.h @@ -652,6 +652,10 @@ break; } + case _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT: { + break; + } + case _GUARD_KEYS_VERSION: { break; } diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 36d81fefc9bfe0..0f89779fb9245f 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2788,6 +2788,15 @@ dummy_func( exc_info->exc_value = Py_NewRef(new_exc); } + op(_GUARD_DORV_VALUES_INST_ATTR_FROM_DICT, (owner -- owner)) { + PyTypeObject *owner_cls = Py_TYPE(owner); + assert(owner_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT); + PyDictOrValues *dorv = _PyObject_DictOrValuesPointer(owner); + DEOPT_IF(!_PyDictOrValues_IsValues(*dorv) && + !_PyObject_MakeInstanceAttributesFromDict(owner, dorv), + LOAD_ATTR); + } + op(_GUARD_KEYS_VERSION, (keys_version/2, owner -- owner)) { PyTypeObject *owner_cls = Py_TYPE(owner); PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls; @@ -2808,6 +2817,7 @@ dummy_func( macro(LOAD_ATTR_METHOD_WITH_VALUES) = unused/1 + _GUARD_TYPE_VERSION + + _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT + _GUARD_KEYS_VERSION + _LOAD_ATTR_METHOD_WITH_VALUES; diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 78eb70877b53d3..981db6973f281a 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -2296,6 +2296,18 @@ break; } + case _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT: { + PyObject *owner; + owner = stack_pointer[-1]; + PyTypeObject *owner_cls = Py_TYPE(owner); + assert(owner_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT); + PyDictOrValues *dorv = _PyObject_DictOrValuesPointer(owner); + DEOPT_IF(!_PyDictOrValues_IsValues(*dorv) && + !_PyObject_MakeInstanceAttributesFromDict(owner, dorv), + LOAD_ATTR); + break; + } + case _GUARD_KEYS_VERSION: { PyObject *owner; owner = stack_pointer[-1]; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 7b73b97b514987..17df44019a6581 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -3588,6 +3588,15 @@ assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); } + // _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT + { + PyTypeObject *owner_cls = Py_TYPE(owner); + assert(owner_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT); + PyDictOrValues *dorv = _PyObject_DictOrValuesPointer(owner); + DEOPT_IF(!_PyDictOrValues_IsValues(*dorv) && + !_PyObject_MakeInstanceAttributesFromDict(owner, dorv), + LOAD_ATTR); + } // _GUARD_KEYS_VERSION { uint32_t keys_version = read_u32(&next_instr[3].cache); pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy