Enable free-threaded specialization of LOAD_CONST.
self.assert_specialized(compare_op_str, "COMPARE_OP_STR")
self.assert_no_opcode(compare_op_str, "COMPARE_OP")
+ @cpython_only
+ @requires_specialization_ft
+ def test_load_const(self):
+ def load_const():
+ def unused(): pass
+ # Currently, the empty tuple is immortal, and the otherwise
+ # unused nested function's code object is mortal. This test will
+ # have to use different values if either of that changes.
+ return ()
+
+ load_const()
+ self.assert_specialized(load_const, "LOAD_CONST_IMMORTAL")
+ self.assert_specialized(load_const, "LOAD_CONST_MORTAL")
+ self.assert_no_opcode(load_const, "LOAD_CONST")
if __name__ == "__main__":
unittest.main()
* marshalling can intern strings and make them immortal. */
PyObject *obj = GETITEM(FRAME_CO_CONSTS, oparg);
value = PyStackRef_FromPyObjectNew(obj);
-#if ENABLE_SPECIALIZATION
+#if ENABLE_SPECIALIZATION_FT
+#ifdef Py_GIL_DISABLED
+ uint8_t expected = LOAD_CONST;
+ if (!_Py_atomic_compare_exchange_uint8(
+ &this_instr->op.code, &expected,
+ _Py_IsImmortal(obj) ? LOAD_CONST_IMMORTAL : LOAD_CONST_MORTAL)) {
+ // We might lose a race with instrumentation, which we don't care about.
+ assert(expected >= MIN_INSTRUMENTED_OPCODE);
+ }
+#else
if (this_instr->op.code == LOAD_CONST) {
this_instr->op.code = _Py_IsImmortal(obj) ? LOAD_CONST_IMMORTAL : LOAD_CONST_MORTAL;
}
+#endif
#endif
}
}
OPCODE_DEFERRED_INC(COMPARE_OP);
ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter);
- #endif /* ENABLE_SPECIALIZATION */
+ #endif /* ENABLE_SPECIALIZATION_FT */
}
op(_COMPARE_OP, (left, right -- res)) {
}
OPCODE_DEFERRED_INC(COMPARE_OP);
ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter);
- #endif /* ENABLE_SPECIALIZATION */
+ #endif /* ENABLE_SPECIALIZATION_FT */
}
// _COMPARE_OP
{
* marshalling can intern strings and make them immortal. */
PyObject *obj = GETITEM(FRAME_CO_CONSTS, oparg);
value = PyStackRef_FromPyObjectNew(obj);
- #if ENABLE_SPECIALIZATION
+ #if ENABLE_SPECIALIZATION_FT
+ #ifdef Py_GIL_DISABLED
+ uint8_t expected = LOAD_CONST;
+ if (!_Py_atomic_compare_exchange_uint8(
+ &this_instr->op.code, &expected,
+ _Py_IsImmortal(obj) ? LOAD_CONST_IMMORTAL : LOAD_CONST_MORTAL)) {
+ // We might lose a race with instrumentation, which we don't care about.
+ assert(expected >= MIN_INSTRUMENTED_OPCODE);
+ }
+ #else
if (this_instr->op.code == LOAD_CONST) {
this_instr->op.code = _Py_IsImmortal(obj) ? LOAD_CONST_IMMORTAL : LOAD_CONST_MORTAL;
}
#endif
+ #endif
stack_pointer[0] = value;
stack_pointer += 1;
assert(WITHIN_STACK_BOUNDS());
"_Py_STR",
"_Py_TryIncrefCompare",
"_Py_TryIncrefCompareStackRef",
+ "_Py_atomic_compare_exchange_uint8",
"_Py_atomic_load_ptr_acquire",
"_Py_atomic_load_uintptr_relaxed",
"_Py_set_eval_breaker_bit",