diff --git a/Cinder/Include/cinder/exports.h b/Cinder/Include/cinder/exports.h index f15c03576c8..5120e22b69d 100644 --- a/Cinder/Include/cinder/exports.h +++ b/Cinder/Include/cinder/exports.h @@ -92,8 +92,6 @@ CiAPI_FUNC(PyObject *) Ci_Tuple_Repeat(PyTupleObject *, Py_ssize_t); #define Ci_Py_TPFLAGS_FROZEN (1UL << 21) -CiAPI_FUNC(int) Ci_Type_AssignVersionTag(PyTypeObject *); - // Implementation in Python/bltinmodule.c CiAPI_FUNC(PyObject *) builtin_next(PyObject *self, PyObject *const *args, Py_ssize_t nargs); diff --git a/Cinder/module/known-core-python-exported-symbols b/Cinder/module/known-core-python-exported-symbols index 54b6d3e2573..aa1eae4ad8a 100644 --- a/Cinder/module/known-core-python-exported-symbols +++ b/Cinder/module/known-core-python-exported-symbols @@ -50,7 +50,6 @@ Ci_ThreadState_SetProfileInterpAll Ci_TupleHashItems Ci_Tuple_Repeat Ci_tuple_subscript -Ci_Type_AssignVersionTag ClassDef_fields Delete_fields DictComp_fields @@ -1992,6 +1991,7 @@ Py_UniversalNewlineFgets PyUnstable_GC_VisitObjects PyUnstable_PerfMapState_Fini PyUnstable_PerfMapState_Init +PyUnstable_Type_AssignVersionTag PyUnstable_WritePerfMapEntry _Py_UTF8_Edit_Cost _Py_VaBuildStack diff --git a/Include/cpython/object.h b/Include/cpython/object.h index 427ae1b6069..0c7e9876fe5 100644 --- a/Include/cpython/object.h +++ b/Include/cpython/object.h @@ -564,3 +564,10 @@ PyAPI_FUNC(int) _PyTrash_cond(PyObject *op, destructor dealloc); * unconditionally */ #define Py_TRASHCAN_SAFE_BEGIN(op) Py_TRASHCAN_BEGIN_CONDITION(op, 1) #define Py_TRASHCAN_SAFE_END(op) Py_TRASHCAN_END + +/* Attempt to assign a version tag to the given type. + * + * Returns 1 if the type already had a valid version tag or a new one was + * assigned, or 0 if a new tag could not be assigned. + */ +PyAPI_FUNC(int) PyUnstable_Type_AssignVersionTag(PyTypeObject *type); diff --git a/Jit/profile_data.cpp b/Jit/profile_data.cpp index 81dd9016a1a..9f58d25f378 100644 --- a/Jit/profile_data.cpp +++ b/Jit/profile_data.cpp @@ -414,7 +414,7 @@ void registerProfiledType(PyTypeObject* type) { PyDictKeysObject* old_keys = ht->ht_cached_keys; ht->ht_cached_keys = keys; PyType_Modified(type); - Ci_Type_AssignVersionTag(type); + PyUnstable_Type_AssignVersionTag(type); if (old_keys != nullptr) { _PyDictKeys_DecRef(old_keys); } diff --git a/Jit/type_deopt_patchers.cpp b/Jit/type_deopt_patchers.cpp index 3b52630a1ee..52384067589 100644 --- a/Jit/type_deopt_patchers.cpp +++ b/Jit/type_deopt_patchers.cpp @@ -47,7 +47,7 @@ bool shouldPatchForAttr( return true; } - return !Ci_Type_AssignVersionTag(new_ty); + return !PyUnstable_Type_AssignVersionTag(new_ty); } } // namespace diff --git a/Jit/util.cpp b/Jit/util.cpp index b55a2e8cbd1..dfe8fbd21d2 100644 --- a/Jit/util.cpp +++ b/Jit/util.cpp @@ -198,7 +198,7 @@ bool ensureVersionTag(BorrowedRef type) { return true; } ThreadedCompileSerialize guard; - return Ci_Type_AssignVersionTag(type); + return PyUnstable_Type_AssignVersionTag(type); } } // namespace jit diff --git a/Lib/test/test_type_cache.py b/Lib/test/test_type_cache.py index 8502f6b0584..24f83cd3e17 100644 --- a/Lib/test/test_type_cache.py +++ b/Lib/test/test_type_cache.py @@ -9,6 +9,7 @@ # Skip this test if the _testcapi module isn't available. type_get_version = import_helper.import_module('_testcapi').type_get_version +type_assign_version = import_helper.import_module('_testcapi').type_assign_version @support.cpython_only @@ -42,6 +43,19 @@ def test_tp_version_tag_unique(self): self.assertEqual(len(set(all_version_tags)), 30, msg=f"{all_version_tags} contains non-unique versions") + def test_type_assign_version(self): + class C: + x = 5 + + self.assertEqual(type_assign_version(C), 1) + c_ver = type_get_version(C) + + C.x = 6 + self.assertEqual(type_get_version(C), 0) + self.assertEqual(type_assign_version(C), 1) + self.assertNotEqual(type_get_version(C), 0) + self.assertNotEqual(type_get_version(C), c_ver) + if __name__ == "__main__": support.run_unittest(TypeCacheTests) diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 7fb56699189..1d99abd6a58 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -5818,6 +5818,18 @@ type_get_version(PyObject *self, PyObject *type) } +static PyObject * +type_assign_version(PyObject *self, PyObject *type) +{ + if (!PyType_Check(type)) { + PyErr_SetString(PyExc_TypeError, "argument must be a type"); + return NULL; + } + int res = PyUnstable_Type_AssignVersionTag((PyTypeObject *)type); + return PyLong_FromLong(res); +} + + static PyObject *test_buildvalue_issue38913(PyObject *, PyObject *); static PyObject *getargs_s_hash_int(PyObject *, PyObject *, PyObject*); @@ -6899,6 +6911,7 @@ static PyMethodDef TestMethods[] = { {"get_context_helpers_for_task", _get_context_helpers_for_task, METH_NOARGS}, {"test_dict_has_unsafe_keys", test_dict_has_unsafe_keys, METH_NOARGS}, {"type_get_version", type_get_version, METH_O, PyDoc_STR("type->tp_version_tag")}, + {"type_assign_version", type_assign_version, METH_O, PyDoc_STR("PyUnstable_Type_AssignVersionTag")}, {"add_dict_watcher", add_dict_watcher, METH_O}, {"clear_dict_watcher", clear_dict_watcher, METH_O}, {"watch_dict", watch_dict, METH_VARARGS}, diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 963f4b1747a..c16252b2edb 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -2041,7 +2041,7 @@ immortalize_object(PyObject *obj, PyObject * /* unused */ args) } if (PyType_Check(obj)) { - Ci_Type_AssignVersionTag((PyTypeObject *)obj); + PyUnstable_Type_AssignVersionTag((PyTypeObject *)obj); } if (!_PyImmortal_RecursiveHeapWalk) { return 0; diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 70d8a4e2215..6be7ea17fad 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -522,8 +522,8 @@ assign_version_tag(struct type_cache *cache, PyTypeObject *type) return 1; } -int -Ci_Type_AssignVersionTag(PyTypeObject *type) { +int PyUnstable_Type_AssignVersionTag(PyTypeObject *type) +{ return assign_version_tag(get_type_cache(), type); }