Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 35.2k
gh-141594: A free-threaded JIT (Part 1)#141595
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base:main
Are you sure you want to change the base?
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
6a3bd75ba9a65a725894d1e5713df0d4c5767de7d67f0bc57f05e61cf78e8c8e1f1b3053c5e1dcc38ee4f8fefb3d76a24bfa99108fcfed96ba67ab7b46385b46285be8ce83cdfa5564392f3dbf7240b15cb87676f9726373ef237b44356d6b819053527aac1b80c02e4278c9dd84215db08ef60c2c8fbe162b1ece0890ff197e9f446413cfb5d6571a93c26c97d5f2bc3819030d6751a8190a5c973e9612f39aa8e08c43400ae7b54d9ffa1a1ca3a7cdbbbe30678505dc1e25cc2416a665b6dd07d974371a4f2d02494965aff296a8df9aedfb56baa5d987e8File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| Add free-threading support to the JIT. The JIT is only enabled on | ||
| single-threaded code in free-threading, and is disabled when multiple | ||
| threads are spawned. Patch by Ken Jin. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -298,7 +298,7 @@ functions is running. | ||
| */ | ||
| #ifndef Py_GIL_DISABLED | ||
| #if _Py_TIER2 | ||
| static inline struct _func_version_cache_item * | ||
| get_cache_item(PyInterpreterState *interp, uint32_t version) | ||
| { | ||
| @@ -315,11 +315,13 @@ _PyFunction_SetVersion(PyFunctionObject *func, uint32_t version) | ||
| // This should only be called from MAKE_FUNCTION. No code is specialized | ||
| // based on the version, so we do not need to stop the world to set it. | ||
| func->func_version = version; | ||
| #ifndef Py_GIL_DISABLED | ||
| #if _Py_TIER2 | ||
| PyInterpreterState *interp = _PyInterpreterState_GET(); | ||
| FT_MUTEX_LOCK(&interp->func_state.mutex); | ||
| struct _func_version_cache_item *slot = get_cache_item(interp, version); | ||
| slot->func = func; | ||
| slot->code = func->func_code; | ||
| FT_MUTEX_UNLOCK(&interp->func_state.mutex); | ||
| #endif | ||
| } | ||
| @@ -330,13 +332,15 @@ func_clear_version(PyInterpreterState *interp, PyFunctionObject *func) | ||
| // Version was never set or has already been cleared. | ||
| return; | ||
| } | ||
| #ifndef Py_GIL_DISABLED | ||
| #if _Py_TIER2 | ||
| FT_MUTEX_LOCK(&interp->func_state.mutex); | ||
| struct _func_version_cache_item *slot = | ||
| get_cache_item(interp, func->func_version); | ||
| if (slot->func == func) { | ||
| slot->func = NULL; | ||
| // Leave slot->code alone, there may be use for it. | ||
| } | ||
| FT_MUTEX_UNLOCK(&interp->func_state.mutex); | ||
| #endif | ||
| func->func_version = FUNC_VERSION_CLEARED; | ||
| } | ||
| @@ -358,8 +362,9 @@ _PyFunction_ClearVersion(PyFunctionObject *func) | ||
| void | ||
| _PyFunction_ClearCodeByVersion(uint32_t version) | ||
| { | ||
| #ifndef Py_GIL_DISABLED | ||
| #if _Py_TIER2 | ||
| PyInterpreterState *interp = _PyInterpreterState_GET(); | ||
| FT_MUTEX_LOCK(&interp->func_state.mutex); | ||
| struct _func_version_cache_item *slot = get_cache_item(interp, version); | ||
| if (slot->code) { | ||
| assert(PyCode_Check(slot->code)); | ||
| @@ -369,15 +374,19 @@ _PyFunction_ClearCodeByVersion(uint32_t version) | ||
| slot->func = NULL; | ||
| } | ||
| } | ||
| FT_MUTEX_UNLOCK(&interp->func_state.mutex); | ||
| #endif | ||
| } | ||
| PyFunctionObject * | ||
| _PyFunction_LookupByVersion(uint32_t version, PyObject **p_code) | ||
Member There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this function really used somewhere? MemberAuthor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's strange, you're right, it's not used. It's useful for the optimizer though, so we might want to use it in the future. | ||
| { | ||
| #ifdef Py_GIL_DISABLED | ||
| #ifndef _Py_TIER2 | ||
| return NULL; | ||
| #else | ||
| // This function does not need locking/atomics as it can only be | ||
| // called from the optimizer, which is currently disabled | ||
| // when there are multiple threads. | ||
| PyInterpreterState *interp = _PyInterpreterState_GET(); | ||
| struct _func_version_cache_item *slot = get_cache_item(interp, version); | ||
| if (slot->code) { | ||
| @@ -401,6 +410,10 @@ _PyFunction_LookupByVersion(uint32_t version, PyObject **p_code) | ||
| uint32_t | ||
| _PyFunction_GetVersionForCurrentState(PyFunctionObject *func) | ||
| { | ||
| // This function does not need locking/atomics as it can only be | ||
Member There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We use the function version in specialized instructions, so it is used in tier 1. MemberAuthor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The use in the specializer is protected because it's accessing a stack variable which holds a strong reference to it. I will clarify that the unsnchronized use is only in the optimizer and it's fine there. | ||
| // called from the specializing interpreter or optimizer. | ||
| // The specializing interpreter holds a strong reference to the function. | ||
| // The optimizer is currently disabled when there are multiple threads. | ||
| return func->func_version; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1149,7 +1149,8 @@ static void | ||
| set_version_unlocked(PyTypeObject *tp, unsigned int version) | ||
| { | ||
| assert(version == 0 || (tp->tp_versions_used != _Py_ATTR_CACHE_UNUSED)); | ||
| #ifndef Py_GIL_DISABLED | ||
| #if _Py_TIER2 | ||
Fidget-Spinner marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. Fidget-Spinner marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| ASSERT_TYPE_LOCK_HELD(); | ||
| PyInterpreterState *interp = _PyInterpreterState_GET(); | ||
| // lookup the old version and set to null | ||
| if (tp->tp_version_tag != 0) { | ||
| @@ -1158,6 +1159,8 @@ set_version_unlocked(PyTypeObject *tp, unsigned int version) | ||
| + (tp->tp_version_tag % TYPE_VERSION_CACHE_SIZE); | ||
| *slot = NULL; | ||
| } | ||
| #endif | ||
| #ifndef Py_GIL_DISABLED | ||
| if (version) { | ||
| tp->tp_versions_used++; | ||
| } | ||
| @@ -1167,7 +1170,7 @@ set_version_unlocked(PyTypeObject *tp, unsigned int version) | ||
| } | ||
| #endif | ||
| FT_ATOMIC_STORE_UINT_RELAXED(tp->tp_version_tag, version); | ||
| #ifndef Py_GIL_DISABLED | ||
| #if _Py_TIER2 | ||
| if (version != 0) { | ||
| PyTypeObject **slot = | ||
| interp->types.type_version_cache | ||
| @@ -1358,9 +1361,12 @@ _PyType_SetVersion(PyTypeObject *tp, unsigned int version) | ||
| PyTypeObject * | ||
| _PyType_LookupByVersion(unsigned int version) | ||
| { | ||
| #ifdef Py_GIL_DISABLED | ||
| #ifndef _Py_TIER2 | ||
| return NULL; | ||
| #else | ||
| // This function does not need locking/atomics as it can only be | ||
| // called from the optimizer, which is currently disabled | ||
| // when there are multiple threads. | ||
| PyInterpreterState *interp = _PyInterpreterState_GET(); | ||
| PyTypeObject **slot = | ||
| interp->types.type_version_cache | ||
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This changes the tier 1 with-gil behavior.
I don't see why we would need the cache in tier 1, but can you double check?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I double checked.