You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
make codegen threadsafe, sinking the necessary lock now into JuliaOJIT (JuliaLang#55106)
This adds a new helper `jl_read_codeinst_invoke` that should help manage
reading the state out of a CodeInstance correctly everywhere. Then
replaces all of the places where we have optimizations in codegen where
we check for this (to build a name in the JIT for it) with that call.
And finally moves the `jl_codegen_lock` into
`jl_ExecutionEngine->jitlock` so that it is now more clear that this is
only protecting concurrent access to the JIT state it manages (which
includes the invoke field of all CodeInstance objects). In a subsequent
followup, that `jitlock` and `codeinst_in_flight` will be replaced with
something akin to the new engine (for CodeInfo inference) which helps
partition that JIT lock mechanism (for CodeInstance / JIT insertion) to
correspond just to a single CodeInstance, and not globally to all of
them.
Copy file name to clipboardExpand all lines: doc/src/devdocs/jit.md
+7-5Lines changed: 7 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -59,20 +59,22 @@ In addition, there are a number of different transitional states that occur duri
59
59
60
60
1. When writing `invoke`, `specsigflags`, and `specptr`:
61
61
1. Perform an atomic compare-exchange operation of specptr assuming the old value was NULL. This compare-exchange operation should have at least acquire-release ordering, to provide ordering guarantees of the remaining memory operations in the write.
62
-
2. If `specptr` was non-null, cease the write operation and wait for bit 0b10 of `specsigflags` to be written.
62
+
2. If `specptr` was non-null, cease the write operation and wait for bit 0b10 of `specsigflags` to be written, then restart from step 1 if desired.
63
63
3. Write the new low bit of `specsigflags` to its final value. This may be a relaxed write.
64
64
4. Write the new `invoke` pointer to its final value. This must have at least a release memory ordering to synchronize with reads of `invoke`.
65
65
5. Set the second bit of `specsigflags` to 1. This must be at least a release memory ordering to synchronize with reads of `specsigflags`. This step completes the write operation and announces to all other threads that all fields have been set.
66
66
2. When reading all of `invoke`, `specsigflags`, and `specptr`:
67
-
1. Read the `invoke` field with at least an acquire memory ordering. This load will be referred to as `initial_invoke`.
68
-
2.If `initial_invoke` is NULL, the codeinst is not yet executable. `invoke` is NULL, `specsigflags` may be treated as 0b00, `specptr` may be treated as NULL.
69
-
3.Read the `specptr` field with at least an acquire memory ordering.
67
+
1. Read the `specptr` field with any memory ordering.
68
+
2.Read the `invoke` field with at least an acquire memory ordering. This load will be referred to as `initial_invoke`.
69
+
3.If `initial_invoke` is NULL, the codeinst is not yet executable. `invoke` is NULL, `specsigflags` may be treated as 0b00, `specptr` may be treated as NULL.
70
70
4. If `specptr` is NULL, then the `initial_invoke` pointer must not be relying on `specptr` to guarantee correct execution. Therefore, `invoke` is non-null, `specsigflags` may be treated as 0b00, `specptr` may be treated as NULL.
71
71
5. If `specptr` is non-null, then `initial_invoke` might not be the final `invoke` field that uses `specptr`. This can occur if `specptr` has been written, but `invoke` has not yet been written. Therefore, spin on the second bit of `specsigflags` until it is set to 1 with at least acquire memory ordering.
72
-
6. Re-read the `invoke` field with at least an acquire memory ordering. This load will be referred to as `final_invoke`.
72
+
6. Re-read the `invoke` field with any memory ordering. This load will be referred to as `final_invoke`.
73
73
7. Read the `specsigflags` field with any memory ordering.
74
74
8.`invoke` is `final_invoke`, `specsigflags` is the value read in step 7, `specptr` is the value read in step 3.
75
75
3. When updating a `specptr` to a different but equivalent function pointer:
76
76
1. Perform a release store of the new function pointer to `specptr`. Races here must be benign, as the old function pointer is required to still be valid, and any new ones are also required to be valid as well. Once a pointer has been written to `specptr`, it must always be callable whether or not it is later overwritten.
77
77
78
+
Correctly reading these fields is implemented in `jl_read_codeinst_invoke`.
79
+
78
80
Although these write, read, and update steps are complicated, they ensure that the JIT can update codeinsts without invalidating existing codeinsts, and that the JIT can update codeinsts without invalidating existing `invoke` pointers. This allows the JIT to potentially reoptimize functions at higher optimization levels in the future, and also will allow the JIT to support concurrent compilation of functions in the future.
// Check if it is already compiled (either JIT or externally)
5191
-
if (cache_valid) {
5191
+
if (need_to_emit && cache_valid) {
5192
5192
// optimization: emit the correct name immediately, if we know it
5193
5193
// TODO: use `emitted` map here too to try to consolidate names?
5194
-
// WARNING: isspecsig is protected by the codegen-lock. If that lock is removed, then the isspecsig load needs to be properly atomically sequenced with this.
5195
-
auto fptr = jl_atomic_load_relaxed(&codeinst->specptr.fptr);
5196
-
if (fptr) {
5197
-
while (!(jl_atomic_load_acquire(&codeinst->specsigflags) & 0b10)) {
// WARNING: this invoke load is protected by the codegen-lock. If that lock is removed, then the isspecsig load needs to be properly atomically sequenced with this.
// try to emit code for this item from the workqueue
9914
9902
StringRef preal_decl = "";
9915
9903
bool preal_specsig = false;
9916
-
auto invoke = jl_atomic_load_acquire(&codeinst->invoke);
9917
-
bool cache_valid = params.cache;
9918
-
// WARNING: isspecsig is protected by the codegen-lock. If that lock is removed, then the isspecsig load needs to be properly atomically sequenced with this.
0 commit comments