gh-115999: Add free-threaded specialization for `TO_BOOL` (gh-126616)

This commit is contained in:
Donghee Na 2024-11-22 07:52:16 +09:00 committed by GitHub
parent 09c240f20c
commit 78a530a578
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 168 additions and 69 deletions

View file

@ -2667,101 +2667,106 @@ success:
cache->counter = adaptive_counter_cooldown();
}
#ifdef Py_STATS
static int
to_bool_fail_kind(PyObject *value)
{
if (PyByteArray_CheckExact(value)) {
return SPEC_FAIL_TO_BOOL_BYTEARRAY;
}
if (PyBytes_CheckExact(value)) {
return SPEC_FAIL_TO_BOOL_BYTES;
}
if (PyDict_CheckExact(value)) {
return SPEC_FAIL_TO_BOOL_DICT;
}
if (PyFloat_CheckExact(value)) {
return SPEC_FAIL_TO_BOOL_FLOAT;
}
if (PyMemoryView_Check(value)) {
return SPEC_FAIL_TO_BOOL_MEMORY_VIEW;
}
if (PyAnySet_CheckExact(value)) {
return SPEC_FAIL_TO_BOOL_SET;
}
if (PyTuple_CheckExact(value)) {
return SPEC_FAIL_TO_BOOL_TUPLE;
}
return SPEC_FAIL_OTHER;
}
#endif // Py_STATS
static int
check_type_always_true(PyTypeObject *ty)
{
PyNumberMethods *nb = ty->tp_as_number;
if (nb && nb->nb_bool) {
return SPEC_FAIL_TO_BOOL_NUMBER;
}
PyMappingMethods *mp = ty->tp_as_mapping;
if (mp && mp->mp_length) {
return SPEC_FAIL_TO_BOOL_MAPPING;
}
PySequenceMethods *sq = ty->tp_as_sequence;
if (sq && sq->sq_length) {
return SPEC_FAIL_TO_BOOL_SEQUENCE;
}
return 0;
}
void
_Py_Specialize_ToBool(_PyStackRef value_o, _Py_CODEUNIT *instr)
{
assert(ENABLE_SPECIALIZATION);
assert(ENABLE_SPECIALIZATION_FT);
assert(_PyOpcode_Caches[TO_BOOL] == INLINE_CACHE_ENTRIES_TO_BOOL);
_PyToBoolCache *cache = (_PyToBoolCache *)(instr + 1);
PyObject *value = PyStackRef_AsPyObjectBorrow(value_o);
uint8_t specialized_op;
if (PyBool_Check(value)) {
instr->op.code = TO_BOOL_BOOL;
specialized_op = TO_BOOL_BOOL;
goto success;
}
if (PyLong_CheckExact(value)) {
instr->op.code = TO_BOOL_INT;
specialized_op = TO_BOOL_INT;
goto success;
}
if (PyList_CheckExact(value)) {
instr->op.code = TO_BOOL_LIST;
specialized_op = TO_BOOL_LIST;
goto success;
}
if (Py_IsNone(value)) {
instr->op.code = TO_BOOL_NONE;
specialized_op = TO_BOOL_NONE;
goto success;
}
if (PyUnicode_CheckExact(value)) {
instr->op.code = TO_BOOL_STR;
specialized_op = TO_BOOL_STR;
goto success;
}
if (PyType_HasFeature(Py_TYPE(value), Py_TPFLAGS_HEAPTYPE)) {
PyNumberMethods *nb = Py_TYPE(value)->tp_as_number;
if (nb && nb->nb_bool) {
SPECIALIZATION_FAIL(TO_BOOL, SPEC_FAIL_TO_BOOL_NUMBER);
goto failure;
}
PyMappingMethods *mp = Py_TYPE(value)->tp_as_mapping;
if (mp && mp->mp_length) {
SPECIALIZATION_FAIL(TO_BOOL, SPEC_FAIL_TO_BOOL_MAPPING);
goto failure;
}
PySequenceMethods *sq = Py_TYPE(value)->tp_as_sequence;
if (sq && sq->sq_length) {
SPECIALIZATION_FAIL(TO_BOOL, SPEC_FAIL_TO_BOOL_SEQUENCE);
goto failure;
}
if (!PyUnstable_Type_AssignVersionTag(Py_TYPE(value))) {
unsigned int version = 0;
int err = _PyType_Validate(Py_TYPE(value), check_type_always_true, &version);
if (err < 0) {
SPECIALIZATION_FAIL(TO_BOOL, SPEC_FAIL_OUT_OF_VERSIONS);
goto failure;
}
uint32_t version = type_get_version(Py_TYPE(value), TO_BOOL);
if (version == 0) {
else if (err > 0) {
SPECIALIZATION_FAIL(TO_BOOL, err);
goto failure;
}
instr->op.code = TO_BOOL_ALWAYS_TRUE;
write_u32(cache->version, version);
assert(err == 0);
assert(version);
write_u32(cache->version, version);
specialized_op = TO_BOOL_ALWAYS_TRUE;
goto success;
}
#ifdef Py_STATS
if (PyByteArray_CheckExact(value)) {
SPECIALIZATION_FAIL(TO_BOOL, SPEC_FAIL_TO_BOOL_BYTEARRAY);
goto failure;
}
if (PyBytes_CheckExact(value)) {
SPECIALIZATION_FAIL(TO_BOOL, SPEC_FAIL_TO_BOOL_BYTES);
goto failure;
}
if (PyDict_CheckExact(value)) {
SPECIALIZATION_FAIL(TO_BOOL, SPEC_FAIL_TO_BOOL_DICT);
goto failure;
}
if (PyFloat_CheckExact(value)) {
SPECIALIZATION_FAIL(TO_BOOL, SPEC_FAIL_TO_BOOL_FLOAT);
goto failure;
}
if (PyMemoryView_Check(value)) {
SPECIALIZATION_FAIL(TO_BOOL, SPEC_FAIL_TO_BOOL_MEMORY_VIEW);
goto failure;
}
if (PyAnySet_CheckExact(value)) {
SPECIALIZATION_FAIL(TO_BOOL, SPEC_FAIL_TO_BOOL_SET);
goto failure;
}
if (PyTuple_CheckExact(value)) {
SPECIALIZATION_FAIL(TO_BOOL, SPEC_FAIL_TO_BOOL_TUPLE);
goto failure;
}
SPECIALIZATION_FAIL(TO_BOOL, SPEC_FAIL_OTHER);
#endif // Py_STATS
SPECIALIZATION_FAIL(TO_BOOL, to_bool_fail_kind(value));
failure:
STAT_INC(TO_BOOL, failure);
instr->op.code = TO_BOOL;
cache->counter = adaptive_counter_backoff(cache->counter);
unspecialize(instr);
return;
success:
STAT_INC(TO_BOOL, success);
cache->counter = adaptive_counter_cooldown();
specialize(instr, specialized_op);
}
#ifdef Py_STATS