Skip to content

Commit 94d95af

Browse files
vtjnashKristofferC
authored andcommitted
add METHOD_SIG_LATEST_ONLY optimization to MethodInstance too (#58825)
Add the same optimization from Method to MethodInstance, although the performance gain seems to be negligible in my specific testing, there doesn't seem any likely downside to adding one caching bit to avoid some recomputations. (cherry picked from commit b459d88)
1 parent 5659aef commit 94d95af

File tree

9 files changed

+165
-89
lines changed

9 files changed

+165
-89
lines changed

base/essentials.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -684,7 +684,7 @@ Neither `convert` nor `cconvert` should take a Julia object and turn it into a `
684684
"""
685685
function cconvert end
686686

687-
cconvert(T::Type, x) = x isa T ? x : convert(T, x) # do the conversion eagerly in most cases
687+
cconvert(::Type{T}, x) where {T} = x isa T ? x : convert(T, x) # do the conversion eagerly in most cases
688688
cconvert(::Type{Union{}}, x...) = convert(Union{}, x...)
689689
cconvert(::Type{<:Ptr}, x) = x # but defer the conversion to Ptr to unsafe_convert
690690
unsafe_convert(::Type{T}, x::T) where {T} = x # unsafe_convert (like convert) defaults to assuming the convert occurred

base/staticdata.jl

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,7 @@ end
290290

291291
function verify_call(@nospecialize(sig), expecteds::Core.SimpleVector, i::Int, n::Int, world::UInt)
292292
# verify that these edges intersect with the same methods as before
293+
mi = nothing
293294
if n == 1
294295
# first, fast-path a check if the expected method simply dominates its sig anyways
295296
# so the result of ml_matches is already simply known
@@ -298,11 +299,18 @@ function verify_call(@nospecialize(sig), expecteds::Core.SimpleVector, i::Int, n
298299
meth = t
299300
else
300301
if t isa CodeInstance
301-
t = get_ci_mi(t)
302+
mi = get_ci_mi(t)::MethodInstance
302303
else
303-
t = t::MethodInstance
304+
mi = t::MethodInstance
305+
end
306+
meth = mi.def::Method
307+
if !iszero(mi.dispatch_status & METHOD_SIG_LATEST_ONLY)
308+
minworld = meth.primary_world
309+
@assert minworld world
310+
maxworld = typemax(UInt)
311+
result = Any[] # result is unused
312+
return minworld, maxworld, result
304313
end
305-
meth = t.def::Method
306314
end
307315
if !iszero(meth.dispatch_status & METHOD_SIG_LATEST_ONLY)
308316
minworld = meth.primary_world
@@ -336,7 +344,7 @@ function verify_call(@nospecialize(sig), expecteds::Core.SimpleVector, i::Int, n
336344
meth = t
337345
else
338346
if t isa CodeInstance
339-
t = get_ci_mi(t)
347+
t = get_ci_mi(t)::MethodInstance
340348
else
341349
t = t::MethodInstance
342350
end
@@ -363,6 +371,9 @@ function verify_call(@nospecialize(sig), expecteds::Core.SimpleVector, i::Int, n
363371
resize!(result, ins)
364372
end
365373
end
374+
if maxworld[] == typemax(UInt) && mi isa MethodInstance
375+
ccall(:jl_promote_mi_to_current, Cvoid, (Any, UInt, UInt), mi, minworld[], world)
376+
end
366377
return minworld[], maxworld[], result
367378
end
368379

doc/src/devdocs/locks.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,10 @@ may result in pernicious and hard-to-find deadlocks. BE VERY CAREFUL!
8585
>
8686
> * Libdl.LazyLibrary lock
8787
88+
The following is a level 7 lock, which can only be acquired when not holding any other locks:
89+
90+
> * world_counter_lock
91+
8892

8993
The following is the root lock, meaning no other lock shall be held when trying to acquire it:
9094

src/gf.c

Lines changed: 130 additions & 33 deletions
Large diffs are not rendered by default.

src/jltypes.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3575,7 +3575,7 @@ void jl_init_types(void) JL_GC_DISABLED
35753575
jl_module_type,
35763576
jl_symbol_type,
35773577
jl_int32_type,
3578-
jl_int32_type,
3578+
jl_uint8_type,
35793579
jl_ulong_type,
35803580
jl_type_type,
35813581
jl_any_type, // union(jl_simplevector_type, jl_method_instance_type),
@@ -3613,27 +3613,29 @@ void jl_init_types(void) JL_GC_DISABLED
36133613
jl_method_instance_type =
36143614
jl_new_datatype(jl_symbol("MethodInstance"), core,
36153615
jl_any_type, jl_emptysvec,
3616-
jl_perm_symsvec(7,
3616+
jl_perm_symsvec(8,
36173617
"def",
36183618
"specTypes",
36193619
"sparam_vals",
36203620
"backedges",
36213621
"cache",
36223622
"cache_with_orig",
3623-
"flags"),
3624-
jl_svec(7,
3623+
"flags",
3624+
"dispatch_status"),
3625+
jl_svec(8,
36253626
jl_new_struct(jl_uniontype_type, jl_method_type, jl_module_type),
36263627
jl_any_type,
36273628
jl_simplevector_type,
36283629
jl_array_any_type,
36293630
jl_any_type/*jl_code_instance_type*/,
36303631
jl_bool_type,
3631-
jl_bool_type),
3632+
jl_bool_type,
3633+
jl_uint8_type),
36323634
jl_emptysvec,
36333635
0, 1, 3);
36343636
// These fields should be constant, but Serialization wants to mutate them in initialization
36353637
//const static uint32_t method_instance_constfields[1] = { 0b0000111 }; // fields 1, 2, 3
3636-
const static uint32_t method_instance_atomicfields[1] = { 0b1010000 }; // fields 5, 7
3638+
const static uint32_t method_instance_atomicfields[1] = { 0b11010000 }; // fields 5, 7, 8
36373639
//Fields 4 and 5 must be protected by method->write_lock, and thus all operations on jl_method_instance_t are threadsafe.
36383640
//jl_method_instance_type->name->constfields = method_instance_constfields;
36393641
jl_method_instance_type->name->atomicfields = method_instance_atomicfields;

src/julia.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ typedef struct _jl_method_t {
332332
struct _jl_module_t *module;
333333
jl_sym_t *file;
334334
int32_t line;
335-
_Atomic(int32_t) dispatch_status; // bits defined in staticdata.jl
335+
_Atomic(uint8_t) dispatch_status; // bits defined in staticdata.jl
336336
_Atomic(size_t) primary_world;
337337

338338
// method's type signature. redundant with TypeMapEntry->specTypes
@@ -417,6 +417,7 @@ struct _jl_method_instance_t {
417417
// bit 2: The ->backedges field is currently being walked higher up the stack - entries may be deleted, but not moved
418418
// bit 3: The ->backedges field was modified and should be compacted when clearing bit 2
419419
_Atomic(uint8_t) flags;
420+
_Atomic(uint8_t) dispatch_status; // bits defined in staticdata.jl
420421
};
421422
#define JL_MI_FLAGS_MASK_PRECOMPILED 0x01
422423
#define JL_MI_FLAGS_MASK_DISPATCHED 0x02

src/method.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,7 @@ JL_DLLEXPORT jl_method_instance_t *jl_new_method_instance_uninit(void)
609609
jl_atomic_store_relaxed(&mi->cache, NULL);
610610
mi->cache_with_orig = 0;
611611
jl_atomic_store_relaxed(&mi->flags, 0);
612+
jl_atomic_store_relaxed(&mi->dispatch_status, 0);
612613
return mi;
613614
}
614615

src/staticdata.c

Lines changed: 3 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1846,6 +1846,9 @@ static void jl_write_values(jl_serializer_state *s) JL_GC_DISABLED
18461846
assert(f == s->s);
18471847
jl_method_instance_t *newmi = (jl_method_instance_t*)&f->buf[reloc_offset];
18481848
jl_atomic_store_relaxed(&newmi->flags, 0);
1849+
if (s->incremental) {
1850+
jl_atomic_store_relaxed(&newmi->dispatch_status, 0);
1851+
}
18491852
}
18501853
else if (jl_is_code_instance(v)) {
18511854
assert(f == s->s);
@@ -4544,49 +4547,6 @@ JL_DLLEXPORT jl_value_t *jl_restore_package_image_from_file(const char *fname, j
45444547
return mod;
45454548
}
45464549

4547-
JL_DLLEXPORT void _jl_promote_ci_to_current(jl_code_instance_t *ci, size_t validated_world) JL_NOTSAFEPOINT
4548-
{
4549-
if (jl_atomic_load_relaxed(&ci->max_world) != validated_world)
4550-
return;
4551-
jl_atomic_store_relaxed(&ci->max_world, ~(size_t)0);
4552-
jl_svec_t *edges = jl_atomic_load_relaxed(&ci->edges);
4553-
for (size_t i = 0; i < jl_svec_len(edges); i++) {
4554-
jl_value_t *edge = jl_svecref(edges, i);
4555-
if (!jl_is_code_instance(edge))
4556-
continue;
4557-
_jl_promote_ci_to_current((jl_code_instance_t *)edge, validated_world);
4558-
}
4559-
}
4560-
4561-
JL_DLLEXPORT void jl_promote_ci_to_current(jl_code_instance_t *ci, size_t validated_world)
4562-
{
4563-
size_t current_world = jl_atomic_load_relaxed(&jl_world_counter);
4564-
// No need to acquire the lock if we've been invalidated anyway
4565-
if (current_world > validated_world)
4566-
return;
4567-
JL_LOCK(&world_counter_lock);
4568-
current_world = jl_atomic_load_relaxed(&jl_world_counter);
4569-
if (current_world == validated_world) {
4570-
_jl_promote_ci_to_current(ci, validated_world);
4571-
}
4572-
JL_UNLOCK(&world_counter_lock);
4573-
}
4574-
4575-
JL_DLLEXPORT void jl_promote_cis_to_current(jl_code_instance_t **cis, size_t n, size_t validated_world)
4576-
{
4577-
size_t current_world = jl_atomic_load_relaxed(&jl_world_counter);
4578-
// No need to acquire the lock if we've been invalidated anyway
4579-
if (current_world > validated_world)
4580-
return;
4581-
JL_LOCK(&world_counter_lock);
4582-
current_world = jl_atomic_load_relaxed(&jl_world_counter);
4583-
if (current_world == validated_world) {
4584-
for (size_t i = 0; i < n; i++) {
4585-
_jl_promote_ci_to_current(cis[i], validated_world);
4586-
}
4587-
}
4588-
JL_UNLOCK(&world_counter_lock);
4589-
}
45904550

45914551
#ifdef __cplusplus
45924552
}

test/core.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ for (T, c) in (
3737
(Core.CodeInfo, []),
3838
(Core.CodeInstance, [:next, :min_world, :max_world, :inferred, :edges, :debuginfo, :ipo_purity_bits, :invoke, :specptr, :specsigflags, :precompile, :time_compile]),
3939
(Core.Method, [:primary_world, :did_scan_source, :dispatch_status]),
40-
(Core.MethodInstance, [:cache, :flags]),
40+
(Core.MethodInstance, [:cache, :flags, :dispatch_status]),
4141
(Core.MethodTable, [:defs]),
4242
(Core.MethodCache, [:leafcache, :cache, :var""]),
4343
(Core.TypeMapEntry, [:next, :min_world, :max_world]),

0 commit comments

Comments
 (0)