From 3eff0b10a54e6aaa404a9fa560116a17c9625cf7 Mon Sep 17 00:00:00 2001 From: Brett Simmers Date: Tue, 27 Feb 2024 11:23:50 -0800 Subject: [PATCH 1/5] Disable the specializing adaptive interpreter in free-threaded builds --- Include/internal/pycore_code.h | 5 +++ Lib/test/test_generated_cases.py | 8 ++++ Python/ceval_macros.h | 8 ++++ Python/generated_cases.c.h | 55 ++++++++++++++++++++++++ Tools/cases_generator/tier1_generator.py | 5 +++ 5 files changed, 81 insertions(+) diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index 85536162132072..a4e64825743ada 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -245,7 +245,12 @@ extern int _PyLineTable_PreviousAddressRange(PyCodeAddressRange *range); /** API for executors */ extern void _PyCode_Clear_Executors(PyCodeObject *code); +#ifdef Py_GIL_DISABLED +// gh-115999 tracks progress on addressing this. +#define ENABLE_SPECIALIZATION 0 +#else #define ENABLE_SPECIALIZATION 1 +#endif /* Specialization functions */ diff --git a/Lib/test/test_generated_cases.py b/Lib/test/test_generated_cases.py index 18bf8ab29148c4..cd91cefd2ff646 100644 --- a/Lib/test/test_generated_cases.py +++ b/Lib/test/test_generated_cases.py @@ -350,12 +350,15 @@ def test_cache_effect(self): output = """ TARGET(OP) { _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + (void)this_instr; next_instr += 4; INSTRUCTION_STATS(OP); PyObject *value; value = stack_pointer[-1]; uint16_t counter = read_u16(&this_instr[1].cache); + (void)counter; uint32_t extra = read_u32(&this_instr[2].cache); + (void)extra; stack_pointer += -1; DISPATCH(); } @@ -399,6 +402,7 @@ def test_macro_instruction(self): INSTRUCTION_STATS(OP); PREDICTED(OP); _Py_CODEUNIT *this_instr = next_instr - 6; + (void)this_instr; PyObject *right; PyObject *left; PyObject *arg2; @@ -408,6 +412,7 @@ def test_macro_instruction(self): left = stack_pointer[-2]; { uint16_t counter = read_u16(&this_instr[1].cache); + (void)counter; op1(left, right); } /* Skip 2 cache entries */ @@ -415,6 +420,7 @@ def test_macro_instruction(self): arg2 = stack_pointer[-3]; { uint32_t extra = read_u32(&this_instr[4].cache); + (void)extra; res = op2(arg2, left, right); } stack_pointer[-3] = res; @@ -424,6 +430,7 @@ def test_macro_instruction(self): TARGET(OP1) { _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + (void)this_instr; next_instr += 2; INSTRUCTION_STATS(OP1); PyObject *right; @@ -431,6 +438,7 @@ def test_macro_instruction(self): right = stack_pointer[-1]; left = stack_pointer[-2]; uint16_t counter = read_u16(&this_instr[1].cache); + (void)counter; op1(left, right); DISPATCH(); } diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h index 085199416c1523..c0699a4644f5a5 100644 --- a/Python/ceval_macros.h +++ b/Python/ceval_macros.h @@ -296,11 +296,19 @@ GETITEM(PyObject *v, Py_ssize_t i) { #define ADAPTIVE_COUNTER_IS_MAX(COUNTER) \ (((COUNTER) >> ADAPTIVE_BACKOFF_BITS) == ((1 << MAX_BACKOFF_VALUE) - 1)) +#ifdef Py_GIL_DISABLED +#define DECREMENT_ADAPTIVE_COUNTER(COUNTER) \ + do { \ + /* gh-115999 tracks progress on addressing this. */ \ + Py_FatalError("The adaptive interpreter is not thread-safe"); \ + } while (0); +#else #define DECREMENT_ADAPTIVE_COUNTER(COUNTER) \ do { \ assert(!ADAPTIVE_COUNTER_IS_ZERO((COUNTER))); \ (COUNTER) -= (1 << ADAPTIVE_BACKOFF_BITS); \ } while (0); +#endif #define INCREMENT_ADAPTIVE_COUNTER(COUNTER) \ do { \ diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 8b90e448a7b8fa..ae953d1dfcc302 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -104,6 +104,7 @@ INSTRUCTION_STATS(BINARY_OP); PREDICTED(BINARY_OP); _Py_CODEUNIT *this_instr = next_instr - 2; + (void)this_instr; PyObject *rhs; PyObject *lhs; PyObject *res; @@ -112,6 +113,7 @@ lhs = stack_pointer[-2]; { uint16_t counter = read_u16(&this_instr[1].cache); + (void)counter; #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { next_instr = this_instr; @@ -419,6 +421,7 @@ INSTRUCTION_STATS(BINARY_SUBSCR); PREDICTED(BINARY_SUBSCR); _Py_CODEUNIT *this_instr = next_instr - 2; + (void)this_instr; PyObject *sub; PyObject *container; PyObject *res; @@ -427,6 +430,7 @@ container = stack_pointer[-2]; { uint16_t counter = read_u16(&this_instr[1].cache); + (void)counter; #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { next_instr = this_instr; @@ -747,6 +751,7 @@ INSTRUCTION_STATS(CALL); PREDICTED(CALL); _Py_CODEUNIT *this_instr = next_instr - 4; + (void)this_instr; PyObject **args; PyObject *self_or_null; PyObject *callable; @@ -757,6 +762,7 @@ callable = stack_pointer[-2 - oparg]; { uint16_t counter = read_u16(&this_instr[1].cache); + (void)counter; #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { next_instr = this_instr; @@ -1176,6 +1182,7 @@ INSTRUCTION_STATS(CALL_FUNCTION_EX); PREDICTED(CALL_FUNCTION_EX); _Py_CODEUNIT *this_instr = next_instr - 1; + (void)this_instr; PyObject *kwargs = NULL; PyObject *callargs; PyObject *func; @@ -1336,6 +1343,7 @@ INSTRUCTION_STATS(CALL_KW); PREDICTED(CALL_KW); _Py_CODEUNIT *this_instr = next_instr - 1; + (void)this_instr; PyObject *kwnames; PyObject **args; PyObject *self_or_null; @@ -1939,6 +1947,7 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 1; INSTRUCTION_STATS(CLEANUP_THROW); + (void)this_instr; PyObject *exc_value; PyObject *last_sent_val; PyObject *sub_iter; @@ -1973,6 +1982,7 @@ INSTRUCTION_STATS(COMPARE_OP); PREDICTED(COMPARE_OP); _Py_CODEUNIT *this_instr = next_instr - 2; + (void)this_instr; PyObject *right; PyObject *left; PyObject *res; @@ -1981,6 +1991,7 @@ left = stack_pointer[-2]; { uint16_t counter = read_u16(&this_instr[1].cache); + (void)counter; #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { next_instr = this_instr; @@ -2326,6 +2337,7 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 1; INSTRUCTION_STATS(END_ASYNC_FOR); + (void)this_instr; PyObject *exc; PyObject *awaitable; exc = stack_pointer[-1]; @@ -2460,12 +2472,14 @@ INSTRUCTION_STATS(FOR_ITER); PREDICTED(FOR_ITER); _Py_CODEUNIT *this_instr = next_instr - 2; + (void)this_instr; PyObject *iter; PyObject *next; // _SPECIALIZE_FOR_ITER iter = stack_pointer[-1]; { uint16_t counter = read_u16(&this_instr[1].cache); + (void)counter; #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { next_instr = this_instr; @@ -2886,6 +2900,7 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 4; INSTRUCTION_STATS(INSTRUMENTED_CALL); + (void)this_instr; /* Skip 3 cache entries */ int is_meth = PEEK(oparg + 1) != NULL; int total_args = oparg + is_meth; @@ -2911,6 +2926,7 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 1; INSTRUCTION_STATS(INSTRUMENTED_CALL_KW); + (void)this_instr; int is_meth = PEEK(oparg + 2) != NULL; int total_args = oparg + is_meth; PyObject *function = PEEK(oparg + 3); @@ -2927,6 +2943,7 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 1; INSTRUCTION_STATS(INSTRUMENTED_END_FOR); + (void)this_instr; PyObject *value; PyObject *receiver; value = stack_pointer[-1]; @@ -2949,6 +2966,7 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 1; INSTRUCTION_STATS(INSTRUMENTED_END_SEND); + (void)this_instr; PyObject *value; PyObject *receiver; value = stack_pointer[-1]; @@ -2970,6 +2988,7 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 2; INSTRUCTION_STATS(INSTRUMENTED_FOR_ITER); + (void)this_instr; /* Skip 1 cache entry */ _Py_CODEUNIT *target; PyObject *iter = TOP(); @@ -3002,6 +3021,7 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 1; INSTRUCTION_STATS(INSTRUMENTED_INSTRUCTION); + (void)this_instr; int next_opcode = _Py_call_instrumentation_instruction( tstate, frame, this_instr); if (next_opcode < 0) goto error; @@ -3018,6 +3038,7 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 2; INSTRUCTION_STATS(INSTRUMENTED_JUMP_BACKWARD); + (void)this_instr; /* Skip 1 cache entry */ CHECK_EVAL_BREAKER(); INSTRUMENTED_JUMP(this_instr, next_instr - oparg, PY_MONITORING_EVENT_JUMP); @@ -3028,6 +3049,7 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 1; INSTRUCTION_STATS(INSTRUMENTED_JUMP_FORWARD); + (void)this_instr; INSTRUMENTED_JUMP(this_instr, next_instr + oparg, PY_MONITORING_EVENT_JUMP); DISPATCH(); } @@ -3036,6 +3058,7 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 2; INSTRUCTION_STATS(INSTRUMENTED_LOAD_SUPER_ATTR); + (void)this_instr; /* Skip 1 cache entry */ // cancel out the decrement that will happen in LOAD_SUPER_ATTR; we // don't want to specialize instrumented instructions @@ -3047,6 +3070,7 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 2; INSTRUCTION_STATS(INSTRUMENTED_POP_JUMP_IF_FALSE); + (void)this_instr; /* Skip 1 cache entry */ PyObject *cond = POP(); assert(PyBool_Check(cond)); @@ -3063,6 +3087,7 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 2; INSTRUCTION_STATS(INSTRUMENTED_POP_JUMP_IF_NONE); + (void)this_instr; /* Skip 1 cache entry */ PyObject *value = POP(); int flag = Py_IsNone(value); @@ -3085,6 +3110,7 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 2; INSTRUCTION_STATS(INSTRUMENTED_POP_JUMP_IF_NOT_NONE); + (void)this_instr; /* Skip 1 cache entry */ PyObject *value = POP(); int offset; @@ -3107,6 +3133,7 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 2; INSTRUCTION_STATS(INSTRUMENTED_POP_JUMP_IF_TRUE); + (void)this_instr; /* Skip 1 cache entry */ PyObject *cond = POP(); assert(PyBool_Check(cond)); @@ -3123,6 +3150,7 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 1; INSTRUCTION_STATS(INSTRUMENTED_RESUME); + (void)this_instr; uintptr_t global_version = _Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & ~_PY_EVAL_EVENTS_MASK; uintptr_t code_version = _PyFrame_GetCode(frame)->_co_instrumentation_version; if (code_version != global_version) { @@ -3153,6 +3181,7 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 1; INSTRUCTION_STATS(INSTRUMENTED_RETURN_CONST); + (void)this_instr; PyObject *retval = GETITEM(FRAME_CO_CONSTS, oparg); int err = _Py_call_instrumentation_arg( tstate, PY_MONITORING_EVENT_PY_RETURN, @@ -3176,6 +3205,7 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 1; INSTRUCTION_STATS(INSTRUMENTED_RETURN_VALUE); + (void)this_instr; PyObject *retval; retval = stack_pointer[-1]; int err = _Py_call_instrumentation_arg( @@ -3200,6 +3230,7 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 1; INSTRUCTION_STATS(INSTRUMENTED_YIELD_VALUE); + (void)this_instr; PyObject *retval; retval = stack_pointer[-1]; assert(frame != &entry_frame); @@ -3263,6 +3294,7 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 2; INSTRUCTION_STATS(JUMP_BACKWARD); + (void)this_instr; /* Skip 1 cache entry */ CHECK_EVAL_BREAKER(); assert(oparg <= INSTR_OFFSET()); @@ -3387,6 +3419,7 @@ INSTRUCTION_STATS(LOAD_ATTR); PREDICTED(LOAD_ATTR); _Py_CODEUNIT *this_instr = next_instr - 10; + (void)this_instr; PyObject *owner; PyObject *attr; PyObject *self_or_null = NULL; @@ -3394,6 +3427,7 @@ owner = stack_pointer[-1]; { uint16_t counter = read_u16(&this_instr[1].cache); + (void)counter; #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1); @@ -4083,11 +4117,13 @@ INSTRUCTION_STATS(LOAD_GLOBAL); PREDICTED(LOAD_GLOBAL); _Py_CODEUNIT *this_instr = next_instr - 5; + (void)this_instr; PyObject *res; PyObject *null = NULL; // _SPECIALIZE_LOAD_GLOBAL { uint16_t counter = read_u16(&this_instr[1].cache); + (void)counter; #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1); @@ -4279,6 +4315,7 @@ INSTRUCTION_STATS(LOAD_SUPER_ATTR); PREDICTED(LOAD_SUPER_ATTR); _Py_CODEUNIT *this_instr = next_instr - 2; + (void)this_instr; PyObject *class; PyObject *global_super; PyObject *self; @@ -4289,6 +4326,7 @@ global_super = stack_pointer[-3]; { uint16_t counter = read_u16(&this_instr[1].cache); + (void)counter; #if ENABLE_SPECIALIZATION int load_method = oparg & 1; if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { @@ -4567,6 +4605,7 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 2; INSTRUCTION_STATS(POP_JUMP_IF_FALSE); + (void)this_instr; PyObject *cond; /* Skip 1 cache entry */ cond = stack_pointer[-1]; @@ -4584,6 +4623,7 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 2; INSTRUCTION_STATS(POP_JUMP_IF_NONE); + (void)this_instr; PyObject *value; PyObject *b; PyObject *cond; @@ -4617,6 +4657,7 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 2; INSTRUCTION_STATS(POP_JUMP_IF_NOT_NONE); + (void)this_instr; PyObject *value; PyObject *b; PyObject *cond; @@ -4650,6 +4691,7 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 2; INSTRUCTION_STATS(POP_JUMP_IF_TRUE); + (void)this_instr; PyObject *cond; /* Skip 1 cache entry */ cond = stack_pointer[-1]; @@ -4711,6 +4753,7 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 1; INSTRUCTION_STATS(RAISE_VARARGS); + (void)this_instr; PyObject **args; args = &stack_pointer[-oparg]; PyObject *cause = NULL, *exc = NULL; @@ -4740,6 +4783,7 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 1; INSTRUCTION_STATS(RERAISE); + (void)this_instr; PyObject *exc; PyObject **values; exc = stack_pointer[-1]; @@ -4779,6 +4823,7 @@ INSTRUCTION_STATS(RESUME); PREDICTED(RESUME); _Py_CODEUNIT *this_instr = next_instr - 1; + (void)this_instr; assert(frame == tstate->current_frame); uintptr_t global_version = _Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & @@ -4915,6 +4960,7 @@ INSTRUCTION_STATS(SEND); PREDICTED(SEND); _Py_CODEUNIT *this_instr = next_instr - 2; + (void)this_instr; PyObject *receiver; PyObject *v; PyObject *retval; @@ -4922,6 +4968,7 @@ receiver = stack_pointer[-2]; { uint16_t counter = read_u16(&this_instr[1].cache); + (void)counter; #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { next_instr = this_instr; @@ -5102,12 +5149,14 @@ INSTRUCTION_STATS(STORE_ATTR); PREDICTED(STORE_ATTR); _Py_CODEUNIT *this_instr = next_instr - 5; + (void)this_instr; PyObject *owner; PyObject *v; // _SPECIALIZE_STORE_ATTR owner = stack_pointer[-1]; { uint16_t counter = read_u16(&this_instr[1].cache); + (void)counter; #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); @@ -5391,6 +5440,7 @@ INSTRUCTION_STATS(STORE_SUBSCR); PREDICTED(STORE_SUBSCR); _Py_CODEUNIT *this_instr = next_instr - 2; + (void)this_instr; PyObject *sub; PyObject *container; PyObject *v; @@ -5399,6 +5449,7 @@ container = stack_pointer[-2]; { uint16_t counter = read_u16(&this_instr[1].cache); + (void)counter; #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { next_instr = this_instr; @@ -5494,12 +5545,14 @@ INSTRUCTION_STATS(TO_BOOL); PREDICTED(TO_BOOL); _Py_CODEUNIT *this_instr = next_instr - 4; + (void)this_instr; PyObject *value; PyObject *res; // _SPECIALIZE_TO_BOOL value = stack_pointer[-1]; { uint16_t counter = read_u16(&this_instr[1].cache); + (void)counter; #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { next_instr = this_instr; @@ -5703,11 +5756,13 @@ INSTRUCTION_STATS(UNPACK_SEQUENCE); PREDICTED(UNPACK_SEQUENCE); _Py_CODEUNIT *this_instr = next_instr - 2; + (void)this_instr; PyObject *seq; // _SPECIALIZE_UNPACK_SEQUENCE seq = stack_pointer[-1]; { uint16_t counter = read_u16(&this_instr[1].cache); + (void)counter; #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { next_instr = this_instr; diff --git a/Tools/cases_generator/tier1_generator.py b/Tools/cases_generator/tier1_generator.py index aba36ec74e5766..fb2ab931b1c108 100644 --- a/Tools/cases_generator/tier1_generator.py +++ b/Tools/cases_generator/tier1_generator.py @@ -87,6 +87,8 @@ def write_uop( out.emit( f"{type}{cache.name} = {reader}(&this_instr[{offset}].cache);\n" ) + if inst.family is None: + out.emit(f"(void){cache.name};\n") offset += cache.size emit_tokens(out, uop, stack, inst) if uop.properties.stores_sp: @@ -131,8 +133,10 @@ def generate_tier1( needs_this = uses_this(inst) out.emit("\n") out.emit(f"TARGET({name}) {{\n") + unused_guard = "(void)this_instr;\n" if inst.family is None else "" if needs_this and not inst.is_target: out.emit(f"_Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr;\n") + out.emit(unused_guard) else: out.emit(f"frame->instr_ptr = next_instr;\n") out.emit(f"next_instr += {inst.size};\n") @@ -141,6 +145,7 @@ def generate_tier1( out.emit(f"PREDICTED({name});\n") if needs_this: out.emit(f"_Py_CODEUNIT *this_instr = next_instr - {inst.size};\n") + out.emit(unused_guard) if inst.family is not None: out.emit( f"static_assert({inst.family.size} == {inst.size-1}" From c98987b5e5e3644403c884e8b5673de9c59075bd Mon Sep 17 00:00:00 2001 From: Brett Simmers Date: Tue, 27 Feb 2024 15:23:31 -0800 Subject: [PATCH 2/5] Forgot to make regen-cases again --- Python/generated_cases.c.h | 52 +++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index ae953d1dfcc302..a593c1f95dbf8a 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -1945,9 +1945,9 @@ TARGET(CLEANUP_THROW) { _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + (void)this_instr; next_instr += 1; INSTRUCTION_STATS(CLEANUP_THROW); - (void)this_instr; PyObject *exc_value; PyObject *last_sent_val; PyObject *sub_iter; @@ -2335,9 +2335,9 @@ TARGET(END_ASYNC_FOR) { _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + (void)this_instr; next_instr += 1; INSTRUCTION_STATS(END_ASYNC_FOR); - (void)this_instr; PyObject *exc; PyObject *awaitable; exc = stack_pointer[-1]; @@ -2898,9 +2898,9 @@ TARGET(INSTRUMENTED_CALL) { _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + (void)this_instr; next_instr += 4; INSTRUCTION_STATS(INSTRUMENTED_CALL); - (void)this_instr; /* Skip 3 cache entries */ int is_meth = PEEK(oparg + 1) != NULL; int total_args = oparg + is_meth; @@ -2924,9 +2924,9 @@ TARGET(INSTRUMENTED_CALL_KW) { _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + (void)this_instr; next_instr += 1; INSTRUCTION_STATS(INSTRUMENTED_CALL_KW); - (void)this_instr; int is_meth = PEEK(oparg + 2) != NULL; int total_args = oparg + is_meth; PyObject *function = PEEK(oparg + 3); @@ -2941,9 +2941,9 @@ TARGET(INSTRUMENTED_END_FOR) { _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + (void)this_instr; next_instr += 1; INSTRUCTION_STATS(INSTRUMENTED_END_FOR); - (void)this_instr; PyObject *value; PyObject *receiver; value = stack_pointer[-1]; @@ -2964,9 +2964,9 @@ TARGET(INSTRUMENTED_END_SEND) { _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + (void)this_instr; next_instr += 1; INSTRUCTION_STATS(INSTRUMENTED_END_SEND); - (void)this_instr; PyObject *value; PyObject *receiver; value = stack_pointer[-1]; @@ -2986,9 +2986,9 @@ TARGET(INSTRUMENTED_FOR_ITER) { _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + (void)this_instr; next_instr += 2; INSTRUCTION_STATS(INSTRUMENTED_FOR_ITER); - (void)this_instr; /* Skip 1 cache entry */ _Py_CODEUNIT *target; PyObject *iter = TOP(); @@ -3019,9 +3019,9 @@ TARGET(INSTRUMENTED_INSTRUCTION) { _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + (void)this_instr; next_instr += 1; INSTRUCTION_STATS(INSTRUMENTED_INSTRUCTION); - (void)this_instr; int next_opcode = _Py_call_instrumentation_instruction( tstate, frame, this_instr); if (next_opcode < 0) goto error; @@ -3036,9 +3036,9 @@ TARGET(INSTRUMENTED_JUMP_BACKWARD) { _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + (void)this_instr; next_instr += 2; INSTRUCTION_STATS(INSTRUMENTED_JUMP_BACKWARD); - (void)this_instr; /* Skip 1 cache entry */ CHECK_EVAL_BREAKER(); INSTRUMENTED_JUMP(this_instr, next_instr - oparg, PY_MONITORING_EVENT_JUMP); @@ -3047,18 +3047,18 @@ TARGET(INSTRUMENTED_JUMP_FORWARD) { _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + (void)this_instr; next_instr += 1; INSTRUCTION_STATS(INSTRUMENTED_JUMP_FORWARD); - (void)this_instr; INSTRUMENTED_JUMP(this_instr, next_instr + oparg, PY_MONITORING_EVENT_JUMP); DISPATCH(); } TARGET(INSTRUMENTED_LOAD_SUPER_ATTR) { _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + (void)this_instr; next_instr += 2; INSTRUCTION_STATS(INSTRUMENTED_LOAD_SUPER_ATTR); - (void)this_instr; /* Skip 1 cache entry */ // cancel out the decrement that will happen in LOAD_SUPER_ATTR; we // don't want to specialize instrumented instructions @@ -3068,9 +3068,9 @@ TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) { _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + (void)this_instr; next_instr += 2; INSTRUCTION_STATS(INSTRUMENTED_POP_JUMP_IF_FALSE); - (void)this_instr; /* Skip 1 cache entry */ PyObject *cond = POP(); assert(PyBool_Check(cond)); @@ -3085,9 +3085,9 @@ TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) { _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + (void)this_instr; next_instr += 2; INSTRUCTION_STATS(INSTRUMENTED_POP_JUMP_IF_NONE); - (void)this_instr; /* Skip 1 cache entry */ PyObject *value = POP(); int flag = Py_IsNone(value); @@ -3108,9 +3108,9 @@ TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) { _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + (void)this_instr; next_instr += 2; INSTRUCTION_STATS(INSTRUMENTED_POP_JUMP_IF_NOT_NONE); - (void)this_instr; /* Skip 1 cache entry */ PyObject *value = POP(); int offset; @@ -3131,9 +3131,9 @@ TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) { _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + (void)this_instr; next_instr += 2; INSTRUCTION_STATS(INSTRUMENTED_POP_JUMP_IF_TRUE); - (void)this_instr; /* Skip 1 cache entry */ PyObject *cond = POP(); assert(PyBool_Check(cond)); @@ -3148,9 +3148,9 @@ TARGET(INSTRUMENTED_RESUME) { _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + (void)this_instr; next_instr += 1; INSTRUCTION_STATS(INSTRUMENTED_RESUME); - (void)this_instr; uintptr_t global_version = _Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & ~_PY_EVAL_EVENTS_MASK; uintptr_t code_version = _PyFrame_GetCode(frame)->_co_instrumentation_version; if (code_version != global_version) { @@ -3179,9 +3179,9 @@ TARGET(INSTRUMENTED_RETURN_CONST) { _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + (void)this_instr; next_instr += 1; INSTRUCTION_STATS(INSTRUMENTED_RETURN_CONST); - (void)this_instr; PyObject *retval = GETITEM(FRAME_CO_CONSTS, oparg); int err = _Py_call_instrumentation_arg( tstate, PY_MONITORING_EVENT_PY_RETURN, @@ -3203,9 +3203,9 @@ TARGET(INSTRUMENTED_RETURN_VALUE) { _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + (void)this_instr; next_instr += 1; INSTRUCTION_STATS(INSTRUMENTED_RETURN_VALUE); - (void)this_instr; PyObject *retval; retval = stack_pointer[-1]; int err = _Py_call_instrumentation_arg( @@ -3228,9 +3228,9 @@ TARGET(INSTRUMENTED_YIELD_VALUE) { _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + (void)this_instr; next_instr += 1; INSTRUCTION_STATS(INSTRUMENTED_YIELD_VALUE); - (void)this_instr; PyObject *retval; retval = stack_pointer[-1]; assert(frame != &entry_frame); @@ -3292,9 +3292,9 @@ TARGET(JUMP_BACKWARD) { _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + (void)this_instr; next_instr += 2; INSTRUCTION_STATS(JUMP_BACKWARD); - (void)this_instr; /* Skip 1 cache entry */ CHECK_EVAL_BREAKER(); assert(oparg <= INSTR_OFFSET()); @@ -4603,9 +4603,9 @@ TARGET(POP_JUMP_IF_FALSE) { _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + (void)this_instr; next_instr += 2; INSTRUCTION_STATS(POP_JUMP_IF_FALSE); - (void)this_instr; PyObject *cond; /* Skip 1 cache entry */ cond = stack_pointer[-1]; @@ -4621,9 +4621,9 @@ TARGET(POP_JUMP_IF_NONE) { _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + (void)this_instr; next_instr += 2; INSTRUCTION_STATS(POP_JUMP_IF_NONE); - (void)this_instr; PyObject *value; PyObject *b; PyObject *cond; @@ -4655,9 +4655,9 @@ TARGET(POP_JUMP_IF_NOT_NONE) { _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + (void)this_instr; next_instr += 2; INSTRUCTION_STATS(POP_JUMP_IF_NOT_NONE); - (void)this_instr; PyObject *value; PyObject *b; PyObject *cond; @@ -4689,9 +4689,9 @@ TARGET(POP_JUMP_IF_TRUE) { _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + (void)this_instr; next_instr += 2; INSTRUCTION_STATS(POP_JUMP_IF_TRUE); - (void)this_instr; PyObject *cond; /* Skip 1 cache entry */ cond = stack_pointer[-1]; @@ -4751,9 +4751,9 @@ TARGET(RAISE_VARARGS) { _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + (void)this_instr; next_instr += 1; INSTRUCTION_STATS(RAISE_VARARGS); - (void)this_instr; PyObject **args; args = &stack_pointer[-oparg]; PyObject *cause = NULL, *exc = NULL; @@ -4781,9 +4781,9 @@ TARGET(RERAISE) { _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + (void)this_instr; next_instr += 1; INSTRUCTION_STATS(RERAISE); - (void)this_instr; PyObject *exc; PyObject **values; exc = stack_pointer[-1]; From 20b081c6f5c98a329ddc992dc04d0508b6772b5c Mon Sep 17 00:00:00 2001 From: Brett Simmers Date: Wed, 28 Feb 2024 12:22:51 -0800 Subject: [PATCH 3/5] Mark some tests that require specialization --- Lib/test/test_capi/test_opt.py | 5 ++++- Lib/test/test_monitoring.py | 5 +++++ Lib/test/test_opcache.py | 4 +++- Lib/test/test_type_cache.py | 3 ++- 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 25fc36dec93ddc..54dfe73781382a 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -8,7 +8,7 @@ import _testinternalcapi -from test.support import script_helper +from test.support import script_helper, requires_specialization @contextlib.contextmanager @@ -31,6 +31,7 @@ def clear_executors(func): func.__code__ = func.__code__.replace() +@requires_specialization class TestOptimizerAPI(unittest.TestCase): def test_new_counter_optimizer_dealloc(self): @@ -133,6 +134,7 @@ def get_opnames(ex): return set(iter_opnames(ex)) +@requires_specialization class TestExecutorInvalidation(unittest.TestCase): def setUp(self): @@ -210,6 +212,7 @@ def f(): exe = get_first_executor(f) self.assertIsNone(exe) +@requires_specialization class TestUops(unittest.TestCase): def test_basic_loop(self): diff --git a/Lib/test/test_monitoring.py b/Lib/test/test_monitoring.py index 2fd822036bcff5..b02795903f6d17 100644 --- a/Lib/test/test_monitoring.py +++ b/Lib/test/test_monitoring.py @@ -9,6 +9,7 @@ import types import unittest import asyncio +from test.support import requires_specialization PAIR = (0,1) @@ -815,6 +816,9 @@ def func1(): self.check_events(func1, [("raise", KeyError)]) + # gh-116090: This test doesn't really require specialization, but running + # it without specialization exposes a monitoring bug. + @requires_specialization def test_implicit_stop_iteration(self): def gen(): @@ -963,6 +967,7 @@ def func(): ) self.assertEqual(events[0], ("throw", IndexError)) + @requires_specialization def test_no_unwind_for_shim_frame(self): class B: diff --git a/Lib/test/test_opcache.py b/Lib/test/test_opcache.py index 2b2783d57be8f4..5fb4b815c95d07 100644 --- a/Lib/test/test_opcache.py +++ b/Lib/test/test_opcache.py @@ -4,7 +4,7 @@ import threading import types import unittest -from test.support import threading_helper, check_impl_detail +from test.support import threading_helper, check_impl_detail, requires_specialization # Skip this module on other interpreters, it is cpython specific: if check_impl_detail(cpython=False): @@ -506,6 +506,7 @@ def f(x, y): @threading_helper.requires_working_threading() +@requires_specialization class TestRacesDoNotCrash(unittest.TestCase): # Careful with these. Bigger numbers have a higher chance of catching bugs, # but you can also burn through a *ton* of type/dict/function versions: @@ -1021,6 +1022,7 @@ def write(items): class C: pass +@requires_specialization class TestInstanceDict(unittest.TestCase): def setUp(self): diff --git a/Lib/test/test_type_cache.py b/Lib/test/test_type_cache.py index 58572c6f4d3157..e90e315c808361 100644 --- a/Lib/test/test_type_cache.py +++ b/Lib/test/test_type_cache.py @@ -2,7 +2,7 @@ import unittest import dis from test import support -from test.support import import_helper +from test.support import import_helper, requires_specialization try: from sys import _clear_type_cache except ImportError: @@ -94,6 +94,7 @@ class C: @support.cpython_only +@requires_specialization class TypeCacheWithSpecializationTests(unittest.TestCase): def tearDown(self): _clear_type_cache() From db4f433b835d551bc85580e1cc5d9f7d8bd9ad1e Mon Sep 17 00:00:00 2001 From: Brett Simmers Date: Wed, 28 Feb 2024 18:31:53 -0800 Subject: [PATCH 4/5] Disable more tests --- Lib/test/test_capi/test_opt.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index f11c24f6c943ee..15a8c911068a3f 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -575,6 +575,7 @@ def testfunc(n): self.assertLessEqual(count, 2) +@requires_specialization @unittest.skipIf(os.getenv("PYTHON_UOPS_OPTIMIZE") == "0", "Needs uop optimizer to run.") class TestUopsOptimization(unittest.TestCase): From 4c4400abdecf8aefdbffec6186a95961bf0d8f52 Mon Sep 17 00:00:00 2001 From: Brett Simmers Date: Thu, 29 Feb 2024 10:33:47 -0800 Subject: [PATCH 5/5] Make DECREMENT_ADAPTIVE_COUNTER fail at compile time --- Python/ceval_macros.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h index 6d7640b309126c..0267c9b1cd38ab 100644 --- a/Python/ceval_macros.h +++ b/Python/ceval_macros.h @@ -297,10 +297,10 @@ GETITEM(PyObject *v, Py_ssize_t i) { (((COUNTER) >> ADAPTIVE_BACKOFF_BITS) == ((1 << MAX_BACKOFF_VALUE) - 1)) #ifdef Py_GIL_DISABLED -#define DECREMENT_ADAPTIVE_COUNTER(COUNTER) \ - do { \ - /* gh-115999 tracks progress on addressing this. */ \ - Py_FatalError("The adaptive interpreter is not thread-safe"); \ +#define DECREMENT_ADAPTIVE_COUNTER(COUNTER) \ + do { \ + /* gh-115999 tracks progress on addressing this. */ \ + static_assert(0, "The specializing interpreter is not yet thread-safe"); \ } while (0); #else #define DECREMENT_ADAPTIVE_COUNTER(COUNTER) \