2025-09-18 13:33:07 +01:00
|
|
|
#if !_Py_TAIL_CALL_INTERP
|
2025-09-18 21:12:07 +08:00
|
|
|
static void *opcode_targets_table[256] = {
|
2022-03-07 11:45:00 -08:00
|
|
|
&&TARGET_CACHE,
|
2023-08-16 23:25:18 +01:00
|
|
|
&&TARGET_BINARY_SLICE,
|
2025-04-30 11:46:41 +02:00
|
|
|
&&TARGET_BUILD_TEMPLATE,
|
2025-02-07 22:39:54 +00:00
|
|
|
&&TARGET_BINARY_OP_INPLACE_ADD_UNICODE,
|
2025-04-30 11:46:41 +02:00
|
|
|
&&TARGET_CALL_FUNCTION_EX,
|
2023-08-16 23:25:18 +01:00
|
|
|
&&TARGET_CHECK_EG_MATCH,
|
|
|
|
|
&&TARGET_CHECK_EXC_MATCH,
|
2022-08-19 12:33:44 -07:00
|
|
|
&&TARGET_CLEANUP_THROW,
|
2023-06-29 13:49:54 -07:00
|
|
|
&&TARGET_DELETE_SUBSCR,
|
2023-08-16 23:25:18 +01:00
|
|
|
&&TARGET_END_FOR,
|
|
|
|
|
&&TARGET_END_SEND,
|
|
|
|
|
&&TARGET_EXIT_INIT_CHECK,
|
|
|
|
|
&&TARGET_FORMAT_SIMPLE,
|
|
|
|
|
&&TARGET_FORMAT_WITH_SPEC,
|
|
|
|
|
&&TARGET_GET_AITER,
|
|
|
|
|
&&TARGET_GET_ANEXT,
|
2025-01-27 16:24:48 +00:00
|
|
|
&&TARGET_GET_ITER,
|
2025-03-07 14:30:31 +00:00
|
|
|
&&TARGET_RESERVED,
|
2025-04-30 11:46:41 +02:00
|
|
|
&&TARGET_GET_LEN,
|
2023-06-29 13:49:54 -07:00
|
|
|
&&TARGET_GET_YIELD_FROM_ITER,
|
2023-08-16 23:25:18 +01:00
|
|
|
&&TARGET_INTERPRETER_EXIT,
|
|
|
|
|
&&TARGET_LOAD_BUILD_CLASS,
|
|
|
|
|
&&TARGET_LOAD_LOCALS,
|
|
|
|
|
&&TARGET_MAKE_FUNCTION,
|
|
|
|
|
&&TARGET_MATCH_KEYS,
|
|
|
|
|
&&TARGET_MATCH_MAPPING,
|
|
|
|
|
&&TARGET_MATCH_SEQUENCE,
|
|
|
|
|
&&TARGET_NOP,
|
2024-12-19 16:59:51 +00:00
|
|
|
&&TARGET_NOT_TAKEN,
|
2023-08-16 23:25:18 +01:00
|
|
|
&&TARGET_POP_EXCEPT,
|
2025-01-06 17:54:47 +00:00
|
|
|
&&TARGET_POP_ITER,
|
2023-08-16 23:25:18 +01:00
|
|
|
&&TARGET_POP_TOP,
|
|
|
|
|
&&TARGET_PUSH_EXC_INFO,
|
|
|
|
|
&&TARGET_PUSH_NULL,
|
2023-06-29 13:49:54 -07:00
|
|
|
&&TARGET_RETURN_GENERATOR,
|
2023-04-12 12:04:55 +01:00
|
|
|
&&TARGET_RETURN_VALUE,
|
|
|
|
|
&&TARGET_SETUP_ANNOTATIONS,
|
2023-08-16 23:25:18 +01:00
|
|
|
&&TARGET_STORE_SLICE,
|
|
|
|
|
&&TARGET_STORE_SUBSCR,
|
|
|
|
|
&&TARGET_TO_BOOL,
|
|
|
|
|
&&TARGET_UNARY_INVERT,
|
|
|
|
|
&&TARGET_UNARY_NEGATIVE,
|
|
|
|
|
&&TARGET_UNARY_NOT,
|
|
|
|
|
&&TARGET_WITH_EXCEPT_START,
|
|
|
|
|
&&TARGET_BINARY_OP,
|
2025-04-30 11:46:41 +02:00
|
|
|
&&TARGET_BUILD_INTERPOLATION,
|
2010-05-09 15:52:27 +00:00
|
|
|
&&TARGET_BUILD_LIST,
|
|
|
|
|
&&TARGET_BUILD_MAP,
|
2023-08-16 23:25:18 +01:00
|
|
|
&&TARGET_BUILD_SET,
|
|
|
|
|
&&TARGET_BUILD_SLICE,
|
|
|
|
|
&&TARGET_BUILD_STRING,
|
|
|
|
|
&&TARGET_BUILD_TUPLE,
|
|
|
|
|
&&TARGET_CALL,
|
|
|
|
|
&&TARGET_CALL_INTRINSIC_1,
|
|
|
|
|
&&TARGET_CALL_INTRINSIC_2,
|
2023-09-13 10:25:45 -07:00
|
|
|
&&TARGET_CALL_KW,
|
2010-05-09 15:52:27 +00:00
|
|
|
&&TARGET_COMPARE_OP,
|
2020-01-14 10:12:45 +00:00
|
|
|
&&TARGET_CONTAINS_OP,
|
2023-08-16 23:25:18 +01:00
|
|
|
&&TARGET_CONVERT_VALUE,
|
2021-10-27 02:45:35 -07:00
|
|
|
&&TARGET_COPY,
|
2023-08-16 23:25:18 +01:00
|
|
|
&&TARGET_COPY_FREE_VARS,
|
|
|
|
|
&&TARGET_DELETE_ATTR,
|
|
|
|
|
&&TARGET_DELETE_DEREF,
|
2010-05-09 15:52:27 +00:00
|
|
|
&&TARGET_DELETE_FAST,
|
2023-08-16 23:25:18 +01:00
|
|
|
&&TARGET_DELETE_GLOBAL,
|
|
|
|
|
&&TARGET_DELETE_NAME,
|
|
|
|
|
&&TARGET_DICT_MERGE,
|
|
|
|
|
&&TARGET_DICT_UPDATE,
|
2025-03-07 14:30:31 +00:00
|
|
|
&&TARGET_END_ASYNC_FOR,
|
2023-08-16 23:25:18 +01:00
|
|
|
&&TARGET_EXTENDED_ARG,
|
|
|
|
|
&&TARGET_FOR_ITER,
|
|
|
|
|
&&TARGET_GET_AWAITABLE,
|
|
|
|
|
&&TARGET_IMPORT_FROM,
|
|
|
|
|
&&TARGET_IMPORT_NAME,
|
|
|
|
|
&&TARGET_IS_OP,
|
|
|
|
|
&&TARGET_JUMP_BACKWARD,
|
2022-04-05 12:49:08 +01:00
|
|
|
&&TARGET_JUMP_BACKWARD_NO_INTERRUPT,
|
2023-08-16 23:25:18 +01:00
|
|
|
&&TARGET_JUMP_FORWARD,
|
|
|
|
|
&&TARGET_LIST_APPEND,
|
|
|
|
|
&&TARGET_LIST_EXTEND,
|
|
|
|
|
&&TARGET_LOAD_ATTR,
|
2024-05-21 20:46:39 -04:00
|
|
|
&&TARGET_LOAD_COMMON_CONSTANT,
|
2023-08-16 23:25:18 +01:00
|
|
|
&&TARGET_LOAD_CONST,
|
2010-05-09 15:52:27 +00:00
|
|
|
&&TARGET_LOAD_DEREF,
|
2023-08-16 23:25:18 +01:00
|
|
|
&&TARGET_LOAD_FAST,
|
2023-05-09 11:02:14 -06:00
|
|
|
&&TARGET_LOAD_FAST_AND_CLEAR,
|
2025-04-01 10:18:42 -07:00
|
|
|
&&TARGET_LOAD_FAST_BORROW,
|
|
|
|
|
&&TARGET_LOAD_FAST_BORROW_LOAD_FAST_BORROW,
|
2023-08-16 23:25:18 +01:00
|
|
|
&&TARGET_LOAD_FAST_CHECK,
|
|
|
|
|
&&TARGET_LOAD_FAST_LOAD_FAST,
|
|
|
|
|
&&TARGET_LOAD_FROM_DICT_OR_DEREF,
|
|
|
|
|
&&TARGET_LOAD_FROM_DICT_OR_GLOBALS,
|
|
|
|
|
&&TARGET_LOAD_GLOBAL,
|
|
|
|
|
&&TARGET_LOAD_NAME,
|
2024-10-29 11:15:42 +00:00
|
|
|
&&TARGET_LOAD_SMALL_INT,
|
2024-06-18 12:17:46 +01:00
|
|
|
&&TARGET_LOAD_SPECIAL,
|
2023-08-16 23:25:18 +01:00
|
|
|
&&TARGET_LOAD_SUPER_ATTR,
|
|
|
|
|
&&TARGET_MAKE_CELL,
|
2010-05-09 15:52:27 +00:00
|
|
|
&&TARGET_MAP_ADD,
|
2021-02-26 14:51:55 -08:00
|
|
|
&&TARGET_MATCH_CLASS,
|
2023-08-16 23:25:18 +01:00
|
|
|
&&TARGET_POP_JUMP_IF_FALSE,
|
|
|
|
|
&&TARGET_POP_JUMP_IF_NONE,
|
|
|
|
|
&&TARGET_POP_JUMP_IF_NOT_NONE,
|
|
|
|
|
&&TARGET_POP_JUMP_IF_TRUE,
|
|
|
|
|
&&TARGET_RAISE_VARARGS,
|
2023-09-07 14:39:03 +01:00
|
|
|
&&TARGET_RERAISE,
|
2023-08-16 23:25:18 +01:00
|
|
|
&&TARGET_SEND,
|
|
|
|
|
&&TARGET_SET_ADD,
|
|
|
|
|
&&TARGET_SET_FUNCTION_ATTRIBUTE,
|
2022-11-09 10:50:09 -08:00
|
|
|
&&TARGET_SET_UPDATE,
|
2023-08-16 23:25:18 +01:00
|
|
|
&&TARGET_STORE_ATTR,
|
|
|
|
|
&&TARGET_STORE_DEREF,
|
|
|
|
|
&&TARGET_STORE_FAST,
|
2023-06-05 11:07:04 +01:00
|
|
|
&&TARGET_STORE_FAST_LOAD_FAST,
|
|
|
|
|
&&TARGET_STORE_FAST_STORE_FAST,
|
2023-08-16 23:25:18 +01:00
|
|
|
&&TARGET_STORE_GLOBAL,
|
|
|
|
|
&&TARGET_STORE_NAME,
|
|
|
|
|
&&TARGET_SWAP,
|
|
|
|
|
&&TARGET_UNPACK_EX,
|
|
|
|
|
&&TARGET_UNPACK_SEQUENCE,
|
2023-11-03 10:01:36 +00:00
|
|
|
&&TARGET_YIELD_VALUE,
|
2024-10-07 14:56:39 +01:00
|
|
|
&&_unknown_opcode,
|
2010-05-09 15:52:27 +00:00
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
2023-09-12 11:36:17 +01:00
|
|
|
&&TARGET_RESUME,
|
|
|
|
|
&&TARGET_BINARY_OP_ADD_FLOAT,
|
|
|
|
|
&&TARGET_BINARY_OP_ADD_INT,
|
|
|
|
|
&&TARGET_BINARY_OP_ADD_UNICODE,
|
2025-01-16 15:22:13 +00:00
|
|
|
&&TARGET_BINARY_OP_EXTEND,
|
2023-09-12 11:36:17 +01:00
|
|
|
&&TARGET_BINARY_OP_MULTIPLY_FLOAT,
|
|
|
|
|
&&TARGET_BINARY_OP_MULTIPLY_INT,
|
2025-02-07 22:39:54 +00:00
|
|
|
&&TARGET_BINARY_OP_SUBSCR_DICT,
|
|
|
|
|
&&TARGET_BINARY_OP_SUBSCR_GETITEM,
|
|
|
|
|
&&TARGET_BINARY_OP_SUBSCR_LIST_INT,
|
2025-05-01 11:28:52 +01:00
|
|
|
&&TARGET_BINARY_OP_SUBSCR_LIST_SLICE,
|
2025-02-07 22:39:54 +00:00
|
|
|
&&TARGET_BINARY_OP_SUBSCR_STR_INT,
|
|
|
|
|
&&TARGET_BINARY_OP_SUBSCR_TUPLE_INT,
|
2023-09-12 11:36:17 +01:00
|
|
|
&&TARGET_BINARY_OP_SUBTRACT_FLOAT,
|
|
|
|
|
&&TARGET_BINARY_OP_SUBTRACT_INT,
|
2023-09-13 10:25:45 -07:00
|
|
|
&&TARGET_CALL_ALLOC_AND_ENTER_INIT,
|
2023-09-12 11:36:17 +01:00
|
|
|
&&TARGET_CALL_BOUND_METHOD_EXACT_ARGS,
|
2024-05-04 12:11:11 +01:00
|
|
|
&&TARGET_CALL_BOUND_METHOD_GENERAL,
|
2023-09-12 11:36:17 +01:00
|
|
|
&&TARGET_CALL_BUILTIN_CLASS,
|
2023-09-13 10:25:45 -07:00
|
|
|
&&TARGET_CALL_BUILTIN_FAST,
|
2023-09-12 11:36:17 +01:00
|
|
|
&&TARGET_CALL_BUILTIN_FAST_WITH_KEYWORDS,
|
2023-09-13 10:25:45 -07:00
|
|
|
&&TARGET_CALL_BUILTIN_O,
|
|
|
|
|
&&TARGET_CALL_ISINSTANCE,
|
2024-08-16 17:11:24 +01:00
|
|
|
&&TARGET_CALL_KW_BOUND_METHOD,
|
|
|
|
|
&&TARGET_CALL_KW_NON_PY,
|
|
|
|
|
&&TARGET_CALL_KW_PY,
|
2023-09-13 10:25:45 -07:00
|
|
|
&&TARGET_CALL_LEN,
|
|
|
|
|
&&TARGET_CALL_LIST_APPEND,
|
|
|
|
|
&&TARGET_CALL_METHOD_DESCRIPTOR_FAST,
|
2023-09-12 11:36:17 +01:00
|
|
|
&&TARGET_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS,
|
2023-09-13 10:25:45 -07:00
|
|
|
&&TARGET_CALL_METHOD_DESCRIPTOR_NOARGS,
|
|
|
|
|
&&TARGET_CALL_METHOD_DESCRIPTOR_O,
|
2024-05-04 12:11:11 +01:00
|
|
|
&&TARGET_CALL_NON_PY_GENERAL,
|
2023-09-12 11:36:17 +01:00
|
|
|
&&TARGET_CALL_PY_EXACT_ARGS,
|
2024-05-04 12:11:11 +01:00
|
|
|
&&TARGET_CALL_PY_GENERAL,
|
2023-09-13 10:25:45 -07:00
|
|
|
&&TARGET_CALL_STR_1,
|
|
|
|
|
&&TARGET_CALL_TUPLE_1,
|
|
|
|
|
&&TARGET_CALL_TYPE_1,
|
2023-09-12 11:36:17 +01:00
|
|
|
&&TARGET_COMPARE_OP_FLOAT,
|
|
|
|
|
&&TARGET_COMPARE_OP_INT,
|
|
|
|
|
&&TARGET_COMPARE_OP_STR,
|
2024-03-07 03:30:11 +08:00
|
|
|
&&TARGET_CONTAINS_OP_DICT,
|
|
|
|
|
&&TARGET_CONTAINS_OP_SET,
|
2023-09-12 11:36:17 +01:00
|
|
|
&&TARGET_FOR_ITER_GEN,
|
|
|
|
|
&&TARGET_FOR_ITER_LIST,
|
|
|
|
|
&&TARGET_FOR_ITER_RANGE,
|
|
|
|
|
&&TARGET_FOR_ITER_TUPLE,
|
2025-01-28 16:10:51 -08:00
|
|
|
&&TARGET_JUMP_BACKWARD_JIT,
|
|
|
|
|
&&TARGET_JUMP_BACKWARD_NO_JIT,
|
2023-09-12 11:36:17 +01:00
|
|
|
&&TARGET_LOAD_ATTR_CLASS,
|
2024-08-23 10:22:35 +01:00
|
|
|
&&TARGET_LOAD_ATTR_CLASS_WITH_METACLASS_CHECK,
|
2023-09-12 11:36:17 +01:00
|
|
|
&&TARGET_LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN,
|
|
|
|
|
&&TARGET_LOAD_ATTR_INSTANCE_VALUE,
|
2025-01-23 04:26:25 -05:00
|
|
|
&&TARGET_LOAD_ATTR_METHOD_LAZY_DICT,
|
|
|
|
|
&&TARGET_LOAD_ATTR_METHOD_NO_DICT,
|
|
|
|
|
&&TARGET_LOAD_ATTR_METHOD_WITH_VALUES,
|
2023-09-12 11:36:17 +01:00
|
|
|
&&TARGET_LOAD_ATTR_MODULE,
|
|
|
|
|
&&TARGET_LOAD_ATTR_NONDESCRIPTOR_NO_DICT,
|
|
|
|
|
&&TARGET_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES,
|
|
|
|
|
&&TARGET_LOAD_ATTR_PROPERTY,
|
|
|
|
|
&&TARGET_LOAD_ATTR_SLOT,
|
|
|
|
|
&&TARGET_LOAD_ATTR_WITH_HINT,
|
|
|
|
|
&&TARGET_LOAD_GLOBAL_BUILTIN,
|
|
|
|
|
&&TARGET_LOAD_GLOBAL_MODULE,
|
|
|
|
|
&&TARGET_LOAD_SUPER_ATTR_ATTR,
|
2025-01-23 04:26:25 -05:00
|
|
|
&&TARGET_LOAD_SUPER_ATTR_METHOD,
|
2023-09-12 11:36:17 +01:00
|
|
|
&&TARGET_RESUME_CHECK,
|
|
|
|
|
&&TARGET_SEND_GEN,
|
|
|
|
|
&&TARGET_STORE_ATTR_INSTANCE_VALUE,
|
|
|
|
|
&&TARGET_STORE_ATTR_SLOT,
|
|
|
|
|
&&TARGET_STORE_ATTR_WITH_HINT,
|
|
|
|
|
&&TARGET_STORE_SUBSCR_DICT,
|
|
|
|
|
&&TARGET_STORE_SUBSCR_LIST_INT,
|
|
|
|
|
&&TARGET_TO_BOOL_ALWAYS_TRUE,
|
|
|
|
|
&&TARGET_TO_BOOL_BOOL,
|
|
|
|
|
&&TARGET_TO_BOOL_INT,
|
|
|
|
|
&&TARGET_TO_BOOL_LIST,
|
|
|
|
|
&&TARGET_TO_BOOL_NONE,
|
|
|
|
|
&&TARGET_TO_BOOL_STR,
|
|
|
|
|
&&TARGET_UNPACK_SEQUENCE_LIST,
|
|
|
|
|
&&TARGET_UNPACK_SEQUENCE_TUPLE,
|
|
|
|
|
&&TARGET_UNPACK_SEQUENCE_TWO_TUPLE,
|
2010-05-09 15:52:27 +00:00
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
2025-03-06 03:59:36 -05:00
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
2025-05-20 11:24:11 -04:00
|
|
|
&&_unknown_opcode,
|
2023-08-16 23:25:18 +01:00
|
|
|
&&TARGET_INSTRUMENTED_END_FOR,
|
2025-01-06 17:54:47 +00:00
|
|
|
&&TARGET_INSTRUMENTED_POP_ITER,
|
2023-08-16 23:25:18 +01:00
|
|
|
&&TARGET_INSTRUMENTED_END_SEND,
|
|
|
|
|
&&TARGET_INSTRUMENTED_FOR_ITER,
|
|
|
|
|
&&TARGET_INSTRUMENTED_INSTRUCTION,
|
2023-04-12 12:04:55 +01:00
|
|
|
&&TARGET_INSTRUMENTED_JUMP_FORWARD,
|
2024-12-19 16:59:51 +00:00
|
|
|
&&TARGET_INSTRUMENTED_NOT_TAKEN,
|
2023-04-12 12:04:55 +01:00
|
|
|
&&TARGET_INSTRUMENTED_POP_JUMP_IF_TRUE,
|
2023-08-16 23:25:18 +01:00
|
|
|
&&TARGET_INSTRUMENTED_POP_JUMP_IF_FALSE,
|
|
|
|
|
&&TARGET_INSTRUMENTED_POP_JUMP_IF_NONE,
|
|
|
|
|
&&TARGET_INSTRUMENTED_POP_JUMP_IF_NOT_NONE,
|
2024-08-14 12:04:05 +01:00
|
|
|
&&TARGET_INSTRUMENTED_RESUME,
|
2024-07-26 12:24:12 +01:00
|
|
|
&&TARGET_INSTRUMENTED_RETURN_VALUE,
|
|
|
|
|
&&TARGET_INSTRUMENTED_YIELD_VALUE,
|
2025-02-27 09:36:41 +00:00
|
|
|
&&TARGET_INSTRUMENTED_END_ASYNC_FOR,
|
2025-02-03 15:09:21 +00:00
|
|
|
&&TARGET_INSTRUMENTED_LOAD_SUPER_ATTR,
|
2024-07-26 14:35:57 +01:00
|
|
|
&&TARGET_INSTRUMENTED_CALL,
|
2025-02-03 15:09:21 +00:00
|
|
|
&&TARGET_INSTRUMENTED_CALL_KW,
|
|
|
|
|
&&TARGET_INSTRUMENTED_CALL_FUNCTION_EX,
|
2024-08-14 12:04:05 +01:00
|
|
|
&&TARGET_INSTRUMENTED_JUMP_BACKWARD,
|
2023-04-12 12:04:55 +01:00
|
|
|
&&TARGET_INSTRUMENTED_LINE,
|
2024-08-13 14:22:57 +01:00
|
|
|
&&TARGET_ENTER_EXECUTOR,
|
2025-11-18 13:31:48 +00:00
|
|
|
&&TARGET_TRACE_RECORD,
|
2023-12-20 15:09:12 +00:00
|
|
|
};
|
gh-139109: A new tracing JIT compiler frontend for CPython (GH-140310)
This PR changes the current JIT model from trace projection to trace recording. Benchmarking: better pyperformance (about 1.7% overall) geomean versus current https://raw.githubusercontent.com/facebookexperimental/free-threading-benchmarking/refs/heads/main/results/bm-20251108-3.15.0a1%2B-7e2bc1d-JIT/bm-20251108-vultr-x86_64-Fidget%252dSpinner-tracing_jit-3.15.0a1%2B-7e2bc1d-vs-base.svg, 100% faster Richards on the most improved benchmark versus the current JIT. Slowdown of about 10-15% on the worst benchmark versus the current JIT. **Note: the fastest version isn't the one merged, as it relies on fixing bugs in the specializing interpreter, which is left to another PR**. The speedup in the merged version is about 1.1%. https://raw.githubusercontent.com/facebookexperimental/free-threading-benchmarking/refs/heads/main/results/bm-20251112-3.15.0a1%2B-f8a764a-JIT/bm-20251112-vultr-x86_64-Fidget%252dSpinner-tracing_jit-3.15.0a1%2B-f8a764a-vs-base.svg
Stats: 50% more uops executed, 30% more traces entered the last time we ran them. It also suggests our trace lengths for a real trace recording JIT are too short, as a lot of trace too long aborts https://github.com/facebookexperimental/free-threading-benchmarking/blob/main/results/bm-20251023-3.15.0a1%2B-eb73378-CLANG%2CJIT/bm-20251023-vultr-x86_64-Fidget%252dSpinner-tracing_jit-3.15.0a1%2B-eb73378-pystats-vs-base.md .
This new JIT frontend is already able to record/execute significantly more instructions than the previous JIT frontend. In this PR, we are now able to record through custom dunders, simple object creation, generators, etc. None of these were done by the old JIT frontend. Some custom dunders uops were discovered to be broken as part of this work gh-140277
The optimizer stack space check is disabled, as it's no longer valid to deal with underflow.
Pros:
* Ignoring the generated tracer code as it's automatically created, this is only additional 1k lines of code. The maintenance burden is handled by the DSL and code generator.
* `optimizer.c` is now significantly simpler, as we don't have to do strange things to recover the bytecode from a trace.
* The new JIT frontend is able to handle a lot more control-flow than the old one.
* Tracing is very low overhead. We use the tail calling interpreter/computed goto interpreter to switch between tracing mode and non-tracing mode. I call this mechanism dual dispatch, as we have two dispatch tables dispatching to each other. Specialization is still enabled while tracing.
* Better handling of polymorphism. We leverage the specializing interpreter for this.
Cons:
* (For now) requires tail calling interpreter or computed gotos. This means no Windows JIT for now :(. Not to fret, tail calling is coming soon to Windows though https://github.com/python/cpython/pull/139962
Design:
* After each instruction, the `record_previous_inst` function/label is executed. This does as the name suggests.
* The tracing interpreter lowers bytecode to uops directly so that it can obtain "fresh" values at the point of lowering.
* The tracing version behaves nearly identical to the normal interpreter, in fact it even has specialization! This allows it to run without much of a slowdown when tracing. The actual cost of tracing is only a function call and writes to memory.
* The tracing interpreter uses the specializing interpreter's deopt to naturally form the side exit chains. This allows it to side exit chain effectively, without repeating much code. We force a re-specializing when tracing a deopt.
* The tracing interpreter can even handle goto errors/exceptions, but I chose to disable them for now as it's not tested.
* Because we do not share interpreter dispatch, there is should be no significant slowdown to the original specializing interpreter on tailcall and computed got with JIT disabled. With JIT enabled, there might be a slowdown in the form of the JIT trying to trace.
* Things that could have dynamic instruction pointer effects are guarded on. The guard deopts to a new instruction --- `_DYNAMIC_EXIT`.
2025-11-14 02:08:32 +08:00
|
|
|
#if _Py_TIER2
|
|
|
|
|
static void *opcode_tracing_targets_table[256] = {
|
2025-11-18 13:31:48 +00:00
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
gh-139109: A new tracing JIT compiler frontend for CPython (GH-140310)
This PR changes the current JIT model from trace projection to trace recording. Benchmarking: better pyperformance (about 1.7% overall) geomean versus current https://raw.githubusercontent.com/facebookexperimental/free-threading-benchmarking/refs/heads/main/results/bm-20251108-3.15.0a1%2B-7e2bc1d-JIT/bm-20251108-vultr-x86_64-Fidget%252dSpinner-tracing_jit-3.15.0a1%2B-7e2bc1d-vs-base.svg, 100% faster Richards on the most improved benchmark versus the current JIT. Slowdown of about 10-15% on the worst benchmark versus the current JIT. **Note: the fastest version isn't the one merged, as it relies on fixing bugs in the specializing interpreter, which is left to another PR**. The speedup in the merged version is about 1.1%. https://raw.githubusercontent.com/facebookexperimental/free-threading-benchmarking/refs/heads/main/results/bm-20251112-3.15.0a1%2B-f8a764a-JIT/bm-20251112-vultr-x86_64-Fidget%252dSpinner-tracing_jit-3.15.0a1%2B-f8a764a-vs-base.svg
Stats: 50% more uops executed, 30% more traces entered the last time we ran them. It also suggests our trace lengths for a real trace recording JIT are too short, as a lot of trace too long aborts https://github.com/facebookexperimental/free-threading-benchmarking/blob/main/results/bm-20251023-3.15.0a1%2B-eb73378-CLANG%2CJIT/bm-20251023-vultr-x86_64-Fidget%252dSpinner-tracing_jit-3.15.0a1%2B-eb73378-pystats-vs-base.md .
This new JIT frontend is already able to record/execute significantly more instructions than the previous JIT frontend. In this PR, we are now able to record through custom dunders, simple object creation, generators, etc. None of these were done by the old JIT frontend. Some custom dunders uops were discovered to be broken as part of this work gh-140277
The optimizer stack space check is disabled, as it's no longer valid to deal with underflow.
Pros:
* Ignoring the generated tracer code as it's automatically created, this is only additional 1k lines of code. The maintenance burden is handled by the DSL and code generator.
* `optimizer.c` is now significantly simpler, as we don't have to do strange things to recover the bytecode from a trace.
* The new JIT frontend is able to handle a lot more control-flow than the old one.
* Tracing is very low overhead. We use the tail calling interpreter/computed goto interpreter to switch between tracing mode and non-tracing mode. I call this mechanism dual dispatch, as we have two dispatch tables dispatching to each other. Specialization is still enabled while tracing.
* Better handling of polymorphism. We leverage the specializing interpreter for this.
Cons:
* (For now) requires tail calling interpreter or computed gotos. This means no Windows JIT for now :(. Not to fret, tail calling is coming soon to Windows though https://github.com/python/cpython/pull/139962
Design:
* After each instruction, the `record_previous_inst` function/label is executed. This does as the name suggests.
* The tracing interpreter lowers bytecode to uops directly so that it can obtain "fresh" values at the point of lowering.
* The tracing version behaves nearly identical to the normal interpreter, in fact it even has specialization! This allows it to run without much of a slowdown when tracing. The actual cost of tracing is only a function call and writes to memory.
* The tracing interpreter uses the specializing interpreter's deopt to naturally form the side exit chains. This allows it to side exit chain effectively, without repeating much code. We force a re-specializing when tracing a deopt.
* The tracing interpreter can even handle goto errors/exceptions, but I chose to disable them for now as it's not tested.
* Because we do not share interpreter dispatch, there is should be no significant slowdown to the original specializing interpreter on tailcall and computed got with JIT disabled. With JIT enabled, there might be a slowdown in the form of the JIT trying to trace.
* Things that could have dynamic instruction pointer effects are guarded on. The guard deopts to a new instruction --- `_DYNAMIC_EXIT`.
2025-11-14 02:08:32 +08:00
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
2025-11-18 13:31:48 +00:00
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
gh-139109: A new tracing JIT compiler frontend for CPython (GH-140310)
This PR changes the current JIT model from trace projection to trace recording. Benchmarking: better pyperformance (about 1.7% overall) geomean versus current https://raw.githubusercontent.com/facebookexperimental/free-threading-benchmarking/refs/heads/main/results/bm-20251108-3.15.0a1%2B-7e2bc1d-JIT/bm-20251108-vultr-x86_64-Fidget%252dSpinner-tracing_jit-3.15.0a1%2B-7e2bc1d-vs-base.svg, 100% faster Richards on the most improved benchmark versus the current JIT. Slowdown of about 10-15% on the worst benchmark versus the current JIT. **Note: the fastest version isn't the one merged, as it relies on fixing bugs in the specializing interpreter, which is left to another PR**. The speedup in the merged version is about 1.1%. https://raw.githubusercontent.com/facebookexperimental/free-threading-benchmarking/refs/heads/main/results/bm-20251112-3.15.0a1%2B-f8a764a-JIT/bm-20251112-vultr-x86_64-Fidget%252dSpinner-tracing_jit-3.15.0a1%2B-f8a764a-vs-base.svg
Stats: 50% more uops executed, 30% more traces entered the last time we ran them. It also suggests our trace lengths for a real trace recording JIT are too short, as a lot of trace too long aborts https://github.com/facebookexperimental/free-threading-benchmarking/blob/main/results/bm-20251023-3.15.0a1%2B-eb73378-CLANG%2CJIT/bm-20251023-vultr-x86_64-Fidget%252dSpinner-tracing_jit-3.15.0a1%2B-eb73378-pystats-vs-base.md .
This new JIT frontend is already able to record/execute significantly more instructions than the previous JIT frontend. In this PR, we are now able to record through custom dunders, simple object creation, generators, etc. None of these were done by the old JIT frontend. Some custom dunders uops were discovered to be broken as part of this work gh-140277
The optimizer stack space check is disabled, as it's no longer valid to deal with underflow.
Pros:
* Ignoring the generated tracer code as it's automatically created, this is only additional 1k lines of code. The maintenance burden is handled by the DSL and code generator.
* `optimizer.c` is now significantly simpler, as we don't have to do strange things to recover the bytecode from a trace.
* The new JIT frontend is able to handle a lot more control-flow than the old one.
* Tracing is very low overhead. We use the tail calling interpreter/computed goto interpreter to switch between tracing mode and non-tracing mode. I call this mechanism dual dispatch, as we have two dispatch tables dispatching to each other. Specialization is still enabled while tracing.
* Better handling of polymorphism. We leverage the specializing interpreter for this.
Cons:
* (For now) requires tail calling interpreter or computed gotos. This means no Windows JIT for now :(. Not to fret, tail calling is coming soon to Windows though https://github.com/python/cpython/pull/139962
Design:
* After each instruction, the `record_previous_inst` function/label is executed. This does as the name suggests.
* The tracing interpreter lowers bytecode to uops directly so that it can obtain "fresh" values at the point of lowering.
* The tracing version behaves nearly identical to the normal interpreter, in fact it even has specialization! This allows it to run without much of a slowdown when tracing. The actual cost of tracing is only a function call and writes to memory.
* The tracing interpreter uses the specializing interpreter's deopt to naturally form the side exit chains. This allows it to side exit chain effectively, without repeating much code. We force a re-specializing when tracing a deopt.
* The tracing interpreter can even handle goto errors/exceptions, but I chose to disable them for now as it's not tested.
* Because we do not share interpreter dispatch, there is should be no significant slowdown to the original specializing interpreter on tailcall and computed got with JIT disabled. With JIT enabled, there might be a slowdown in the form of the JIT trying to trace.
* Things that could have dynamic instruction pointer effects are guarded on. The guard deopts to a new instruction --- `_DYNAMIC_EXIT`.
2025-11-14 02:08:32 +08:00
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
|
|
|
|
&&_unknown_opcode,
|
2025-11-18 13:31:48 +00:00
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
|
|
|
|
&&TARGET_TRACE_RECORD,
|
gh-139109: A new tracing JIT compiler frontend for CPython (GH-140310)
This PR changes the current JIT model from trace projection to trace recording. Benchmarking: better pyperformance (about 1.7% overall) geomean versus current https://raw.githubusercontent.com/facebookexperimental/free-threading-benchmarking/refs/heads/main/results/bm-20251108-3.15.0a1%2B-7e2bc1d-JIT/bm-20251108-vultr-x86_64-Fidget%252dSpinner-tracing_jit-3.15.0a1%2B-7e2bc1d-vs-base.svg, 100% faster Richards on the most improved benchmark versus the current JIT. Slowdown of about 10-15% on the worst benchmark versus the current JIT. **Note: the fastest version isn't the one merged, as it relies on fixing bugs in the specializing interpreter, which is left to another PR**. The speedup in the merged version is about 1.1%. https://raw.githubusercontent.com/facebookexperimental/free-threading-benchmarking/refs/heads/main/results/bm-20251112-3.15.0a1%2B-f8a764a-JIT/bm-20251112-vultr-x86_64-Fidget%252dSpinner-tracing_jit-3.15.0a1%2B-f8a764a-vs-base.svg
Stats: 50% more uops executed, 30% more traces entered the last time we ran them. It also suggests our trace lengths for a real trace recording JIT are too short, as a lot of trace too long aborts https://github.com/facebookexperimental/free-threading-benchmarking/blob/main/results/bm-20251023-3.15.0a1%2B-eb73378-CLANG%2CJIT/bm-20251023-vultr-x86_64-Fidget%252dSpinner-tracing_jit-3.15.0a1%2B-eb73378-pystats-vs-base.md .
This new JIT frontend is already able to record/execute significantly more instructions than the previous JIT frontend. In this PR, we are now able to record through custom dunders, simple object creation, generators, etc. None of these were done by the old JIT frontend. Some custom dunders uops were discovered to be broken as part of this work gh-140277
The optimizer stack space check is disabled, as it's no longer valid to deal with underflow.
Pros:
* Ignoring the generated tracer code as it's automatically created, this is only additional 1k lines of code. The maintenance burden is handled by the DSL and code generator.
* `optimizer.c` is now significantly simpler, as we don't have to do strange things to recover the bytecode from a trace.
* The new JIT frontend is able to handle a lot more control-flow than the old one.
* Tracing is very low overhead. We use the tail calling interpreter/computed goto interpreter to switch between tracing mode and non-tracing mode. I call this mechanism dual dispatch, as we have two dispatch tables dispatching to each other. Specialization is still enabled while tracing.
* Better handling of polymorphism. We leverage the specializing interpreter for this.
Cons:
* (For now) requires tail calling interpreter or computed gotos. This means no Windows JIT for now :(. Not to fret, tail calling is coming soon to Windows though https://github.com/python/cpython/pull/139962
Design:
* After each instruction, the `record_previous_inst` function/label is executed. This does as the name suggests.
* The tracing interpreter lowers bytecode to uops directly so that it can obtain "fresh" values at the point of lowering.
* The tracing version behaves nearly identical to the normal interpreter, in fact it even has specialization! This allows it to run without much of a slowdown when tracing. The actual cost of tracing is only a function call and writes to memory.
* The tracing interpreter uses the specializing interpreter's deopt to naturally form the side exit chains. This allows it to side exit chain effectively, without repeating much code. We force a re-specializing when tracing a deopt.
* The tracing interpreter can even handle goto errors/exceptions, but I chose to disable them for now as it's not tested.
* Because we do not share interpreter dispatch, there is should be no significant slowdown to the original specializing interpreter on tailcall and computed got with JIT disabled. With JIT enabled, there might be a slowdown in the form of the JIT trying to trace.
* Things that could have dynamic instruction pointer effects are guarded on. The guard deopts to a new instruction --- `_DYNAMIC_EXIT`.
2025-11-14 02:08:32 +08:00
|
|
|
};
|
|
|
|
|
#endif
|
2025-09-18 13:33:07 +01:00
|
|
|
#else /* _Py_TAIL_CALL_INTERP */
|
gh-139109: A new tracing JIT compiler frontend for CPython (GH-140310)
This PR changes the current JIT model from trace projection to trace recording. Benchmarking: better pyperformance (about 1.7% overall) geomean versus current https://raw.githubusercontent.com/facebookexperimental/free-threading-benchmarking/refs/heads/main/results/bm-20251108-3.15.0a1%2B-7e2bc1d-JIT/bm-20251108-vultr-x86_64-Fidget%252dSpinner-tracing_jit-3.15.0a1%2B-7e2bc1d-vs-base.svg, 100% faster Richards on the most improved benchmark versus the current JIT. Slowdown of about 10-15% on the worst benchmark versus the current JIT. **Note: the fastest version isn't the one merged, as it relies on fixing bugs in the specializing interpreter, which is left to another PR**. The speedup in the merged version is about 1.1%. https://raw.githubusercontent.com/facebookexperimental/free-threading-benchmarking/refs/heads/main/results/bm-20251112-3.15.0a1%2B-f8a764a-JIT/bm-20251112-vultr-x86_64-Fidget%252dSpinner-tracing_jit-3.15.0a1%2B-f8a764a-vs-base.svg
Stats: 50% more uops executed, 30% more traces entered the last time we ran them. It also suggests our trace lengths for a real trace recording JIT are too short, as a lot of trace too long aborts https://github.com/facebookexperimental/free-threading-benchmarking/blob/main/results/bm-20251023-3.15.0a1%2B-eb73378-CLANG%2CJIT/bm-20251023-vultr-x86_64-Fidget%252dSpinner-tracing_jit-3.15.0a1%2B-eb73378-pystats-vs-base.md .
This new JIT frontend is already able to record/execute significantly more instructions than the previous JIT frontend. In this PR, we are now able to record through custom dunders, simple object creation, generators, etc. None of these were done by the old JIT frontend. Some custom dunders uops were discovered to be broken as part of this work gh-140277
The optimizer stack space check is disabled, as it's no longer valid to deal with underflow.
Pros:
* Ignoring the generated tracer code as it's automatically created, this is only additional 1k lines of code. The maintenance burden is handled by the DSL and code generator.
* `optimizer.c` is now significantly simpler, as we don't have to do strange things to recover the bytecode from a trace.
* The new JIT frontend is able to handle a lot more control-flow than the old one.
* Tracing is very low overhead. We use the tail calling interpreter/computed goto interpreter to switch between tracing mode and non-tracing mode. I call this mechanism dual dispatch, as we have two dispatch tables dispatching to each other. Specialization is still enabled while tracing.
* Better handling of polymorphism. We leverage the specializing interpreter for this.
Cons:
* (For now) requires tail calling interpreter or computed gotos. This means no Windows JIT for now :(. Not to fret, tail calling is coming soon to Windows though https://github.com/python/cpython/pull/139962
Design:
* After each instruction, the `record_previous_inst` function/label is executed. This does as the name suggests.
* The tracing interpreter lowers bytecode to uops directly so that it can obtain "fresh" values at the point of lowering.
* The tracing version behaves nearly identical to the normal interpreter, in fact it even has specialization! This allows it to run without much of a slowdown when tracing. The actual cost of tracing is only a function call and writes to memory.
* The tracing interpreter uses the specializing interpreter's deopt to naturally form the side exit chains. This allows it to side exit chain effectively, without repeating much code. We force a re-specializing when tracing a deopt.
* The tracing interpreter can even handle goto errors/exceptions, but I chose to disable them for now as it's not tested.
* Because we do not share interpreter dispatch, there is should be no significant slowdown to the original specializing interpreter on tailcall and computed got with JIT disabled. With JIT enabled, there might be a slowdown in the form of the JIT trying to trace.
* Things that could have dynamic instruction pointer effects are guarded on. The guard deopts to a new instruction --- `_DYNAMIC_EXIT`.
2025-11-14 02:08:32 +08:00
|
|
|
static py_tail_call_funcptr instruction_funcptr_handler_table[256];
|
|
|
|
|
|
|
|
|
|
static py_tail_call_funcptr instruction_funcptr_tracing_table[256];
|
2025-02-06 23:21:57 +08:00
|
|
|
|
2025-12-23 00:01:34 +01:00
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_pop_2_error(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_pop_1_error(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_error(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_exception_unwind(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_exit_unwind(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_start_frame(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_stop_tracing(TAIL_CALL_PARAMS);
|
2025-02-06 23:21:57 +08:00
|
|
|
|
2025-12-23 00:01:34 +01:00
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_BINARY_OP(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_BINARY_OP_ADD_FLOAT(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_BINARY_OP_ADD_INT(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_BINARY_OP_ADD_UNICODE(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_BINARY_OP_EXTEND(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_BINARY_OP_INPLACE_ADD_UNICODE(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_BINARY_OP_MULTIPLY_FLOAT(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_BINARY_OP_MULTIPLY_INT(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_BINARY_OP_SUBSCR_DICT(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_BINARY_OP_SUBSCR_GETITEM(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_BINARY_OP_SUBSCR_LIST_INT(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_BINARY_OP_SUBSCR_LIST_SLICE(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_BINARY_OP_SUBSCR_STR_INT(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_BINARY_OP_SUBSCR_TUPLE_INT(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_BINARY_OP_SUBTRACT_FLOAT(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_BINARY_OP_SUBTRACT_INT(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_BINARY_SLICE(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_BUILD_INTERPOLATION(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_BUILD_LIST(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_BUILD_MAP(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_BUILD_SET(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_BUILD_SLICE(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_BUILD_STRING(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_BUILD_TEMPLATE(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_BUILD_TUPLE(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CACHE(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CALL(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CALL_ALLOC_AND_ENTER_INIT(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CALL_BOUND_METHOD_EXACT_ARGS(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CALL_BOUND_METHOD_GENERAL(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CALL_BUILTIN_CLASS(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CALL_BUILTIN_FAST(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CALL_BUILTIN_FAST_WITH_KEYWORDS(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CALL_BUILTIN_O(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CALL_FUNCTION_EX(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CALL_INTRINSIC_1(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CALL_INTRINSIC_2(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CALL_ISINSTANCE(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CALL_KW(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CALL_KW_BOUND_METHOD(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CALL_KW_NON_PY(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CALL_KW_PY(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CALL_LEN(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CALL_LIST_APPEND(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CALL_METHOD_DESCRIPTOR_FAST(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CALL_METHOD_DESCRIPTOR_NOARGS(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CALL_METHOD_DESCRIPTOR_O(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CALL_NON_PY_GENERAL(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CALL_PY_EXACT_ARGS(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CALL_PY_GENERAL(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CALL_STR_1(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CALL_TUPLE_1(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CALL_TYPE_1(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CHECK_EG_MATCH(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CHECK_EXC_MATCH(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CLEANUP_THROW(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_COMPARE_OP(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_COMPARE_OP_FLOAT(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_COMPARE_OP_INT(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_COMPARE_OP_STR(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CONTAINS_OP(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CONTAINS_OP_DICT(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CONTAINS_OP_SET(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CONVERT_VALUE(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_COPY(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_COPY_FREE_VARS(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_DELETE_ATTR(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_DELETE_DEREF(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_DELETE_FAST(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_DELETE_GLOBAL(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_DELETE_NAME(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_DELETE_SUBSCR(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_DICT_MERGE(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_DICT_UPDATE(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_END_ASYNC_FOR(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_END_FOR(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_END_SEND(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_ENTER_EXECUTOR(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_EXIT_INIT_CHECK(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_EXTENDED_ARG(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_FORMAT_SIMPLE(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_FORMAT_WITH_SPEC(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_FOR_ITER(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_FOR_ITER_GEN(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_FOR_ITER_LIST(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_FOR_ITER_RANGE(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_FOR_ITER_TUPLE(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_GET_AITER(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_GET_ANEXT(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_GET_AWAITABLE(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_GET_ITER(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_GET_LEN(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_GET_YIELD_FROM_ITER(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_IMPORT_FROM(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_IMPORT_NAME(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_INSTRUMENTED_CALL(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_INSTRUMENTED_CALL_FUNCTION_EX(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_INSTRUMENTED_CALL_KW(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_INSTRUMENTED_END_ASYNC_FOR(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_INSTRUMENTED_END_FOR(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_INSTRUMENTED_END_SEND(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_INSTRUMENTED_FOR_ITER(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_INSTRUMENTED_INSTRUCTION(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_INSTRUMENTED_JUMP_BACKWARD(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_INSTRUMENTED_JUMP_FORWARD(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_INSTRUMENTED_LINE(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_INSTRUMENTED_LOAD_SUPER_ATTR(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_INSTRUMENTED_NOT_TAKEN(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_INSTRUMENTED_POP_ITER(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_INSTRUMENTED_POP_JUMP_IF_FALSE(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_INSTRUMENTED_POP_JUMP_IF_NONE(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_INSTRUMENTED_POP_JUMP_IF_NOT_NONE(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_INSTRUMENTED_POP_JUMP_IF_TRUE(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_INSTRUMENTED_RESUME(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_INSTRUMENTED_RETURN_VALUE(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_INSTRUMENTED_YIELD_VALUE(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_INTERPRETER_EXIT(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_IS_OP(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_JUMP_BACKWARD(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_JUMP_BACKWARD_JIT(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_JUMP_BACKWARD_NO_INTERRUPT(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_JUMP_BACKWARD_NO_JIT(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_JUMP_FORWARD(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_LIST_APPEND(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_LIST_EXTEND(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_LOAD_ATTR(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_LOAD_ATTR_CLASS(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_LOAD_ATTR_CLASS_WITH_METACLASS_CHECK(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_LOAD_ATTR_INSTANCE_VALUE(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_LOAD_ATTR_METHOD_LAZY_DICT(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_LOAD_ATTR_METHOD_NO_DICT(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_LOAD_ATTR_METHOD_WITH_VALUES(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_LOAD_ATTR_MODULE(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_LOAD_ATTR_NONDESCRIPTOR_NO_DICT(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_LOAD_ATTR_PROPERTY(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_LOAD_ATTR_SLOT(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_LOAD_ATTR_WITH_HINT(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_LOAD_BUILD_CLASS(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_LOAD_COMMON_CONSTANT(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_LOAD_CONST(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_LOAD_DEREF(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_LOAD_FAST(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_LOAD_FAST_AND_CLEAR(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_LOAD_FAST_BORROW(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_LOAD_FAST_BORROW_LOAD_FAST_BORROW(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_LOAD_FAST_CHECK(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_LOAD_FAST_LOAD_FAST(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_LOAD_FROM_DICT_OR_DEREF(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_LOAD_FROM_DICT_OR_GLOBALS(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_LOAD_GLOBAL(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_LOAD_GLOBAL_BUILTIN(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_LOAD_GLOBAL_MODULE(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_LOAD_LOCALS(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_LOAD_NAME(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_LOAD_SMALL_INT(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_LOAD_SPECIAL(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_LOAD_SUPER_ATTR(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_LOAD_SUPER_ATTR_ATTR(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_LOAD_SUPER_ATTR_METHOD(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_MAKE_CELL(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_MAKE_FUNCTION(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_MAP_ADD(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_MATCH_CLASS(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_MATCH_KEYS(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_MATCH_MAPPING(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_MATCH_SEQUENCE(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_NOP(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_NOT_TAKEN(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_POP_EXCEPT(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_POP_ITER(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_POP_JUMP_IF_FALSE(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_POP_JUMP_IF_NONE(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_POP_JUMP_IF_NOT_NONE(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_POP_JUMP_IF_TRUE(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_POP_TOP(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_PUSH_EXC_INFO(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_PUSH_NULL(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_RAISE_VARARGS(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_RERAISE(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_RESERVED(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_RESUME(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_RESUME_CHECK(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_RETURN_GENERATOR(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_RETURN_VALUE(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_SEND(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_SEND_GEN(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_SETUP_ANNOTATIONS(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_SET_ADD(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_SET_FUNCTION_ATTRIBUTE(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_SET_UPDATE(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_STORE_ATTR(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_STORE_ATTR_INSTANCE_VALUE(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_STORE_ATTR_SLOT(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_STORE_ATTR_WITH_HINT(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_STORE_DEREF(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_STORE_FAST(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_STORE_FAST_LOAD_FAST(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_STORE_FAST_STORE_FAST(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_STORE_GLOBAL(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_STORE_NAME(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_STORE_SLICE(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_STORE_SUBSCR(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_STORE_SUBSCR_DICT(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_STORE_SUBSCR_LIST_INT(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_SWAP(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_TO_BOOL(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_TO_BOOL_ALWAYS_TRUE(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_TO_BOOL_BOOL(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_TO_BOOL_INT(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_TO_BOOL_LIST(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_TO_BOOL_NONE(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_TO_BOOL_STR(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_TRACE_RECORD(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_UNARY_INVERT(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_UNARY_NEGATIVE(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_UNARY_NOT(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_UNPACK_EX(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_UNPACK_SEQUENCE(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_UNPACK_SEQUENCE_LIST(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_UNPACK_SEQUENCE_TUPLE(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_UNPACK_SEQUENCE_TWO_TUPLE(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_WITH_EXCEPT_START(TAIL_CALL_PARAMS);
|
|
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_YIELD_VALUE(TAIL_CALL_PARAMS);
|
2025-02-06 23:21:57 +08:00
|
|
|
|
2025-12-23 00:01:34 +01:00
|
|
|
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_UNKNOWN_OPCODE(TAIL_CALL_PARAMS) {
|
2025-02-06 23:21:57 +08:00
|
|
|
int opcode = next_instr->op.code;
|
|
|
|
|
_PyErr_Format(tstate, PyExc_SystemError,
|
|
|
|
|
"%U:%d: unknown opcode %d",
|
|
|
|
|
_PyFrame_GetCode(frame)->co_filename,
|
|
|
|
|
PyUnstable_InterpreterFrame_GetLine(frame),
|
|
|
|
|
opcode);
|
|
|
|
|
JUMP_TO_LABEL(error);
|
|
|
|
|
}
|
|
|
|
|
|
gh-139109: A new tracing JIT compiler frontend for CPython (GH-140310)
This PR changes the current JIT model from trace projection to trace recording. Benchmarking: better pyperformance (about 1.7% overall) geomean versus current https://raw.githubusercontent.com/facebookexperimental/free-threading-benchmarking/refs/heads/main/results/bm-20251108-3.15.0a1%2B-7e2bc1d-JIT/bm-20251108-vultr-x86_64-Fidget%252dSpinner-tracing_jit-3.15.0a1%2B-7e2bc1d-vs-base.svg, 100% faster Richards on the most improved benchmark versus the current JIT. Slowdown of about 10-15% on the worst benchmark versus the current JIT. **Note: the fastest version isn't the one merged, as it relies on fixing bugs in the specializing interpreter, which is left to another PR**. The speedup in the merged version is about 1.1%. https://raw.githubusercontent.com/facebookexperimental/free-threading-benchmarking/refs/heads/main/results/bm-20251112-3.15.0a1%2B-f8a764a-JIT/bm-20251112-vultr-x86_64-Fidget%252dSpinner-tracing_jit-3.15.0a1%2B-f8a764a-vs-base.svg
Stats: 50% more uops executed, 30% more traces entered the last time we ran them. It also suggests our trace lengths for a real trace recording JIT are too short, as a lot of trace too long aborts https://github.com/facebookexperimental/free-threading-benchmarking/blob/main/results/bm-20251023-3.15.0a1%2B-eb73378-CLANG%2CJIT/bm-20251023-vultr-x86_64-Fidget%252dSpinner-tracing_jit-3.15.0a1%2B-eb73378-pystats-vs-base.md .
This new JIT frontend is already able to record/execute significantly more instructions than the previous JIT frontend. In this PR, we are now able to record through custom dunders, simple object creation, generators, etc. None of these were done by the old JIT frontend. Some custom dunders uops were discovered to be broken as part of this work gh-140277
The optimizer stack space check is disabled, as it's no longer valid to deal with underflow.
Pros:
* Ignoring the generated tracer code as it's automatically created, this is only additional 1k lines of code. The maintenance burden is handled by the DSL and code generator.
* `optimizer.c` is now significantly simpler, as we don't have to do strange things to recover the bytecode from a trace.
* The new JIT frontend is able to handle a lot more control-flow than the old one.
* Tracing is very low overhead. We use the tail calling interpreter/computed goto interpreter to switch between tracing mode and non-tracing mode. I call this mechanism dual dispatch, as we have two dispatch tables dispatching to each other. Specialization is still enabled while tracing.
* Better handling of polymorphism. We leverage the specializing interpreter for this.
Cons:
* (For now) requires tail calling interpreter or computed gotos. This means no Windows JIT for now :(. Not to fret, tail calling is coming soon to Windows though https://github.com/python/cpython/pull/139962
Design:
* After each instruction, the `record_previous_inst` function/label is executed. This does as the name suggests.
* The tracing interpreter lowers bytecode to uops directly so that it can obtain "fresh" values at the point of lowering.
* The tracing version behaves nearly identical to the normal interpreter, in fact it even has specialization! This allows it to run without much of a slowdown when tracing. The actual cost of tracing is only a function call and writes to memory.
* The tracing interpreter uses the specializing interpreter's deopt to naturally form the side exit chains. This allows it to side exit chain effectively, without repeating much code. We force a re-specializing when tracing a deopt.
* The tracing interpreter can even handle goto errors/exceptions, but I chose to disable them for now as it's not tested.
* Because we do not share interpreter dispatch, there is should be no significant slowdown to the original specializing interpreter on tailcall and computed got with JIT disabled. With JIT enabled, there might be a slowdown in the form of the JIT trying to trace.
* Things that could have dynamic instruction pointer effects are guarded on. The guard deopts to a new instruction --- `_DYNAMIC_EXIT`.
2025-11-14 02:08:32 +08:00
|
|
|
static py_tail_call_funcptr instruction_funcptr_handler_table[256] = {
|
2025-02-06 23:21:57 +08:00
|
|
|
[BINARY_OP] = _TAIL_CALL_BINARY_OP,
|
|
|
|
|
[BINARY_OP_ADD_FLOAT] = _TAIL_CALL_BINARY_OP_ADD_FLOAT,
|
|
|
|
|
[BINARY_OP_ADD_INT] = _TAIL_CALL_BINARY_OP_ADD_INT,
|
|
|
|
|
[BINARY_OP_ADD_UNICODE] = _TAIL_CALL_BINARY_OP_ADD_UNICODE,
|
|
|
|
|
[BINARY_OP_EXTEND] = _TAIL_CALL_BINARY_OP_EXTEND,
|
|
|
|
|
[BINARY_OP_INPLACE_ADD_UNICODE] = _TAIL_CALL_BINARY_OP_INPLACE_ADD_UNICODE,
|
|
|
|
|
[BINARY_OP_MULTIPLY_FLOAT] = _TAIL_CALL_BINARY_OP_MULTIPLY_FLOAT,
|
|
|
|
|
[BINARY_OP_MULTIPLY_INT] = _TAIL_CALL_BINARY_OP_MULTIPLY_INT,
|
2025-02-07 22:39:54 +00:00
|
|
|
[BINARY_OP_SUBSCR_DICT] = _TAIL_CALL_BINARY_OP_SUBSCR_DICT,
|
|
|
|
|
[BINARY_OP_SUBSCR_GETITEM] = _TAIL_CALL_BINARY_OP_SUBSCR_GETITEM,
|
|
|
|
|
[BINARY_OP_SUBSCR_LIST_INT] = _TAIL_CALL_BINARY_OP_SUBSCR_LIST_INT,
|
2025-05-01 11:28:52 +01:00
|
|
|
[BINARY_OP_SUBSCR_LIST_SLICE] = _TAIL_CALL_BINARY_OP_SUBSCR_LIST_SLICE,
|
2025-02-07 22:39:54 +00:00
|
|
|
[BINARY_OP_SUBSCR_STR_INT] = _TAIL_CALL_BINARY_OP_SUBSCR_STR_INT,
|
|
|
|
|
[BINARY_OP_SUBSCR_TUPLE_INT] = _TAIL_CALL_BINARY_OP_SUBSCR_TUPLE_INT,
|
2025-02-06 23:21:57 +08:00
|
|
|
[BINARY_OP_SUBTRACT_FLOAT] = _TAIL_CALL_BINARY_OP_SUBTRACT_FLOAT,
|
|
|
|
|
[BINARY_OP_SUBTRACT_INT] = _TAIL_CALL_BINARY_OP_SUBTRACT_INT,
|
|
|
|
|
[BINARY_SLICE] = _TAIL_CALL_BINARY_SLICE,
|
2025-04-30 11:46:41 +02:00
|
|
|
[BUILD_INTERPOLATION] = _TAIL_CALL_BUILD_INTERPOLATION,
|
2025-02-06 23:21:57 +08:00
|
|
|
[BUILD_LIST] = _TAIL_CALL_BUILD_LIST,
|
|
|
|
|
[BUILD_MAP] = _TAIL_CALL_BUILD_MAP,
|
|
|
|
|
[BUILD_SET] = _TAIL_CALL_BUILD_SET,
|
|
|
|
|
[BUILD_SLICE] = _TAIL_CALL_BUILD_SLICE,
|
|
|
|
|
[BUILD_STRING] = _TAIL_CALL_BUILD_STRING,
|
2025-04-30 11:46:41 +02:00
|
|
|
[BUILD_TEMPLATE] = _TAIL_CALL_BUILD_TEMPLATE,
|
2025-02-06 23:21:57 +08:00
|
|
|
[BUILD_TUPLE] = _TAIL_CALL_BUILD_TUPLE,
|
|
|
|
|
[CACHE] = _TAIL_CALL_CACHE,
|
|
|
|
|
[CALL] = _TAIL_CALL_CALL,
|
|
|
|
|
[CALL_ALLOC_AND_ENTER_INIT] = _TAIL_CALL_CALL_ALLOC_AND_ENTER_INIT,
|
|
|
|
|
[CALL_BOUND_METHOD_EXACT_ARGS] = _TAIL_CALL_CALL_BOUND_METHOD_EXACT_ARGS,
|
|
|
|
|
[CALL_BOUND_METHOD_GENERAL] = _TAIL_CALL_CALL_BOUND_METHOD_GENERAL,
|
|
|
|
|
[CALL_BUILTIN_CLASS] = _TAIL_CALL_CALL_BUILTIN_CLASS,
|
|
|
|
|
[CALL_BUILTIN_FAST] = _TAIL_CALL_CALL_BUILTIN_FAST,
|
|
|
|
|
[CALL_BUILTIN_FAST_WITH_KEYWORDS] = _TAIL_CALL_CALL_BUILTIN_FAST_WITH_KEYWORDS,
|
|
|
|
|
[CALL_BUILTIN_O] = _TAIL_CALL_CALL_BUILTIN_O,
|
|
|
|
|
[CALL_FUNCTION_EX] = _TAIL_CALL_CALL_FUNCTION_EX,
|
|
|
|
|
[CALL_INTRINSIC_1] = _TAIL_CALL_CALL_INTRINSIC_1,
|
|
|
|
|
[CALL_INTRINSIC_2] = _TAIL_CALL_CALL_INTRINSIC_2,
|
|
|
|
|
[CALL_ISINSTANCE] = _TAIL_CALL_CALL_ISINSTANCE,
|
|
|
|
|
[CALL_KW] = _TAIL_CALL_CALL_KW,
|
|
|
|
|
[CALL_KW_BOUND_METHOD] = _TAIL_CALL_CALL_KW_BOUND_METHOD,
|
|
|
|
|
[CALL_KW_NON_PY] = _TAIL_CALL_CALL_KW_NON_PY,
|
|
|
|
|
[CALL_KW_PY] = _TAIL_CALL_CALL_KW_PY,
|
|
|
|
|
[CALL_LEN] = _TAIL_CALL_CALL_LEN,
|
|
|
|
|
[CALL_LIST_APPEND] = _TAIL_CALL_CALL_LIST_APPEND,
|
|
|
|
|
[CALL_METHOD_DESCRIPTOR_FAST] = _TAIL_CALL_CALL_METHOD_DESCRIPTOR_FAST,
|
|
|
|
|
[CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = _TAIL_CALL_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS,
|
|
|
|
|
[CALL_METHOD_DESCRIPTOR_NOARGS] = _TAIL_CALL_CALL_METHOD_DESCRIPTOR_NOARGS,
|
|
|
|
|
[CALL_METHOD_DESCRIPTOR_O] = _TAIL_CALL_CALL_METHOD_DESCRIPTOR_O,
|
|
|
|
|
[CALL_NON_PY_GENERAL] = _TAIL_CALL_CALL_NON_PY_GENERAL,
|
|
|
|
|
[CALL_PY_EXACT_ARGS] = _TAIL_CALL_CALL_PY_EXACT_ARGS,
|
|
|
|
|
[CALL_PY_GENERAL] = _TAIL_CALL_CALL_PY_GENERAL,
|
|
|
|
|
[CALL_STR_1] = _TAIL_CALL_CALL_STR_1,
|
|
|
|
|
[CALL_TUPLE_1] = _TAIL_CALL_CALL_TUPLE_1,
|
|
|
|
|
[CALL_TYPE_1] = _TAIL_CALL_CALL_TYPE_1,
|
|
|
|
|
[CHECK_EG_MATCH] = _TAIL_CALL_CHECK_EG_MATCH,
|
|
|
|
|
[CHECK_EXC_MATCH] = _TAIL_CALL_CHECK_EXC_MATCH,
|
|
|
|
|
[CLEANUP_THROW] = _TAIL_CALL_CLEANUP_THROW,
|
|
|
|
|
[COMPARE_OP] = _TAIL_CALL_COMPARE_OP,
|
|
|
|
|
[COMPARE_OP_FLOAT] = _TAIL_CALL_COMPARE_OP_FLOAT,
|
|
|
|
|
[COMPARE_OP_INT] = _TAIL_CALL_COMPARE_OP_INT,
|
|
|
|
|
[COMPARE_OP_STR] = _TAIL_CALL_COMPARE_OP_STR,
|
|
|
|
|
[CONTAINS_OP] = _TAIL_CALL_CONTAINS_OP,
|
|
|
|
|
[CONTAINS_OP_DICT] = _TAIL_CALL_CONTAINS_OP_DICT,
|
|
|
|
|
[CONTAINS_OP_SET] = _TAIL_CALL_CONTAINS_OP_SET,
|
|
|
|
|
[CONVERT_VALUE] = _TAIL_CALL_CONVERT_VALUE,
|
|
|
|
|
[COPY] = _TAIL_CALL_COPY,
|
|
|
|
|
[COPY_FREE_VARS] = _TAIL_CALL_COPY_FREE_VARS,
|
|
|
|
|
[DELETE_ATTR] = _TAIL_CALL_DELETE_ATTR,
|
|
|
|
|
[DELETE_DEREF] = _TAIL_CALL_DELETE_DEREF,
|
|
|
|
|
[DELETE_FAST] = _TAIL_CALL_DELETE_FAST,
|
|
|
|
|
[DELETE_GLOBAL] = _TAIL_CALL_DELETE_GLOBAL,
|
|
|
|
|
[DELETE_NAME] = _TAIL_CALL_DELETE_NAME,
|
|
|
|
|
[DELETE_SUBSCR] = _TAIL_CALL_DELETE_SUBSCR,
|
|
|
|
|
[DICT_MERGE] = _TAIL_CALL_DICT_MERGE,
|
|
|
|
|
[DICT_UPDATE] = _TAIL_CALL_DICT_UPDATE,
|
|
|
|
|
[END_ASYNC_FOR] = _TAIL_CALL_END_ASYNC_FOR,
|
|
|
|
|
[END_FOR] = _TAIL_CALL_END_FOR,
|
|
|
|
|
[END_SEND] = _TAIL_CALL_END_SEND,
|
|
|
|
|
[ENTER_EXECUTOR] = _TAIL_CALL_ENTER_EXECUTOR,
|
|
|
|
|
[EXIT_INIT_CHECK] = _TAIL_CALL_EXIT_INIT_CHECK,
|
|
|
|
|
[EXTENDED_ARG] = _TAIL_CALL_EXTENDED_ARG,
|
|
|
|
|
[FORMAT_SIMPLE] = _TAIL_CALL_FORMAT_SIMPLE,
|
|
|
|
|
[FORMAT_WITH_SPEC] = _TAIL_CALL_FORMAT_WITH_SPEC,
|
|
|
|
|
[FOR_ITER] = _TAIL_CALL_FOR_ITER,
|
|
|
|
|
[FOR_ITER_GEN] = _TAIL_CALL_FOR_ITER_GEN,
|
|
|
|
|
[FOR_ITER_LIST] = _TAIL_CALL_FOR_ITER_LIST,
|
|
|
|
|
[FOR_ITER_RANGE] = _TAIL_CALL_FOR_ITER_RANGE,
|
|
|
|
|
[FOR_ITER_TUPLE] = _TAIL_CALL_FOR_ITER_TUPLE,
|
|
|
|
|
[GET_AITER] = _TAIL_CALL_GET_AITER,
|
|
|
|
|
[GET_ANEXT] = _TAIL_CALL_GET_ANEXT,
|
|
|
|
|
[GET_AWAITABLE] = _TAIL_CALL_GET_AWAITABLE,
|
|
|
|
|
[GET_ITER] = _TAIL_CALL_GET_ITER,
|
|
|
|
|
[GET_LEN] = _TAIL_CALL_GET_LEN,
|
|
|
|
|
[GET_YIELD_FROM_ITER] = _TAIL_CALL_GET_YIELD_FROM_ITER,
|
|
|
|
|
[IMPORT_FROM] = _TAIL_CALL_IMPORT_FROM,
|
|
|
|
|
[IMPORT_NAME] = _TAIL_CALL_IMPORT_NAME,
|
|
|
|
|
[INSTRUMENTED_CALL] = _TAIL_CALL_INSTRUMENTED_CALL,
|
|
|
|
|
[INSTRUMENTED_CALL_FUNCTION_EX] = _TAIL_CALL_INSTRUMENTED_CALL_FUNCTION_EX,
|
|
|
|
|
[INSTRUMENTED_CALL_KW] = _TAIL_CALL_INSTRUMENTED_CALL_KW,
|
2025-02-27 09:36:41 +00:00
|
|
|
[INSTRUMENTED_END_ASYNC_FOR] = _TAIL_CALL_INSTRUMENTED_END_ASYNC_FOR,
|
2025-02-06 23:21:57 +08:00
|
|
|
[INSTRUMENTED_END_FOR] = _TAIL_CALL_INSTRUMENTED_END_FOR,
|
|
|
|
|
[INSTRUMENTED_END_SEND] = _TAIL_CALL_INSTRUMENTED_END_SEND,
|
|
|
|
|
[INSTRUMENTED_FOR_ITER] = _TAIL_CALL_INSTRUMENTED_FOR_ITER,
|
|
|
|
|
[INSTRUMENTED_INSTRUCTION] = _TAIL_CALL_INSTRUMENTED_INSTRUCTION,
|
|
|
|
|
[INSTRUMENTED_JUMP_BACKWARD] = _TAIL_CALL_INSTRUMENTED_JUMP_BACKWARD,
|
|
|
|
|
[INSTRUMENTED_JUMP_FORWARD] = _TAIL_CALL_INSTRUMENTED_JUMP_FORWARD,
|
|
|
|
|
[INSTRUMENTED_LINE] = _TAIL_CALL_INSTRUMENTED_LINE,
|
|
|
|
|
[INSTRUMENTED_LOAD_SUPER_ATTR] = _TAIL_CALL_INSTRUMENTED_LOAD_SUPER_ATTR,
|
|
|
|
|
[INSTRUMENTED_NOT_TAKEN] = _TAIL_CALL_INSTRUMENTED_NOT_TAKEN,
|
|
|
|
|
[INSTRUMENTED_POP_ITER] = _TAIL_CALL_INSTRUMENTED_POP_ITER,
|
|
|
|
|
[INSTRUMENTED_POP_JUMP_IF_FALSE] = _TAIL_CALL_INSTRUMENTED_POP_JUMP_IF_FALSE,
|
|
|
|
|
[INSTRUMENTED_POP_JUMP_IF_NONE] = _TAIL_CALL_INSTRUMENTED_POP_JUMP_IF_NONE,
|
|
|
|
|
[INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = _TAIL_CALL_INSTRUMENTED_POP_JUMP_IF_NOT_NONE,
|
|
|
|
|
[INSTRUMENTED_POP_JUMP_IF_TRUE] = _TAIL_CALL_INSTRUMENTED_POP_JUMP_IF_TRUE,
|
|
|
|
|
[INSTRUMENTED_RESUME] = _TAIL_CALL_INSTRUMENTED_RESUME,
|
|
|
|
|
[INSTRUMENTED_RETURN_VALUE] = _TAIL_CALL_INSTRUMENTED_RETURN_VALUE,
|
|
|
|
|
[INSTRUMENTED_YIELD_VALUE] = _TAIL_CALL_INSTRUMENTED_YIELD_VALUE,
|
|
|
|
|
[INTERPRETER_EXIT] = _TAIL_CALL_INTERPRETER_EXIT,
|
|
|
|
|
[IS_OP] = _TAIL_CALL_IS_OP,
|
|
|
|
|
[JUMP_BACKWARD] = _TAIL_CALL_JUMP_BACKWARD,
|
|
|
|
|
[JUMP_BACKWARD_JIT] = _TAIL_CALL_JUMP_BACKWARD_JIT,
|
|
|
|
|
[JUMP_BACKWARD_NO_INTERRUPT] = _TAIL_CALL_JUMP_BACKWARD_NO_INTERRUPT,
|
|
|
|
|
[JUMP_BACKWARD_NO_JIT] = _TAIL_CALL_JUMP_BACKWARD_NO_JIT,
|
|
|
|
|
[JUMP_FORWARD] = _TAIL_CALL_JUMP_FORWARD,
|
|
|
|
|
[LIST_APPEND] = _TAIL_CALL_LIST_APPEND,
|
|
|
|
|
[LIST_EXTEND] = _TAIL_CALL_LIST_EXTEND,
|
|
|
|
|
[LOAD_ATTR] = _TAIL_CALL_LOAD_ATTR,
|
|
|
|
|
[LOAD_ATTR_CLASS] = _TAIL_CALL_LOAD_ATTR_CLASS,
|
|
|
|
|
[LOAD_ATTR_CLASS_WITH_METACLASS_CHECK] = _TAIL_CALL_LOAD_ATTR_CLASS_WITH_METACLASS_CHECK,
|
|
|
|
|
[LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = _TAIL_CALL_LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN,
|
|
|
|
|
[LOAD_ATTR_INSTANCE_VALUE] = _TAIL_CALL_LOAD_ATTR_INSTANCE_VALUE,
|
|
|
|
|
[LOAD_ATTR_METHOD_LAZY_DICT] = _TAIL_CALL_LOAD_ATTR_METHOD_LAZY_DICT,
|
|
|
|
|
[LOAD_ATTR_METHOD_NO_DICT] = _TAIL_CALL_LOAD_ATTR_METHOD_NO_DICT,
|
|
|
|
|
[LOAD_ATTR_METHOD_WITH_VALUES] = _TAIL_CALL_LOAD_ATTR_METHOD_WITH_VALUES,
|
|
|
|
|
[LOAD_ATTR_MODULE] = _TAIL_CALL_LOAD_ATTR_MODULE,
|
|
|
|
|
[LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = _TAIL_CALL_LOAD_ATTR_NONDESCRIPTOR_NO_DICT,
|
|
|
|
|
[LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = _TAIL_CALL_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES,
|
|
|
|
|
[LOAD_ATTR_PROPERTY] = _TAIL_CALL_LOAD_ATTR_PROPERTY,
|
|
|
|
|
[LOAD_ATTR_SLOT] = _TAIL_CALL_LOAD_ATTR_SLOT,
|
|
|
|
|
[LOAD_ATTR_WITH_HINT] = _TAIL_CALL_LOAD_ATTR_WITH_HINT,
|
|
|
|
|
[LOAD_BUILD_CLASS] = _TAIL_CALL_LOAD_BUILD_CLASS,
|
|
|
|
|
[LOAD_COMMON_CONSTANT] = _TAIL_CALL_LOAD_COMMON_CONSTANT,
|
|
|
|
|
[LOAD_CONST] = _TAIL_CALL_LOAD_CONST,
|
|
|
|
|
[LOAD_DEREF] = _TAIL_CALL_LOAD_DEREF,
|
|
|
|
|
[LOAD_FAST] = _TAIL_CALL_LOAD_FAST,
|
|
|
|
|
[LOAD_FAST_AND_CLEAR] = _TAIL_CALL_LOAD_FAST_AND_CLEAR,
|
2025-04-01 10:18:42 -07:00
|
|
|
[LOAD_FAST_BORROW] = _TAIL_CALL_LOAD_FAST_BORROW,
|
|
|
|
|
[LOAD_FAST_BORROW_LOAD_FAST_BORROW] = _TAIL_CALL_LOAD_FAST_BORROW_LOAD_FAST_BORROW,
|
2025-02-06 23:21:57 +08:00
|
|
|
[LOAD_FAST_CHECK] = _TAIL_CALL_LOAD_FAST_CHECK,
|
|
|
|
|
[LOAD_FAST_LOAD_FAST] = _TAIL_CALL_LOAD_FAST_LOAD_FAST,
|
|
|
|
|
[LOAD_FROM_DICT_OR_DEREF] = _TAIL_CALL_LOAD_FROM_DICT_OR_DEREF,
|
|
|
|
|
[LOAD_FROM_DICT_OR_GLOBALS] = _TAIL_CALL_LOAD_FROM_DICT_OR_GLOBALS,
|
|
|
|
|
[LOAD_GLOBAL] = _TAIL_CALL_LOAD_GLOBAL,
|
|
|
|
|
[LOAD_GLOBAL_BUILTIN] = _TAIL_CALL_LOAD_GLOBAL_BUILTIN,
|
|
|
|
|
[LOAD_GLOBAL_MODULE] = _TAIL_CALL_LOAD_GLOBAL_MODULE,
|
|
|
|
|
[LOAD_LOCALS] = _TAIL_CALL_LOAD_LOCALS,
|
|
|
|
|
[LOAD_NAME] = _TAIL_CALL_LOAD_NAME,
|
|
|
|
|
[LOAD_SMALL_INT] = _TAIL_CALL_LOAD_SMALL_INT,
|
|
|
|
|
[LOAD_SPECIAL] = _TAIL_CALL_LOAD_SPECIAL,
|
|
|
|
|
[LOAD_SUPER_ATTR] = _TAIL_CALL_LOAD_SUPER_ATTR,
|
|
|
|
|
[LOAD_SUPER_ATTR_ATTR] = _TAIL_CALL_LOAD_SUPER_ATTR_ATTR,
|
|
|
|
|
[LOAD_SUPER_ATTR_METHOD] = _TAIL_CALL_LOAD_SUPER_ATTR_METHOD,
|
|
|
|
|
[MAKE_CELL] = _TAIL_CALL_MAKE_CELL,
|
|
|
|
|
[MAKE_FUNCTION] = _TAIL_CALL_MAKE_FUNCTION,
|
|
|
|
|
[MAP_ADD] = _TAIL_CALL_MAP_ADD,
|
|
|
|
|
[MATCH_CLASS] = _TAIL_CALL_MATCH_CLASS,
|
|
|
|
|
[MATCH_KEYS] = _TAIL_CALL_MATCH_KEYS,
|
|
|
|
|
[MATCH_MAPPING] = _TAIL_CALL_MATCH_MAPPING,
|
|
|
|
|
[MATCH_SEQUENCE] = _TAIL_CALL_MATCH_SEQUENCE,
|
|
|
|
|
[NOP] = _TAIL_CALL_NOP,
|
|
|
|
|
[NOT_TAKEN] = _TAIL_CALL_NOT_TAKEN,
|
|
|
|
|
[POP_EXCEPT] = _TAIL_CALL_POP_EXCEPT,
|
|
|
|
|
[POP_ITER] = _TAIL_CALL_POP_ITER,
|
|
|
|
|
[POP_JUMP_IF_FALSE] = _TAIL_CALL_POP_JUMP_IF_FALSE,
|
|
|
|
|
[POP_JUMP_IF_NONE] = _TAIL_CALL_POP_JUMP_IF_NONE,
|
|
|
|
|
[POP_JUMP_IF_NOT_NONE] = _TAIL_CALL_POP_JUMP_IF_NOT_NONE,
|
|
|
|
|
[POP_JUMP_IF_TRUE] = _TAIL_CALL_POP_JUMP_IF_TRUE,
|
|
|
|
|
[POP_TOP] = _TAIL_CALL_POP_TOP,
|
|
|
|
|
[PUSH_EXC_INFO] = _TAIL_CALL_PUSH_EXC_INFO,
|
|
|
|
|
[PUSH_NULL] = _TAIL_CALL_PUSH_NULL,
|
|
|
|
|
[RAISE_VARARGS] = _TAIL_CALL_RAISE_VARARGS,
|
|
|
|
|
[RERAISE] = _TAIL_CALL_RERAISE,
|
|
|
|
|
[RESERVED] = _TAIL_CALL_RESERVED,
|
|
|
|
|
[RESUME] = _TAIL_CALL_RESUME,
|
|
|
|
|
[RESUME_CHECK] = _TAIL_CALL_RESUME_CHECK,
|
|
|
|
|
[RETURN_GENERATOR] = _TAIL_CALL_RETURN_GENERATOR,
|
|
|
|
|
[RETURN_VALUE] = _TAIL_CALL_RETURN_VALUE,
|
|
|
|
|
[SEND] = _TAIL_CALL_SEND,
|
|
|
|
|
[SEND_GEN] = _TAIL_CALL_SEND_GEN,
|
|
|
|
|
[SETUP_ANNOTATIONS] = _TAIL_CALL_SETUP_ANNOTATIONS,
|
|
|
|
|
[SET_ADD] = _TAIL_CALL_SET_ADD,
|
|
|
|
|
[SET_FUNCTION_ATTRIBUTE] = _TAIL_CALL_SET_FUNCTION_ATTRIBUTE,
|
|
|
|
|
[SET_UPDATE] = _TAIL_CALL_SET_UPDATE,
|
|
|
|
|
[STORE_ATTR] = _TAIL_CALL_STORE_ATTR,
|
|
|
|
|
[STORE_ATTR_INSTANCE_VALUE] = _TAIL_CALL_STORE_ATTR_INSTANCE_VALUE,
|
|
|
|
|
[STORE_ATTR_SLOT] = _TAIL_CALL_STORE_ATTR_SLOT,
|
|
|
|
|
[STORE_ATTR_WITH_HINT] = _TAIL_CALL_STORE_ATTR_WITH_HINT,
|
|
|
|
|
[STORE_DEREF] = _TAIL_CALL_STORE_DEREF,
|
|
|
|
|
[STORE_FAST] = _TAIL_CALL_STORE_FAST,
|
|
|
|
|
[STORE_FAST_LOAD_FAST] = _TAIL_CALL_STORE_FAST_LOAD_FAST,
|
|
|
|
|
[STORE_FAST_STORE_FAST] = _TAIL_CALL_STORE_FAST_STORE_FAST,
|
|
|
|
|
[STORE_GLOBAL] = _TAIL_CALL_STORE_GLOBAL,
|
|
|
|
|
[STORE_NAME] = _TAIL_CALL_STORE_NAME,
|
|
|
|
|
[STORE_SLICE] = _TAIL_CALL_STORE_SLICE,
|
|
|
|
|
[STORE_SUBSCR] = _TAIL_CALL_STORE_SUBSCR,
|
|
|
|
|
[STORE_SUBSCR_DICT] = _TAIL_CALL_STORE_SUBSCR_DICT,
|
|
|
|
|
[STORE_SUBSCR_LIST_INT] = _TAIL_CALL_STORE_SUBSCR_LIST_INT,
|
|
|
|
|
[SWAP] = _TAIL_CALL_SWAP,
|
|
|
|
|
[TO_BOOL] = _TAIL_CALL_TO_BOOL,
|
|
|
|
|
[TO_BOOL_ALWAYS_TRUE] = _TAIL_CALL_TO_BOOL_ALWAYS_TRUE,
|
|
|
|
|
[TO_BOOL_BOOL] = _TAIL_CALL_TO_BOOL_BOOL,
|
|
|
|
|
[TO_BOOL_INT] = _TAIL_CALL_TO_BOOL_INT,
|
|
|
|
|
[TO_BOOL_LIST] = _TAIL_CALL_TO_BOOL_LIST,
|
|
|
|
|
[TO_BOOL_NONE] = _TAIL_CALL_TO_BOOL_NONE,
|
|
|
|
|
[TO_BOOL_STR] = _TAIL_CALL_TO_BOOL_STR,
|
2025-11-18 13:31:48 +00:00
|
|
|
[TRACE_RECORD] = _TAIL_CALL_TRACE_RECORD,
|
2025-02-06 23:21:57 +08:00
|
|
|
[UNARY_INVERT] = _TAIL_CALL_UNARY_INVERT,
|
|
|
|
|
[UNARY_NEGATIVE] = _TAIL_CALL_UNARY_NEGATIVE,
|
|
|
|
|
[UNARY_NOT] = _TAIL_CALL_UNARY_NOT,
|
|
|
|
|
[UNPACK_EX] = _TAIL_CALL_UNPACK_EX,
|
|
|
|
|
[UNPACK_SEQUENCE] = _TAIL_CALL_UNPACK_SEQUENCE,
|
|
|
|
|
[UNPACK_SEQUENCE_LIST] = _TAIL_CALL_UNPACK_SEQUENCE_LIST,
|
|
|
|
|
[UNPACK_SEQUENCE_TUPLE] = _TAIL_CALL_UNPACK_SEQUENCE_TUPLE,
|
|
|
|
|
[UNPACK_SEQUENCE_TWO_TUPLE] = _TAIL_CALL_UNPACK_SEQUENCE_TWO_TUPLE,
|
|
|
|
|
[WITH_EXCEPT_START] = _TAIL_CALL_WITH_EXCEPT_START,
|
|
|
|
|
[YIELD_VALUE] = _TAIL_CALL_YIELD_VALUE,
|
|
|
|
|
[121] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[122] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[123] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[124] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[125] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[126] = _TAIL_CALL_UNKNOWN_OPCODE,
|
gh-139109: A new tracing JIT compiler frontend for CPython (GH-140310)
This PR changes the current JIT model from trace projection to trace recording. Benchmarking: better pyperformance (about 1.7% overall) geomean versus current https://raw.githubusercontent.com/facebookexperimental/free-threading-benchmarking/refs/heads/main/results/bm-20251108-3.15.0a1%2B-7e2bc1d-JIT/bm-20251108-vultr-x86_64-Fidget%252dSpinner-tracing_jit-3.15.0a1%2B-7e2bc1d-vs-base.svg, 100% faster Richards on the most improved benchmark versus the current JIT. Slowdown of about 10-15% on the worst benchmark versus the current JIT. **Note: the fastest version isn't the one merged, as it relies on fixing bugs in the specializing interpreter, which is left to another PR**. The speedup in the merged version is about 1.1%. https://raw.githubusercontent.com/facebookexperimental/free-threading-benchmarking/refs/heads/main/results/bm-20251112-3.15.0a1%2B-f8a764a-JIT/bm-20251112-vultr-x86_64-Fidget%252dSpinner-tracing_jit-3.15.0a1%2B-f8a764a-vs-base.svg
Stats: 50% more uops executed, 30% more traces entered the last time we ran them. It also suggests our trace lengths for a real trace recording JIT are too short, as a lot of trace too long aborts https://github.com/facebookexperimental/free-threading-benchmarking/blob/main/results/bm-20251023-3.15.0a1%2B-eb73378-CLANG%2CJIT/bm-20251023-vultr-x86_64-Fidget%252dSpinner-tracing_jit-3.15.0a1%2B-eb73378-pystats-vs-base.md .
This new JIT frontend is already able to record/execute significantly more instructions than the previous JIT frontend. In this PR, we are now able to record through custom dunders, simple object creation, generators, etc. None of these were done by the old JIT frontend. Some custom dunders uops were discovered to be broken as part of this work gh-140277
The optimizer stack space check is disabled, as it's no longer valid to deal with underflow.
Pros:
* Ignoring the generated tracer code as it's automatically created, this is only additional 1k lines of code. The maintenance burden is handled by the DSL and code generator.
* `optimizer.c` is now significantly simpler, as we don't have to do strange things to recover the bytecode from a trace.
* The new JIT frontend is able to handle a lot more control-flow than the old one.
* Tracing is very low overhead. We use the tail calling interpreter/computed goto interpreter to switch between tracing mode and non-tracing mode. I call this mechanism dual dispatch, as we have two dispatch tables dispatching to each other. Specialization is still enabled while tracing.
* Better handling of polymorphism. We leverage the specializing interpreter for this.
Cons:
* (For now) requires tail calling interpreter or computed gotos. This means no Windows JIT for now :(. Not to fret, tail calling is coming soon to Windows though https://github.com/python/cpython/pull/139962
Design:
* After each instruction, the `record_previous_inst` function/label is executed. This does as the name suggests.
* The tracing interpreter lowers bytecode to uops directly so that it can obtain "fresh" values at the point of lowering.
* The tracing version behaves nearly identical to the normal interpreter, in fact it even has specialization! This allows it to run without much of a slowdown when tracing. The actual cost of tracing is only a function call and writes to memory.
* The tracing interpreter uses the specializing interpreter's deopt to naturally form the side exit chains. This allows it to side exit chain effectively, without repeating much code. We force a re-specializing when tracing a deopt.
* The tracing interpreter can even handle goto errors/exceptions, but I chose to disable them for now as it's not tested.
* Because we do not share interpreter dispatch, there is should be no significant slowdown to the original specializing interpreter on tailcall and computed got with JIT disabled. With JIT enabled, there might be a slowdown in the form of the JIT trying to trace.
* Things that could have dynamic instruction pointer effects are guarded on. The guard deopts to a new instruction --- `_DYNAMIC_EXIT`.
2025-11-14 02:08:32 +08:00
|
|
|
[127] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[210] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[211] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[212] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[213] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[214] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[215] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[216] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[217] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[218] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[219] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[220] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[221] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[222] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[223] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[224] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[225] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[226] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[227] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[228] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[229] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[230] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[231] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[232] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
};
|
|
|
|
|
static py_tail_call_funcptr instruction_funcptr_tracing_table[256] = {
|
2025-11-18 13:31:48 +00:00
|
|
|
[BINARY_OP] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[BINARY_OP_ADD_FLOAT] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[BINARY_OP_ADD_INT] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[BINARY_OP_ADD_UNICODE] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[BINARY_OP_EXTEND] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[BINARY_OP_INPLACE_ADD_UNICODE] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[BINARY_OP_MULTIPLY_FLOAT] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[BINARY_OP_MULTIPLY_INT] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[BINARY_OP_SUBSCR_DICT] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[BINARY_OP_SUBSCR_GETITEM] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[BINARY_OP_SUBSCR_LIST_INT] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[BINARY_OP_SUBSCR_LIST_SLICE] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[BINARY_OP_SUBSCR_STR_INT] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[BINARY_OP_SUBSCR_TUPLE_INT] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[BINARY_OP_SUBTRACT_FLOAT] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[BINARY_OP_SUBTRACT_INT] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[BINARY_SLICE] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[BUILD_INTERPOLATION] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[BUILD_LIST] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[BUILD_MAP] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[BUILD_SET] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[BUILD_SLICE] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[BUILD_STRING] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[BUILD_TEMPLATE] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[BUILD_TUPLE] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[CACHE] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[CALL] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[CALL_ALLOC_AND_ENTER_INIT] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[CALL_BOUND_METHOD_EXACT_ARGS] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[CALL_BOUND_METHOD_GENERAL] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[CALL_BUILTIN_CLASS] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[CALL_BUILTIN_FAST] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[CALL_BUILTIN_FAST_WITH_KEYWORDS] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[CALL_BUILTIN_O] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[CALL_FUNCTION_EX] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[CALL_INTRINSIC_1] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[CALL_INTRINSIC_2] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[CALL_ISINSTANCE] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[CALL_KW] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[CALL_KW_BOUND_METHOD] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[CALL_KW_NON_PY] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[CALL_KW_PY] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[CALL_LEN] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[CALL_LIST_APPEND] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[CALL_METHOD_DESCRIPTOR_FAST] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[CALL_METHOD_DESCRIPTOR_NOARGS] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[CALL_METHOD_DESCRIPTOR_O] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[CALL_NON_PY_GENERAL] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[CALL_PY_EXACT_ARGS] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[CALL_PY_GENERAL] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[CALL_STR_1] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[CALL_TUPLE_1] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[CALL_TYPE_1] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[CHECK_EG_MATCH] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[CHECK_EXC_MATCH] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[CLEANUP_THROW] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[COMPARE_OP] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[COMPARE_OP_FLOAT] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[COMPARE_OP_INT] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[COMPARE_OP_STR] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[CONTAINS_OP] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[CONTAINS_OP_DICT] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[CONTAINS_OP_SET] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[CONVERT_VALUE] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[COPY] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[COPY_FREE_VARS] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[DELETE_ATTR] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[DELETE_DEREF] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[DELETE_FAST] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[DELETE_GLOBAL] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[DELETE_NAME] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[DELETE_SUBSCR] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[DICT_MERGE] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[DICT_UPDATE] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[END_ASYNC_FOR] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[END_FOR] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[END_SEND] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[ENTER_EXECUTOR] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[EXIT_INIT_CHECK] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[EXTENDED_ARG] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[FORMAT_SIMPLE] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[FORMAT_WITH_SPEC] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[FOR_ITER] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[FOR_ITER_GEN] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[FOR_ITER_LIST] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[FOR_ITER_RANGE] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[FOR_ITER_TUPLE] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[GET_AITER] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[GET_ANEXT] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[GET_AWAITABLE] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[GET_ITER] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[GET_LEN] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[GET_YIELD_FROM_ITER] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[IMPORT_FROM] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[IMPORT_NAME] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[INSTRUMENTED_CALL] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[INSTRUMENTED_CALL_FUNCTION_EX] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[INSTRUMENTED_CALL_KW] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[INSTRUMENTED_END_ASYNC_FOR] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[INSTRUMENTED_END_FOR] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[INSTRUMENTED_END_SEND] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[INSTRUMENTED_FOR_ITER] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[INSTRUMENTED_INSTRUCTION] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[INSTRUMENTED_JUMP_BACKWARD] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[INSTRUMENTED_JUMP_FORWARD] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[INSTRUMENTED_LINE] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[INSTRUMENTED_LOAD_SUPER_ATTR] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[INSTRUMENTED_NOT_TAKEN] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[INSTRUMENTED_POP_ITER] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[INSTRUMENTED_POP_JUMP_IF_FALSE] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[INSTRUMENTED_POP_JUMP_IF_NONE] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[INSTRUMENTED_POP_JUMP_IF_TRUE] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[INSTRUMENTED_RESUME] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[INSTRUMENTED_RETURN_VALUE] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[INSTRUMENTED_YIELD_VALUE] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[INTERPRETER_EXIT] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[IS_OP] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[JUMP_BACKWARD] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[JUMP_BACKWARD_JIT] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[JUMP_BACKWARD_NO_INTERRUPT] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[JUMP_BACKWARD_NO_JIT] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[JUMP_FORWARD] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[LIST_APPEND] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[LIST_EXTEND] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[LOAD_ATTR] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[LOAD_ATTR_CLASS] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[LOAD_ATTR_CLASS_WITH_METACLASS_CHECK] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[LOAD_ATTR_INSTANCE_VALUE] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[LOAD_ATTR_METHOD_LAZY_DICT] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[LOAD_ATTR_METHOD_NO_DICT] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[LOAD_ATTR_METHOD_WITH_VALUES] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[LOAD_ATTR_MODULE] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[LOAD_ATTR_PROPERTY] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[LOAD_ATTR_SLOT] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[LOAD_ATTR_WITH_HINT] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[LOAD_BUILD_CLASS] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[LOAD_COMMON_CONSTANT] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[LOAD_CONST] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[LOAD_DEREF] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[LOAD_FAST] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[LOAD_FAST_AND_CLEAR] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[LOAD_FAST_BORROW] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[LOAD_FAST_BORROW_LOAD_FAST_BORROW] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[LOAD_FAST_CHECK] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[LOAD_FAST_LOAD_FAST] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[LOAD_FROM_DICT_OR_DEREF] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[LOAD_FROM_DICT_OR_GLOBALS] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[LOAD_GLOBAL] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[LOAD_GLOBAL_BUILTIN] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[LOAD_GLOBAL_MODULE] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[LOAD_LOCALS] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[LOAD_NAME] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[LOAD_SMALL_INT] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[LOAD_SPECIAL] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[LOAD_SUPER_ATTR] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[LOAD_SUPER_ATTR_ATTR] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[LOAD_SUPER_ATTR_METHOD] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[MAKE_CELL] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[MAKE_FUNCTION] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[MAP_ADD] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[MATCH_CLASS] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[MATCH_KEYS] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[MATCH_MAPPING] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[MATCH_SEQUENCE] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[NOP] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[NOT_TAKEN] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[POP_EXCEPT] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[POP_ITER] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[POP_JUMP_IF_FALSE] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[POP_JUMP_IF_NONE] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[POP_JUMP_IF_NOT_NONE] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[POP_JUMP_IF_TRUE] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[POP_TOP] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[PUSH_EXC_INFO] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[PUSH_NULL] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[RAISE_VARARGS] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[RERAISE] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[RESERVED] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[RESUME] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[RESUME_CHECK] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[RETURN_GENERATOR] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[RETURN_VALUE] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[SEND] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[SEND_GEN] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[SETUP_ANNOTATIONS] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[SET_ADD] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[SET_FUNCTION_ATTRIBUTE] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[SET_UPDATE] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[STORE_ATTR] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[STORE_ATTR_INSTANCE_VALUE] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[STORE_ATTR_SLOT] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[STORE_ATTR_WITH_HINT] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[STORE_DEREF] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[STORE_FAST] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[STORE_FAST_LOAD_FAST] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[STORE_FAST_STORE_FAST] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[STORE_GLOBAL] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[STORE_NAME] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[STORE_SLICE] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[STORE_SUBSCR] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[STORE_SUBSCR_DICT] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[STORE_SUBSCR_LIST_INT] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[SWAP] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[TO_BOOL] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[TO_BOOL_ALWAYS_TRUE] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[TO_BOOL_BOOL] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[TO_BOOL_INT] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[TO_BOOL_LIST] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[TO_BOOL_NONE] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[TO_BOOL_STR] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[TRACE_RECORD] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[UNARY_INVERT] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[UNARY_NEGATIVE] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[UNARY_NOT] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[UNPACK_EX] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[UNPACK_SEQUENCE] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[UNPACK_SEQUENCE_LIST] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[UNPACK_SEQUENCE_TUPLE] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[UNPACK_SEQUENCE_TWO_TUPLE] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[WITH_EXCEPT_START] = _TAIL_CALL_TRACE_RECORD,
|
|
|
|
|
[YIELD_VALUE] = _TAIL_CALL_TRACE_RECORD,
|
gh-139109: A new tracing JIT compiler frontend for CPython (GH-140310)
This PR changes the current JIT model from trace projection to trace recording. Benchmarking: better pyperformance (about 1.7% overall) geomean versus current https://raw.githubusercontent.com/facebookexperimental/free-threading-benchmarking/refs/heads/main/results/bm-20251108-3.15.0a1%2B-7e2bc1d-JIT/bm-20251108-vultr-x86_64-Fidget%252dSpinner-tracing_jit-3.15.0a1%2B-7e2bc1d-vs-base.svg, 100% faster Richards on the most improved benchmark versus the current JIT. Slowdown of about 10-15% on the worst benchmark versus the current JIT. **Note: the fastest version isn't the one merged, as it relies on fixing bugs in the specializing interpreter, which is left to another PR**. The speedup in the merged version is about 1.1%. https://raw.githubusercontent.com/facebookexperimental/free-threading-benchmarking/refs/heads/main/results/bm-20251112-3.15.0a1%2B-f8a764a-JIT/bm-20251112-vultr-x86_64-Fidget%252dSpinner-tracing_jit-3.15.0a1%2B-f8a764a-vs-base.svg
Stats: 50% more uops executed, 30% more traces entered the last time we ran them. It also suggests our trace lengths for a real trace recording JIT are too short, as a lot of trace too long aborts https://github.com/facebookexperimental/free-threading-benchmarking/blob/main/results/bm-20251023-3.15.0a1%2B-eb73378-CLANG%2CJIT/bm-20251023-vultr-x86_64-Fidget%252dSpinner-tracing_jit-3.15.0a1%2B-eb73378-pystats-vs-base.md .
This new JIT frontend is already able to record/execute significantly more instructions than the previous JIT frontend. In this PR, we are now able to record through custom dunders, simple object creation, generators, etc. None of these were done by the old JIT frontend. Some custom dunders uops were discovered to be broken as part of this work gh-140277
The optimizer stack space check is disabled, as it's no longer valid to deal with underflow.
Pros:
* Ignoring the generated tracer code as it's automatically created, this is only additional 1k lines of code. The maintenance burden is handled by the DSL and code generator.
* `optimizer.c` is now significantly simpler, as we don't have to do strange things to recover the bytecode from a trace.
* The new JIT frontend is able to handle a lot more control-flow than the old one.
* Tracing is very low overhead. We use the tail calling interpreter/computed goto interpreter to switch between tracing mode and non-tracing mode. I call this mechanism dual dispatch, as we have two dispatch tables dispatching to each other. Specialization is still enabled while tracing.
* Better handling of polymorphism. We leverage the specializing interpreter for this.
Cons:
* (For now) requires tail calling interpreter or computed gotos. This means no Windows JIT for now :(. Not to fret, tail calling is coming soon to Windows though https://github.com/python/cpython/pull/139962
Design:
* After each instruction, the `record_previous_inst` function/label is executed. This does as the name suggests.
* The tracing interpreter lowers bytecode to uops directly so that it can obtain "fresh" values at the point of lowering.
* The tracing version behaves nearly identical to the normal interpreter, in fact it even has specialization! This allows it to run without much of a slowdown when tracing. The actual cost of tracing is only a function call and writes to memory.
* The tracing interpreter uses the specializing interpreter's deopt to naturally form the side exit chains. This allows it to side exit chain effectively, without repeating much code. We force a re-specializing when tracing a deopt.
* The tracing interpreter can even handle goto errors/exceptions, but I chose to disable them for now as it's not tested.
* Because we do not share interpreter dispatch, there is should be no significant slowdown to the original specializing interpreter on tailcall and computed got with JIT disabled. With JIT enabled, there might be a slowdown in the form of the JIT trying to trace.
* Things that could have dynamic instruction pointer effects are guarded on. The guard deopts to a new instruction --- `_DYNAMIC_EXIT`.
2025-11-14 02:08:32 +08:00
|
|
|
[121] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[122] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[123] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[124] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[125] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[126] = _TAIL_CALL_UNKNOWN_OPCODE,
|
2025-02-06 23:21:57 +08:00
|
|
|
[127] = _TAIL_CALL_UNKNOWN_OPCODE,
|
2025-05-20 11:24:11 -04:00
|
|
|
[210] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[211] = _TAIL_CALL_UNKNOWN_OPCODE,
|
2025-03-06 03:59:36 -05:00
|
|
|
[212] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[213] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[214] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[215] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[216] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[217] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[218] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[219] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[220] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[221] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[222] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[223] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[224] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[225] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[226] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[227] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[228] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[229] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[230] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
[231] = _TAIL_CALL_UNKNOWN_OPCODE,
|
2025-02-06 23:21:57 +08:00
|
|
|
[232] = _TAIL_CALL_UNKNOWN_OPCODE,
|
|
|
|
|
};
|
2025-09-18 13:33:07 +01:00
|
|
|
#endif /* _Py_TAIL_CALL_INTERP */
|