From 9d665ff3a89e62564da0cd1c3006de963a3bf413 Mon Sep 17 00:00:00 2001 From: Cody Tapscott <84105208+topolarity@users.noreply.github.com> Date: Mon, 14 Apr 2025 21:47:16 -0400 Subject: [PATCH 01/83] gf.c: Fix backedge de-duplication bug (#58106) This code was checking for the old edge type (`MethodInstance`) instead of the new one (`CodeInstance`), causing duplicate non-invoke edges to accumulate in our `backedges`. (cherry picked from commit cf875c1ff1f8a3679f84e51789654e50630c361f) --- Compiler/src/typeinfer.jl | 2 ++ Compiler/test/invalidation.jl | 37 +++++++++++++++++++++++++++++++++++ src/gf.c | 2 +- 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/Compiler/src/typeinfer.jl b/Compiler/src/typeinfer.jl index 2e7c7a5018e06..5b36e38168b4c 100644 --- a/Compiler/src/typeinfer.jl +++ b/Compiler/src/typeinfer.jl @@ -610,6 +610,8 @@ function store_backedges(caller::CodeInstance, edges::SimpleVector) # `invoke` edge elseif isa(callee, CodeInstance) callee = get_ci_mi(callee) + else + callee = callee::MethodInstance end ccall(:jl_method_instance_add_backedge, Cvoid, (Any, Any, Any), callee, item, caller) i += 2 diff --git a/Compiler/test/invalidation.jl b/Compiler/test/invalidation.jl index 32f462f06f4e9..b4d69c8f0c3b8 100644 --- a/Compiler/test/invalidation.jl +++ b/Compiler/test/invalidation.jl @@ -161,6 +161,43 @@ begin @test "42" == String(take!(GLOBAL_BUFFER)) end +begin + deduped_callee(x::Int) = @noinline rand(Int) + deduped_caller1(x::Int) = @noinline deduped_callee(x) + deduped_caller2(x::Int) = @noinline deduped_callee(x) + + # run inference on both `deduped_callerx` and `deduped_callee` + let (src, rt) = code_typed((Int,); interp=InvalidationTester()) do x + @inline deduped_caller1(x) + @inline deduped_caller2(x) + end |> only + @test rt === Int + @test any(isinvoke(:deduped_callee), src.code) + end + + # Verify that adding the backedge again does not actually add a new backedge + let mi1 = Base.method_instance(deduped_caller1, (Int,)), + mi2 = Base.method_instance(deduped_caller2, (Int,)), + ci1 = mi1.cache + ci2 = mi2.cache + + callee_mi = Base.method_instance(deduped_callee, (Int,)) + + # Inference should have added the callers to the callee's backedges + @test ci1 in callee_mi.backedges + @test ci2 in callee_mi.backedges + + N = length(callee_mi.backedges) + Core.Compiler.store_backedges(ci1, Core.svec(callee_mi)) + Core.Compiler.store_backedges(ci2, Core.svec(callee_mi)) + N′ = length(callee_mi.backedges) + + # The number of backedges should not be affected by an additional store, + # since de-duplication should have noticed the edge is already tracked + @test N == N′ + end +end + # we can avoid adding backedge even if the callee's return type is not the top # when the return value is not used within the caller begin take!(GLOBAL_BUFFER) diff --git a/src/gf.c b/src/gf.c index 7b2f996563dda..8ed37503b80a9 100644 --- a/src/gf.c +++ b/src/gf.c @@ -2023,7 +2023,7 @@ JL_DLLEXPORT void jl_method_instance_add_backedge(jl_method_instance_t *callee, if (ciedge != (jl_value_t*)caller) continue; jl_value_t *invokeTypes = i > 0 ? jl_array_ptr_ref(backedges, i - 1) : NULL; - if (invokeTypes && jl_is_method_instance(invokeTypes)) + if (invokeTypes && jl_is_code_instance(invokeTypes)) invokeTypes = NULL; if ((invokesig == NULL && invokeTypes == NULL) || (invokesig && invokeTypes && jl_types_equal(invokesig, invokeTypes))) { From 42dabfd73a26686566a57da96798352db7a167a0 Mon Sep 17 00:00:00 2001 From: Cody Tapscott Date: Mon, 14 Apr 2025 17:34:28 -0400 Subject: [PATCH 02/83] typeinfer: De-duplicate backedges as they are stored Since the caller CodeInstance is always part of the identity that we are de-duplicating on, this makes the linear scan much faster than it is in `gf.c` (cherry picked from commit 366a2246b243c5b831bdcded3a046a86d1559f8f) --- Compiler/src/typeinfer.jl | 82 ++++++++++++++++++++++++++------------- 1 file changed, 54 insertions(+), 28 deletions(-) diff --git a/Compiler/src/typeinfer.jl b/Compiler/src/typeinfer.jl index 5b36e38168b4c..e11b6138a209c 100644 --- a/Compiler/src/typeinfer.jl +++ b/Compiler/src/typeinfer.jl @@ -572,12 +572,17 @@ function finishinfer!(me::InferenceState, interp::AbstractInterpreter, cycleid:: nothing end -# record the backedges -function store_backedges(caller::CodeInstance, edges::SimpleVector) - isa(caller.def.def, Method) || return # don't add backedges to toplevel method instance - i = 1 - while true - i > length(edges) && return nothing +# Iterate a series of back-edges that need registering, based on the provided forward edge list. +# Back-edges are returned as (invokesig, item), where the item is a Binding, MethodInstance, or +# MethodTable. +struct ForwardToBackedgeIterator + forward_edges::SimpleVector +end + +function Base.iterate(it::ForwardToBackedgeIterator, i::Int = 1) + edges = it.forward_edges + i > length(edges) && return nothing + while i ≤ length(edges) item = edges[i] if item isa Int i += 2 @@ -587,34 +592,55 @@ function store_backedges(caller::CodeInstance, edges::SimpleVector) i += 1 continue elseif isa(item, Core.Binding) - i += 1 - maybe_add_binding_backedge!(item, caller) - continue + return ((nothing, item), i + 1) end if isa(item, CodeInstance) - item = item.def - end - if isa(item, MethodInstance) # regular dispatch - ccall(:jl_method_instance_add_backedge, Cvoid, (Any, Any, Any), item, nothing, caller) - i += 1 + item = get_ci_mi(item) + return ((nothing, item), i + 1) + elseif isa(item, MethodInstance) # regular dispatch + return ((nothing, item), i + 1) else + invokesig = item callee = edges[i+1] - if isa(callee, MethodTable) # abstract dispatch (legacy style edges) - ccall(:jl_method_table_add_backedge, Cvoid, (Any, Any, Any), callee, item, caller) - i += 2 - continue - elseif isa(callee, Method) - # ignore `Method`-edges (from e.g. failed `abstract_call_method`) - i += 2 - continue - # `invoke` edge - elseif isa(callee, CodeInstance) - callee = get_ci_mi(callee) + isa(callee, Method) && (i += 2; continue) # ignore `Method`-edges (from e.g. failed `abstract_call_method`) + if isa(callee, MethodTable) + # abstract dispatch (legacy style edges) + return ((invokesig, callee), i + 2) else - callee = callee::MethodInstance + # `invoke` edge + callee = isa(callee, CodeInstance) ? get_ci_mi(callee) : callee::MethodInstance + return ((invokesig, callee), i + 2) + end + end + end + return nothing +end + +# record the backedges +function store_backedges(caller::CodeInstance, edges::SimpleVector) + isa(caller.def.def, Method) || return # don't add backedges to toplevel method instance + + backedges = ForwardToBackedgeIterator(edges) + for (i, (invokesig, item)) in enumerate(backedges) + # check for any duplicate edges we've already registered + duplicate_found = false + for (i′, (invokesig′, item′)) in enumerate(backedges) + i == i′ && break + if item′ === item && invokesig′ == invokesig + duplicate_found = true + break + end + end + + if !duplicate_found + if item isa Core.Binding + maybe_add_binding_backedge!(item, caller) + elseif item isa MethodTable + ccall(:jl_method_table_add_backedge, Cvoid, (Any, Any, Any), item, invokesig, caller) + else + item::MethodInstance + ccall(:jl_method_instance_add_backedge, Cvoid, (Any, Any, Any), item, invokesig, caller) end - ccall(:jl_method_instance_add_backedge, Cvoid, (Any, Any, Any), callee, item, caller) - i += 2 end end nothing From c0aaabe1ffd90213debeb2e8bc9bb8eb18144f2c Mon Sep 17 00:00:00 2001 From: Cody Tapscott Date: Mon, 14 Apr 2025 17:37:23 -0400 Subject: [PATCH 03/83] staticdata: do not serialize backedges for `MethodInstance` / `MethodTable` These are restored in their entirety by staticdata.jl, so there's no need to serialize them. Dropping them has the additional advantage of making it unnecessary to de-duplicate edges in `gf.c` (cherry picked from commit 5c66152aec65f0a33f105be220675290f0ded383) --- src/staticdata.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/staticdata.c b/src/staticdata.c index 1ed933107dd46..634e8ae40fe27 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -854,6 +854,12 @@ static void jl_insert_into_serialization_queue(jl_serializer_state *s, jl_value_ } goto done_fields; // for now } + if (s->incremental && jl_is_mtable(v)) { + jl_methtable_t *mt = (jl_methtable_t *)v; + // Any back-edges will be re-validated and added by staticdata.jl, so + // drop them from the image here + record_field_change((jl_value_t**)&mt->backedges, NULL); + } if (jl_is_method_instance(v)) { jl_method_instance_t *mi = (jl_method_instance_t*)v; if (s->incremental) { @@ -869,12 +875,14 @@ static void jl_insert_into_serialization_queue(jl_serializer_state *s, jl_value_ // we only need 3 specific fields of this (the rest are restored afterward, if valid) // in particular, cache is repopulated by jl_mi_cache_insert for all foreign function, // so must not be present here - record_field_change((jl_value_t**)&mi->backedges, NULL); record_field_change((jl_value_t**)&mi->cache, NULL); } else { assert(!needs_recaching(v, s->query_cache)); } + // Any back-edges will be re-validated and added by staticdata.jl, so + // drop them from the image here + record_field_change((jl_value_t**)&mi->backedges, NULL); // n.b. opaque closures cannot be inspected and relied upon like a // normal method since they can get improperly introduced by generated // functions, so if they appeared at all, we will probably serialize From b2aa9a2c4078749aa6eeff8f37f948a8cce8ecda Mon Sep 17 00:00:00 2001 From: Cody Tapscott Date: Mon, 14 Apr 2025 17:39:20 -0400 Subject: [PATCH 04/83] gf.c: make edge de-duplication a caller responsibility On my system, this saves ~500 ms when loading CairoMakie (and all dependent packages) (cherry picked from commit bf725f1fb487ebbbda259b04da282ad04b151031) --- src/gf.c | 29 +---------------------------- 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/src/gf.c b/src/gf.c index 8ed37503b80a9..42d026dd2d329 100644 --- a/src/gf.c +++ b/src/gf.c @@ -2006,7 +2006,6 @@ JL_DLLEXPORT void jl_method_instance_add_backedge(jl_method_instance_t *callee, assert(invokesig == NULL || jl_is_type(invokesig)); JL_LOCK(&callee->def.method->writelock); if (jl_atomic_load_relaxed(&allow_new_worlds)) { - int found = 0; jl_array_t *backedges = jl_mi_get_backedges(callee); // TODO: use jl_cache_type_(invokesig) like cache_method does to save memory if (!backedges) { @@ -2015,25 +2014,7 @@ JL_DLLEXPORT void jl_method_instance_add_backedge(jl_method_instance_t *callee, callee->backedges = backedges; jl_gc_wb(callee, backedges); } - else { - size_t i = 0, l = jl_array_nrows(backedges); - for (i = 0; i < l; i++) { - // optimized version of while (i < l) i = get_next_edge(callee->backedges, i, &invokeTypes, &mi); - jl_value_t *ciedge = jl_array_ptr_ref(backedges, i); - if (ciedge != (jl_value_t*)caller) - continue; - jl_value_t *invokeTypes = i > 0 ? jl_array_ptr_ref(backedges, i - 1) : NULL; - if (invokeTypes && jl_is_code_instance(invokeTypes)) - invokeTypes = NULL; - if ((invokesig == NULL && invokeTypes == NULL) || - (invokesig && invokeTypes && jl_types_equal(invokesig, invokeTypes))) { - found = 1; - break; - } - } - } - if (!found) - push_edge(backedges, invokesig, caller); + push_edge(backedges, invokesig, caller); } JL_UNLOCK(&callee->def.method->writelock); } @@ -2056,14 +2037,6 @@ JL_DLLEXPORT void jl_method_table_add_backedge(jl_methtable_t *mt, jl_value_t *t else { // check if the edge is already present and avoid adding a duplicate size_t i, l = jl_array_nrows(mt->backedges); - for (i = 1; i < l; i += 2) { - if (jl_array_ptr_ref(mt->backedges, i) == (jl_value_t*)caller) { - if (jl_types_equal(jl_array_ptr_ref(mt->backedges, i - 1), typ)) { - JL_UNLOCK(&mt->writelock); - return; - } - } - } // reuse an already cached instance of this type, if possible // TODO: use jl_cache_type_(tt) like cache_method does, instead of this linear scan? for (i = 1; i < l; i += 2) { From 4206e21f25e55a38dd61ef3b8ae2cbd5acab5a5a Mon Sep 17 00:00:00 2001 From: Cody Tapscott Date: Thu, 8 May 2025 11:27:40 -0400 Subject: [PATCH 05/83] Update back-edge de-duplication test (cherry picked from commit 75255683192e98b07d22cf0cd4e7242401ba84fb) --- Compiler/test/invalidation.jl | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/Compiler/test/invalidation.jl b/Compiler/test/invalidation.jl index b4d69c8f0c3b8..0135009673aef 100644 --- a/Compiler/test/invalidation.jl +++ b/Compiler/test/invalidation.jl @@ -176,25 +176,24 @@ begin end # Verify that adding the backedge again does not actually add a new backedge - let mi1 = Base.method_instance(deduped_caller1, (Int,)), - mi2 = Base.method_instance(deduped_caller2, (Int,)), - ci1 = mi1.cache - ci2 = mi2.cache + let mi = Base.method_instance(deduped_caller1, (Int,)), + ci = mi.cache callee_mi = Base.method_instance(deduped_callee, (Int,)) # Inference should have added the callers to the callee's backedges - @test ci1 in callee_mi.backedges - @test ci2 in callee_mi.backedges + @test ci in callee_mi.backedges + # In practice, inference will never end up calling `store_backedges` + # twice on the same CodeInstance like this - we only need to check + # that de-duplication works for a single invocation N = length(callee_mi.backedges) - Core.Compiler.store_backedges(ci1, Core.svec(callee_mi)) - Core.Compiler.store_backedges(ci2, Core.svec(callee_mi)) + Core.Compiler.store_backedges(ci, Core.svec(callee_mi, callee_mi)) N′ = length(callee_mi.backedges) - # The number of backedges should not be affected by an additional store, - # since de-duplication should have noticed the edge is already tracked - @test N == N′ + # A single `store_backedges` invocation should de-duplicate any of the + # edges it is adding. + @test N′ - N == 1 end end From 63df57764a74eacd6e6de78d105c8eeeb1c8df0c Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Thu, 24 Apr 2025 10:25:48 -0400 Subject: [PATCH 06/83] reduce places where Builtins are listed (#58205) DRY code somewhat by consolidating builtin declarations to use a table or macro definition to auto-generate the required reflection metadata. Mostly NFC, but does include a couple bugfixes caused by the consistency this enforces. Adding a new `Builtin` is now simply a matter of declaring it in `builtin_proto.h` and defining it in `builtins.c` and any relevant declarations are handled automatically. (cherry picked from commit 907b201cedec1b4d00e27f27535cce7e192beb26) --- src/builtin_proto.h | 152 ++++++------ src/builtins.c | 143 ++++------- src/cgutils.cpp | 2 +- src/codegen.cpp | 312 +++++++++++------------- src/common_symbols2.inc | 2 +- src/gf.c | 12 +- src/init.c | 2 - src/julia_internal.h | 10 +- src/llvm-codegen-shared.h | 3 - src/llvm-lower-handlers.cpp | 3 + src/llvm-pass-helpers.cpp | 3 + src/method.c | 5 +- src/signals-mach.c | 2 - src/staticdata.c | 456 ++++++++++++++++-------------------- src/toplevel.c | 4 +- 15 files changed, 475 insertions(+), 636 deletions(-) diff --git a/src/builtin_proto.h b/src/builtin_proto.h index c82ec77414129..586d948f722c1 100644 --- a/src/builtin_proto.h +++ b/src/builtin_proto.h @@ -8,82 +8,88 @@ extern "C" { #endif // declarations for julia-callable builtin functions +#define JL_BUILTIN_FUNCTIONS(XX) \ + XX(_abstracttype,"_abstracttype") \ + XX(_apply_iterate,"_apply_iterate") \ + XX(_call_in_world_total,"_call_in_world_total") \ + XX(_compute_sparams,"_compute_sparams") \ + XX(_defaultctors,"_defaultctors") \ + XX(_equiv_typedef,"_equiv_typedef") \ + XX(_expr,"_expr") \ + XX(_primitivetype,"_primitivetype") \ + XX(_setsuper,"_setsuper!") \ + XX(_structtype,"_structtype") \ + XX(_svec_ref,"_svec_ref") \ + XX(_typebody,"_typebody!") \ + XX(_typevar,"_typevar") \ + XX(applicable,"applicable") \ + XX(apply_type,"apply_type") \ + XX(compilerbarrier,"compilerbarrier") \ + XX(current_scope,"current_scope") \ + XX(donotdelete,"donotdelete") \ + XX(fieldtype,"fieldtype") \ + XX(finalizer,"finalizer") \ + XX(get_binding_type,"get_binding_type") \ + XX(getfield,"getfield") \ + XX(getglobal,"getglobal") \ + XX(ifelse,"ifelse") \ + XX(intrinsic_call,"intrinsic_call") \ + XX(invoke,"invoke") \ + XX(invoke_in_world,"invoke_in_world") \ + XX(invokelatest,"invokelatest") \ + XX(is,"===") \ + XX(isa,"isa") \ + XX(isdefined,"isdefined") \ + XX(isdefinedglobal,"isdefinedglobal") \ + XX(issubtype,"<:") \ + XX(memorynew,"memorynew") \ + XX(memoryrefnew,"memoryrefnew") \ + XX(memoryref_isassigned,"memoryref_isassigned") \ + XX(memoryrefget,"memoryrefget") \ + XX(memoryrefmodify,"memoryrefmodify!") \ + XX(memoryrefoffset,"memoryrefoffset") \ + XX(memoryrefreplace,"memoryrefreplace!") \ + XX(memoryrefset,"memoryrefset!") \ + XX(memoryrefsetonce,"memoryrefsetonce!") \ + XX(memoryrefswap,"memoryrefswap!") \ + XX(modifyfield,"modifyfield!") \ + XX(modifyglobal,"modifyglobal!") \ + XX(nfields,"nfields") \ + XX(opaque_closure_call,"opaque_closure_call") \ + XX(replacefield,"replacefield!") \ + XX(replaceglobal,"replaceglobal!") \ + XX(setfield,"setfield!") \ + XX(setfieldonce,"setfieldonce!") \ + XX(setglobal,"setglobal!") \ + XX(setglobalonce,"setglobalonce!") \ + XX(sizeof,"sizeof") \ + XX(svec,"svec") \ + XX(swapfield,"swapfield!") \ + XX(swapglobal,"swapglobal!") \ + XX(throw,"throw") \ + XX(throw_methoderror,"throw_methoderror") \ + XX(tuple,"tuple") \ + XX(typeassert,"typeassert") \ + XX(typeof,"typeof") \ -#ifdef DEFINE_BUILTIN_GLOBALS -#define DECLARE_BUILTIN(name) \ - JL_CALLABLE(jl_f_##name); \ - JL_DLLEXPORT jl_value_t *jl_builtin_##name; \ - JL_DLLEXPORT jl_fptr_args_t jl_f_##name##_addr = &jl_f_##name -#else -#define DECLARE_BUILTIN(name) \ - JL_CALLABLE(jl_f_##name); \ - JL_DLLEXPORT extern jl_value_t *jl_builtin_##name; \ - JL_DLLEXPORT extern jl_fptr_args_t jl_f_##name##_addr -#endif +#define DECLARE_BUILTIN(cname,jlname) \ + JL_CALLABLE(jl_f_##cname); +JL_BUILTIN_FUNCTIONS(DECLARE_BUILTIN) +#undef DECLARE_BUILTIN + +#define BUILTIN(cname) (jl_builtin_instances[jl_builtin_id_##cname]) + +enum jl_builtin_ids { +#define BUILTIN_IDS(cname,jlname) jl_builtin_id_##cname, +JL_BUILTIN_FUNCTIONS(BUILTIN_IDS) +#undef BUILTIN_IDS + jl_n_builtins +}; -DECLARE_BUILTIN(_apply_iterate); -DECLARE_BUILTIN(invoke_in_world); -DECLARE_BUILTIN(_call_in_world_total); -DECLARE_BUILTIN(invokelatest); -DECLARE_BUILTIN(_compute_sparams); -DECLARE_BUILTIN(_expr); -DECLARE_BUILTIN(_svec_ref); -DECLARE_BUILTIN(_typebody); -DECLARE_BUILTIN(_typevar); -DECLARE_BUILTIN(applicable); -DECLARE_BUILTIN(apply_type); -DECLARE_BUILTIN(compilerbarrier); -DECLARE_BUILTIN(current_scope); -DECLARE_BUILTIN(donotdelete); -DECLARE_BUILTIN(fieldtype); -DECLARE_BUILTIN(finalizer); -DECLARE_BUILTIN(getfield); -DECLARE_BUILTIN(getglobal); -DECLARE_BUILTIN(ifelse); -DECLARE_BUILTIN(invoke); -DECLARE_BUILTIN(is); -DECLARE_BUILTIN(isa); -DECLARE_BUILTIN(isdefined); -DECLARE_BUILTIN(isdefinedglobal); -DECLARE_BUILTIN(issubtype); -DECLARE_BUILTIN(memorynew); -DECLARE_BUILTIN(memoryref); -DECLARE_BUILTIN(memoryref_isassigned); -DECLARE_BUILTIN(memoryrefget); -DECLARE_BUILTIN(memoryrefmodify); -DECLARE_BUILTIN(memoryrefoffset); -DECLARE_BUILTIN(memoryrefreplace); -DECLARE_BUILTIN(memoryrefset); -DECLARE_BUILTIN(memoryrefsetonce); -DECLARE_BUILTIN(memoryrefswap); -DECLARE_BUILTIN(modifyfield); -DECLARE_BUILTIN(modifyglobal); -DECLARE_BUILTIN(nfields); -DECLARE_BUILTIN(replacefield); -DECLARE_BUILTIN(replaceglobal); -DECLARE_BUILTIN(setfield); -DECLARE_BUILTIN(setfieldonce); -DECLARE_BUILTIN(setglobal); -DECLARE_BUILTIN(setglobalonce); -DECLARE_BUILTIN(sizeof); -DECLARE_BUILTIN(svec); -DECLARE_BUILTIN(swapfield); -DECLARE_BUILTIN(swapglobal); -DECLARE_BUILTIN(throw); -DECLARE_BUILTIN(throw_methoderror); -DECLARE_BUILTIN(tuple); -DECLARE_BUILTIN(typeassert); -DECLARE_BUILTIN(typeof); +JL_DLLEXPORT extern jl_fptr_args_t const jl_builtin_f_addrs[]; +JL_DLLEXPORT extern const char *const jl_builtin_f_names[]; +JL_DLLEXPORT extern jl_value_t *jl_builtin_instances[]; -JL_CALLABLE(jl_f__structtype); -JL_CALLABLE(jl_f__abstracttype); -JL_CALLABLE(jl_f__primitivetype); -JL_CALLABLE(jl_f__setsuper); -JL_CALLABLE(jl_f__defaultctors); -JL_CALLABLE(jl_f__equiv_typedef); -JL_CALLABLE(jl_f_get_binding_type); -JL_CALLABLE(jl_f__compute_sparams); -JL_CALLABLE(jl_f__svec_ref); #ifdef __cplusplus } #endif diff --git a/src/builtins.c b/src/builtins.c index a2cae857f26b4..e3a0380182e15 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -30,6 +30,27 @@ extern "C" { #endif +jl_fptr_args_t const jl_builtin_f_addrs[jl_n_builtins] = { +#define BUILTIN_ADDRS(cname,jlname) &jl_f_##cname, +JL_BUILTIN_FUNCTIONS(BUILTIN_ADDRS) +#undef BUILTIN_ADDRS +}; + +const char *const jl_builtin_f_names[jl_n_builtins] = { +#define BUILTIN_F_NAMES(cname,jlname) XSTR(jl_f_##cname), +JL_BUILTIN_FUNCTIONS(BUILTIN_F_NAMES) +#undef BUILTIN_F_NAMES +}; + +jl_value_t *jl_builtin_instances[jl_n_builtins]; + +static const char *const jl_builtin_names[jl_n_builtins] = { +#define BUILTIN_NAMES(cname,jlname) jlname, +JL_BUILTIN_FUNCTIONS(BUILTIN_NAMES) +#undef BUILTIN_NAMES +}; + + // egal and object_id --------------------------------------------------------- static int bits_equal(const void *a, const void *b, int sz) JL_NOTSAFEPOINT @@ -647,7 +668,7 @@ JL_CALLABLE(jl_f__apply_iterate) nargs -= 1; if (nargs == 2) { // some common simple cases - if (f == jl_builtin_svec) { + if (f == BUILTIN(svec)) { if (jl_is_svec(args[1])) return args[1]; if (jl_is_genericmemory(args[1])) { @@ -672,7 +693,7 @@ JL_CALLABLE(jl_f__apply_iterate) return (jl_value_t*)t; } } - else if (f == jl_builtin_tuple && jl_is_tuple(args[1])) { + else if (f == BUILTIN(tuple) && jl_is_tuple(args[1])) { return args[1]; } } @@ -1691,11 +1712,11 @@ JL_CALLABLE(jl_f_memorynew) return (jl_value_t*)jl_alloc_genericmemory(args[0], nel); } -JL_CALLABLE(jl_f_memoryref) +JL_CALLABLE(jl_f_memoryrefnew) { - JL_NARGS(memoryref, 1, 3); + JL_NARGS(memoryrefnew, 1, 3); if (nargs == 1) { - JL_TYPECHK(memoryref, genericmemory, args[0]); + JL_TYPECHK(memoryrefnew, genericmemory, args[0]); jl_genericmemory_t *m = (jl_genericmemory_t*)args[0]; jl_value_t *typ = jl_apply_type((jl_value_t*)jl_genericmemoryref_type, jl_svec_data(((jl_datatype_t*)jl_typetagof(m))->parameters), 3); JL_GC_PROMISE_ROOTED(typ); // it is a concrete type @@ -1705,10 +1726,10 @@ JL_CALLABLE(jl_f_memoryref) return (jl_value_t*)jl_new_memoryref(typ, m, m->ptr); } else { - JL_TYPECHK(memoryref, genericmemoryref, args[0]); - JL_TYPECHK(memoryref, long, args[1]); + JL_TYPECHK(memoryrefnew, genericmemoryref, args[0]); + JL_TYPECHK(memoryrefnew, long, args[1]); if (nargs == 3) - JL_TYPECHK(memoryref, bool, args[2]); + JL_TYPECHK(memoryrefnew, bool, args[2]); jl_genericmemoryref_t *m = (jl_genericmemoryref_t*)args[0]; size_t i = jl_unbox_long(args[1]) - 1; const jl_datatype_layout_t *layout = ((jl_datatype_t*)jl_typetagof(m->mem))->layout; @@ -1735,7 +1756,7 @@ JL_CALLABLE(jl_f_memoryref) JL_CALLABLE(jl_f_memoryrefoffset) { JL_NARGS(memoryrefoffset, 1, 1); - JL_TYPECHK(memoryref, genericmemoryref, args[0]); + JL_TYPECHK(memoryrefoffest, genericmemoryref, args[0]); jl_genericmemoryref_t m = *(jl_genericmemoryref_t*)args[0]; const jl_datatype_layout_t *layout = ((jl_datatype_t*)jl_typetagof(m.mem))->layout; size_t offset; @@ -2415,10 +2436,10 @@ void jl_init_intrinsic_functions(void) JL_GC_DISABLED { jl_module_t *inm = jl_new_module_(jl_symbol("Intrinsics"), jl_core_module, 0, 1); jl_set_initial_const(jl_core_module, jl_symbol("Intrinsics"), (jl_value_t*)inm, 0); - jl_mk_builtin_func(jl_intrinsic_type, "IntrinsicFunction", jl_f_intrinsic_call); + jl_mk_builtin_func(jl_intrinsic_type, jl_symbol("IntrinsicFunction"), jl_f_intrinsic_call); jl_mk_builtin_func( (jl_datatype_t*)jl_unwrap_unionall((jl_value_t*)jl_opaque_closure_type), - "OpaqueClosure", jl_f_opaque_closure_call); + jl_symbol("OpaqueClosure"), jl_f_opaque_closure_call); // Save a reference to the just created OpaqueClosure method, so we can provide special // codegen for it later. @@ -2439,93 +2460,21 @@ static void add_builtin(const char *name, jl_value_t *v) jl_set_initial_const(jl_core_module, jl_symbol(name), v, 0); } -jl_fptr_args_t jl_get_builtin_fptr(jl_datatype_t *dt) -{ - assert(jl_subtype((jl_value_t*)dt, (jl_value_t*)jl_builtin_type)); - jl_typemap_entry_t *entry = (jl_typemap_entry_t*)jl_atomic_load_relaxed(&dt->name->mt->defs); - jl_method_instance_t *mi = jl_atomic_load_relaxed(&entry->func.method->unspecialized); - jl_code_instance_t *ci = jl_atomic_load_relaxed(&mi->cache); - assert(ci->owner == jl_nothing); - return jl_atomic_load_relaxed(&ci->specptr.fptr1); -} - -static jl_value_t *add_builtin_func(const char *name, jl_fptr_args_t fptr) -{ - return jl_mk_builtin_func(NULL, name, fptr)->instance; -} - void jl_init_primitives(void) JL_GC_DISABLED { - jl_builtin_is = add_builtin_func("===", jl_f_is); - jl_builtin_typeof = add_builtin_func("typeof", jl_f_typeof); - jl_builtin_sizeof = add_builtin_func("sizeof", jl_f_sizeof); - jl_builtin_issubtype = add_builtin_func("<:", jl_f_issubtype); - jl_builtin_isa = add_builtin_func("isa", jl_f_isa); - jl_builtin_typeassert = add_builtin_func("typeassert", jl_f_typeassert); - jl_builtin_throw = add_builtin_func("throw", jl_f_throw); - jl_builtin_tuple = add_builtin_func("tuple", jl_f_tuple); - jl_builtin_ifelse = add_builtin_func("ifelse", jl_f_ifelse); - - // field access - jl_builtin_getfield = add_builtin_func("getfield", jl_f_getfield); - jl_builtin_setfield = add_builtin_func("setfield!", jl_f_setfield); - jl_builtin_setfieldonce = add_builtin_func("setfieldonce!", jl_f_setfieldonce); - jl_builtin_swapfield = add_builtin_func("swapfield!", jl_f_swapfield); - jl_builtin_modifyfield = add_builtin_func("modifyfield!", jl_f_modifyfield); - jl_builtin_replacefield = add_builtin_func("replacefield!", jl_f_replacefield); - jl_builtin_fieldtype = add_builtin_func("fieldtype", jl_f_fieldtype); - jl_builtin_nfields = add_builtin_func("nfields", jl_f_nfields); - jl_builtin_isdefined = add_builtin_func("isdefined", jl_f_isdefined); - - // module bindings - jl_builtin_getglobal = add_builtin_func("getglobal", jl_f_getglobal); - jl_builtin_setglobal = add_builtin_func("setglobal!", jl_f_setglobal); - jl_builtin_isdefinedglobal = add_builtin_func("isdefinedglobal", jl_f_isdefinedglobal); - add_builtin_func("get_binding_type", jl_f_get_binding_type); - jl_builtin_swapglobal = add_builtin_func("swapglobal!", jl_f_swapglobal); - jl_builtin_replaceglobal = add_builtin_func("replaceglobal!", jl_f_replaceglobal); - jl_builtin_modifyglobal = add_builtin_func("modifyglobal!", jl_f_modifyglobal); - jl_builtin_setglobalonce = add_builtin_func("setglobalonce!", jl_f_setglobalonce); - - // memory primitives - jl_builtin_memorynew = add_builtin_func("memorynew", jl_f_memorynew); - jl_builtin_memoryref = add_builtin_func("memoryrefnew", jl_f_memoryref); - jl_builtin_memoryrefoffset = add_builtin_func("memoryrefoffset", jl_f_memoryrefoffset); - jl_builtin_memoryrefget = add_builtin_func("memoryrefget", jl_f_memoryrefget); - jl_builtin_memoryrefset = add_builtin_func("memoryrefset!", jl_f_memoryrefset); - jl_builtin_memoryref_isassigned = add_builtin_func("memoryref_isassigned", jl_f_memoryref_isassigned); - jl_builtin_memoryrefswap = add_builtin_func("memoryrefswap!", jl_f_memoryrefswap); - jl_builtin_memoryrefreplace = add_builtin_func("memoryrefreplace!", jl_f_memoryrefreplace); - jl_builtin_memoryrefmodify = add_builtin_func("memoryrefmodify!", jl_f_memoryrefmodify); - jl_builtin_memoryrefsetonce = add_builtin_func("memoryrefsetonce!", jl_f_memoryrefsetonce); - - // method table utils - jl_builtin_applicable = add_builtin_func("applicable", jl_f_applicable); - jl_builtin_invoke = add_builtin_func("invoke", jl_f_invoke); - - // internal functions - jl_builtin_apply_type = add_builtin_func("apply_type", jl_f_apply_type); - jl_builtin__apply_iterate = add_builtin_func("_apply_iterate", jl_f__apply_iterate); - jl_builtin__expr = add_builtin_func("_expr", jl_f__expr); - jl_builtin_svec = add_builtin_func("svec", jl_f_svec); - add_builtin_func("invokelatest", jl_f_invokelatest); - add_builtin_func("invoke_in_world", jl_f_invoke_in_world); - add_builtin_func("_call_in_world_total", jl_f__call_in_world_total); - add_builtin_func("_typevar", jl_f__typevar); - add_builtin_func("_structtype", jl_f__structtype); - add_builtin_func("_abstracttype", jl_f__abstracttype); - add_builtin_func("_primitivetype", jl_f__primitivetype); - add_builtin_func("_setsuper!", jl_f__setsuper); - add_builtin_func("_defaultctors", jl_f__defaultctors); - jl_builtin__typebody = add_builtin_func("_typebody!", jl_f__typebody); - add_builtin_func("_equiv_typedef", jl_f__equiv_typedef); - jl_builtin_donotdelete = add_builtin_func("donotdelete", jl_f_donotdelete); - jl_builtin_compilerbarrier = add_builtin_func("compilerbarrier", jl_f_compilerbarrier); - add_builtin_func("finalizer", jl_f_finalizer); - add_builtin_func("_compute_sparams", jl_f__compute_sparams); - add_builtin_func("_svec_ref", jl_f__svec_ref); - jl_builtin_current_scope = add_builtin_func("current_scope", jl_f_current_scope); - add_builtin_func("throw_methoderror", jl_f_throw_methoderror); + // Builtins are specially considered available from world 0 + for (int i = 0; i < jl_n_builtins; i++) { + if (i == jl_builtin_id_intrinsic_call || + i == jl_builtin_id_opaque_closure_call) + continue; + jl_sym_t *sname = jl_symbol(jl_builtin_names[i]); + jl_value_t *builtin = jl_new_generic_function_with_supertype(sname, jl_core_module, jl_builtin_type, 0); + jl_set_initial_const(jl_core_module, sname, builtin, 0); + jl_mk_builtin_func((jl_datatype_t*)jl_typeof(builtin), sname, jl_builtin_f_addrs[i]); + jl_builtin_instances[i] = builtin; + } + add_builtin("OpaqueClosure", (jl_value_t*)jl_opaque_closure_type); + add_builtin("IntrinsicFunction", (jl_value_t*)jl_intrinsic_type); // builtin types add_builtin("Any", (jl_value_t*)jl_any_type); @@ -2558,14 +2507,12 @@ void jl_init_primitives(void) JL_GC_DISABLED add_builtin("PartialOpaque", (jl_value_t*)jl_partial_opaque_type); add_builtin("InterConditional", (jl_value_t*)jl_interconditional_type); add_builtin("MethodMatch", (jl_value_t*)jl_method_match_type); - add_builtin("IntrinsicFunction", (jl_value_t*)jl_intrinsic_type); add_builtin("Function", (jl_value_t*)jl_function_type); add_builtin("Builtin", (jl_value_t*)jl_builtin_type); add_builtin("MethodInstance", (jl_value_t*)jl_method_instance_type); add_builtin("CodeInfo", (jl_value_t*)jl_code_info_type); add_builtin("LLVMPtr", (jl_value_t*)jl_llvmpointer_type); add_builtin("Task", (jl_value_t*)jl_task_type); - add_builtin("OpaqueClosure", (jl_value_t*)jl_opaque_closure_type); add_builtin("AddrSpace", (jl_value_t*)jl_addrspace_type); add_builtin("Ref", (jl_value_t*)jl_ref_type); diff --git a/src/cgutils.cpp b/src/cgutils.cpp index beaad5f85fec3..a4618a32e1d7c 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -4638,7 +4638,7 @@ static Value *emit_memoryref_FCA(jl_codectx_t &ctx, const jl_cgval_t &ref, const static jl_cgval_t emit_memoryref(jl_codectx_t &ctx, const jl_cgval_t &ref, jl_cgval_t idx, jl_value_t *inbounds, const jl_datatype_layout_t *layout) { ++EmittedArrayNdIndex; - emit_typecheck(ctx, idx, (jl_value_t*)jl_long_type, "memoryref"); + emit_typecheck(ctx, idx, (jl_value_t*)jl_long_type, "memoryrefnew"); idx = update_julia_type(ctx, idx, (jl_value_t*)jl_long_type); if (idx.typ == jl_bottom_type) return jl_cgval_t(); diff --git a/src/codegen.cpp b/src/codegen.cpp index 6f6328c2a5758..4b857f95dc3bf 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -354,7 +354,7 @@ struct jl_tbaacache_t { MDNode *tbaa_ptrarraybuf; // Data in an array of boxed values MDNode *tbaa_arraybuf; // Data in an array of POD MDNode *tbaa_array; // jl_array_t or jl_genericmemory_t - MDNode *tbaa_arrayptr; // The pointer inside a jl_array_t (to memoryref) + MDNode *tbaa_arrayptr; // The pointer inside a jl_array_t (to a memoryref) MDNode *tbaa_arraysize; // A size in a jl_array_t MDNode *tbaa_arrayselbyte; // a selector byte in a isbits Union jl_genericmemory_t MDNode *tbaa_memoryptr; // The pointer inside a jl_genericmemory_t @@ -568,7 +568,14 @@ FunctionType *invoke_type(TypeFnContextAndTriple f, Module &M) template struct JuliaFunction { public: - llvm::StringLiteral name; + template + constexpr JuliaFunction(const char (&cname)[N], TypeFn_t _type, llvm::AttributeList (*_attrs)(llvm::LLVMContext &C)) + : name(StringRef(cname, N-1)), _type(_type), _attrs(_attrs) {} + JuliaFunction(StringRef cname, TypeFn_t _type, llvm::AttributeList (*_attrs)(llvm::LLVMContext &C)) + : name(cname), _type(_type), _attrs(_attrs) {} + JuliaFunction(char *cname, TypeFn_t _type, llvm::AttributeList (*_attrs)(llvm::LLVMContext &C)) = delete; + + llvm::StringRef name; TypeFn_t _type; llvm::AttributeList (*_attrs)(llvm::LLVMContext &C); @@ -617,10 +624,6 @@ static FunctionType *get_func_sig(LLVMContext &C) { return JuliaType::get_jlfunc static FunctionType *get_func2_sig(LLVMContext &C) { return JuliaType::get_jlfunc2_ty(C); } static FunctionType *get_func3_sig(LLVMContext &C) { return JuliaType::get_jlfunc3_ty(C); } -static FunctionType *get_donotdelete_sig(LLVMContext &C) { - return FunctionType::get(getVoidTy(C), true); -} - static AttributeList get_func_attrs(LLVMContext &C) { return AttributeList::get(C, @@ -630,18 +633,6 @@ static AttributeList get_func_attrs(LLVMContext &C) Attributes(C, {Attribute::NoAlias, Attribute::ReadOnly, Attribute::NoCapture, Attribute::NoUndef})}); } -static AttributeList get_donotdelete_func_attrs(LLVMContext &C) -{ - AttrBuilder FnAttrs(C); - FnAttrs.addMemoryAttr(MemoryEffects::inaccessibleMemOnly()); - FnAttrs.addAttribute(Attribute::WillReturn); - FnAttrs.addAttribute(Attribute::NoUnwind); - return AttributeList::get(C, - AttributeSet::get(C, FnAttrs), - Attributes(C, {}), - None); -} - static AttributeList get_attrs_noreturn(LLVMContext &C) { return AttributeList::get(C, @@ -1454,11 +1445,21 @@ static const auto box_ssavalue_func = new JuliaFunction{ }, get_attrs_basic, }; -static const auto jlgetbuiltinfptr_func = new JuliaFunction<>{ - XSTR(jl_get_builtin_fptr), - [](LLVMContext &C) { return FunctionType::get(get_func_sig(C)->getPointerTo(), - {JuliaType::get_prjlvalue_ty(C)}, false); }, - nullptr, +static const auto jldnd_func = new JuliaFunction<>{ + XSTR(jl_f_donotdelete), + [](LLVMContext &C) { + return FunctionType::get(getVoidTy(C), true); + }, + [](LLVMContext &C) { + AttrBuilder FnAttrs(C); + FnAttrs.addMemoryAttr(MemoryEffects::inaccessibleMemOnly()); + FnAttrs.addAttribute(Attribute::WillReturn); + FnAttrs.addAttribute(Attribute::NoUnwind); + return AttributeList::get(C, + AttributeSet::get(C, FnAttrs), + Attributes(C, {}), + None); + }, }; // placeholder functions @@ -1583,56 +1584,23 @@ static const auto julia_call3 = new JuliaFunction<>{ static const auto jltuple_func = new JuliaFunction<>{XSTR(jl_f_tuple), get_func_sig, get_func_attrs}; static const auto jlintrinsic_func = new JuliaFunction<>{XSTR(jl_f_intrinsic_call), get_func3_sig, get_func_attrs}; +static const auto jl_new_opaque_closure_jlcall_func = new JuliaFunction<>{XSTR(jl_new_opaque_closure_jlcall), get_func_sig, get_func_attrs}; + +static const auto mk_builtin_func_map() { + auto builtin_addrs = new DenseMap*>(); + for (int i = 0; i < jl_n_builtins; i++) { + jl_value_t *builtin = jl_builtin_instances[i]; + if (builtin) // a couple do not have instances (e.g. IntrinsicFunction) + (*builtin_addrs)[builtin] = new JuliaFunction<>{StringRef(jl_builtin_f_names[i]), get_func_sig, get_func_attrs}; + } + return builtin_addrs; +} static const auto &builtin_func_map() { - static auto builtins = new DenseMap*> { - { jl_f_is_addr, new JuliaFunction<>{XSTR(jl_f_is), get_func_sig, get_func_attrs} }, - { jl_f_typeof_addr, new JuliaFunction<>{XSTR(jl_f_typeof), get_func_sig, get_func_attrs} }, - { jl_f_sizeof_addr, new JuliaFunction<>{XSTR(jl_f_sizeof), get_func_sig, get_func_attrs} }, - { jl_f_issubtype_addr, new JuliaFunction<>{XSTR(jl_f_issubtype), get_func_sig, get_func_attrs} }, - { jl_f_isa_addr, new JuliaFunction<>{XSTR(jl_f_isa), get_func_sig, get_func_attrs} }, - { jl_f_typeassert_addr, new JuliaFunction<>{XSTR(jl_f_typeassert), get_func_sig, get_func_attrs} }, - { jl_f_ifelse_addr, new JuliaFunction<>{XSTR(jl_f_ifelse), get_func_sig, get_func_attrs} }, - { jl_f__apply_iterate_addr, new JuliaFunction<>{XSTR(jl_f__apply_iterate), get_func_sig, get_func_attrs} }, - { jl_f_invokelatest_addr, new JuliaFunction<>{XSTR(jl_f_invokelatest), get_func_sig, get_func_attrs} }, - { jl_f_invoke_in_world_addr, new JuliaFunction<>{XSTR(jl_f_invoke_in_world), get_func_sig, get_func_attrs} }, - { jl_f__call_in_world_total_addr, new JuliaFunction<>{XSTR(jl_f__call_in_world_total), get_func_sig, get_func_attrs} }, - { jl_f_throw_addr, new JuliaFunction<>{XSTR(jl_f_throw), get_func_sig, get_func_attrs} }, - { jl_f_throw_methoderror_addr, new JuliaFunction<>{XSTR(jl_f_throw_methoderror), get_func_sig, get_func_attrs} }, - { jl_f_tuple_addr, jltuple_func }, - { jl_f_svec_addr, new JuliaFunction<>{XSTR(jl_f_svec), get_func_sig, get_func_attrs} }, - { jl_f_applicable_addr, new JuliaFunction<>{XSTR(jl_f_applicable), get_func_sig, get_func_attrs} }, - { jl_f_invoke_addr, new JuliaFunction<>{XSTR(jl_f_invoke), get_func_sig, get_func_attrs} }, - { jl_f_isdefined_addr, new JuliaFunction<>{XSTR(jl_f_isdefined), get_func_sig, get_func_attrs} }, - { jl_f_getfield_addr, new JuliaFunction<>{XSTR(jl_f_getfield), get_func_sig, get_func_attrs} }, - { jl_f_setfield_addr, new JuliaFunction<>{XSTR(jl_f_setfield), get_func_sig, get_func_attrs} }, - { jl_f_swapfield_addr, new JuliaFunction<>{XSTR(jl_f_swapfield), get_func_sig, get_func_attrs} }, - { jl_f_modifyfield_addr, new JuliaFunction<>{XSTR(jl_f_modifyfield), get_func_sig, get_func_attrs} }, - { jl_f_fieldtype_addr, new JuliaFunction<>{XSTR(jl_f_fieldtype), get_func_sig, get_func_attrs} }, - { jl_f_nfields_addr, new JuliaFunction<>{XSTR(jl_f_nfields), get_func_sig, get_func_attrs} }, - { jl_f__expr_addr, new JuliaFunction<>{XSTR(jl_f__expr), get_func_sig, get_func_attrs} }, - { jl_f__typevar_addr, new JuliaFunction<>{XSTR(jl_f__typevar), get_func_sig, get_func_attrs} }, - { jl_f_memorynew_addr, new JuliaFunction<>{XSTR(jl_f_memorynew), get_func_sig, get_func_attrs} }, - { jl_f_memoryref_addr, new JuliaFunction<>{XSTR(jl_f_memoryref), get_func_sig, get_func_attrs} }, - { jl_f_memoryrefoffset_addr, new JuliaFunction<>{XSTR(jl_f_memoryrefoffset), get_func_sig, get_func_attrs} }, - { jl_f_memoryrefset_addr, new JuliaFunction<>{XSTR(jl_f_memoryrefset), get_func_sig, get_func_attrs} }, - { jl_f_memoryrefswap_addr, new JuliaFunction<>{XSTR(jl_f_memoryrefswap), get_func_sig, get_func_attrs} }, - { jl_f_memoryrefreplace_addr, new JuliaFunction<>{XSTR(jl_f_memoryrefreplace), get_func_sig, get_func_attrs} }, - { jl_f_memoryrefmodify_addr, new JuliaFunction<>{XSTR(jl_f_memoryrefmodify), get_func_sig, get_func_attrs} }, - { jl_f_memoryrefsetonce_addr, new JuliaFunction<>{XSTR(jl_f_memoryrefsetonce), get_func_sig, get_func_attrs} }, - { jl_f_memoryref_isassigned_addr,new JuliaFunction<>{XSTR(jl_f_memoryref_isassigned), get_func_sig, get_func_attrs} }, - { jl_f_apply_type_addr, new JuliaFunction<>{XSTR(jl_f_apply_type), get_func_sig, get_func_attrs} }, - { jl_f_donotdelete_addr, new JuliaFunction<>{XSTR(jl_f_donotdelete), get_donotdelete_sig, get_donotdelete_func_attrs} }, - { jl_f_compilerbarrier_addr, new JuliaFunction<>{XSTR(jl_f_compilerbarrier), get_func_sig, get_func_attrs} }, - { jl_f_finalizer_addr, new JuliaFunction<>{XSTR(jl_f_finalizer), get_func_sig, get_func_attrs} }, - { jl_f__svec_ref_addr, new JuliaFunction<>{XSTR(jl_f__svec_ref), get_func_sig, get_func_attrs} }, - { jl_f_current_scope_addr, new JuliaFunction<>{XSTR(jl_f_current_scope), get_func_sig, get_func_attrs} }, - }; + static auto builtins = mk_builtin_func_map(); return *builtins; } -static const auto jl_new_opaque_closure_jlcall_func = new JuliaFunction<>{XSTR(jl_new_opaque_closure_jlcall), get_func_sig, get_func_attrs}; - static _Atomic(uint64_t) globalUniqueGeneratedNames{1}; // --- code generation --- @@ -2912,7 +2880,7 @@ static jl_value_t *static_apply_type(jl_codectx_t &ctx, ArrayRef arg return NULL; v[i] = args[i].constant; } - assert(v[0] == jl_builtin_apply_type); + assert(v[0] == BUILTIN(apply_type)); size_t last_age = jl_current_task->world_age; // call apply_type, but ignore errors. we know that will work in world 1. jl_current_task->world_age = 1; @@ -2982,7 +2950,7 @@ static jl_value_t *static_eval(jl_codectx_t &ctx, jl_value_t *ex) if (e->head == jl_call_sym) { jl_value_t *f = static_eval(ctx, jl_exprarg(e, 0)); if (f) { - if (jl_array_dim0(e->args) == 3 && (f == jl_builtin_getfield || f == jl_builtin_getglobal)) { + if (jl_array_dim0(e->args) == 3 && (f == BUILTIN(getfield) || f == BUILTIN(getglobal))) { m = (jl_module_t*)static_eval(ctx, jl_exprarg(e, 1)); // Check the tag before evaluating `s` so that a value of random // type won't be corrupted. @@ -3001,10 +2969,11 @@ static jl_value_t *static_eval(jl_codectx_t &ctx, jl_value_t *ex) } } } - else if (f==jl_builtin_tuple || f==jl_builtin_apply_type) { + else if (f==BUILTIN(tuple) || f==BUILTIN(apply_type)) { size_t i; size_t n = jl_array_dim0(e->args)-1; - if (n==0 && f==jl_builtin_tuple) return (jl_value_t*)jl_emptytuple; + if (n==0 && f==BUILTIN(tuple)) + return (jl_value_t*)jl_emptytuple; jl_value_t **v; JL_GC_PUSHARGS(v, n+1); v[0] = f; @@ -3631,11 +3600,11 @@ static Value *emit_f_is(jl_codectx_t &ctx, const jl_cgval_t &arg1, const jl_cgva static bool emit_f_opglobal(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, ArrayRef argv, size_t nargs, const jl_cgval_t *modifyop) { - bool issetglobal = f == jl_builtin_setglobal; - bool isreplaceglobal = f == jl_builtin_replaceglobal; - bool isswapglobal = f == jl_builtin_swapglobal; - bool ismodifyglobal = f == jl_builtin_modifyglobal; - bool issetglobalonce = f == jl_builtin_setglobalonce; + bool issetglobal = f == BUILTIN(setglobal); + bool isreplaceglobal = f == BUILTIN(replaceglobal); + bool isswapglobal = f == BUILTIN(swapglobal); + bool ismodifyglobal = f == BUILTIN(modifyglobal); + bool issetglobalonce = f == BUILTIN(setglobalonce); const jl_cgval_t undefval; const jl_cgval_t &mod = argv[1]; const jl_cgval_t &sym = argv[2]; @@ -3704,11 +3673,11 @@ static bool emit_f_opfield(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, ArrayRef argv, size_t nargs, const jl_cgval_t *modifyop) { ++EmittedOpfields; - bool issetfield = f == jl_builtin_setfield; - bool isreplacefield = f == jl_builtin_replacefield; - bool isswapfield = f == jl_builtin_swapfield; - bool ismodifyfield = f == jl_builtin_modifyfield; - bool issetfieldonce = f == jl_builtin_setfieldonce; + bool issetfield = f == BUILTIN(setfield); + bool isreplacefield = f == BUILTIN(replacefield); + bool isswapfield = f == BUILTIN(swapfield); + bool ismodifyfield = f == BUILTIN(modifyfield); + bool issetfieldonce = f == BUILTIN(setfieldonce); const jl_cgval_t undefval; const jl_cgval_t &obj = argv[1]; const jl_cgval_t &fld = argv[2]; @@ -3851,11 +3820,11 @@ static jl_cgval_t emit_isdefinedglobal(jl_codectx_t &ctx, jl_module_t *modu, jl_ static bool emit_f_opmemory(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, ArrayRef argv, size_t nargs, const jl_cgval_t *modifyop) { - bool issetmemory = f == jl_builtin_memoryrefset; - bool isreplacememory = f == jl_builtin_memoryrefreplace; - bool isswapmemory = f == jl_builtin_memoryrefswap; - bool ismodifymemory = f == jl_builtin_memoryrefmodify; - bool issetmemoryonce = f == jl_builtin_memoryrefsetonce; + bool issetmemory = f == BUILTIN(memoryrefset); + bool isreplacememory = f == BUILTIN(memoryrefreplace); + bool isswapmemory = f == BUILTIN(memoryrefswap); + bool ismodifymemory = f == BUILTIN(memoryrefmodify); + bool issetmemoryonce = f == BUILTIN(memoryrefsetonce); const jl_cgval_t undefval; const jl_cgval_t &ref = argv[1]; @@ -4041,14 +4010,19 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, // returns true if the call has been handled { ++EmittedBuiltinCalls; - if (f == jl_builtin_is && nargs == 2) { + if (f == BUILTIN(is) && nargs == 2) { // emit comparison test Value *ans = emit_f_is(ctx, argv[1], argv[2]); *ret = mark_julia_type(ctx, ans, false, jl_bool_type); return true; } - else if (f == jl_builtin_typeof && nargs == 1) { + else if (f == BUILTIN(ifelse) && nargs == 3) { + *ret = emit_ifelse(ctx, argv[1], argv[2], argv[3], rt); + return true; + } + + else if (f == BUILTIN(typeof) && nargs == 1) { const jl_cgval_t &p = argv[1]; if (p.constant) *ret = mark_julia_const(ctx, jl_typeof(p.constant)); @@ -4059,7 +4033,7 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, return true; } - else if (f == jl_builtin_typeassert && nargs == 2) { + else if (f == BUILTIN(typeassert) && nargs == 2) { const jl_cgval_t &arg = argv[1]; const jl_cgval_t &ty = argv[2]; if (jl_is_type_type(ty.typ) && !jl_has_free_typevars(ty.typ)) { @@ -4077,7 +4051,7 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, } } - else if (f == jl_builtin_isa && nargs == 2) { + else if (f == BUILTIN(isa) && nargs == 2) { const jl_cgval_t &arg = argv[1]; const jl_cgval_t &ty = argv[2]; if (jl_is_type_type(ty.typ) && !jl_has_free_typevars(ty.typ)) { @@ -4088,7 +4062,7 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, } } - else if (f == jl_builtin_issubtype && nargs == 2) { + else if (f == BUILTIN(issubtype) && nargs == 2) { const jl_cgval_t &ta = argv[1]; const jl_cgval_t &tb = argv[2]; if (jl_is_type_type(ta.typ) && !jl_has_free_typevars(ta.typ) && @@ -4099,7 +4073,7 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, } } - else if ((f == jl_builtin__apply_iterate && nargs == 3) && ctx.vaSlot > 0) { + else if ((f == BUILTIN(_apply_iterate) && nargs == 3) && ctx.vaSlot > 0) { // turn Core._apply_iterate(iter, f, Tuple) ==> f(Tuple...) using the jlcall calling convention if Tuple is the va allocation if (LoadInst *load = dyn_cast_or_null(argv[3].V)) { if (load->getPointerOperand() == ctx.slots[ctx.vaSlot].boxroot && ctx.argArray) { @@ -4116,7 +4090,7 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, } } - else if (f == jl_builtin_tuple) { + else if (f == BUILTIN(tuple)) { if (nargs == 0) { *ret = ghostValue(ctx, jl_emptytuple_type); return true; @@ -4127,14 +4101,14 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, } } - else if (f == jl_builtin_throw && nargs == 1) { + else if (f == BUILTIN(throw) && nargs == 1) { Value *arg1 = boxed(ctx, argv[1]); raise_exception(ctx, arg1); *ret = jl_cgval_t(); return true; } - else if (f == jl_builtin_memorynew && (nargs == 2)) { + else if (f == BUILTIN(memorynew) && (nargs == 2)) { const jl_cgval_t &memty = argv[1]; if (!memty.constant) return false; @@ -4158,7 +4132,7 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, return true; } - else if (f == jl_builtin_memoryref && nargs == 1) { + else if (f == BUILTIN(memoryrefnew) && nargs == 1) { const jl_cgval_t &mem = argv[1]; jl_datatype_t *mty_dt = (jl_datatype_t*)jl_unwrap_unionall(mem.typ); if (jl_is_genericmemory_type(mty_dt) && jl_is_concrete_type((jl_value_t*)mty_dt)) { @@ -4169,7 +4143,7 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, } } - else if (f == jl_builtin_memoryref && (nargs == 2 || nargs == 3)) { + else if (f == BUILTIN(memoryrefnew) && (nargs == 2 || nargs == 3)) { const jl_cgval_t &ref = argv[1]; jl_value_t *mty_dt = jl_unwrap_unionall(ref.typ); if (jl_is_genericmemoryref_type(mty_dt) && jl_is_concrete_type(mty_dt)) { @@ -4177,13 +4151,13 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, const jl_datatype_layout_t *layout = ((jl_datatype_t*)mty_dt)->layout; jl_value_t *boundscheck = nargs == 3 ? argv[3].constant : nullptr; if (nargs == 3) - emit_typecheck(ctx, argv[3], (jl_value_t*)jl_bool_type, "memoryref"); + emit_typecheck(ctx, argv[3], (jl_value_t*)jl_bool_type, "memoryrefnew"); *ret = emit_memoryref(ctx, ref, argv[2], boundscheck, layout); return true; } } - else if (f == jl_builtin_memoryrefoffset && nargs == 1) { + else if (f == BUILTIN(memoryrefoffset) && nargs == 1) { const jl_cgval_t &ref = argv[1]; jl_value_t *mty_dt = jl_unwrap_unionall(ref.typ); if (jl_is_genericmemoryref_type(mty_dt) && jl_is_concrete_type(mty_dt)) { @@ -4194,7 +4168,7 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, } } - else if (f == jl_builtin_memoryrefget && nargs == 3) { + else if (f == BUILTIN(memoryrefget) && nargs == 3) { const jl_cgval_t &ref = argv[1]; jl_value_t *mty_dt = jl_unwrap_unionall(ref.typ); if (jl_is_genericmemoryref_type(mty_dt) && jl_is_concrete_type(mty_dt)) { @@ -4233,7 +4207,7 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, order = isatomic ? jl_memory_order_unordered : jl_memory_order_notatomic; } jl_value_t *boundscheck = argv[3].constant; - emit_typecheck(ctx, argv[3], (jl_value_t*)jl_bool_type, "memoryref"); + emit_typecheck(ctx, argv[3], (jl_value_t*)jl_bool_type, "memoryrefget"); const jl_datatype_layout_t *layout = ((jl_datatype_t*)mty_dt)->layout; Value *mem = emit_memoryref_mem(ctx, ref, layout); Value *mlen = emit_genericmemorylen(ctx, mem, ref.typ); @@ -4310,16 +4284,16 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, } } - else if ((f == jl_builtin_memoryrefset && nargs == 4) || - (f == jl_builtin_memoryrefswap && nargs == 4) || - (f == jl_builtin_memoryrefreplace && nargs == 6) || - (f == jl_builtin_memoryrefmodify && nargs == 5) || - (f == jl_builtin_memoryrefsetonce && nargs == 5)) { + else if ((f == BUILTIN(memoryrefset) && nargs == 4) || + (f == BUILTIN(memoryrefswap) && nargs == 4) || + (f == BUILTIN(memoryrefreplace) && nargs == 6) || + (f == BUILTIN(memoryrefmodify) && nargs == 5) || + (f == BUILTIN(memoryrefsetonce) && nargs == 5)) { return emit_f_opmemory(ctx, ret, f, argv, nargs, nullptr); } - else if (f == jl_builtin_memoryref_isassigned && nargs == 3) { + else if (f == BUILTIN(memoryref_isassigned) && nargs == 3) { const jl_cgval_t &ref = argv[1]; jl_value_t *mty_dt = jl_unwrap_unionall(ref.typ); if (jl_is_genericmemoryref_type(mty_dt) && jl_is_concrete_type(mty_dt)) { @@ -4390,7 +4364,7 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, } if (!isboxed) elem = emit_ptrgep(ctx, elem, layout->first_ptr * sizeof(void*)); - // emit this using the same type as jl_builtin_memoryrefget + // emit this using the same type as BUILTIN(memoryrefget) // so that LLVM may be able to load-load forward them and fold the result auto tbaa = isboxed ? ctx.tbaa().tbaa_ptrarraybuf : ctx.tbaa().tbaa_arraybuf; jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA(ctx, tbaa); @@ -4419,7 +4393,7 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, } - else if (f == jl_builtin_getfield && (nargs == 2 || nargs == 3 || nargs == 4)) { + else if (f == BUILTIN(getfield) && (nargs == 2 || nargs == 3 || nargs == 4)) { const jl_cgval_t &obj = argv[1]; const jl_cgval_t &fld = argv[2]; enum jl_memory_order order = jl_memory_order_unspecified; @@ -4579,7 +4553,7 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, return false; } - else if (f == jl_builtin_getglobal && (nargs == 2 || nargs == 3)) { + else if (f == BUILTIN(getglobal) && (nargs == 2 || nargs == 3)) { const jl_cgval_t &mod = argv[1]; const jl_cgval_t &sym = argv[2]; enum jl_memory_order order = jl_memory_order_unspecified; @@ -4611,23 +4585,23 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, return false; } - else if ((f == jl_builtin_setglobal && (nargs == 3 || nargs == 4)) || - (f == jl_builtin_swapglobal && (nargs == 3 || nargs == 4)) || - (f == jl_builtin_replaceglobal && (nargs == 4 || nargs == 5 || nargs == 6)) || - (f == jl_builtin_modifyglobal && (nargs == 4 || nargs == 5)) || - (f == jl_builtin_setglobalonce && (nargs == 3 || nargs == 4 || nargs == 5))) { + else if ((f == BUILTIN(setglobal) && (nargs == 3 || nargs == 4)) || + (f == BUILTIN(swapglobal) && (nargs == 3 || nargs == 4)) || + (f == BUILTIN(replaceglobal) && (nargs == 4 || nargs == 5 || nargs == 6)) || + (f == BUILTIN(modifyglobal) && (nargs == 4 || nargs == 5)) || + (f == BUILTIN(setglobalonce) && (nargs == 3 || nargs == 4 || nargs == 5))) { return emit_f_opglobal(ctx, ret, f, argv, nargs, nullptr); } - else if ((f == jl_builtin_setfield && (nargs == 3 || nargs == 4)) || - (f == jl_builtin_swapfield && (nargs == 3 || nargs == 4)) || - (f == jl_builtin_replacefield && (nargs == 4 || nargs == 5 || nargs == 6)) || - (f == jl_builtin_modifyfield && (nargs == 4 || nargs == 5)) || - (f == jl_builtin_setfieldonce && (nargs == 3 || nargs == 4 || nargs == 5))) { + else if ((f == BUILTIN(setfield) && (nargs == 3 || nargs == 4)) || + (f == BUILTIN(swapfield) && (nargs == 3 || nargs == 4)) || + (f == BUILTIN(replacefield) && (nargs == 4 || nargs == 5 || nargs == 6)) || + (f == BUILTIN(modifyfield) && (nargs == 4 || nargs == 5)) || + (f == BUILTIN(setfieldonce) && (nargs == 3 || nargs == 4 || nargs == 5))) { return emit_f_opfield(ctx, ret, f, argv, nargs, nullptr); } - else if (f == jl_builtin_nfields && nargs == 1) { + else if (f == BUILTIN(nfields) && nargs == 1) { const jl_cgval_t &obj = argv[1]; if (ctx.vaSlot > 0) { // optimize VA tuple @@ -4659,7 +4633,7 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, return true; } - else if (f == jl_builtin_fieldtype && (nargs == 2 || nargs == 3)) { + else if (f == BUILTIN(fieldtype) && (nargs == 2 || nargs == 3)) { const jl_cgval_t &typ = argv[1]; const jl_cgval_t &fld = argv[2]; if ((jl_is_type_type(typ.typ) && jl_is_concrete_type(jl_tparam0(typ.typ))) || @@ -4684,7 +4658,7 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, } } - else if (f == jl_builtin_sizeof && nargs == 1) { + else if (f == BUILTIN(sizeof) && nargs == 1) { const jl_cgval_t &obj = argv[1]; jl_datatype_t *sty = (jl_datatype_t*)jl_unwrap_unionall(obj.typ); assert(jl_string_type->name->mutabl); @@ -4729,7 +4703,7 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, } } - else if (f == jl_builtin_apply_type && nargs > 0) { + else if (f == BUILTIN(apply_type) && nargs > 0) { if (jl_is_method(ctx.linfo->def.method)) { // don't bother codegen constant-folding for toplevel. jl_value_t *ty = static_apply_type(ctx, argv, nargs + 1); @@ -4743,7 +4717,7 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, } } - else if (f == jl_builtin_isdefinedglobal && (nargs == 2 || nargs == 3 || nargs == 4)) { + else if (f == BUILTIN(isdefinedglobal) && (nargs == 2 || nargs == 3 || nargs == 4)) { const jl_cgval_t &mod = argv[1]; const jl_cgval_t &sym = argv[2]; bool allow_import = true; @@ -4779,7 +4753,7 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, return true; } - else if (f == jl_builtin_isdefined && (nargs == 2 || nargs == 3)) { + else if (f == BUILTIN(isdefined) && (nargs == 2 || nargs == 3)) { const jl_cgval_t &obj = argv[1]; const jl_cgval_t &fld = argv[2]; jl_datatype_t *stt = (jl_datatype_t*)obj.typ; @@ -4895,7 +4869,7 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, return true; } - else if (f == jl_builtin_current_scope && (nargs == 0)) { + else if (f == BUILTIN(current_scope) && (nargs == 0)) { jl_aliasinfo_t scope_ai = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_gcframe); Instruction *v = scope_ai.decorateInst( ctx.builder.CreateAlignedLoad(ctx.types().T_prjlvalue, get_scope_field(ctx), ctx.types().alignof_ptr)); @@ -4903,18 +4877,13 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, return true; } - else if (f == jl_builtin_donotdelete) { + else if (f == BUILTIN(donotdelete)) { // For now we emit this as a vararg call to the builtin // (which doesn't look at the arguments). In the future, // this should be an LLVM builtin. - auto it = builtin_func_map().find(jl_f_donotdelete_addr); - if (it == builtin_func_map().end()) { - return false; - } - *ret = mark_julia_const(ctx, jl_nothing); FunctionType *Fty = FunctionType::get(getVoidTy(ctx.builder.getContext()), true); - Function *dnd = prepare_call(it->second); + Function *dnd = prepare_call(jldnd_func); SmallVector call_args; for (size_t i = 1; i <= nargs; ++i) { @@ -4933,7 +4902,7 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, return true; } - else if (f == jl_builtin_compilerbarrier && (nargs == 2)) { + else if (f == BUILTIN(compilerbarrier) && (nargs == 2)) { emit_typecheck(ctx, argv[1], (jl_value_t*)jl_symbol_type, "compilerbarrier"); *ret = argv[2]; return true; @@ -5356,22 +5325,22 @@ static jl_cgval_t emit_invoke_modify(jl_codectx_t &ctx, jl_expr_t *ex, jl_value_ if (f.constant) { jl_cgval_t ret; auto it = builtin_func_map().end(); - if (f.constant == jl_builtin_modifyfield) { - if (emit_f_opfield(ctx, &ret, jl_builtin_modifyfield, argv, nargs - 1, &lival)) + if (f.constant == BUILTIN(modifyfield)) { + if (emit_f_opfield(ctx, &ret, BUILTIN(modifyfield), argv, nargs - 1, &lival)) return ret; - it = builtin_func_map().find(jl_f_modifyfield_addr); + it = builtin_func_map().find(f.constant); assert(it != builtin_func_map().end()); } - else if (f.constant == jl_builtin_modifyglobal) { - if (emit_f_opglobal(ctx, &ret, jl_builtin_modifyglobal, argv, nargs - 1, &lival)) + else if (f.constant == BUILTIN(modifyglobal)) { + if (emit_f_opglobal(ctx, &ret, BUILTIN(modifyglobal), argv, nargs - 1, &lival)) return ret; - it = builtin_func_map().find(jl_f_modifyglobal_addr); + it = builtin_func_map().find(f.constant); assert(it != builtin_func_map().end()); } - else if (f.constant == jl_builtin_memoryrefmodify) { - if (emit_f_opmemory(ctx, &ret, jl_builtin_memoryrefmodify, argv, nargs - 1, &lival)) + else if (f.constant == BUILTIN(memoryrefmodify)) { + if (emit_f_opmemory(ctx, &ret, BUILTIN(memoryrefmodify), argv, nargs - 1, &lival)) return ret; - it = builtin_func_map().find(jl_f_memoryrefmodify_addr); + it = builtin_func_map().find(f.constant); assert(it != builtin_func_map().end()); } else if (jl_typetagis(f.constant, jl_intrinsic_type)) { @@ -5431,15 +5400,15 @@ static jl_cgval_t emit_call(jl_codectx_t &ctx, jl_expr_t *ex, jl_value_t *rt, bo return jl_cgval_t(); } + // a couple intrinsics (really just llvmcall, though partly cglobal too) + // have non-standard (aka invalid) evaluation semantics, so we must handle these first if (f.constant && jl_typetagis(f.constant, jl_intrinsic_type)) { JL_I::intrinsic fi = (intrinsic)*(uint32_t*)jl_data_ptr(f.constant); return emit_intrinsic(ctx, fi, args, nargs - 1); } size_t n_generic_args = nargs; - SmallVector argv(n_generic_args); - argv[0] = f; for (size_t i = 1; i < nargs; ++i) { argv[i] = emit_expr(ctx, args[i]); @@ -5447,37 +5416,23 @@ static jl_cgval_t emit_call(jl_codectx_t &ctx, jl_expr_t *ex, jl_value_t *rt, bo return jl_cgval_t(); // anything past here is unreachable } - if (jl_subtype(f.typ, (jl_value_t*)jl_builtin_type)) { - if (f.constant) { - if (f.constant == jl_builtin_ifelse && nargs == 4) - return emit_ifelse(ctx, argv[1], argv[2], argv[3], rt); - jl_cgval_t result; - bool handled = emit_builtin_call(ctx, &result, f.constant, argv, nargs - 1, rt, ex, is_promotable); - if (handled) - return result; - jl_fptr_args_t builtin_fptr = jl_get_builtin_fptr((jl_datatype_t*)jl_typeof(f.constant)); - // special case for some known builtin not handled by emit_builtin_call - auto it = builtin_func_map().find(builtin_fptr); - if (it != builtin_func_map().end()) { - Value *ret = emit_jlcall(ctx, it->second, Constant::getNullValue(ctx.types().T_prjlvalue), ArrayRef(argv).drop_front(), nargs - 1, julia_call); - setName(ctx.emission_context, ret, it->second->name + "_ret"); - return mark_julia_type(ctx, ret, true, rt); - } - } - Value *fptr; - JuliaFunction<> *cc; - if (f.typ == (jl_value_t*)jl_intrinsic_type) { - fptr = prepare_call(jlintrinsic_func); - cc = julia_call3; - } - else { - fptr = ctx.builder.CreateCall(prepare_call(jlgetbuiltinfptr_func), {emit_typeof(ctx, f)}); - cc = julia_call; - } - Value *ret = emit_jlcall(ctx, fptr, nullptr, argv, nargs, cc); + if (f.typ == (jl_value_t*)jl_intrinsic_type) { + Value *ret = emit_jlcall(ctx, prepare_call(jlintrinsic_func), nullptr, argv, nargs, julia_call3); setName(ctx.emission_context, ret, "Builtin_ret"); return mark_julia_type(ctx, ret, true, rt); } + else if (f.constant && jl_isa(f.constant, (jl_value_t*)jl_builtin_type)) { + jl_cgval_t result; + bool handled = emit_builtin_call(ctx, &result, f.constant, argv, nargs - 1, rt, ex, is_promotable); + if (handled) + return result; + auto it = builtin_func_map().find(f.constant); + if (it != builtin_func_map().end()) { + Value *ret = emit_jlcall(ctx, it->second, Constant::getNullValue(ctx.types().T_prjlvalue), ArrayRef(argv).drop_front(), nargs - 1, julia_call); + setName(ctx.emission_context, ret, it->second->name + "_ret"); + return mark_julia_type(ctx, ret, true, rt); + } + } // handle calling an OpaqueClosure if (jl_is_concrete_type(f.typ) && jl_subtype(f.typ, (jl_value_t*)jl_opaque_closure_type)) { @@ -9818,7 +9773,6 @@ static void init_jit_functions(void) { add_named_global("jl_fptr_args", jl_fptr_args_addr); add_named_global("jl_fptr_sparam", jl_fptr_sparam_addr); - add_named_global("jl_f_opaque_closure_call", &jl_f_opaque_closure_call); add_named_global(jl_small_typeof_var, &jl_small_typeof); add_named_global(jlstack_chk_guard_var, &__stack_chk_guard); add_named_global(jlRTLD_DEFAULT_var, &jl_RTLD_DEFAULT_handle); @@ -9855,10 +9809,8 @@ static void init_jit_functions(void) add_named_global(jlcheckassign_func, &jl_checked_assignment); add_named_global(jlcheckbpwritable_func, &jl_check_binding_currently_writable); add_named_global(jlboundp_func, &jl_boundp); - for (auto it : builtin_func_map()) - add_named_global(it.second, it.first); - add_named_global(jlintrinsic_func, &jl_f_intrinsic_call); - add_named_global(jlgetbuiltinfptr_func, &jl_get_builtin_fptr); + for (int i = 0; i < jl_n_builtins; i++) + add_named_global(jl_builtin_f_names[i], jl_builtin_f_addrs[i]); add_named_global(jlapplygeneric_func, &jl_apply_generic); add_named_global(jlinvoke_func, &jl_invoke); add_named_global(jltopeval_func, &jl_toplevel_eval); diff --git a/src/common_symbols2.inc b/src/common_symbols2.inc index 2a6990bac52ff..e9c070ee8da6a 100644 --- a/src/common_symbols2.inc +++ b/src/common_symbols2.inc @@ -97,7 +97,7 @@ jl_symbol("pointerref"), jl_symbol("multidimensional.jl"), jl_symbol("Generator"), jl_symbol("leave"), -jl_symbol("memoryref"), +jl_symbol("memoryrefnew"), jl_symbol("show.jl"), jl_symbol("pointer_from_objref"), jl_symbol("memoryrefget"), diff --git a/src/gf.c b/src/gf.c index 42d026dd2d329..cadea9491a61c 100644 --- a/src/gf.c +++ b/src/gf.c @@ -288,16 +288,8 @@ JL_DLLEXPORT jl_value_t *jl_methtable_lookup(jl_methtable_t *mt, jl_value_t *typ // ----- MethodInstance specialization instantiation ----- // -jl_datatype_t *jl_mk_builtin_func(jl_datatype_t *dt, const char *name, jl_fptr_args_t fptr) JL_GC_DISABLED +void jl_mk_builtin_func(jl_datatype_t *dt, jl_sym_t *sname, jl_fptr_args_t fptr) JL_GC_DISABLED { - jl_sym_t *sname = jl_symbol(name); - if (dt == NULL) { - // Builtins are specially considered available from world 0 - jl_value_t *f = jl_new_generic_function_with_supertype(sname, jl_core_module, jl_builtin_type, 0); - jl_set_initial_const(jl_core_module, sname, f, 0); - dt = (jl_datatype_t*)jl_typeof(f); - } - jl_method_t *m = jl_new_method_uninit(jl_core_module); m->name = sname; m->module = jl_core_module; @@ -335,7 +327,6 @@ jl_datatype_t *jl_mk_builtin_func(jl_datatype_t *dt, const char *name, jl_fptr_a mt->frozen = 1; JL_GC_POP(); - return dt; } // only relevant for bootstrapping. otherwise fairly broken. @@ -3130,6 +3121,7 @@ JL_DLLEXPORT const jl_callptr_t jl_fptr_const_return_addr = &jl_fptr_const_retur JL_DLLEXPORT const jl_callptr_t jl_fptr_sparam_addr = &jl_fptr_sparam; +JL_CALLABLE(jl_f_opaque_closure_call); JL_DLLEXPORT const jl_callptr_t jl_f_opaque_closure_call_addr = (jl_callptr_t)&jl_f_opaque_closure_call; JL_DLLEXPORT const jl_callptr_t jl_fptr_wait_for_compiled_addr = &jl_fptr_wait_for_compiled; diff --git a/src/init.c b/src/init.c index 83cff02872b96..c4388589dd581 100644 --- a/src/init.c +++ b/src/init.c @@ -23,9 +23,7 @@ #include "julia.h" #include "julia_internal.h" -#define DEFINE_BUILTIN_GLOBALS #include "builtin_proto.h" -#undef DEFINE_BUILTIN_GLOBALS #include "threading.h" #include "julia_assert.h" #include "processor.h" diff --git a/src/julia_internal.h b/src/julia_internal.h index 8a4b9d42c4c20..4c424f04bf8f3 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -21,6 +21,9 @@ #include #include +#define STR(x) #x +#define XSTR(x) STR(x) + #if !defined(_WIN32) #include #else @@ -775,16 +778,11 @@ JL_DLLEXPORT void jl_typeassert(jl_value_t *x, jl_value_t *t); #define JL_CALLABLE(name) \ JL_DLLEXPORT jl_value_t *name(jl_value_t *F, jl_value_t **args, uint32_t nargs) -JL_CALLABLE(jl_f_svec); JL_CALLABLE(jl_f_tuple); -JL_CALLABLE(jl_f_intrinsic_call); -JL_CALLABLE(jl_f_opaque_closure_call); void jl_install_default_signal_handlers(void); void restore_signals(void); void jl_install_thread_signal_handler(jl_ptls_t ptls); -JL_DLLEXPORT jl_fptr_args_t jl_get_builtin_fptr(jl_datatype_t *dt); - extern uv_loop_t *jl_io_loop; JL_DLLEXPORT void jl_uv_flush(uv_stream_t *stream); @@ -811,7 +809,7 @@ jl_tupletype_t *jl_lookup_arg_tuple_type(jl_value_t *arg1 JL_PROPAGATES_ROOT, jl JL_DLLEXPORT void jl_method_table_insert(jl_methtable_t *mt, jl_method_t *method, jl_tupletype_t *simpletype); void jl_method_table_activate(jl_methtable_t *mt, jl_typemap_entry_t *newentry); jl_typemap_entry_t *jl_method_table_add(jl_methtable_t *mt, jl_method_t *method, jl_tupletype_t *simpletype); -jl_datatype_t *jl_mk_builtin_func(jl_datatype_t *dt, const char *name, jl_fptr_args_t fptr) JL_GC_DISABLED; +void jl_mk_builtin_func(jl_datatype_t *dt, jl_sym_t *name, jl_fptr_args_t fptr) JL_GC_DISABLED; int jl_obviously_unequal(jl_value_t *a, jl_value_t *b); int jl_has_bound_typevars(jl_value_t *v, jl_typeenv_t *env) JL_NOTSAFEPOINT; JL_DLLEXPORT jl_array_t *jl_find_free_typevars(jl_value_t *v); diff --git a/src/llvm-codegen-shared.h b/src/llvm-codegen-shared.h index d474fb4f61183..fcdecb365b1c7 100644 --- a/src/llvm-codegen-shared.h +++ b/src/llvm-codegen-shared.h @@ -13,9 +13,6 @@ #include "julia.h" -#define STR(csym) #csym -#define XSTR(csym) STR(csym) - static constexpr std::nullopt_t None = std::nullopt; enum AddressSpace { diff --git a/src/llvm-lower-handlers.cpp b/src/llvm-lower-handlers.cpp index c359bf6c117ce..f67baf26cc372 100644 --- a/src/llvm-lower-handlers.cpp +++ b/src/llvm-lower-handlers.cpp @@ -27,6 +27,9 @@ #include "llvm-codegen-shared.h" #include +#define STR(x) #x +#define XSTR(x) STR(x) + #define DEBUG_TYPE "lower_handlers" #undef DEBUG STATISTIC(MaxExceptionHandlerDepth, "Maximum nesting of exception handlers"); diff --git a/src/llvm-pass-helpers.cpp b/src/llvm-pass-helpers.cpp index 9d415d923ecb6..e596efd94807a 100644 --- a/src/llvm-pass-helpers.cpp +++ b/src/llvm-pass-helpers.cpp @@ -18,6 +18,9 @@ #include "julia_assert.h" #include "llvm-pass-helpers.h" +#define STR(csym) #csym +#define XSTR(csym) STR(csym) + using namespace llvm; JuliaPassContext::JuliaPassContext() diff --git a/src/method.c b/src/method.c index 09d9eae9ad037..f71f09ceb83bc 100644 --- a/src/method.c +++ b/src/method.c @@ -10,13 +10,12 @@ #include "julia.h" #include "julia_internal.h" #include "julia_assert.h" +#include "builtin_proto.h" #ifdef __cplusplus extern "C" { #endif -extern jl_value_t *jl_builtin_getfield; -extern jl_value_t *jl_builtin_tuple; jl_methtable_t *jl_kwcall_mt; jl_method_t *jl_opaque_closure_method; @@ -225,7 +224,7 @@ static jl_value_t *resolve_definition_effects(jl_value_t *expr, jl_module_t *mod jl_sym_t *fe_sym = jl_globalref_name(fe); // look at some known called functions jl_binding_t *b = jl_get_binding(fe_mod, fe_sym); - if (jl_get_latest_binding_value_if_const(b) == jl_builtin_tuple) { + if (jl_get_latest_binding_value_if_const(b) == BUILTIN(tuple)) { size_t j; for (j = 1; j < nargs; j++) { if (!jl_is_quotenode(jl_exprarg(e, j))) diff --git a/src/signals-mach.c b/src/signals-mach.c index 1c4af2cf9d033..4a670547bdfcd 100644 --- a/src/signals-mach.c +++ b/src/signals-mach.c @@ -146,8 +146,6 @@ static void jl_mach_gc_wait(jl_ptls_t ptls2, mach_port_t thread, int16_t tid) static mach_port_t segv_port = 0; -#define STR(x) #x -#define XSTR(x) STR(x) #define HANDLE_MACH_ERROR(msg, retval) \ if (retval != KERN_SUCCESS) { mach_error(msg XSTR(: __FILE__:__LINE__:), (retval)); abort(); } diff --git a/src/staticdata.c b/src/staticdata.c index 634e8ae40fe27..a7a41d98eb505 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -116,228 +116,177 @@ extern "C" { // TODO: put WeakRefs on the weak_refs list during deserialization // TODO: handle finalizers -#define NUM_TAGS 197 +#define NUM_TAGS 152 // An array of references that need to be restored from the sysimg // This is a manually constructed dual of the gvars array, which would be produced by codegen for Julia code, for C. -jl_value_t **const*const get_tags(void) { +static void get_tags(jl_value_t **tags[NUM_TAGS]) +{ // Make sure to keep an extra slot at the end to sentinel length - static void * _tags[NUM_TAGS] = {NULL}; - - // Lazyily-initialize this list - if (_tags[0] == NULL) { - unsigned int i = 0; -#define INSERT_TAG(sym) _tags[i++] = &(sym) - // builtin types - INSERT_TAG(jl_any_type); - INSERT_TAG(jl_symbol_type); - INSERT_TAG(jl_ssavalue_type); - INSERT_TAG(jl_datatype_type); - INSERT_TAG(jl_slotnumber_type); - INSERT_TAG(jl_simplevector_type); - INSERT_TAG(jl_array_type); - INSERT_TAG(jl_expr_type); - INSERT_TAG(jl_binding_type); - INSERT_TAG(jl_binding_partition_type); - INSERT_TAG(jl_globalref_type); - INSERT_TAG(jl_string_type); - INSERT_TAG(jl_module_type); - INSERT_TAG(jl_tvar_type); - INSERT_TAG(jl_method_instance_type); - INSERT_TAG(jl_method_type); - INSERT_TAG(jl_code_instance_type); - INSERT_TAG(jl_linenumbernode_type); - INSERT_TAG(jl_lineinfonode_type); - INSERT_TAG(jl_gotonode_type); - INSERT_TAG(jl_quotenode_type); - INSERT_TAG(jl_gotoifnot_type); - INSERT_TAG(jl_enternode_type); - INSERT_TAG(jl_argument_type); - INSERT_TAG(jl_returnnode_type); - INSERT_TAG(jl_const_type); - INSERT_TAG(jl_partial_struct_type); - INSERT_TAG(jl_partial_opaque_type); - INSERT_TAG(jl_interconditional_type); - INSERT_TAG(jl_method_match_type); - INSERT_TAG(jl_pinode_type); - INSERT_TAG(jl_phinode_type); - INSERT_TAG(jl_phicnode_type); - INSERT_TAG(jl_upsilonnode_type); - INSERT_TAG(jl_type_type); - INSERT_TAG(jl_bottom_type); - INSERT_TAG(jl_ref_type); - INSERT_TAG(jl_pointer_type); - INSERT_TAG(jl_llvmpointer_type); - INSERT_TAG(jl_vararg_type); - INSERT_TAG(jl_abstractarray_type); - INSERT_TAG(jl_densearray_type); - INSERT_TAG(jl_nothing_type); - INSERT_TAG(jl_function_type); - INSERT_TAG(jl_typeofbottom_type); - INSERT_TAG(jl_unionall_type); - INSERT_TAG(jl_typename_type); - INSERT_TAG(jl_builtin_type); - INSERT_TAG(jl_code_info_type); - INSERT_TAG(jl_opaque_closure_type); - INSERT_TAG(jl_task_type); - INSERT_TAG(jl_uniontype_type); - INSERT_TAG(jl_abstractstring_type); - INSERT_TAG(jl_array_any_type); - INSERT_TAG(jl_intrinsic_type); - INSERT_TAG(jl_methtable_type); - INSERT_TAG(jl_typemap_level_type); - INSERT_TAG(jl_typemap_entry_type); - INSERT_TAG(jl_voidpointer_type); - INSERT_TAG(jl_uint8pointer_type); - INSERT_TAG(jl_newvarnode_type); - INSERT_TAG(jl_anytuple_type_type); - INSERT_TAG(jl_anytuple_type); - INSERT_TAG(jl_namedtuple_type); - INSERT_TAG(jl_emptytuple_type); - INSERT_TAG(jl_array_symbol_type); - INSERT_TAG(jl_array_uint8_type); - INSERT_TAG(jl_array_uint32_type); - INSERT_TAG(jl_array_int32_type); - INSERT_TAG(jl_array_uint64_type); - INSERT_TAG(jl_int32_type); - INSERT_TAG(jl_int64_type); - INSERT_TAG(jl_bool_type); - INSERT_TAG(jl_uint8_type); - INSERT_TAG(jl_uint16_type); - INSERT_TAG(jl_uint32_type); - INSERT_TAG(jl_uint64_type); - INSERT_TAG(jl_char_type); - INSERT_TAG(jl_weakref_type); - INSERT_TAG(jl_int8_type); - INSERT_TAG(jl_int16_type); - INSERT_TAG(jl_float16_type); - INSERT_TAG(jl_float32_type); - INSERT_TAG(jl_float64_type); - INSERT_TAG(jl_bfloat16_type); - INSERT_TAG(jl_floatingpoint_type); - INSERT_TAG(jl_number_type); - INSERT_TAG(jl_signed_type); - INSERT_TAG(jl_pair_type); - INSERT_TAG(jl_genericmemory_type); - INSERT_TAG(jl_memory_any_type); - INSERT_TAG(jl_memory_uint8_type); - INSERT_TAG(jl_memory_uint16_type); - INSERT_TAG(jl_memory_uint32_type); - INSERT_TAG(jl_memory_uint64_type); - INSERT_TAG(jl_genericmemoryref_type); - INSERT_TAG(jl_memoryref_any_type); - INSERT_TAG(jl_memoryref_uint8_type); - INSERT_TAG(jl_addrspace_type); - INSERT_TAG(jl_addrspace_typename); - INSERT_TAG(jl_addrspacecore_type); - INSERT_TAG(jl_debuginfo_type); - INSERT_TAG(jl_abioverride_type); - - // special typenames - INSERT_TAG(jl_tuple_typename); - INSERT_TAG(jl_pointer_typename); - INSERT_TAG(jl_llvmpointer_typename); - INSERT_TAG(jl_array_typename); - INSERT_TAG(jl_type_typename); - INSERT_TAG(jl_namedtuple_typename); - INSERT_TAG(jl_vecelement_typename); - INSERT_TAG(jl_opaque_closure_typename); - INSERT_TAG(jl_genericmemory_typename); - INSERT_TAG(jl_genericmemoryref_typename); - - // special exceptions - INSERT_TAG(jl_errorexception_type); - INSERT_TAG(jl_argumenterror_type); - INSERT_TAG(jl_typeerror_type); - INSERT_TAG(jl_methoderror_type); - INSERT_TAG(jl_loaderror_type); - INSERT_TAG(jl_initerror_type); - INSERT_TAG(jl_undefvarerror_type); - INSERT_TAG(jl_fielderror_type); - INSERT_TAG(jl_stackovf_exception); - INSERT_TAG(jl_diverror_exception); - INSERT_TAG(jl_interrupt_exception); - INSERT_TAG(jl_boundserror_type); - INSERT_TAG(jl_memory_exception); - INSERT_TAG(jl_undefref_exception); - INSERT_TAG(jl_readonlymemory_exception); - INSERT_TAG(jl_atomicerror_type); - INSERT_TAG(jl_missingcodeerror_type); - INSERT_TAG(jl_precompilable_error); - INSERT_TAG(jl_trimfailure_type); - - // other special values - INSERT_TAG(jl_emptysvec); - INSERT_TAG(jl_emptytuple); - INSERT_TAG(jl_false); - INSERT_TAG(jl_true); - INSERT_TAG(jl_an_empty_string); - INSERT_TAG(jl_an_empty_vec_any); - INSERT_TAG(jl_an_empty_memory_any); - INSERT_TAG(jl_module_init_order); - INSERT_TAG(jl_core_module); - INSERT_TAG(jl_base_module); - INSERT_TAG(jl_main_module); - INSERT_TAG(jl_top_module); - INSERT_TAG(jl_typeinf_func); - INSERT_TAG(jl_type_type_mt); - INSERT_TAG(jl_nonfunction_mt); - INSERT_TAG(jl_kwcall_mt); - INSERT_TAG(jl_kwcall_func); - INSERT_TAG(jl_opaque_closure_method); - INSERT_TAG(jl_nulldebuginfo); - - // some Core.Builtin Functions that we want to be able to reference: - INSERT_TAG(jl_builtin_throw); - INSERT_TAG(jl_builtin_is); - INSERT_TAG(jl_builtin_typeof); - INSERT_TAG(jl_builtin_sizeof); - INSERT_TAG(jl_builtin_issubtype); - INSERT_TAG(jl_builtin_isa); - INSERT_TAG(jl_builtin_typeassert); - INSERT_TAG(jl_builtin__apply_iterate); - INSERT_TAG(jl_builtin_isdefined); - INSERT_TAG(jl_builtin_nfields); - INSERT_TAG(jl_builtin_tuple); - INSERT_TAG(jl_builtin_svec); - INSERT_TAG(jl_builtin_getfield); - INSERT_TAG(jl_builtin_setfield); - INSERT_TAG(jl_builtin_swapfield); - INSERT_TAG(jl_builtin_modifyfield); - INSERT_TAG(jl_builtin_replacefield); - INSERT_TAG(jl_builtin_setfieldonce); - INSERT_TAG(jl_builtin_fieldtype); - INSERT_TAG(jl_builtin_memorynew); - INSERT_TAG(jl_builtin_memoryref); - INSERT_TAG(jl_builtin_memoryrefoffset); - INSERT_TAG(jl_builtin_memoryrefget); - INSERT_TAG(jl_builtin_memoryrefset); - INSERT_TAG(jl_builtin_memoryref_isassigned); - INSERT_TAG(jl_builtin_memoryrefswap); - INSERT_TAG(jl_builtin_memoryrefmodify); - INSERT_TAG(jl_builtin_memoryrefreplace); - INSERT_TAG(jl_builtin_memoryrefsetonce); - INSERT_TAG(jl_builtin_apply_type); - INSERT_TAG(jl_builtin_applicable); - INSERT_TAG(jl_builtin_invoke); - INSERT_TAG(jl_builtin__expr); - INSERT_TAG(jl_builtin_ifelse); - INSERT_TAG(jl_builtin__typebody); - INSERT_TAG(jl_builtin_donotdelete); - INSERT_TAG(jl_builtin_compilerbarrier); - INSERT_TAG(jl_builtin_getglobal); - INSERT_TAG(jl_builtin_setglobal); - INSERT_TAG(jl_builtin_isdefinedglobal); - INSERT_TAG(jl_builtin_swapglobal); - INSERT_TAG(jl_builtin_modifyglobal); - INSERT_TAG(jl_builtin_replaceglobal); - INSERT_TAG(jl_builtin_setglobalonce); - INSERT_TAG(jl_builtin_current_scope); - // n.b. must update NUM_TAGS when you add something here + unsigned int i = 0; +#define INSERT_TAG(sym) tags[i++] = (jl_value_t**)&(sym) + // builtin types + INSERT_TAG(jl_any_type); + INSERT_TAG(jl_symbol_type); + INSERT_TAG(jl_ssavalue_type); + INSERT_TAG(jl_datatype_type); + INSERT_TAG(jl_slotnumber_type); + INSERT_TAG(jl_simplevector_type); + INSERT_TAG(jl_array_type); + INSERT_TAG(jl_expr_type); + INSERT_TAG(jl_binding_type); + INSERT_TAG(jl_binding_partition_type); + INSERT_TAG(jl_globalref_type); + INSERT_TAG(jl_string_type); + INSERT_TAG(jl_module_type); + INSERT_TAG(jl_tvar_type); + INSERT_TAG(jl_method_instance_type); + INSERT_TAG(jl_method_type); + INSERT_TAG(jl_code_instance_type); + INSERT_TAG(jl_linenumbernode_type); + INSERT_TAG(jl_lineinfonode_type); + INSERT_TAG(jl_gotonode_type); + INSERT_TAG(jl_quotenode_type); + INSERT_TAG(jl_gotoifnot_type); + INSERT_TAG(jl_enternode_type); + INSERT_TAG(jl_argument_type); + INSERT_TAG(jl_returnnode_type); + INSERT_TAG(jl_const_type); + INSERT_TAG(jl_partial_struct_type); + INSERT_TAG(jl_partial_opaque_type); + INSERT_TAG(jl_interconditional_type); + INSERT_TAG(jl_method_match_type); + INSERT_TAG(jl_pinode_type); + INSERT_TAG(jl_phinode_type); + INSERT_TAG(jl_phicnode_type); + INSERT_TAG(jl_upsilonnode_type); + INSERT_TAG(jl_type_type); + INSERT_TAG(jl_bottom_type); + INSERT_TAG(jl_ref_type); + INSERT_TAG(jl_pointer_type); + INSERT_TAG(jl_llvmpointer_type); + INSERT_TAG(jl_vararg_type); + INSERT_TAG(jl_abstractarray_type); + INSERT_TAG(jl_densearray_type); + INSERT_TAG(jl_nothing_type); + INSERT_TAG(jl_function_type); + INSERT_TAG(jl_typeofbottom_type); + INSERT_TAG(jl_unionall_type); + INSERT_TAG(jl_typename_type); + INSERT_TAG(jl_builtin_type); + INSERT_TAG(jl_code_info_type); + INSERT_TAG(jl_opaque_closure_type); + INSERT_TAG(jl_task_type); + INSERT_TAG(jl_uniontype_type); + INSERT_TAG(jl_abstractstring_type); + INSERT_TAG(jl_array_any_type); + INSERT_TAG(jl_intrinsic_type); + INSERT_TAG(jl_methtable_type); + INSERT_TAG(jl_typemap_level_type); + INSERT_TAG(jl_typemap_entry_type); + INSERT_TAG(jl_voidpointer_type); + INSERT_TAG(jl_uint8pointer_type); + INSERT_TAG(jl_newvarnode_type); + INSERT_TAG(jl_anytuple_type_type); + INSERT_TAG(jl_anytuple_type); + INSERT_TAG(jl_namedtuple_type); + INSERT_TAG(jl_emptytuple_type); + INSERT_TAG(jl_array_symbol_type); + INSERT_TAG(jl_array_uint8_type); + INSERT_TAG(jl_array_uint32_type); + INSERT_TAG(jl_array_int32_type); + INSERT_TAG(jl_array_uint64_type); + INSERT_TAG(jl_int32_type); + INSERT_TAG(jl_int64_type); + INSERT_TAG(jl_bool_type); + INSERT_TAG(jl_uint8_type); + INSERT_TAG(jl_uint16_type); + INSERT_TAG(jl_uint32_type); + INSERT_TAG(jl_uint64_type); + INSERT_TAG(jl_char_type); + INSERT_TAG(jl_weakref_type); + INSERT_TAG(jl_int8_type); + INSERT_TAG(jl_int16_type); + INSERT_TAG(jl_float16_type); + INSERT_TAG(jl_float32_type); + INSERT_TAG(jl_float64_type); + INSERT_TAG(jl_bfloat16_type); + INSERT_TAG(jl_floatingpoint_type); + INSERT_TAG(jl_number_type); + INSERT_TAG(jl_signed_type); + INSERT_TAG(jl_pair_type); + INSERT_TAG(jl_genericmemory_type); + INSERT_TAG(jl_memory_any_type); + INSERT_TAG(jl_memory_uint8_type); + INSERT_TAG(jl_memory_uint16_type); + INSERT_TAG(jl_memory_uint32_type); + INSERT_TAG(jl_memory_uint64_type); + INSERT_TAG(jl_genericmemoryref_type); + INSERT_TAG(jl_memoryref_any_type); + INSERT_TAG(jl_memoryref_uint8_type); + INSERT_TAG(jl_addrspace_type); + INSERT_TAG(jl_addrspace_typename); + INSERT_TAG(jl_addrspacecore_type); + INSERT_TAG(jl_debuginfo_type); + INSERT_TAG(jl_abioverride_type); + + // special typenames + INSERT_TAG(jl_tuple_typename); + INSERT_TAG(jl_pointer_typename); + INSERT_TAG(jl_llvmpointer_typename); + INSERT_TAG(jl_array_typename); + INSERT_TAG(jl_type_typename); + INSERT_TAG(jl_namedtuple_typename); + INSERT_TAG(jl_vecelement_typename); + INSERT_TAG(jl_opaque_closure_typename); + INSERT_TAG(jl_genericmemory_typename); + INSERT_TAG(jl_genericmemoryref_typename); + + // special exceptions + INSERT_TAG(jl_errorexception_type); + INSERT_TAG(jl_argumenterror_type); + INSERT_TAG(jl_typeerror_type); + INSERT_TAG(jl_methoderror_type); + INSERT_TAG(jl_loaderror_type); + INSERT_TAG(jl_initerror_type); + INSERT_TAG(jl_undefvarerror_type); + INSERT_TAG(jl_fielderror_type); + INSERT_TAG(jl_stackovf_exception); + INSERT_TAG(jl_diverror_exception); + INSERT_TAG(jl_interrupt_exception); + INSERT_TAG(jl_boundserror_type); + INSERT_TAG(jl_memory_exception); + INSERT_TAG(jl_undefref_exception); + INSERT_TAG(jl_readonlymemory_exception); + INSERT_TAG(jl_atomicerror_type); + INSERT_TAG(jl_missingcodeerror_type); + INSERT_TAG(jl_precompilable_error); + INSERT_TAG(jl_trimfailure_type); + + // other special values + INSERT_TAG(jl_emptysvec); + INSERT_TAG(jl_emptytuple); + INSERT_TAG(jl_false); + INSERT_TAG(jl_true); + INSERT_TAG(jl_an_empty_string); + INSERT_TAG(jl_an_empty_vec_any); + INSERT_TAG(jl_an_empty_memory_any); + INSERT_TAG(jl_module_init_order); + INSERT_TAG(jl_core_module); + INSERT_TAG(jl_base_module); + INSERT_TAG(jl_main_module); + INSERT_TAG(jl_top_module); + INSERT_TAG(jl_typeinf_func); + INSERT_TAG(jl_type_type_mt); + INSERT_TAG(jl_nonfunction_mt); + INSERT_TAG(jl_kwcall_mt); + INSERT_TAG(jl_kwcall_func); + INSERT_TAG(jl_opaque_closure_method); + INSERT_TAG(jl_nulldebuginfo); + // n.b. must update NUM_TAGS when you add something here #undef INSERT_TAG - assert(i == NUM_TAGS - 1); - } - return (jl_value_t**const*const) _tags; + assert(i == NUM_TAGS - 1); + tags[i] = NULL; } // hash of definitions for predefined tagged object @@ -373,12 +322,12 @@ static uintptr_t img_max; // HT_NOTFOUND is a valid integer ID, so we store the integer ids mangled. // This pair of functions mangles/demanges -static size_t from_seroder_entry(void *entry) +static size_t from_seroder_entry(void *entry) JL_NOTSAFEPOINT { return (size_t)((char*)entry - (char*)HT_NOTFOUND - 1); } -static void *to_seroder_entry(size_t idx) +static void *to_seroder_entry(size_t idx) JL_NOTSAFEPOINT { return (void*)((char*)HT_NOTFOUND + 1 + idx); } @@ -386,7 +335,7 @@ static void *to_seroder_entry(size_t idx) static htable_t new_methtables; static size_t precompilation_world; -static int ptr_cmp(const void *l, const void *r) +static int ptr_cmp(const void *l, const void *r) JL_NOTSAFEPOINT { uintptr_t left = *(const uintptr_t*)l; uintptr_t right = *(const uintptr_t*)r; @@ -394,7 +343,7 @@ static int ptr_cmp(const void *l, const void *r) } // Build an eytzinger tree from a sorted array -static int eytzinger(uintptr_t *src, uintptr_t *dest, size_t i, size_t k, size_t n) +static int eytzinger(uintptr_t *src, uintptr_t *dest, size_t i, size_t k, size_t n) JL_NOTSAFEPOINT { if (k <= n) { i = eytzinger(src, dest, i, 2 * k, n); @@ -434,7 +383,7 @@ static size_t eyt_obj_idx(jl_value_t *obj) JL_NOTSAFEPOINT } //used in staticdata.c after we add an image -void rebuild_image_blob_tree(void) +void rebuild_image_blob_tree(void) JL_NOTSAFEPOINT { size_t inc = 1 + jl_linkage_blobs.len - eytzinger_image_tree.len; assert(eytzinger_idxs.len == eytzinger_image_tree.len); @@ -510,33 +459,15 @@ JL_DLLEXPORT jl_value_t *jl_object_top_module(jl_value_t* v) JL_NOTSAFEPOINT } // hash of definitions for predefined function pointers +// (reverse is jl_builtin_f_addrs) static htable_t fptr_to_id; + void *native_functions; // opaque jl_native_code_desc_t blob used for fetching data from LLVM // table of struct field addresses to rewrite during saving static htable_t field_replace; static htable_t bits_replace; -// array of definitions for the predefined function pointers -// (reverse of fptr_to_id) -// This is a manually constructed dual of the fvars array, which would be produced by codegen for Julia code, for C. -static const jl_fptr_args_t id_to_fptrs[] = { - &jl_f_throw, &jl_f_throw_methoderror, &jl_f_is, &jl_f_typeof, &jl_f_issubtype, &jl_f_isa, - &jl_f_typeassert, &jl_f__apply_iterate, - &jl_f_invokelatest, &jl_f_invoke_in_world, &jl_f__call_in_world_total, &jl_f_isdefined, &jl_f_isdefinedglobal, - &jl_f_tuple, &jl_f_svec, &jl_f_intrinsic_call, - &jl_f_getfield, &jl_f_setfield, &jl_f_swapfield, &jl_f_modifyfield, &jl_f_setfieldonce, - &jl_f_replacefield, &jl_f_fieldtype, &jl_f_nfields, &jl_f_apply_type, &jl_f_memorynew, - &jl_f_memoryref, &jl_f_memoryrefoffset, &jl_f_memoryrefget, &jl_f_memoryref_isassigned, - &jl_f_memoryrefset, &jl_f_memoryrefswap, &jl_f_memoryrefmodify, &jl_f_memoryrefreplace, &jl_f_memoryrefsetonce, - &jl_f_applicable, &jl_f_invoke, &jl_f_sizeof, &jl_f__expr, &jl_f__typevar, - &jl_f_ifelse, &jl_f__structtype, &jl_f__abstracttype, &jl_f__primitivetype, - &jl_f__typebody, &jl_f__setsuper, &jl_f__equiv_typedef, &jl_f__defaultctors, - &jl_f_opaque_closure_call, &jl_f_donotdelete, &jl_f_compilerbarrier, &jl_f_get_binding_type, - &jl_f_getglobal, &jl_f_setglobal, &jl_f_swapglobal, &jl_f_modifyglobal, &jl_f_replaceglobal, &jl_f_setglobalonce, - &jl_f_finalizer, &jl_f__compute_sparams, &jl_f__svec_ref, - &jl_f_current_scope, - NULL }; typedef struct { ios_t *s; // the main stream @@ -1210,7 +1141,8 @@ static void write_pointer(ios_t *s) JL_NOTSAFEPOINT } // Records the buildid holding `v` and returns the tagged offset within the corresponding image -static uintptr_t add_external_linkage(jl_serializer_state *s, jl_value_t *v, jl_array_t *link_ids) { +static uintptr_t add_external_linkage(jl_serializer_state *s, jl_value_t *v, jl_array_t *link_ids) JL_GC_DISABLED +{ size_t i = external_blob_index(v); if (i < n_linkage_blobs()) { // We found the sysimg/pkg that this item links against @@ -1239,7 +1171,7 @@ static uintptr_t add_external_linkage(jl_serializer_state *s, jl_value_t *v, jl_ // but symbols, small integers, and a couple of special items (`nothing` and the root Task) // have special handling. #define backref_id(s, v, link_ids) _backref_id(s, (jl_value_t*)(v), link_ids) -static uintptr_t _backref_id(jl_serializer_state *s, jl_value_t *v, jl_array_t *link_ids) JL_NOTSAFEPOINT +static uintptr_t _backref_id(jl_serializer_state *s, jl_value_t *v, jl_array_t *link_ids) JL_GC_DISABLED { assert(v != NULL && "cannot get backref to NULL object"); if (jl_is_symbol(v)) { @@ -1452,7 +1384,7 @@ static void record_memoryrefs_inside(jl_serializer_state *s, jl_datatype_t *t, s } } -static void record_gvars(jl_serializer_state *s, arraylist_t *globals) JL_NOTSAFEPOINT +static void record_gvars(jl_serializer_state *s, arraylist_t *globals) JL_GC_DISABLED { for (size_t i = 0; i < globals->len; i++) jl_queue_for_serialization(s, globals->items[i]); @@ -2089,7 +2021,7 @@ static uintptr_t get_reloc_for_item(uintptr_t reloc_item, size_t reloc_offset) case FunctionRef: if (offset & BuiltinFunctionTag) { offset &= ~BuiltinFunctionTag; - assert(offset < sizeof(id_to_fptrs) / sizeof(*id_to_fptrs) && "unknown function pointer id"); + assert(offset < jl_n_builtins && "unknown function pointer id"); } else { assert(offset < JL_API_MAX && "unknown function pointer id"); @@ -2144,8 +2076,8 @@ static inline uintptr_t get_item_for_reloc(jl_serializer_state *s, uintptr_t bas case FunctionRef: if (offset & BuiltinFunctionTag) { offset &= ~BuiltinFunctionTag; - assert(offset < sizeof(id_to_fptrs) / sizeof(*id_to_fptrs) && "unknown function pointer ID"); - return (uintptr_t)id_to_fptrs[offset]; + assert(offset < jl_n_builtins && "unknown function pointer ID"); + return (uintptr_t)jl_builtin_f_addrs[offset]; } switch ((jl_callingconv_t)offset) { case JL_API_BOXED: @@ -2358,7 +2290,7 @@ void gc_sweep_sysimg(void) // the image proper. For example, new methods added to external callables require // insertion into the appropriate method table. #define jl_write_value(s, v) _jl_write_value((s), (jl_value_t*)(v)) -static void _jl_write_value(jl_serializer_state *s, jl_value_t *v) +static void _jl_write_value(jl_serializer_state *s, jl_value_t *v) JL_GC_DISABLED { if (v == NULL) { write_reloc_t(s->s, 0); @@ -2460,7 +2392,7 @@ static void jl_update_all_fptrs(jl_serializer_state *s, jl_image_t *image) jl_register_fptrs(image->base, &fvars, linfos, img_fvars_max); } -static uint32_t write_gvars(jl_serializer_state *s, arraylist_t *globals, arraylist_t *external_fns) JL_NOTSAFEPOINT +static uint32_t write_gvars(jl_serializer_state *s, arraylist_t *globals, arraylist_t *external_fns) JL_GC_DISABLED { size_t len = globals->len + external_fns->len; ios_ensureroom(s->gvar_record, len * sizeof(reloc_t)); @@ -3081,10 +3013,10 @@ static void jl_save_system_image_to_stream(ios_t *f, jl_array_t *mod_array, nsym_tag = 0; htable_new(&symbol_table, 0); - htable_new(&fptr_to_id, sizeof(id_to_fptrs) / sizeof(*id_to_fptrs)); + htable_new(&fptr_to_id, jl_n_builtins); uintptr_t i; - for (i = 0; id_to_fptrs[i] != NULL; i++) { - ptrhash_put(&fptr_to_id, (void*)(uintptr_t)id_to_fptrs[i], (void*)(i + 2)); + for (i = 0; i < jl_n_builtins; i++) { + ptrhash_put(&fptr_to_id, (void*)(uintptr_t)jl_builtin_f_addrs[i], (void*)(i + 2)); } htable_new(&serialization_order, 25000); htable_new(&nullptrs, 0); @@ -3123,11 +3055,15 @@ static void jl_save_system_image_to_stream(ios_t *f, jl_array_t *mod_array, s.link_ids_external_fnvars = jl_alloc_array_1d(jl_array_int32_type, 0); s.method_roots_list = NULL; htable_new(&s.method_roots_index, 0); + jl_value_t **_tags[NUM_TAGS]; + jl_value_t ***tags = s.incremental ? NULL : _tags; if (worklist) { s.method_roots_list = jl_alloc_vec_any(0); s.worklist_key = jl_worklist_key(worklist); } - jl_value_t **const*const tags = get_tags(); // worklist == NULL ? get_tags() : NULL; + else { + get_tags(_tags); + } if (worklist == NULL) { // empty!(Core.ARGS) @@ -3153,6 +3089,8 @@ static void jl_save_system_image_to_stream(ios_t *f, jl_array_t *mod_array, jl_value_t *tag = *tags[i]; jl_queue_for_serialization(&s, tag); } + for (i = 0; i < jl_n_builtins; i++) + jl_queue_for_serialization(&s, jl_builtin_instances[i]); jl_queue_for_serialization(&s, s.ptls->root_task->tls); } else { @@ -3334,6 +3272,8 @@ static void jl_save_system_image_to_stream(ios_t *f, jl_array_t *mod_array, jl_value_t *tag = *tags[i]; jl_write_value(&s, tag); } + for (i = 0; i < jl_n_builtins; i++) + jl_write_value(&s, jl_builtin_instances[i]); jl_write_value(&s, global_roots_list); jl_write_value(&s, global_roots_keyset); jl_write_value(&s, s.ptls->root_task->tls); @@ -3770,7 +3710,11 @@ static void jl_restore_system_image_from_stream_(ios_t *f, jl_image_t *image, s.gvar_record = &gvar_record; s.fptr_record = &fptr_record; s.ptls = ct->ptls; - jl_value_t **const*const tags = get_tags(); + jl_value_t **_tags[NUM_TAGS]; + jl_value_t ***tags = s.incremental ? NULL : _tags; + if (!s.incremental) + get_tags(_tags); + htable_t new_dt_objs; htable_new(&new_dt_objs, 0); arraylist_new(&deser_sym, 0); @@ -3832,6 +3776,8 @@ static void jl_restore_system_image_from_stream_(ios_t *f, jl_image_t *image, jl_value_t **tag = tags[i]; *tag = jl_read_value(&s); } + for (i = 0; i < jl_n_builtins; i++) + jl_builtin_instances[i] = jl_read_value(&s); #define XX(name) \ ijl_small_typeof[(jl_##name##_tag << 4) / sizeof(*ijl_small_typeof)] = jl_##name##_type; JL_SMALL_TYPEOF(XX) diff --git a/src/toplevel.c b/src/toplevel.c index b7479e2d1c24b..efdd29cb01030 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -426,7 +426,7 @@ static void expr_attributes(jl_value_t *v, jl_array_t *body, int *has_ccall, int if (jl_is_intrinsic(called) && jl_unbox_int32(called) == (int)llvmcall) { *has_ccall = 1; } - if (called == jl_builtin__typebody) { // TODO: rely on latestworld instead of function callee detection here (or add it to jl_is_toplevel_only_expr) + if (called == BUILTIN(_typebody)) { // TODO: rely on latestworld instead of function callee detection here (or add it to jl_is_toplevel_only_expr) *has_defs = 1; } } @@ -705,7 +705,7 @@ static void jl_eval_throw(jl_module_t *m, jl_value_t *exc, const char *filename, { jl_value_t *throw_ex = (jl_value_t*)jl_exprn(jl_call_sym, 2); JL_GC_PUSH1(&throw_ex); - jl_exprargset(throw_ex, 0, jl_builtin_throw); + jl_exprargset(throw_ex, 0, BUILTIN(throw)); jl_exprargset(throw_ex, 1, exc); jl_toplevel_eval_flex(m, throw_ex, 0, 0, &filename, &lineno); JL_GC_POP(); From bc9450e07f7a52f060801d017f5f12f0b0faaaf9 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Sat, 19 Apr 2025 21:37:34 -0400 Subject: [PATCH 07/83] staticdata: prune backedges table during serialization (#58156) After the bindings change, there is quite a lot of garbage in here now at runtime (it does not de-duplicate entries added for bindings), so attempt to do a bit of that during serialization. Re-landing part of #58078 (cherry picked from commit 3ea60d2274524369823efc7e39067570ba2cbb38) --- src/staticdata.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/src/staticdata.c b/src/staticdata.c index a7a41d98eb505..05617ea3a087e 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -821,12 +821,38 @@ static void jl_insert_into_serialization_queue(jl_serializer_state *s, jl_value_ // prevent this from happening, so we do not need to detect that user // error now. } + // don't recurse into all backedges memory (yet) + jl_value_t *backedges = get_replaceable_field((jl_value_t**)&mi->backedges, 1); + if (backedges) { + assert(!jl_options.trim && !jl_options.strip_ir); + jl_queue_for_serialization_(s, (jl_value_t*)((jl_array_t*)backedges)->ref.mem, 0, 1); + size_t i = 0, n = jl_array_nrows(backedges); + while (i < n) { + jl_value_t *invokeTypes; + jl_code_instance_t *caller; + i = get_next_edge((jl_array_t*)backedges, i, &invokeTypes, &caller); + if (invokeTypes) + jl_queue_for_serialization(s, invokeTypes); + } + } } if (jl_is_mtable(v)) { jl_methtable_t *mt = (jl_methtable_t*)v; if (jl_options.trim || jl_options.strip_ir) { record_field_change((jl_value_t**)&mt->backedges, NULL); } + else { + // don't recurse into all backedges memory (yet) + jl_value_t *backedges = get_replaceable_field((jl_value_t**)&mt->backedges, 1); + if (backedges) { + jl_queue_for_serialization_(s, (jl_value_t*)((jl_array_t*)backedges)->ref.mem, 0, 1); + for (size_t i = 0, n = jl_array_nrows(backedges); i < n; i += 2) { + jl_value_t *t = jl_array_ptr_ref(backedges, i); + assert(!jl_is_code_instance(t)); + jl_queue_for_serialization(s, t); + } + } + } } if (jl_is_binding(v)) { jl_binding_t *b = (jl_binding_t*)v; @@ -838,6 +864,18 @@ static void jl_insert_into_serialization_queue(jl_serializer_state *s, jl_value_ if (jl_options.trim || jl_options.strip_ir) { record_field_change((jl_value_t**)&b->backedges, NULL); } + else { + // don't recurse into all backedges memory (yet) + jl_value_t *backedges = get_replaceable_field((jl_value_t**)&b->backedges, 1); + if (backedges) { + jl_queue_for_serialization_(s, (jl_value_t*)((jl_array_t*)backedges)->ref.mem, 0, 1); + for (size_t i = 0, n = jl_array_nrows(backedges); i < n; i++) { + jl_value_t *b = jl_array_ptr_ref(backedges, i); + if (!jl_is_code_instance(b) && !jl_is_method_instance(b) && !jl_is_method(b)) // otherwise usually a Binding? + jl_queue_for_serialization(s, b); + } + } + } } if (s->incremental && jl_is_globalref(v)) { jl_globalref_t *gr = (jl_globalref_t*)v; @@ -2507,6 +2545,52 @@ static void jl_prune_type_cache_linear(jl_svec_t *cache) jl_svecset(cache, ins++, jl_nothing); } +static void jl_prune_mi_backedges(jl_array_t *backedges) +{ + if (backedges == NULL) + return; + size_t i = 0, ins = 0, n = jl_array_nrows(backedges); + while (i < n) { + jl_value_t *invokeTypes; + jl_code_instance_t *caller; + i = get_next_edge(backedges, i, &invokeTypes, &caller); + if (ptrhash_get(&serialization_order, caller) != HT_NOTFOUND) + ins = set_next_edge(backedges, ins, invokeTypes, caller); + } + jl_array_del_end(backedges, n - ins); +} + +static void jl_prune_mt_backedges(jl_array_t *backedges) +{ + if (backedges == NULL) + return; + size_t i = 0, ins = 0, n = jl_array_nrows(backedges); + for (i = 1; i < n; i += 2) { + jl_value_t *ci = jl_array_ptr_ref(backedges, i); + if (ptrhash_get(&serialization_order, ci) != HT_NOTFOUND) { + jl_array_ptr_set(backedges, ins++, jl_array_ptr_ref(backedges, i - 1)); + jl_array_ptr_set(backedges, ins++, ci); + } + } + jl_array_del_end(backedges, n - ins); +} + + +static void jl_prune_binding_backedges(jl_array_t *backedges) +{ + if (backedges == NULL) + return; + size_t i = 0, ins = 0, n = jl_array_nrows(backedges); + for (i = 0; i < n; i++) { + jl_value_t *b = jl_array_ptr_ref(backedges, i); + if (ptrhash_get(&serialization_order, b) != HT_NOTFOUND) { + jl_array_ptr_set(backedges, ins, b); + ins++; + } + } + jl_array_del_end(backedges, n - ins); +} + uint_t bindingkey_hash(size_t idx, jl_value_t *data); @@ -3174,6 +3258,21 @@ static void jl_save_system_image_to_stream(ios_t *f, jl_array_t *mod_array, jl_gc_wb(tn, jl_atomic_load_relaxed(&tn->cache)); jl_prune_type_cache_linear(jl_atomic_load_relaxed(&tn->linearcache)); } + else if (jl_is_method_instance(v)) { + jl_method_instance_t *mi = (jl_method_instance_t*)v; + jl_value_t *backedges = get_replaceable_field((jl_value_t**)&mi->backedges, 1); + jl_prune_mi_backedges((jl_array_t*)backedges); + } + else if (jl_is_mtable(v)) { + jl_methtable_t *mt = (jl_methtable_t*)v; + jl_value_t *backedges = get_replaceable_field((jl_value_t**)&mt->backedges, 1); + jl_prune_mt_backedges((jl_array_t*)backedges); + } + else if (jl_is_binding(v)) { + jl_binding_t *b = (jl_binding_t*)v; + jl_value_t *backedges = get_replaceable_field((jl_value_t**)&b->backedges, 1); + jl_prune_binding_backedges((jl_array_t*)backedges); + } } } From be99f9eb1bc4204af893d46ef73207c67ddbe420 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Wed, 28 May 2025 11:24:04 -0400 Subject: [PATCH 08/83] make just one MethodTable (#58131) Instead of hiding the fragments of the method table in each TypeName, make one variable `Core.GlobalMethods` with access to all methods. The need to split them early for performance apparently had been long past since kwargs and constructors were already using a single table and cache anyways. Some new concepts introduced here: - A single Method can now be added to multiple functions. So instead of using eval in a for loop, we could define it just once (see example below). - Several fields (`max_args`, `name`, and `backedges`) were moved from MethodTable to their TypeName. - TypeName currently has a (user-modifiable) field called `singletonname`. If set to something other than `name`, it may be used for pretty printing of a singleton object using its "canonical" (unmangled) name, particularly for `function`. - `Core.Builtin` method table entries are even more normal now, with valid `sig` fields, and special logic to specifically prevent adding methods which would become ambiguous with them (as that would violate the tfuncs we have for them). - `Core.GlobalMethods` is a `Base.Experimental.@MethodTable GlobalMethods`. - Each `MethodTable` contains a separate `MethodCache` object for managing fast dispatch lookups. We may want to use this for the `Method` field containing the `invokes` list so that lookups there get more of the same optimizations as global calls. - Methods could be put into any number of different MethodTables (or none). The `Method.primary_world` field is intended to reflect whether it is currently put into the GlobalMethods table, and what world to use in the GlobalMethods table for running its generator, and otherwise is meaningless. - The lock for TypeName backedges is a single global lock now, in `Core.GlobalMethods.mc`. - The `backedges` in TypeName are stored on the "top-most" typename in the hierarchy, to enable efficient lookup (although we might want to consider replacing this entirely with a TypeMap). The "top-most" typename is the typename of the type closest to Any, after union-splitting, which doesn't have an intersection with Builtin (so Function and Any by implication continue to not require scanning for missing backedges since it is not permitted to add a Method applicable to all functions). - Support for having backedges from experimental method tables was removed since it was unsound and had been already replaced with staticdata.jl several months ago. - Documentation lookup for `IncludeInto` is fixed (previously attached only to `Main.include` instead of all `include` functions). Example: given this existing code in base/operators: for op in (:+, :*, :&, :|, :xor, :min, :max, :kron) @eval begin ($op)(a, b, c, xs...) = (@inline; afoldl($op, ($op)(($op)(a,b),c), xs...)) end end It could now instead be equivalently written as: let ops = Union{typeof(+), typeof(*), typeof(&), typeof(|), typeof(xor), typeof(min), typeof(max), typeof(kron)} (op::ops)(a, b, c, xs...) = (@inline; afoldl(op, (op)((op)(a,b),c), xs...)) end Fixes #57560 (cherry picked from commit 1735d8f03c9e4fedba652e4e562c049ac48c93fd) --- Compiler/src/Compiler.jl | 2 +- Compiler/src/abstractinterpretation.jl | 10 +- Compiler/src/stmtinfo.jl | 5 +- Compiler/src/tfuncs.jl | 5 +- Compiler/src/typeinfer.jl | 2 +- Compiler/src/utilities.jl | 6 +- base/Base_compiler.jl | 6 +- base/deprecated.jl | 4 +- base/docs/bindings.jl | 2 +- base/errorshow.jl | 2 +- base/invalidation.jl | 30 - base/methodshow.jl | 29 +- base/operators.jl | 2 +- base/reflection.jl | 8 +- base/runtime_internals.jl | 20 +- base/show.jl | 44 +- base/strings/io.jl | 6 +- base/summarysize.jl | 2 +- base/sysimg.jl | 13 +- doc/src/devdocs/functions.md | 29 +- doc/src/devdocs/types.md | 1 - src/builtins.c | 29 +- src/clangsa/GCChecker.cpp | 1 + src/codegen.cpp | 17 +- src/datatype.c | 50 +- src/gc-stock.c | 2 + src/gf.c | 817 ++++++++++++---------- src/interpreter.c | 3 +- src/ircode.c | 2 - src/jl_exported_data.inc | 5 +- src/jltypes.c | 130 ++-- src/julia.h | 38 +- src/julia_internal.h | 22 +- src/method.c | 106 +-- src/module.c | 10 +- src/precompile_utils.c | 110 +-- src/rtutils.c | 16 +- src/staticdata.c | 148 ++-- src/staticdata_utils.c | 8 +- stdlib/Serialization/src/Serialization.jl | 87 ++- stdlib/Test/src/Test.jl | 50 +- test/clangsa/MissingRoots.c | 14 - test/core.jl | 25 +- test/misc.jl | 4 +- test/precompile.jl | 8 +- test/reflection.jl | 4 +- test/show.jl | 8 +- test/stacktraces.jl | 6 +- test/syntax.jl | 5 +- test/worlds.jl | 39 +- 50 files changed, 982 insertions(+), 1010 deletions(-) diff --git a/Compiler/src/Compiler.jl b/Compiler/src/Compiler.jl index 981001cb2fbe6..080cdc6f7ee0e 100644 --- a/Compiler/src/Compiler.jl +++ b/Compiler/src/Compiler.jl @@ -38,7 +38,7 @@ else using Core.Intrinsics, Core.IR using Core: ABIOverride, Builtin, CodeInstance, IntrinsicFunction, MethodInstance, MethodMatch, - MethodTable, PartialOpaque, SimpleVector, TypeofVararg, + MethodTable, MethodCache, PartialOpaque, SimpleVector, TypeofVararg, _apply_iterate, apply_type, compilerbarrier, donotdelete, memoryref_isassigned, memoryrefget, memoryrefnew, memoryrefoffset, memoryrefset!, print, println, show, svec, typename, unsafe_write, write diff --git a/Compiler/src/abstractinterpretation.jl b/Compiler/src/abstractinterpretation.jl index 01faba6b37d1f..4947368e87858 100644 --- a/Compiler/src/abstractinterpretation.jl +++ b/Compiler/src/abstractinterpretation.jl @@ -363,15 +363,13 @@ function find_union_split_method_matches(interp::AbstractInterpreter, argtypes:: arg_n = split_argtypes[i]::Vector{Any} sig_n = argtypes_to_type(arg_n) sig_n === Bottom && continue - mt = ccall(:jl_method_table_for, Any, (Any,), sig_n) - mt === nothing && return FailedMethodMatch("Could not identify method table for call") - mt = mt::MethodTable thismatches = findall(sig_n, method_table(interp); limit = max_methods) if thismatches === nothing return FailedMethodMatch("For one of the union split cases, too many methods matched") end valid_worlds = intersect(valid_worlds, thismatches.valid_worlds) thisfullmatch = any(match::MethodMatch->match.fully_covers, thismatches) + mt = Core.GlobalMethods thisinfo = MethodMatchInfo(thismatches, mt, sig_n, thisfullmatch) push!(infos, thisinfo) for idx = 1:length(thismatches) @@ -385,11 +383,6 @@ function find_union_split_method_matches(interp::AbstractInterpreter, argtypes:: end function find_simple_method_matches(interp::AbstractInterpreter, @nospecialize(atype), max_methods::Int) - mt = ccall(:jl_method_table_for, Any, (Any,), atype) - if mt === nothing - return FailedMethodMatch("Could not identify method table for call") - end - mt = mt::MethodTable matches = findall(atype, method_table(interp); limit = max_methods) if matches === nothing # this means too many methods matched @@ -397,6 +390,7 @@ function find_simple_method_matches(interp::AbstractInterpreter, @nospecialize(a return FailedMethodMatch("Too many methods matched") end fullmatch = any(match::MethodMatch->match.fully_covers, matches) + mt = Core.GlobalMethods info = MethodMatchInfo(matches, mt, atype, fullmatch) applicable = MethodMatchTarget[MethodMatchTarget(matches[idx], info.edges, idx) for idx = 1:length(matches)] return MethodMatches(applicable, info, matches.valid_worlds) diff --git a/Compiler/src/stmtinfo.jl b/Compiler/src/stmtinfo.jl index 6a85bc6605d3f..2a2e2509b0fc2 100644 --- a/Compiler/src/stmtinfo.jl +++ b/Compiler/src/stmtinfo.jl @@ -47,17 +47,16 @@ end add_edges_impl(edges::Vector{Any}, info::MethodMatchInfo) = _add_edges_impl(edges, info) function _add_edges_impl(edges::Vector{Any}, info::MethodMatchInfo, mi_edge::Bool=false) if !fully_covering(info) - # add legacy-style missing backedge info also exists = false for i in 2:length(edges) - if edges[i] === info.mt && edges[i-1] == info.atype + if edges[i] === Core.GlobalMethods && edges[i-1] == info.atype exists = true break end end if !exists push!(edges, info.atype) - push!(edges, info.mt) + push!(edges, Core.GlobalMethods) end end nmatches = length(info.results) diff --git a/Compiler/src/tfuncs.jl b/Compiler/src/tfuncs.jl index e9fe671b2f781..22a9658845fe3 100644 --- a/Compiler/src/tfuncs.jl +++ b/Compiler/src/tfuncs.jl @@ -3156,15 +3156,12 @@ function _hasmethod_tfunc(interp::AbstractInterpreter, argtypes::Vector{Any}, sv isdispatchelem(ft) || return CallMeta(Bool, Any, Effects(), NoCallInfo()) # check that we might not have a subtype of `ft` at runtime, before doing supertype lookup below types = rewrap_unionall(Tuple{ft, unwrapped.parameters...}, types)::Type end - mt = ccall(:jl_method_table_for, Any, (Any,), types) - if !isa(mt, MethodTable) - return CallMeta(Bool, Any, EFFECTS_THROWS, NoCallInfo()) - end match, valid_worlds = findsup(types, method_table(interp)) update_valid_age!(sv, valid_worlds) if match === nothing rt = Const(false) vresults = MethodLookupResult(Any[], valid_worlds, true) + mt = Core.GlobalMethods vinfo = MethodMatchInfo(vresults, mt, types, false) # XXX: this should actually be an info with invoke-type edge else rt = Const(true) diff --git a/Compiler/src/typeinfer.jl b/Compiler/src/typeinfer.jl index e11b6138a209c..03b19c9282a46 100644 --- a/Compiler/src/typeinfer.jl +++ b/Compiler/src/typeinfer.jl @@ -636,7 +636,7 @@ function store_backedges(caller::CodeInstance, edges::SimpleVector) if item isa Core.Binding maybe_add_binding_backedge!(item, caller) elseif item isa MethodTable - ccall(:jl_method_table_add_backedge, Cvoid, (Any, Any, Any), item, invokesig, caller) + ccall(:jl_method_table_add_backedge, Cvoid, (Any, Any), invokesig, caller) else item::MethodInstance ccall(:jl_method_instance_add_backedge, Cvoid, (Any, Any, Any), item, invokesig, caller) diff --git a/Compiler/src/utilities.jl b/Compiler/src/utilities.jl index dfcff03d70f0e..d5a2fcfc478ff 100644 --- a/Compiler/src/utilities.jl +++ b/Compiler/src/utilities.jl @@ -158,10 +158,8 @@ end function get_compileable_sig(method::Method, @nospecialize(atype), sparams::SimpleVector) isa(atype, DataType) || return nothing - mt = ccall(:jl_method_get_table, Any, (Any,), method) - mt === nothing && return nothing - return ccall(:jl_normalize_to_compilable_sig, Any, (Any, Any, Any, Any, Cint), - mt, atype, sparams, method, #=int return_if_compileable=#1) + return ccall(:jl_normalize_to_compilable_sig, Any, (Any, Any, Any, Cint), + atype, sparams, method, #=int return_if_compileable=#1) end diff --git a/base/Base_compiler.jl b/base/Base_compiler.jl index 16633ba01a17b..6eb4bf4f1a68b 100644 --- a/base/Base_compiler.jl +++ b/base/Base_compiler.jl @@ -215,7 +215,7 @@ function Core.kwcall(kwargs::NamedTuple, ::typeof(invoke), f, T, args...) return invoke(Core.kwcall, T, kwargs, f, args...) end # invoke does not have its own call cache, but kwcall for invoke does -setfield!(typeof(invoke).name.mt, :max_args, 3, :monotonic) # invoke, f, T, args... +setfield!(typeof(invoke).name, :max_args, Int32(3), :monotonic) # invoke, f, T, args... # define applicable(f, T, args...; kwargs...), without kwargs wrapping # to forward to applicable @@ -249,7 +249,7 @@ function Core.kwcall(kwargs::NamedTuple, ::typeof(invokelatest), f, args...) @inline return Core.invokelatest(Core.kwcall, kwargs, f, args...) end -setfield!(typeof(invokelatest).name.mt, :max_args, 2, :monotonic) # invokelatest, f, args... +setfield!(typeof(invokelatest).name, :max_args, Int32(2), :monotonic) # invokelatest, f, args... """ invoke_in_world(world, f, args...; kwargs...) @@ -283,7 +283,7 @@ function Core.kwcall(kwargs::NamedTuple, ::typeof(invoke_in_world), world::UInt, @inline return Core.invoke_in_world(world, Core.kwcall, kwargs, f, args...) end -setfield!(typeof(invoke_in_world).name.mt, :max_args, 3, :monotonic) # invoke_in_world, world, f, args... +setfield!(typeof(invoke_in_world).name, :max_args, Int32(3), :monotonic) # invoke_in_world, world, f, args... # core operations & types include("promotion.jl") diff --git a/base/deprecated.jl b/base/deprecated.jl index eeb7c0e60638e..32bdd52a5288a 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -211,7 +211,7 @@ macro deprecate(old, new, export_old=true) maybe_export, :($(esc(old)) = begin $meta - depwarn($"`$oldcall` is deprecated, use `$newcall` instead.", Core.Typeof($(esc(fnexpr))).name.mt.name) + depwarn($"`$oldcall` is deprecated, use `$newcall` instead.", Core.Typeof($(esc(fnexpr))).name.singletonname) $(esc(new)) end)) else @@ -222,7 +222,7 @@ macro deprecate(old, new, export_old=true) export_old ? Expr(:export, esc(old)) : nothing, :(function $(esc(old))(args...; kwargs...) $meta - depwarn($"`$old` is deprecated, use `$new` instead.", Core.Typeof($(esc(old))).name.mt.name) + depwarn($"`$old` is deprecated, use `$new` instead.", Core.Typeof($(esc(old))).name.singletonname) $(esc(new))(args...; kwargs...) end)) end diff --git a/base/docs/bindings.jl b/base/docs/bindings.jl index 5c65a35659f81..5a0e8e01762e2 100644 --- a/base/docs/bindings.jl +++ b/base/docs/bindings.jl @@ -42,6 +42,6 @@ end aliasof(b::Binding) = defined(b) ? (a = aliasof(resolve(b), b); defined(a) ? a : b) : b aliasof(d::DataType, b) = Binding(d.name.module, d.name.name) -aliasof(λ::Function, b) = (m = typeof(λ).name.mt; Binding(m.module, m.name)) +aliasof(λ::Function, b) = (m = typeof(λ).name; Binding(m.module, m.singletonname)) aliasof(m::Module, b) = Binding(m, nameof(m)) aliasof(other, b) = b diff --git a/base/errorshow.jl b/base/errorshow.jl index 6aab526f87c6c..69b13738d86e4 100644 --- a/base/errorshow.jl +++ b/base/errorshow.jl @@ -326,7 +326,7 @@ function showerror(io::IO, ex::MethodError) print(io, "\nUse square brackets [] for indexing an Array.") end # Check for local functions that shadow methods in Base - let name = ft.name.mt.name + let name = ft.name.singletonname if f_is_function && isdefined(Base, name) basef = getfield(Base, name) if basef !== f && hasmethod(basef, arg_types) diff --git a/base/invalidation.jl b/base/invalidation.jl index e974bcd226de8..2fb308d58ed91 100644 --- a/base/invalidation.jl +++ b/base/invalidation.jl @@ -15,36 +15,6 @@ function iterate(gri::GlobalRefIterator, i = 1) return ((b::Core.Binding).globalref, i+1) end -const TYPE_TYPE_MT = Type.body.name.mt -const NONFUNCTION_MT = Core.MethodTable.name.mt -function foreach_module_mtable(visit, m::Module, world::UInt) - for gb in globalrefs(m) - binding = gb.binding - bpart = lookup_binding_partition(world, binding) - if is_defined_const_binding(binding_kind(bpart)) - v = partition_restriction(bpart) - uw = unwrap_unionall(v) - name = gb.name - if isa(uw, DataType) - tn = uw.name - if tn.module === m && tn.name === name && tn.wrapper === v && isdefined(tn, :mt) - # this is the original/primary binding for the type (name/wrapper) - mt = tn.mt - if mt !== nothing && mt !== TYPE_TYPE_MT && mt !== NONFUNCTION_MT - @assert mt.module === m - visit(mt) || return false - end - end - elseif isa(v, Core.MethodTable) && v.module === m && v.name === name - # this is probably an external method table here, so let's - # assume so as there is no way to precisely distinguish them - visit(v) || return false - end - end - end - return true -end - function foreachgr(visit, src::CodeInfo) stmts = src.code for i = 1:length(stmts) diff --git a/base/methodshow.jl b/base/methodshow.jl index 7fdefc9b7311f..dc3f564d70db7 100644 --- a/base/methodshow.jl +++ b/base/methodshow.jl @@ -81,7 +81,7 @@ function kwarg_decl(m::Method, kwtype = nothing) if m.sig !== Tuple # OpaqueClosure or Builtin kwtype = typeof(Core.kwcall) sig = rewrap_unionall(Tuple{kwtype, NamedTuple, (unwrap_unionall(m.sig)::DataType).parameters...}, m.sig) - kwli = ccall(:jl_methtable_lookup, Any, (Any, Any, UInt), kwtype.name.mt, sig, get_world_counter()) + kwli = ccall(:jl_methtable_lookup, Any, (Any, UInt), sig, get_world_counter()) if kwli !== nothing kwli = kwli::Method slotnames = ccall(:jl_uncompress_argnames, Vector{Symbol}, (Any,), kwli.slot_syms) @@ -259,10 +259,10 @@ function show_method(io::IO, m::Method; modulecolor = :light_black, digit_align_ end function show_method_list_header(io::IO, ms::MethodList, namefmt::Function) - mt = ms.mt - name = mt.name - hasname = isdefined(mt.module, name) && - typeof(getfield(mt.module, name)) <: Function + tn = ms.tn + name = tn.singletonname + hasname = isdefined(tn.module, name) && + typeof(getfield(tn.module, name)) <: Function n = length(ms) m = n==1 ? "method" : "methods" print(io, "# $n $m") @@ -271,18 +271,18 @@ function show_method_list_header(io::IO, ms::MethodList, namefmt::Function) if hasname what = (startswith(sname, '@') ? "macro" - : mt.module === Core && mt.defs isa Core.TypeMapEntry && (mt.defs.func::Method).sig === Tuple ? + : tn.module === Core && tn.wrapper <: Core.Builtin ? "builtin function" : # else "generic function") print(io, " for ", what, " ", namedisplay, " from ") - col = get!(() -> popfirst!(STACKTRACE_MODULECOLORS), STACKTRACE_FIXEDCOLORS, parentmodule_before_main(ms.mt.module)) + col = get!(() -> popfirst!(STACKTRACE_MODULECOLORS), STACKTRACE_FIXEDCOLORS, parentmodule_before_main(tn.module)) - printstyled(io, ms.mt.module, color=col) + printstyled(io, tn.module, color=col) elseif '#' in sname print(io, " for anonymous function ", namedisplay) - elseif mt === _TYPE_NAME.mt + elseif tn === _TYPE_NAME || iskindtype(tn.wrapper) print(io, " for type constructor") else print(io, " for callable object") @@ -293,6 +293,8 @@ end # Determine the `modulecolor` value to pass to `show_method` function _modulecolor(method::Method) mmt = get_methodtable(method) + # TODO: this looks like a buggy bit of internal hacking, so disable for now + return nothing if mmt === nothing || mmt.module === parentmodule(method) return nothing end @@ -314,10 +316,10 @@ function _modulecolor(method::Method) end function show_method_table(io::IO, ms::MethodList, max::Int=-1, header::Bool=true) - mt = ms.mt - name = mt.name - hasname = isdefined(mt.module, name) && - typeof(getfield(mt.module, name)) <: Function + tn = ms.tn + name = tn.singletonname + hasname = isdefined(tn.module, name) && + typeof(getfield(tn.module, name)) <: Function if header show_method_list_header(io, ms, str -> "\""*str*"\"") end @@ -458,7 +460,6 @@ function show(io::IO, ::MIME"text/html", m::Method) end function show(io::IO, mime::MIME"text/html", ms::MethodList) - mt = ms.mt show_method_list_header(io, ms, str -> ""*str*"") print(io, "
    ") for meth in ms diff --git a/base/operators.jl b/base/operators.jl index d01902e302359..f7c431a234e13 100644 --- a/base/operators.jl +++ b/base/operators.jl @@ -632,7 +632,7 @@ function afoldl(op, a, bs...) end return y end -setfield!(typeof(afoldl).name.mt, :max_args, 34, :monotonic) +setfield!(typeof(afoldl).name, :max_args, Int32(34), :monotonic) for op in (:+, :*, :&, :|, :xor, :min, :max, :kron) @eval begin diff --git a/base/reflection.jl b/base/reflection.jl index 51a781002469d..406b14f48c3da 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -933,13 +933,7 @@ this is a compiler-generated name. For explicitly-declared subtypes of `Function`, it is the name of the function's type. """ function nameof(f::Function) - t = typeof(f) - mt = t.name.mt - if mt === Symbol.name.mt - # uses shared method table, so name is not unique to this function type - return nameof(t) - end - return mt.name + return typeof(f).name.singletonname end function nameof(f::Core.IntrinsicFunction) diff --git a/base/runtime_internals.jl b/base/runtime_internals.jl index b6190b3e9044e..bef04fd84e6ff 100644 --- a/base/runtime_internals.jl +++ b/base/runtime_internals.jl @@ -1304,14 +1304,14 @@ hasproperty(x, s::Symbol) = s in propertynames(x) Make method `m` uncallable and force recompilation of any methods that use(d) it. """ function delete_method(m::Method) - ccall(:jl_method_table_disable, Cvoid, (Any, Any), get_methodtable(m), m) + ccall(:jl_method_table_disable, Cvoid, (Any,), m) end # type for reflecting and pretty-printing a subset of methods mutable struct MethodList <: AbstractArray{Method,1} ms::Array{Method,1} - mt::Core.MethodTable + tn::Core.TypeName # contains module.singletonname globalref for altering some aspects of printing end size(m::MethodList) = size(m.ms) @@ -1322,10 +1322,10 @@ function MethodList(mt::Core.MethodTable) visit(mt) do m push!(ms, m) end - return MethodList(ms, mt) + return MethodList(ms, Any.name) end -function matches_to_methods(ms::Array{Any,1}, mt::Core.MethodTable, mod) +function matches_to_methods(ms::Array{Any,1}, tn::Core.TypeName, mod) # Lack of specialization => a comprehension triggers too many invalidations via _collect, so collect the methods manually ms = Method[(ms[i]::Core.MethodMatch).method for i in 1:length(ms)] # Remove shadowed methods with identical type signatures @@ -1340,7 +1340,7 @@ function matches_to_methods(ms::Array{Any,1}, mt::Core.MethodTable, mod) mod === nothing || filter!(ms) do m return parentmodule(m) ∈ mod end - return MethodList(ms, mt) + return MethodList(ms, tn) end """ @@ -1362,7 +1362,7 @@ function methods(@nospecialize(f), @nospecialize(t), world = get_world_counter() world == typemax(UInt) && error("code reflection cannot be used from generated functions") ms = _methods(f, t, -1, world)::Vector{Any} - return matches_to_methods(ms, typeof(f).name.mt, mod) + return matches_to_methods(ms, typeof(f).name, mod) end methods(@nospecialize(f), @nospecialize(t), mod::Module) = methods(f, t, (mod,)) @@ -1373,7 +1373,7 @@ function methods_including_ambiguous(@nospecialize(f), @nospecialize(t)) min = RefValue{UInt}(typemin(UInt)) max = RefValue{UInt}(typemax(UInt)) ms = _methods_by_ftype(tt, nothing, -1, world, true, min, max, Ptr{Int32}(C_NULL))::Vector{Any} - return matches_to_methods(ms, typeof(f).name.mt, nothing) + return matches_to_methods(ms, typeof(f).name, nothing) end function methods(@nospecialize(f), @@ -1562,10 +1562,8 @@ end function get_nospecializeinfer_sig(method::Method, @nospecialize(atype), sparams::SimpleVector) isa(atype, DataType) || return method.sig - mt = ccall(:jl_method_get_table, Any, (Any,), method) - mt === nothing && return method.sig - return ccall(:jl_normalize_to_compilable_sig, Any, (Any, Any, Any, Any, Cint), - mt, atype, sparams, method, #=int return_if_compileable=#0) + return ccall(:jl_normalize_to_compilable_sig, Any, (Any, Any, Any, Cint), + atype, sparams, method, #=int return_if_compileable=#0) end is_nospecialized(method::Method) = method.nospecialize ≠ 0 diff --git a/base/show.jl b/base/show.jl index 3453c29956d59..7bc4dbed851eb 100644 --- a/base/show.jl +++ b/base/show.jl @@ -32,16 +32,16 @@ end function _isself(ft::DataType) ftname = ft.name - isdefined(ftname, :mt) || return false - name = ftname.mt.name - mod = parentmodule(ft) # NOTE: not necessarily the same as ft.name.mt.module - return invokelatest(isdefinedglobal, mod, name) && ft == typeof(invokelatest(getglobal, mod, name)) + name = ftname.singletonname + ftname.name === name && return false + mod = parentmodule(ft) + return invokelatest(isdefinedglobal, mod, name) && ft === typeof(invokelatest(getglobal, mod, name)) end function show(io::IO, ::MIME"text/plain", f::Function) get(io, :compact, false)::Bool && return show(io, f) ft = typeof(f) - name = ft.name.mt.name + name = ft.name.singletonname if isa(f, Core.IntrinsicFunction) print(io, f) id = Core.Intrinsics.bitcast(Int32, f) @@ -535,22 +535,20 @@ module UsesCoreAndBaseOnly end function show_function(io::IO, f::Function, compact::Bool, fallback::Function) - ft = typeof(f) - mt = ft.name.mt - if mt === Symbol.name.mt - # uses shared method table + fname = typeof(f).name + if fname.name === fname.singletonname fallback(io, f) elseif compact - print(io, mt.name) - elseif isdefined(mt, :module) && isdefinedglobal(mt.module, mt.name) && - getglobal(mt.module, mt.name) === f + print(io, fname.singletonname) + elseif isdefined(fname, :module) && isdefinedglobal(fname.module, fname.singletonname) && isconst(fname.module, fname.singletonname) && + getglobal(fname.module, fname.singletonname) === f # this used to call the removed internal function `is_exported_from_stdlib`, which effectively # just checked for exports from Core and Base. mod = get(io, :module, UsesCoreAndBaseOnly) - if !(isvisible(mt.name, mt.module, mod) || mt.module === mod) - print(io, mt.module, ".") + if !(isvisible(fname.singletonname, fname.module, mod) || fname.module === mod) + print(io, fname.module, ".") end - show_sym(io, mt.name) + show_sym(io, fname.singletonname) else fallback(io, f) end @@ -958,7 +956,7 @@ function show(io::IO, ::MIME"text/plain", @nospecialize(x::Type)) # give a helpful hint for function types if x isa DataType && x !== UnionAll && !(get(io, :compact, false)::Bool) tn = x.name::Core.TypeName - globname = isdefined(tn, :mt) ? tn.mt.name : nothing + globname = tn.singletonname if is_global_function(tn, globname) print(io, " (singleton type of function ") show_sym(io, globname) @@ -1041,11 +1039,11 @@ function isvisible(sym::Symbol, parent::Module, from::Module) end function is_global_function(tn::Core.TypeName, globname::Union{Symbol,Nothing}) - if globname !== nothing + if globname !== nothing && isconcretetype(tn.wrapper) && tn !== DataType.name # ignore that typeof(DataType)===DataType, since it is valid but not useful globname_str = string(globname::Symbol) - if ('#' ∉ globname_str && '@' ∉ globname_str && isdefined(tn, :module) && - isdefinedglobal(tn.module, globname) && - isconcretetype(tn.wrapper) && isa(getglobal(tn.module, globname), tn.wrapper)) + if '#' ∉ globname_str && '@' ∉ globname_str && isdefined(tn, :module) && + isdefinedglobal(tn.module, globname) && isconst(tn.module, globname) && + isa(getglobal(tn.module, globname), tn.wrapper) return true end end @@ -1076,7 +1074,7 @@ function show_type_name(io::IO, tn::Core.TypeName) # intercept this case and print `UnionAll` instead. return print(io, "UnionAll") end - globname = isdefined(tn, :mt) ? tn.mt.name : nothing + globname = tn.singletonname globfunc = is_global_function(tn, globname) sym = (globfunc ? globname : tn.name)::Symbol globfunc && print(io, "typeof(") @@ -2553,10 +2551,10 @@ function show_signature_function(io::IO, @nospecialize(ft), demangle=false, farg uw = unwrap_unionall(ft) if ft <: Function && isa(uw, DataType) && isempty(uw.parameters) && _isself(uw) uwmod = parentmodule(uw) - if qualified && !isexported(uwmod, uw.name.mt.name) && uwmod !== Main + if qualified && !isexported(uwmod, uw.name.singletonname) && uwmod !== Main print_within_stacktrace(io, uwmod, '.', bold=true) end - s = sprint(show_sym, (demangle ? demangle_function_name : identity)(uw.name.mt.name), context=io) + s = sprint(show_sym, (demangle ? demangle_function_name : identity)(uw.name.singletonname), context=io) print_within_stacktrace(io, s, bold=true) elseif isType(ft) && (f = ft.parameters[1]; !isa(f, TypeVar)) uwf = unwrap_unionall(f) diff --git a/base/strings/io.jl b/base/strings/io.jl index b27a6049f0b0e..9db196161997a 100644 --- a/base/strings/io.jl +++ b/base/strings/io.jl @@ -51,7 +51,7 @@ function print(io::IO, xs...) return nothing end -setfield!(typeof(print).name.mt, :max_args, 10, :monotonic) +setfield!(typeof(print).name, :max_args, Int32(10), :monotonic) """ println([io::IO], xs...) @@ -76,7 +76,7 @@ julia> String(take!(io)) """ println(io::IO, xs...) = print(io, xs..., "\n") -setfield!(typeof(println).name.mt, :max_args, 10, :monotonic) +setfield!(typeof(println).name, :max_args, Int32(10), :monotonic) ## conversion of general objects to strings ## """ @@ -152,7 +152,7 @@ function print_to_string(xs...) end String(_unsafe_take!(s)) end -setfield!(typeof(print_to_string).name.mt, :max_args, 10, :monotonic) +setfield!(typeof(print_to_string).name, :max_args, Int32(10), :monotonic) function string_with_env(env, xs...) if isempty(xs) diff --git a/base/summarysize.jl b/base/summarysize.jl index 62b0ad0849778..55fc72efad314 100644 --- a/base/summarysize.jl +++ b/base/summarysize.jl @@ -139,7 +139,7 @@ end function (ss::SummarySize)(obj::Core.TypeName) key = pointer_from_objref(obj) haskey(ss.seen, key) ? (return 0) : (ss.seen[key] = true) - return Core.sizeof(obj) + (isdefined(obj, :mt) ? ss(obj.mt) : 0) + return Core.sizeof(obj) end function (ss::SummarySize)(obj::GenericMemory) diff --git a/base/sysimg.jl b/base/sysimg.jl index 4a99f7a9f337e..7e205ca955409 100644 --- a/base/sysimg.jl +++ b/base/sysimg.jl @@ -15,8 +15,8 @@ ccall(:jl_init_restored_module, Cvoid, (Any,), Base) include([mapexpr::Function,] path::AbstractString) Evaluate the contents of the input source file in the global scope of the containing module. -Every module (except those defined with `baremodule`) has its own -definition of `include`, which evaluates the file in that module. +Every `Module` (except those defined with `baremodule`) has a private 1-argument definition +of `include`, which evaluates the file in that module, for use inside that module. Returns the result of the last evaluated expression of the input file. During including, a task-local include path is set to the directory containing the file. Nested calls to `include` will search relative to that path. This function is typically used to load source @@ -40,15 +40,18 @@ Use [`Base.include`](@ref) to evaluate a file into another module. !!! compat "Julia 1.5" Julia 1.5 is required for passing the `mapexpr` argument. """ -const include = Base.IncludeInto(Main) +Base.IncludeInto """ eval(expr) Evaluate an expression in the global scope of the containing module. -Every `Module` (except those defined with `baremodule`) has its own 1-argument -definition of `eval`, which evaluates expressions in that module. +Every `Module` (except those defined with `baremodule`) has a private 1-argument definition +of `eval`, which evaluates expressions in that module, for use inside that module. """ +Core.EvalInto + +const include = Base.IncludeInto(Main) const eval = Core.EvalInto(Main) # Ensure this file is also tracked diff --git a/doc/src/devdocs/functions.md b/doc/src/devdocs/functions.md index 777afaa56348d..cfaf40b96a595 100644 --- a/doc/src/devdocs/functions.md +++ b/doc/src/devdocs/functions.md @@ -1,5 +1,6 @@ # Julia Functions + This document will explain how functions, method definitions, and method tables work. ## Method Tables @@ -15,7 +16,7 @@ has a `TypeName`. ## [Function calls](@id Function-calls) -Given the call `f(x, y)`, the following steps are performed: first, the method table to use is +Given the call `f(x, y)`, the following steps are performed: first, the method cache to use is accessed as `typeof(f).name.mt`. Second, an argument tuple type is formed, `Tuple{typeof(f), typeof(x), typeof(y)}`. Note that the type of the function itself is the first element. This is because the type might have parameters, and so needs to take part in dispatch. This tuple type is looked up in the method @@ -187,7 +188,7 @@ is absent. Finally there is the kwsorter definition: ``` -function (::Core.kwftype(typeof(circle)))(kws, circle, center, radius) +function (::Core.kwcall)(kws, circle, center, radius) if haskey(kws, :color) color = kws.color else @@ -205,30 +206,6 @@ function (::Core.kwftype(typeof(circle)))(kws, circle, center, radius) end ``` -The function `Core.kwftype(t)` creates the field `t.name.mt.kwsorter` (if it hasn't been created -yet), and returns the type of that function. - -This design has the feature that call sites that don't use keyword arguments require no special -handling; everything works as if they were not part of the language at all. Call sites that do -use keyword arguments are dispatched directly to the called function's kwsorter. For example the -call: - -```julia -circle((0, 0), 1.0, color = red; other...) -``` - -is lowered to: - -```julia -kwcall(merge((color = red,), other), circle, (0, 0), 1.0) -``` - -`kwcall` (also in`Core`) denotes a kwcall signature and dispatch. -The keyword splatting operation (written as `other...`) calls the named tuple `merge` function. -This function further unpacks each *element* of `other`, expecting each one to contain two values -(a symbol and a value). -Naturally, a more efficient implementation is available if all splatted arguments are named tuples. -Notice that the original `circle` function is passed through, to handle closures. ## [Compiler efficiency issues](@id compiler-efficiency-issues) diff --git a/doc/src/devdocs/types.md b/doc/src/devdocs/types.md index a09df61e4881d..b63f1c315f457 100644 --- a/doc/src/devdocs/types.md +++ b/doc/src/devdocs/types.md @@ -199,7 +199,6 @@ TypeName name: Symbol Array defs: Nothing nothing cache: Nothing nothing - max_args: Int64 0 module: Module Core : Int64 0 : Int64 0 diff --git a/src/builtins.c b/src/builtins.c index e3a0380182e15..641f54a5fde28 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -2437,14 +2437,11 @@ void jl_init_intrinsic_functions(void) JL_GC_DISABLED jl_module_t *inm = jl_new_module_(jl_symbol("Intrinsics"), jl_core_module, 0, 1); jl_set_initial_const(jl_core_module, jl_symbol("Intrinsics"), (jl_value_t*)inm, 0); jl_mk_builtin_func(jl_intrinsic_type, jl_symbol("IntrinsicFunction"), jl_f_intrinsic_call); - jl_mk_builtin_func( - (jl_datatype_t*)jl_unwrap_unionall((jl_value_t*)jl_opaque_closure_type), - jl_symbol("OpaqueClosure"), jl_f_opaque_closure_call); + jl_datatype_t *oc = (jl_datatype_t*)jl_unwrap_unionall((jl_value_t*)jl_opaque_closure_type); // Save a reference to the just created OpaqueClosure method, so we can provide special // codegen for it later. - jl_opaque_closure_method = (jl_method_t*)jl_methtable_lookup(jl_opaque_closure_typename->mt, - (jl_value_t*)jl_anytuple_type, 1); + jl_opaque_closure_method = jl_mk_builtin_func(oc, jl_symbol("OpaqueClosure"), jl_f_opaque_closure_call); // TODO: awkwardly not actually declared a Builtin, even though it relies on being handled by the special cases for Builtin everywhere else #define ADD_I(name, nargs) add_intrinsic(inm, #name, name); #define ADD_HIDDEN(name, nargs) @@ -2494,6 +2491,8 @@ void jl_init_primitives(void) JL_GC_DISABLED add_builtin("Module", (jl_value_t*)jl_module_type); add_builtin("MethodTable", (jl_value_t*)jl_methtable_type); + add_builtin("GlobalMethods", (jl_value_t*)jl_method_table); + add_builtin("MethodCache", (jl_value_t*)jl_methcache_type); add_builtin("Method", (jl_value_t*)jl_method_type); add_builtin("CodeInstance", (jl_value_t*)jl_code_instance_type); add_builtin("TypeMapEntry", (jl_value_t*)jl_typemap_entry_type); @@ -2558,6 +2557,26 @@ void jl_init_primitives(void) JL_GC_DISABLED add_builtin("AbstractString", (jl_value_t*)jl_abstractstring_type); add_builtin("String", (jl_value_t*)jl_string_type); + + // ensure that primitive types are fully allocated (since jl_init_types is incomplete) + assert(jl_atomic_load_relaxed(&jl_world_counter) == 1); + jl_module_t *core = jl_core_module; + jl_svec_t *bindings = jl_atomic_load_relaxed(&core->bindings); + jl_value_t **table = jl_svec_data(bindings); + for (size_t i = 0; i < jl_svec_len(bindings); i++) { + if (table[i] != jl_nothing) { + jl_binding_t *b = (jl_binding_t*)table[i]; + jl_value_t *v = jl_get_binding_value_in_world(b, 1); + if (v) { + if (jl_is_unionall(v)) + v = jl_unwrap_unionall(v); + if (jl_is_datatype(v)) { + jl_datatype_t *tt = (jl_datatype_t*)v; + tt->name->module = core; + } + } + } + } } #ifdef __cplusplus diff --git a/src/clangsa/GCChecker.cpp b/src/clangsa/GCChecker.cpp index af07ca2227839..09a034a9549d8 100644 --- a/src/clangsa/GCChecker.cpp +++ b/src/clangsa/GCChecker.cpp @@ -836,6 +836,7 @@ bool GCChecker::isGCTrackedType(QualType QT) { Name.ends_with_insensitive("jl_typemap_t") || Name.ends_with_insensitive("jl_unionall_t") || Name.ends_with_insensitive("jl_methtable_t") || + Name.ends_with_insensitive("jl_methcache_t") || Name.ends_with_insensitive("jl_cgval_t") || Name.ends_with_insensitive("jl_codectx_t") || Name.ends_with_insensitive("jl_ast_context_t") || diff --git a/src/codegen.cpp b/src/codegen.cpp index 4b857f95dc3bf..aa0a56b28d1e8 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -7476,16 +7476,11 @@ static const char *derive_sigt_name(jl_value_t *jargty) jl_datatype_t *dt = (jl_datatype_t*)jl_argument_datatype(jargty); if ((jl_value_t*)dt == jl_nothing) return NULL; - jl_sym_t *name = dt->name->name; - // if we have a kwcall, use that as the name anyways - jl_methtable_t *mt = dt->name->mt; - if (mt == jl_type_type_mt || mt == jl_nonfunction_mt || mt == NULL) { - // our value for `name` from MethodTable is not good, try to come up with something better - if (jl_is_type_type((jl_value_t*)dt)) { - dt = (jl_datatype_t*)jl_argument_datatype(jl_tparam0(dt)); - if ((jl_value_t*)dt != jl_nothing) { - name = dt->name->name; - } + jl_sym_t *name = dt->name->singletonname; + if (jl_is_type_type((jl_value_t*)dt)) { + dt = (jl_datatype_t*)jl_argument_datatype(jl_tparam0(dt)); + if ((jl_value_t*)dt != jl_nothing) { + name = dt->name->singletonname; } } return jl_symbol_name(name); @@ -7662,7 +7657,7 @@ const char *jl_generate_ccallable(Module *llvmmod, jl_value_t *nameval, jl_value assert(jl_is_datatype(ft)); jl_value_t *ff = ft->instance; assert(ff); - const char *name = !jl_is_string(nameval) ? jl_symbol_name(ft->name->mt->name) : jl_string_data(nameval); + const char *name = !jl_is_string(nameval) ? jl_symbol_name(ft->name->singletonname) : jl_string_data(nameval); jl_value_t *crt = declrt; if (jl_is_abstract_ref_type(declrt)) { declrt = jl_tparam0(declrt); diff --git a/src/datatype.c b/src/datatype.c index 677f0d0bff65b..a886ba9845dbf 100644 --- a/src/datatype.c +++ b/src/datatype.c @@ -39,22 +39,30 @@ static jl_sym_t *jl_demangle_typename(jl_sym_t *s) JL_NOTSAFEPOINT return _jl_symbol(&n[1], len); } +JL_DLLEXPORT jl_methcache_t *jl_new_method_cache(void) +{ + jl_task_t *ct = jl_current_task; + jl_methcache_t *mc = + (jl_methcache_t*)jl_gc_alloc(ct->ptls, sizeof(jl_methcache_t), + jl_methcache_type); + jl_atomic_store_relaxed(&mc->leafcache, (jl_genericmemory_t*)jl_an_empty_memory_any); + jl_atomic_store_relaxed(&mc->cache, jl_nothing); + JL_MUTEX_INIT(&mc->writelock, "methodtable->writelock"); + return mc; +} + JL_DLLEXPORT jl_methtable_t *jl_new_method_table(jl_sym_t *name, jl_module_t *module) { + jl_methcache_t *mc = jl_new_method_cache(); + JL_GC_PUSH1(&mc); jl_task_t *ct = jl_current_task; jl_methtable_t *mt = - (jl_methtable_t*)jl_gc_alloc(ct->ptls, sizeof(jl_methtable_t), - jl_methtable_type); - mt->name = jl_demangle_typename(name); - mt->module = module; + (jl_methtable_t*)jl_gc_alloc(ct->ptls, sizeof(jl_methtable_t), jl_methtable_type); jl_atomic_store_relaxed(&mt->defs, jl_nothing); - jl_atomic_store_relaxed(&mt->leafcache, (jl_genericmemory_t*)jl_an_empty_memory_any); - jl_atomic_store_relaxed(&mt->cache, jl_nothing); - jl_atomic_store_relaxed(&mt->max_args, 0); - mt->backedges = NULL; - JL_MUTEX_INIT(&mt->writelock, "methodtable->writelock"); - mt->offs = 0; - mt->frozen = 0; + mt->cache = mc; + mt->name = name; + mt->module = module; + JL_GC_POP(); return mt; } @@ -67,21 +75,23 @@ JL_DLLEXPORT jl_typename_t *jl_new_typename_in(jl_sym_t *name, jl_module_t *modu tn->name = name; tn->module = module; tn->wrapper = NULL; + tn->singletonname = jl_demangle_typename(name); jl_atomic_store_relaxed(&tn->Typeofwrapper, NULL); jl_atomic_store_relaxed(&tn->cache, jl_emptysvec); jl_atomic_store_relaxed(&tn->linearcache, jl_emptysvec); tn->names = NULL; tn->hash = bitmix(bitmix(module ? module->build_id.lo : 0, name->hash), 0xa1ada1da); - tn->_reserved = 0; + tn->_unused = 0; tn->abstract = abstract; tn->mutabl = mutabl; tn->mayinlinealloc = 0; - tn->mt = NULL; tn->partial = NULL; tn->atomicfields = NULL; tn->constfields = NULL; - jl_atomic_store_relaxed(&tn->cache_entry_count, 0); + tn->backedges = NULL; tn->max_methods = 0; + jl_atomic_store_relaxed(&tn->max_args, 0); + jl_atomic_store_relaxed(&tn->cache_entry_count, 0); tn->constprop_heustic = 0; return tn; } @@ -861,18 +871,6 @@ JL_DLLEXPORT jl_datatype_t *jl_new_datatype( } else { tn = jl_new_typename_in((jl_sym_t*)name, module, abstract, mutabl); - if (super == jl_function_type || super == jl_builtin_type || is_anonfn_typename(jl_symbol_name(name))) { - // Callable objects (including compiler-generated closures) get independent method tables - // as an optimization - tn->mt = jl_new_method_table(name, module); - jl_gc_wb(tn, tn->mt); - if (jl_svec_len(parameters) == 0 && !abstract) - tn->mt->offs = 1; - } - else { - // Everything else, gets to use the unified table - tn->mt = jl_nonfunction_mt; - } } t->name = tn; jl_gc_wb(t, t->name); diff --git a/src/gc-stock.c b/src/gc-stock.c index 66a1724ecf4ce..55f31b26679ff 100644 --- a/src/gc-stock.c +++ b/src/gc-stock.c @@ -2845,6 +2845,8 @@ static void gc_mark_roots(jl_gc_markqueue_t *mq) gc_try_claim_and_push(mq, jl_main_module, NULL); gc_heap_snapshot_record_gc_roots((jl_value_t*)jl_main_module, "main_module"); // invisible builtin values + gc_try_claim_and_push(mq, jl_method_table, NULL); + gc_heap_snapshot_record_gc_roots((jl_value_t*)jl_method_table, "global_method_table"); gc_try_claim_and_push(mq, jl_an_empty_vec_any, NULL); gc_heap_snapshot_record_gc_roots((jl_value_t*)jl_an_empty_vec_any, "an_empty_vec_any"); gc_try_claim_and_push(mq, jl_module_init_order, NULL); diff --git a/src/gf.c b/src/gf.c index cadea9491a61c..07143d8902550 100644 --- a/src/gf.c +++ b/src/gf.c @@ -27,6 +27,8 @@ extern "C" { _Atomic(int) allow_new_worlds = 1; JL_DLLEXPORT _Atomic(size_t) jl_world_counter = 1; // uses atomic acquire/release jl_mutex_t world_counter_lock; +jl_methtable_t *jl_method_table; + JL_DLLEXPORT size_t jl_get_world_counter(void) JL_NOTSAFEPOINT { jl_task_t *ct = jl_current_task; @@ -41,31 +43,41 @@ JL_DLLEXPORT size_t jl_get_tls_world_age(void) JL_NOTSAFEPOINT } // Compute the maximum number of times to unroll Varargs{T}, based on -// m->max_varargs (if specified) or a heuristic based on the maximum -// number of non-varargs arguments in the provided method table. +// m->max_varargs (if specified) or a heuristic based on the maximum number of +// non-varargs arguments for the function type of the method signature. // // If provided, `may_increase` is set to 1 if the returned value is // heuristic-based and has a chance of increasing in the future. static size_t get_max_varargs( jl_method_t *m, - jl_methtable_t *kwmt, - jl_methtable_t *mt, uint8_t *may_increase) JL_NOTSAFEPOINT { size_t max_varargs = 1; if (may_increase != NULL) *may_increase = 0; - if (m->max_varargs != UINT8_MAX) + if (m->max_varargs != UINT8_MAX) { max_varargs = m->max_varargs; - else if (kwmt != NULL && kwmt != jl_type_type_mt && kwmt != jl_nonfunction_mt && kwmt != jl_kwcall_mt) { - if (may_increase != NULL) - *may_increase = 1; // `max_args` can increase as new methods are inserted - - max_varargs = jl_atomic_load_relaxed(&kwmt->max_args) + 2; - if (mt == jl_kwcall_mt) - max_varargs += 2; - max_varargs -= m->nargs; + } + else { + jl_datatype_t *dt1 = jl_nth_argument_datatype(m->sig, 1); + jl_datatype_t *dt; + if (jl_kwcall_type && dt1 == jl_kwcall_type) + dt = jl_nth_argument_datatype(m->sig, 3); + else + dt = dt1; + if (dt != NULL && !jl_is_type_type((jl_value_t*)dt) && dt != jl_kwcall_type) { + if (may_increase != NULL) + *may_increase = 1; // `max_args` can increase as new methods are inserted + + max_varargs = jl_atomic_load_relaxed(&dt->name->max_args) + 2; + if (jl_kwcall_type && dt1 == jl_kwcall_type) + max_varargs += 2; + if (max_varargs > m->nargs) + max_varargs -= m->nargs; + else + max_varargs = 0; + } } return max_varargs; } @@ -104,9 +116,9 @@ void jl_call_tracer(tracer_cb callback, jl_value_t *tracee) /// ----- Definitions for various internal TypeMaps ----- /// -static int8_t jl_cachearg_offset(jl_methtable_t *mt) +static int8_t jl_cachearg_offset(void) { - return mt->offs; + return 0; } /// ----- Insertion logic for special entries ----- /// @@ -274,13 +286,13 @@ JL_DLLEXPORT jl_value_t *jl_specializations_lookup(jl_method_t *m, jl_value_t *t return mi; } -JL_DLLEXPORT jl_value_t *jl_methtable_lookup(jl_methtable_t *mt, jl_value_t *type, size_t world) +JL_DLLEXPORT jl_value_t *jl_methtable_lookup(jl_value_t *type, size_t world) { // TODO: this is sort of an odd lookup strategy (and the only user of // jl_typemap_assoc_by_type with subtype=0), while normally jl_gf_invoke_lookup would be // expected to be used instead struct jl_typemap_assoc search = {type, world, NULL}; - jl_typemap_entry_t *sf = jl_typemap_assoc_by_type(jl_atomic_load_relaxed(&mt->defs), &search, jl_cachearg_offset(mt), /*subtype*/0); + jl_typemap_entry_t *sf = jl_typemap_assoc_by_type(jl_atomic_load_relaxed(&jl_method_table->defs), &search, 0, /*subtype*/0); if (!sf) return jl_nothing; return sf->func.value; @@ -288,7 +300,7 @@ JL_DLLEXPORT jl_value_t *jl_methtable_lookup(jl_methtable_t *mt, jl_value_t *typ // ----- MethodInstance specialization instantiation ----- // -void jl_mk_builtin_func(jl_datatype_t *dt, jl_sym_t *sname, jl_fptr_args_t fptr) JL_GC_DISABLED +jl_method_t *jl_mk_builtin_func(jl_datatype_t *dt, jl_sym_t *sname, jl_fptr_args_t fptr) JL_GC_DISABLED { jl_method_t *m = jl_new_method_uninit(jl_core_module); m->name = sname; @@ -302,31 +314,36 @@ void jl_mk_builtin_func(jl_datatype_t *dt, jl_sym_t *sname, jl_fptr_args_t fptr) m->nospecialize = 0; m->nospecialize = ~m->nospecialize; - jl_methtable_t *mt = dt->name->mt; jl_typemap_entry_t *newentry = NULL; - JL_GC_PUSH2(&m, &newentry); + jl_datatype_t *tuptyp = NULL; + JL_GC_PUSH3(&m, &newentry, &tuptyp); - newentry = jl_typemap_alloc(jl_anytuple_type, NULL, jl_emptysvec, - (jl_value_t*)m, 1, ~(size_t)0); - jl_typemap_insert(&mt->defs, (jl_value_t*)mt, newentry, jl_cachearg_offset(mt)); + jl_value_t *params[2]; + params[0] = dt->name->wrapper; + params[1] = jl_tparam0(jl_anytuple_type); + tuptyp = (jl_datatype_t*)jl_apply_tuple_type_v(params, 2); - jl_method_instance_t *mi = jl_get_specialized(m, (jl_value_t*)jl_anytuple_type, jl_emptysvec); + jl_method_instance_t *mi = jl_get_specialized(m, (jl_value_t*)tuptyp, jl_emptysvec); jl_atomic_store_relaxed(&m->unspecialized, mi); jl_gc_wb(m, mi); jl_code_instance_t *codeinst = jl_new_codeinst(mi, jl_nothing, (jl_value_t*)jl_any_type, (jl_value_t*)jl_any_type, jl_nothing, jl_nothing, 0, 1, ~(size_t)0, 0, jl_nothing, NULL, NULL); - jl_mi_cache_insert(mi, codeinst); jl_atomic_store_relaxed(&codeinst->specptr.fptr1, fptr); jl_atomic_store_relaxed(&codeinst->invoke, jl_fptr_args); + jl_mi_cache_insert(mi, codeinst); + + newentry = jl_typemap_alloc(tuptyp, NULL, jl_emptysvec, + (jl_value_t*)m, 1, ~(size_t)0); + jl_typemap_insert(&jl_method_table->defs, (jl_value_t*)jl_method_table, newentry, 0); - newentry = jl_typemap_alloc(jl_anytuple_type, NULL, jl_emptysvec, + newentry = jl_typemap_alloc(tuptyp, NULL, jl_emptysvec, (jl_value_t*)mi, 1, ~(size_t)0); - jl_typemap_insert(&mt->cache, (jl_value_t*)mt, newentry, 0); + jl_typemap_insert(&jl_method_table->cache->cache, (jl_value_t*)jl_method_table->cache, newentry, 0); - mt->frozen = 1; JL_GC_POP(); + return m; } // only relevant for bootstrapping. otherwise fairly broken. @@ -537,7 +554,7 @@ JL_DLLEXPORT jl_code_instance_t *jl_get_method_inferred( { jl_value_t *owner = jl_nothing; // TODO: owner should be arg jl_code_instance_t *codeinst = jl_atomic_load_relaxed(&mi->cache); - while (codeinst) { + for (; codeinst; codeinst = jl_atomic_load_relaxed(&codeinst->next)) { if (jl_atomic_load_relaxed(&codeinst->min_world) == min_world && jl_atomic_load_relaxed(&codeinst->max_world) == max_world && jl_egal(codeinst->owner, owner) && @@ -555,7 +572,6 @@ JL_DLLEXPORT jl_code_instance_t *jl_get_method_inferred( if (e && jl_egal((jl_value_t*)e, (jl_value_t*)edges)) return codeinst; } - codeinst = jl_atomic_load_relaxed(&codeinst->next); } codeinst = jl_new_codeinst( mi, owner, rettype, (jl_value_t*)jl_any_type, NULL, NULL, @@ -760,9 +776,9 @@ JL_DLLEXPORT int jl_mi_try_insert(jl_method_instance_t *mi JL_ROOTING_ARGUMENT, return ret; } -int foreach_mtable_in_module( +static int foreach_typename_in_module( jl_module_t *m, - int (*visit)(jl_methtable_t *mt, void *env), + int (*visit)(jl_typename_t *tn, void *env), void *env) { jl_svec_t *table = jl_atomic_load_relaxed(&m->bindings); @@ -778,15 +794,50 @@ int foreach_mtable_in_module( jl_typename_t *tn = ((jl_datatype_t*)uw)->name; if (tn->module == m && tn->name == name && tn->wrapper == v) { // this is the original/primary binding for the type (name/wrapper) - jl_methtable_t *mt = tn->mt; - if (mt != NULL && (jl_value_t*)mt != jl_nothing && mt != jl_type_type_mt && mt != jl_nonfunction_mt) { - assert(mt->module == m); - if (!visit(mt, env)) - return 0; - } + if (!visit(((jl_datatype_t*)uw)->name, env)) + return 0; } } else if (jl_is_module(v)) { + jl_module_t *child = (jl_module_t*)v; + if (child != m && child->parent == m && child->name == name) { + // this is the original/primary binding for the submodule + if (!foreach_typename_in_module(child, visit, env)) + return 0; + } + } + } + table = jl_atomic_load_relaxed(&m->bindings); + } + return 1; +} + +static int jl_foreach_reachable_typename(int (*visit)(jl_typename_t *tn, void *env), jl_array_t *mod_array, void *env) +{ + for (size_t i = 0; i < jl_array_nrows(mod_array); i++) { + jl_module_t *m = (jl_module_t*)jl_array_ptr_ref(mod_array, i); + assert(jl_is_module(m)); + if (m->parent == m) // some toplevel modules (really just Base) aren't actually + if (!foreach_typename_in_module(m, visit, env)) + return 0; + } + return 1; +} + +int foreach_mtable_in_module( + jl_module_t *m, + int (*visit)(jl_methtable_t *mt, void *env), + void *env) +{ + jl_svec_t *table = jl_atomic_load_relaxed(&m->bindings); + for (size_t i = 0; i < jl_svec_len(table); i++) { + jl_binding_t *b = (jl_binding_t*)jl_svecref(table, i); + if ((void*)b == jl_nothing) + break; + jl_sym_t *name = b->globalref->name; + jl_value_t *v = jl_get_latest_binding_value_if_const(b); + if (v) { + if (jl_is_module(v)) { jl_module_t *child = (jl_module_t*)v; if (child != m && child->parent == m && child->name == name) { // this is the original/primary binding for the submodule @@ -796,9 +847,7 @@ int foreach_mtable_in_module( } else if (jl_is_mtable(v)) { jl_methtable_t *mt = (jl_methtable_t*)v; - if (mt->module == m && mt->name == name) { - // this is probably an external method table here, so let's - // assume so as there is no way to precisely distinguish them + if (mt && mt != jl_method_table) { if (!visit(mt, env)) return 0; } @@ -809,37 +858,23 @@ int foreach_mtable_in_module( return 1; } -int jl_foreach_reachable_mtable(int (*visit)(jl_methtable_t *mt, void *env), void *env) + +int jl_foreach_reachable_mtable(int (*visit)(jl_methtable_t *mt, void *env), jl_array_t *mod_array, void *env) { - if (!visit(jl_type_type_mt, env)) + if (!visit(jl_method_table, env)) return 0; - if (!visit(jl_nonfunction_mt, env)) - return 0; - jl_array_t *mod_array = jl_get_loaded_modules(); if (mod_array) { - JL_GC_PUSH1(&mod_array); - int i; - for (i = 0; i < jl_array_nrows(mod_array); i++) { + for (size_t i = 0; i < jl_array_nrows(mod_array); i++) { jl_module_t *m = (jl_module_t*)jl_array_ptr_ref(mod_array, i); assert(jl_is_module(m)); if (m->parent == m) // some toplevel modules (really just Base) aren't actually - if (!foreach_mtable_in_module(m, visit, env)) { - JL_GC_POP(); + if (!foreach_mtable_in_module(m, visit, env)) return 0; - } } - JL_GC_POP(); - } - else { - if (!foreach_mtable_in_module(jl_main_module, visit, env)) - return 0; - if (!foreach_mtable_in_module(jl_core_module, visit, env)) - return 0; } return 1; } - jl_function_t *jl_typeinf_func JL_GLOBALLY_ROOTED = NULL; JL_DLLEXPORT size_t jl_typeinf_world = 1; @@ -923,7 +958,7 @@ static jl_value_t *inst_varargp_in_env(jl_value_t *decl, jl_svec_t *sparams) return vm; } -static jl_value_t *ml_matches(jl_methtable_t *mt, +static jl_value_t *ml_matches(jl_methtable_t *mt, jl_methcache_t *mc, jl_tupletype_t *type, int lim, int include_ambiguous, int intersections, size_t world, int cache_result, size_t *min_valid, size_t *max_valid, int *ambig); @@ -1130,9 +1165,10 @@ static void jl_compilation_sig( // and the types we find should be bigger. if (np >= nspec && jl_va_tuple_kind((jl_datatype_t*)decl) == JL_VARARG_UNBOUND) { if (!*newparams) *newparams = tt->parameters; - if (max_varargs > 0) { + if (max_varargs > 0 && nspec >= 2) { type_i = jl_svecref(*newparams, nspec - 2); - } else { + } + else { // If max varargs is zero, always specialize to (Any...) since // there is no preceding parameter to use for `type_i` type_i = jl_bottom_type; @@ -1207,15 +1243,11 @@ JL_DLLEXPORT int jl_isa_compileable_sig( if (definition->isva) { unsigned nspec_min = nargs + 1; // min number of arg values (including tail vararg) unsigned nspec_max = INT32_MAX; // max number of arg values (including tail vararg) - jl_methtable_t *mt = jl_method_table_for(decl); - jl_methtable_t *kwmt = mt == jl_kwcall_mt ? jl_kwmethod_table_for(decl) : mt; - if ((jl_value_t*)mt != jl_nothing) { - // try to refine estimate of min and max - uint8_t heuristic_used = 0; - nspec_max = nspec_min = nargs + get_max_varargs(definition, kwmt, mt, &heuristic_used); - if (heuristic_used) - nspec_max = INT32_MAX; // new methods may be added, increasing nspec_min later - } + // try to refine estimate of min and max + uint8_t heuristic_used = 0; + nspec_max = nspec_min = nargs + get_max_varargs(definition, &heuristic_used); + if (heuristic_used) + nspec_max = INT32_MAX; // new methods may be added, increasing nspec_min later int isunbound = (jl_va_tuple_kind((jl_datatype_t*)decl) == JL_VARARG_UNBOUND); if (jl_is_vararg(jl_tparam(type, np - 1))) { if (!isunbound || np < nspec_min || np > nspec_max) @@ -1404,18 +1436,18 @@ static inline jl_typemap_entry_t *lookup_leafcache(jl_genericmemory_t *leafcache return NULL; } jl_method_instance_t *cache_method( - jl_methtable_t *mt, _Atomic(jl_typemap_t*) *cache, jl_value_t *parent JL_PROPAGATES_ROOT, + jl_methtable_t *mt, jl_methcache_t *mc, _Atomic(jl_typemap_t*) *cache, jl_value_t *parent JL_PROPAGATES_ROOT, jl_tupletype_t *tt, // the original tupletype of the signature jl_method_t *definition, size_t world, size_t min_valid, size_t max_valid, jl_svec_t *sparams) { - // caller must hold the mt->writelock + // caller must hold the parent->writelock // short-circuit (now that we hold the lock) if this entry is already present - int8_t offs = mt ? jl_cachearg_offset(mt) : 1; + int8_t offs = mc ? jl_cachearg_offset() : 1; { // scope block - if (mt) { - jl_genericmemory_t *leafcache = jl_atomic_load_relaxed(&mt->leafcache); + if (mc) { + jl_genericmemory_t *leafcache = jl_atomic_load_relaxed(&mc->leafcache); jl_typemap_entry_t *entry = lookup_leafcache(leafcache, (jl_value_t*)tt, world); if (entry) return entry->func.linfo; @@ -1428,10 +1460,23 @@ jl_method_instance_t *cache_method( return entry->func.linfo; } + jl_method_instance_t *newmeth = NULL; + if (definition->sig == (jl_value_t*)jl_anytuple_type && definition != jl_opaque_closure_method && !definition->is_for_opaque_closure) { + newmeth = jl_atomic_load_relaxed(&definition->unspecialized); + if (newmeth != NULL) { // handle builtin methods de-specialization (for invoke, or if the global cache entry somehow gets lost) + jl_tupletype_t *cachett = (jl_tupletype_t*)newmeth->specTypes; + assert(cachett != jl_anytuple_type); + jl_typemap_entry_t *newentry = jl_typemap_alloc(cachett, NULL, jl_emptysvec, (jl_value_t*)newmeth, min_valid, max_valid); + JL_GC_PUSH1(&newentry); + jl_typemap_insert(cache, parent, newentry, offs); + JL_GC_POP(); + return newmeth; + } + } + jl_value_t *temp = NULL; jl_value_t *temp2 = NULL; jl_value_t *temp3 = NULL; - jl_method_instance_t *newmeth = NULL; jl_svec_t *newparams = NULL; JL_GC_PUSH5(&temp, &temp2, &temp3, &newmeth, &newparams); @@ -1439,8 +1484,7 @@ jl_method_instance_t *cache_method( // so that we can minimize the number of required cache entries. int cache_with_orig = 1; jl_tupletype_t *compilationsig = tt; - jl_methtable_t *kwmt = mt == jl_kwcall_mt ? jl_kwmethod_table_for(definition->sig) : mt; - intptr_t max_varargs = get_max_varargs(definition, kwmt, mt, NULL); + intptr_t max_varargs = get_max_varargs(definition, NULL); jl_compilation_sig(tt, sparams, definition, max_varargs, &newparams); if (newparams) { temp2 = jl_apply_tuple_type(newparams, 1); @@ -1476,7 +1520,7 @@ jl_method_instance_t *cache_method( // now examine what will happen if we chose to use this sig in the cache size_t min_valid2 = 1; size_t max_valid2 = ~(size_t)0; - temp = ml_matches(mt, compilationsig, MAX_UNSPECIALIZED_CONFLICTS, 1, 1, world, 0, &min_valid2, &max_valid2, NULL); + temp = ml_matches(mt, mc, compilationsig, MAX_UNSPECIALIZED_CONFLICTS, 1, 1, world, 0, &min_valid2, &max_valid2, NULL); int guards = 0; if (temp == jl_nothing) { cache_with_orig = 1; @@ -1524,7 +1568,7 @@ jl_method_instance_t *cache_method( guards++; // alternative approach: insert sentinel entry //jl_typemap_insert(cache, parent, (jl_tupletype_t*)matc->spec_types, - // NULL, jl_emptysvec, /*guard*/NULL, jl_cachearg_offset(mt), other->min_world, other->max_world); + // NULL, jl_emptysvec, /*guard*/NULL, jl_cachearg_offset(), other->min_world, other->max_world); } } assert(guards == jl_svec_len(guardsigs)); @@ -1584,7 +1628,7 @@ jl_method_instance_t *cache_method( jl_typemap_entry_t *newentry = jl_typemap_alloc(cachett, simplett, guardsigs, (jl_value_t*)newmeth, min_valid, max_valid); temp = (jl_value_t*)newentry; - if (mt && cachett == tt && jl_svec_len(guardsigs) == 0 && tt->hash && !tt->hasfreetypevars) { + if (mc && cachett == tt && jl_svec_len(guardsigs) == 0 && tt->hash && !tt->hasfreetypevars) { // we check `tt->hash` exists, since otherwise the NamedTuple // constructor and `structdiff` method pollutes this lookup with a lot // of garbage in the linear table search @@ -1597,14 +1641,14 @@ jl_method_instance_t *cache_method( jl_cache_type_(tt); JL_UNLOCK(&typecache_lock); // Might GC } - jl_genericmemory_t *oldcache = jl_atomic_load_relaxed(&mt->leafcache); + jl_genericmemory_t *oldcache = jl_atomic_load_relaxed(&mc->leafcache); jl_typemap_entry_t *old = (jl_typemap_entry_t*)jl_eqtable_get(oldcache, (jl_value_t*)tt, jl_nothing); jl_atomic_store_relaxed(&newentry->next, old); jl_gc_wb(newentry, old); - jl_genericmemory_t *newcache = jl_eqtable_put(jl_atomic_load_relaxed(&mt->leafcache), (jl_value_t*)tt, (jl_value_t*)newentry, NULL); + jl_genericmemory_t *newcache = jl_eqtable_put(jl_atomic_load_relaxed(&mc->leafcache), (jl_value_t*)tt, (jl_value_t*)newentry, NULL); if (newcache != oldcache) { - jl_atomic_store_release(&mt->leafcache, newcache); - jl_gc_wb(mt, newcache); + jl_atomic_store_release(&mc->leafcache, newcache); + jl_gc_wb(mc, newcache); } } else { @@ -1624,50 +1668,52 @@ jl_method_instance_t *cache_method( return newmeth; } -static jl_method_match_t *_gf_invoke_lookup(jl_value_t *types JL_PROPAGATES_ROOT, jl_value_t *mt, size_t world, size_t *min_valid, size_t *max_valid); +static jl_method_match_t *_gf_invoke_lookup(jl_value_t *types JL_PROPAGATES_ROOT, jl_methtable_t *mt, size_t world, size_t *min_valid, size_t *max_valid); + +JL_DLLEXPORT jl_typemap_entry_t *jl_mt_find_cache_entry(jl_methcache_t *mc JL_PROPAGATES_ROOT, jl_datatype_t *tt JL_MAYBE_UNROOTED JL_ROOTS_TEMPORARILY, size_t world) +{ // exported only for debugging purposes, not for casual use + if (tt->isdispatchtuple) { + jl_genericmemory_t *leafcache = jl_atomic_load_relaxed(&mc->leafcache); + jl_typemap_entry_t *entry = lookup_leafcache(leafcache, (jl_value_t*)tt, world); + if (entry) + return entry; + } + JL_GC_PUSH1(&tt); + struct jl_typemap_assoc search = {(jl_value_t*)tt, world, NULL}; + jl_typemap_entry_t *entry = jl_typemap_assoc_by_type(jl_atomic_load_relaxed(&mc->cache), &search, jl_cachearg_offset(), /*subtype*/1); + JL_GC_POP(); + return entry; +} -static jl_method_instance_t *jl_mt_assoc_by_type(jl_methtable_t *mt JL_PROPAGATES_ROOT, jl_datatype_t *tt JL_MAYBE_UNROOTED, size_t world) +static jl_method_instance_t *jl_mt_assoc_by_type(jl_methcache_t *mc JL_PROPAGATES_ROOT, jl_datatype_t *tt JL_MAYBE_UNROOTED, size_t world) { - jl_genericmemory_t *leafcache = jl_atomic_load_relaxed(&mt->leafcache); - jl_typemap_entry_t *entry = lookup_leafcache(leafcache, (jl_value_t*)tt, world); + jl_typemap_entry_t *entry = jl_mt_find_cache_entry(mc, tt, world); if (entry) return entry->func.linfo; + assert(tt->isdispatchtuple || tt->hasfreetypevars); JL_TIMING(METHOD_LOOKUP_SLOW, METHOD_LOOKUP_SLOW); jl_method_match_t *matc = NULL; JL_GC_PUSH2(&tt, &matc); - JL_LOCK(&mt->writelock); - assert(tt->isdispatchtuple || tt->hasfreetypevars); + JL_LOCK(&mc->writelock); jl_method_instance_t *mi = NULL; - if (tt->isdispatchtuple) { - jl_genericmemory_t *leafcache = jl_atomic_load_relaxed(&mt->leafcache); - jl_typemap_entry_t *entry = lookup_leafcache(leafcache, (jl_value_t*)tt, world); - if (entry) - mi = entry->func.linfo; - } - - if (!mi) { - struct jl_typemap_assoc search = {(jl_value_t*)tt, world, NULL}; - jl_typemap_entry_t *entry = jl_typemap_assoc_by_type(jl_atomic_load_relaxed(&mt->cache), &search, jl_cachearg_offset(mt), /*subtype*/1); - if (entry) - mi = entry->func.linfo; - } - + entry = jl_mt_find_cache_entry(mc, tt, world); + if (entry) + mi = entry->func.linfo; if (!mi) { size_t min_valid = 0; size_t max_valid = ~(size_t)0; - matc = _gf_invoke_lookup((jl_value_t*)tt, jl_nothing, world, &min_valid, &max_valid); + matc = _gf_invoke_lookup((jl_value_t*)tt, jl_method_table, world, &min_valid, &max_valid); if (matc) { jl_method_t *m = matc->method; jl_svec_t *env = matc->sparams; - mi = cache_method(mt, &mt->cache, (jl_value_t*)mt, tt, m, world, min_valid, max_valid, env); + mi = cache_method(jl_method_table, mc, &mc->cache, (jl_value_t*)mc, tt, m, world, min_valid, max_valid, env); } } - JL_UNLOCK(&mt->writelock); + JL_UNLOCK(&mc->writelock); JL_GC_POP(); return mi; } - struct matches_env { struct typemap_intersection_env match; jl_typemap_entry_t *newentry; @@ -1705,7 +1751,7 @@ static int get_intersect_visitor(jl_typemap_entry_t *oldentry, struct typemap_in return 1; } -static jl_value_t *get_intersect_matches(jl_typemap_t *defs, jl_typemap_entry_t *newentry, jl_typemap_entry_t **replaced, int8_t offs, size_t world) +static jl_value_t *get_intersect_matches(jl_typemap_t *defs, jl_typemap_entry_t *newentry, jl_typemap_entry_t **replaced, size_t world) { jl_tupletype_t *type = newentry->sig; jl_tupletype_t *ttypes = (jl_tupletype_t*)jl_unwrap_unionall((jl_value_t*)type); @@ -1724,7 +1770,7 @@ static jl_value_t *get_intersect_matches(jl_typemap_t *defs, jl_typemap_entry_t /* .ti = */ NULL, /* .env = */ jl_emptysvec, /* .issubty = */ 0}, /* .newentry = */ newentry, /* .shadowed */ NULL, /* .replaced */ NULL}; JL_GC_PUSH3(&env.match.env, &env.match.ti, &env.shadowed); - jl_typemap_intersection_visitor(defs, offs, &env.match); + jl_typemap_intersection_visitor(defs, 0, &env.match); env.match.env = NULL; env.match.ti = NULL; *replaced = env.replaced; @@ -1748,7 +1794,7 @@ static void method_overwrite(jl_typemap_entry_t *newentry, jl_method_t *oldvalue jl_module_t *newmod = method->module; jl_module_t *oldmod = oldvalue->module; jl_datatype_t *dt = jl_nth_argument_datatype(oldvalue->sig, 1); - if (dt == (jl_datatype_t*)jl_typeof(jl_kwcall_func)) + if (jl_kwcall_type && dt == jl_kwcall_type) dt = jl_nth_argument_datatype(oldvalue->sig, 3); int anon = dt && is_anonfn_typename(jl_symbol_name(dt->name->name)); if ((jl_options.warn_overwrite == JL_OPTIONS_WARN_OVERWRITE_ON) || @@ -1774,18 +1820,20 @@ static void method_overwrite(jl_typemap_entry_t *newentry, jl_method_t *oldvalue } } -static void update_max_args(jl_methtable_t *mt, jl_value_t *type) +static void update_max_args(jl_value_t *type) { - if (mt == jl_type_type_mt || mt == jl_nonfunction_mt || mt == jl_kwcall_mt) - return; type = jl_unwrap_unionall(type); + jl_datatype_t *dt = jl_nth_argument_datatype(type, 1); + if (dt == NULL || dt == jl_kwcall_type || jl_is_type_type((jl_value_t*)dt)) + return; + jl_typename_t *tn = dt->name; assert(jl_is_datatype(type)); size_t na = jl_nparams(type); if (jl_va_tuple_kind((jl_datatype_t*)type) == JL_VARARG_UNBOUND) na--; - // update occurs inside mt->writelock - if (na > jl_atomic_load_relaxed(&mt->max_args)) - jl_atomic_store_relaxed(&mt->max_args, na); + // update occurs inside global writelock + if (na > jl_atomic_load_relaxed(&tn->max_args)) + jl_atomic_store_relaxed(&tn->max_args, na); } jl_array_t *_jl_debug_method_invalidation JL_GLOBALLY_ROOTED = NULL; @@ -1829,7 +1877,9 @@ static void invalidate_code_instance(jl_code_instance_t *replaced, size_t max_wo jl_atomic_store_release(&replaced->max_world, max_world); // recurse to all backedges to update their valid range also _invalidate_backedges(replaced_mi, replaced, max_world, depth + 1); - } else { + // TODO: should we visit all forward edges now and delete ourself from all of those lists too? + } + else { assert(jl_atomic_load_relaxed(&replaced->max_world) <= max_world); } JL_UNLOCK(&replaced_mi->def.method->writelock); @@ -1893,6 +1943,33 @@ static void _invalidate_backedges(jl_method_instance_t *replaced_mi, jl_code_ins JL_GC_POP(); } +static int jl_type_intersection2(jl_value_t *t1, jl_value_t *t2, jl_value_t **isect JL_REQUIRE_ROOTED_SLOT, jl_value_t **isect2 JL_REQUIRE_ROOTED_SLOT) +{ + *isect2 = NULL; + int is_subty = 0; + *isect = jl_type_intersection_env_s(t1, t2, NULL, &is_subty); + if (*isect == jl_bottom_type) + return 0; + if (is_subty) + return 1; + // TODO: sometimes type intersection returns types with free variables + if (jl_has_free_typevars(t1) || jl_has_free_typevars(t2)) + return 1; + // determine if type-intersection can be convinced to give a better, non-bad answer + // if the intersection was imprecise, see if we can do better by switching the types + *isect2 = jl_type_intersection(t2, t1); + if (*isect2 == jl_bottom_type) { + *isect = jl_bottom_type; + *isect2 = NULL; + return 0; + } + if (jl_types_egal(*isect2, *isect)) { + *isect2 = NULL; + } + return 1; +} + + enum morespec_options { morespec_unknown, morespec_isnot, @@ -2010,39 +2087,128 @@ JL_DLLEXPORT void jl_method_instance_add_backedge(jl_method_instance_t *callee, JL_UNLOCK(&callee->def.method->writelock); } -// add a backedge from a non-existent signature to caller -JL_DLLEXPORT void jl_method_table_add_backedge(jl_methtable_t *mt, jl_value_t *typ, jl_code_instance_t *caller) + +struct _typename_add_backedge { + jl_value_t *typ; + jl_value_t *caller; +}; + +static void _typename_add_backedge(jl_typename_t *tn, void *env0) { - assert(jl_is_code_instance(caller)); - if (!jl_atomic_load_relaxed(&allow_new_worlds)) - return; - JL_LOCK(&mt->writelock); + struct _typename_add_backedge *env = (struct _typename_add_backedge*)env0; + JL_GC_PROMISE_ROOTED(env->typ); + JL_GC_PROMISE_ROOTED(env->caller); if (jl_atomic_load_relaxed(&allow_new_worlds)) { - if (!mt->backedges) { + if (!tn->backedges) { // lazy-init the backedges array - mt->backedges = jl_alloc_vec_any(2); - jl_gc_wb(mt, mt->backedges); - jl_array_ptr_set(mt->backedges, 0, typ); - jl_array_ptr_set(mt->backedges, 1, caller); + tn->backedges = jl_alloc_vec_any(2); + jl_gc_wb(tn, tn->backedges); + jl_array_ptr_set(tn->backedges, 0, env->typ); + jl_array_ptr_set(tn->backedges, 1, env->caller); } else { // check if the edge is already present and avoid adding a duplicate - size_t i, l = jl_array_nrows(mt->backedges); + size_t i, l = jl_array_nrows(tn->backedges); // reuse an already cached instance of this type, if possible // TODO: use jl_cache_type_(tt) like cache_method does, instead of this linear scan? for (i = 1; i < l; i += 2) { - if (jl_array_ptr_ref(mt->backedges, i) != (jl_value_t*)caller) { - if (jl_types_equal(jl_array_ptr_ref(mt->backedges, i - 1), typ)) { - typ = jl_array_ptr_ref(mt->backedges, i - 1); + if (jl_array_ptr_ref(tn->backedges, i) != env->caller) { + if (jl_types_equal(jl_array_ptr_ref(tn->backedges, i - 1), env->typ)) { + env->typ = jl_array_ptr_ref(tn->backedges, i - 1); break; } } } - jl_array_ptr_1d_push(mt->backedges, typ); - jl_array_ptr_1d_push(mt->backedges, (jl_value_t*)caller); + jl_array_ptr_1d_push(tn->backedges, env->typ); + jl_array_ptr_1d_push(tn->backedges, env->caller); } } - JL_UNLOCK(&mt->writelock); +} + +// add a backedge from a non-existent signature to caller +JL_DLLEXPORT void jl_method_table_add_backedge(jl_value_t *typ, jl_code_instance_t *caller) +{ + assert(jl_is_code_instance(caller)); + if (!jl_atomic_load_relaxed(&allow_new_worlds)) + return; + // try to pick the best cache(s) for this typ edge + struct _typename_add_backedge env = {typ, (jl_value_t*)caller}; + jl_methcache_t *mc = jl_method_table->cache; + JL_LOCK(&mc->writelock); + if (jl_atomic_load_relaxed(&allow_new_worlds)) + jl_foreach_top_typename_for(_typename_add_backedge, typ, &env); + JL_UNLOCK(&mc->writelock); +} + +struct _typename_invalidate_backedge { + jl_value_t *type; + jl_value_t **isect; + jl_value_t **isect2; + jl_method_t *const *d; + size_t n; + size_t max_world; + int invalidated; +}; + +static void _typename_invalidate_backedges(jl_typename_t *tn, void *env0) +{ + struct _typename_invalidate_backedge *env = (struct _typename_invalidate_backedge*)env0; + JL_GC_PROMISE_ROOTED(env->type); + JL_GC_PROMISE_ROOTED(env->isect); // isJuliaType considers jl_value_t** to be a julia object too + JL_GC_PROMISE_ROOTED(env->isect2); // isJuliaType considers jl_value_t** to be a julia object too + if (tn->backedges) { + jl_value_t **backedges = jl_array_ptr_data(tn->backedges); + size_t i, na = jl_array_nrows(tn->backedges); + size_t ins = 0; + for (i = 1; i < na; i += 2) { + jl_value_t *backedgetyp = backedges[i - 1]; + JL_GC_PROMISE_ROOTED(backedgetyp); + int missing = 0; + if (jl_type_intersection2(backedgetyp, (jl_value_t*)env->type, env->isect, env->isect2)) { + // See if the intersection was actually already fully + // covered, but that the new method is ambiguous. + // -> no previous method: now there is one, need to update the missing edge + // -> one+ previously matching method(s): + // -> more specific then all of them: need to update the missing edge + // -> some may have been ambiguous: now there is a replacement + // -> some may have been called: now there is a replacement (also will be detected in the loop later) + // -> less specific or ambiguous with any one of them: can ignore the missing edge (not missing) + // -> some may have been ambiguous: still are + // -> some may have been called: they may be partly replaced (will be detected in the loop later) + // c.f. `is_replacing`, which is a similar query, but with an existing method match to compare against + missing = 1; + for (size_t j = 0; j < env->n; j++) { + jl_method_t *m = env->d[j]; + JL_GC_PROMISE_ROOTED(m); + if (jl_subtype(*env->isect, m->sig) || (*env->isect2 && jl_subtype(*env->isect2, m->sig))) { + // We now know that there actually was a previous + // method for this part of the type intersection. + if (!jl_type_morespecific(env->type, m->sig)) { + missing = 0; + break; + } + } + } + } + *env->isect = *env->isect2 = NULL; + if (missing) { + jl_code_instance_t *backedge = (jl_code_instance_t*)backedges[i]; + JL_GC_PROMISE_ROOTED(backedge); + invalidate_code_instance(backedge, env->max_world, 0); + env->invalidated = 1; + if (_jl_debug_method_invalidation) + jl_array_ptr_1d_push(_jl_debug_method_invalidation, (jl_value_t*)backedgetyp); + } + else { + backedges[ins++] = backedges[i - 1]; + backedges[ins++] = backedges[i - 0]; + } + } + if (ins == 0) + tn->backedges = NULL; + else + jl_array_del_end(tn->backedges, na - ins); + } } struct invalidate_mt_env { @@ -2128,35 +2294,36 @@ static jl_typemap_entry_t *do_typemap_search(jl_methtable_t *mt JL_PROPAGATES_RO return (jl_typemap_entry_t *)closure; } -static void jl_method_table_invalidate(jl_methtable_t *mt, jl_method_t *replaced, size_t max_world) +static void _method_table_invalidate(jl_methcache_t *mc, void *env0) { - if (jl_options.incremental && jl_generating_output()) - jl_error("Method deletion is not possible during Module precompile."); - assert(!replaced->is_for_opaque_closure); - assert(jl_atomic_load_relaxed(&jl_world_counter) == max_world); - // drop this method from mt->cache - struct disable_mt_env mt_cache_env; - mt_cache_env.max_world = max_world; - mt_cache_env.replaced = replaced; - jl_typemap_visitor(jl_atomic_load_relaxed(&mt->cache), disable_mt_cache, (void*)&mt_cache_env); - jl_genericmemory_t *leafcache = jl_atomic_load_relaxed(&mt->leafcache); + // drop this method from mc->cache + jl_typemap_visitor(jl_atomic_load_relaxed(&mc->cache), disable_mt_cache, env0); + jl_genericmemory_t *leafcache = jl_atomic_load_relaxed(&mc->leafcache); size_t i, l = leafcache->length; for (i = 1; i < l; i += 2) { jl_typemap_entry_t *oldentry = (jl_typemap_entry_t*)jl_genericmemory_ptr_ref(leafcache, i); if (oldentry) { while ((jl_value_t*)oldentry != jl_nothing) { - disable_mt_cache(oldentry, (void*)&mt_cache_env); + disable_mt_cache(oldentry, env0); oldentry = jl_atomic_load_relaxed(&oldentry->next); } } } +} + +static void jl_method_table_invalidate(jl_method_t *replaced, size_t max_world) +{ + if (jl_options.incremental && jl_generating_output()) + jl_error("Method deletion is not possible during Module precompile."); + assert(!replaced->is_for_opaque_closure); + assert(jl_atomic_load_relaxed(&jl_world_counter) == max_world); // Invalidate the backedges int invalidated = 0; jl_value_t *specializations = jl_atomic_load_relaxed(&replaced->specializations); JL_GC_PUSH1(&specializations); if (!jl_is_svec(specializations)) specializations = (jl_value_t*)jl_svec1(specializations); - l = jl_svec_len(specializations); + size_t i, l = jl_svec_len(specializations); for (i = 0; i < l; i++) { jl_method_instance_t *mi = (jl_method_instance_t*)jl_svecref(specializations, i); if ((jl_value_t*)mi != jl_nothing) { @@ -2164,6 +2331,12 @@ static void jl_method_table_invalidate(jl_methtable_t *mt, jl_method_t *replaced invalidate_backedges(mi, max_world, "jl_method_table_disable"); } } + + jl_methtable_t *mt = jl_method_get_table(replaced); + struct disable_mt_env mt_cache_env; + mt_cache_env.max_world = max_world; + mt_cache_env.replaced = replaced; + _method_table_invalidate(mt->cache, &mt_cache_env); JL_GC_POP(); // XXX: this might have resolved an ambiguity, for which we have not tracked the edge here, // and thus now introduce a mistake into inference @@ -2200,15 +2373,17 @@ static int erase_method_backedges(jl_typemap_entry_t *def, void *closure) static int erase_all_backedges(jl_methtable_t *mt, void *env) { - // removes all method caches - // this might not be entirely safe (GC or MT), thus we only do it very early in bootstrapping - JL_LOCK(&mt->writelock); - mt->backedges = NULL; - JL_UNLOCK(&mt->writelock); - jl_typemap_visitor(jl_atomic_load_relaxed(&mt->defs), erase_method_backedges, env); + return jl_typemap_visitor(jl_atomic_load_relaxed(&mt->defs), erase_method_backedges, env); +} + +static int erase_all_mc_backedges(jl_typename_t *tn, void *env) +{ + tn->backedges = NULL; return 1; } +static int jl_foreach_reachable_typename(int (*visit)(jl_typename_t *tn, void *env), jl_array_t *mod_array, void *env); + JL_DLLEXPORT void jl_disable_new_worlds(void) { if (jl_generating_output()) @@ -2216,59 +2391,39 @@ JL_DLLEXPORT void jl_disable_new_worlds(void) JL_LOCK(&world_counter_lock); jl_atomic_store_relaxed(&allow_new_worlds, 0); JL_UNLOCK(&world_counter_lock); - jl_foreach_reachable_mtable(erase_all_backedges, (void*)NULL); + jl_array_t *mod_array = jl_get_loaded_modules(); + JL_GC_PUSH1(&mod_array); + jl_foreach_reachable_mtable(erase_all_backedges, mod_array, (void*)NULL); + + JL_LOCK(&jl_method_table->cache->writelock); + jl_foreach_reachable_typename(erase_all_mc_backedges, mod_array, (void*)NULL); + JL_UNLOCK(&jl_method_table->cache->writelock); + JL_GC_POP(); } -JL_DLLEXPORT void jl_method_table_disable(jl_methtable_t *mt, jl_method_t *method) +JL_DLLEXPORT void jl_method_table_disable(jl_method_t *method) { + jl_methtable_t *mt = jl_method_get_table(method); jl_typemap_entry_t *methodentry = do_typemap_search(mt, method); JL_LOCK(&world_counter_lock); if (!jl_atomic_load_relaxed(&allow_new_worlds)) jl_error("Method changes have been disabled via a call to disable_new_worlds."); int enabled = jl_atomic_load_relaxed(&methodentry->max_world) == ~(size_t)0; if (enabled) { - JL_LOCK(&mt->writelock); - // Narrow the world age on the method to make it uncallable + // Narrow the world age on the method to make it uncallable size_t world = jl_atomic_load_relaxed(&jl_world_counter); assert(method == methodentry->func.method); jl_atomic_store_relaxed(&method->dispatch_status, 0); assert(jl_atomic_load_relaxed(&methodentry->max_world) == ~(size_t)0); jl_atomic_store_relaxed(&methodentry->max_world, world); - jl_method_table_invalidate(mt, method, world); + jl_method_table_invalidate(method, world); jl_atomic_store_release(&jl_world_counter, world + 1); - JL_UNLOCK(&mt->writelock); - } + } JL_UNLOCK(&world_counter_lock); if (!enabled) jl_errorf("Method of %s already disabled", jl_symbol_name(method->name)); } -static int jl_type_intersection2(jl_value_t *t1, jl_value_t *t2, jl_value_t **isect JL_REQUIRE_ROOTED_SLOT, jl_value_t **isect2 JL_REQUIRE_ROOTED_SLOT) -{ - *isect2 = NULL; - int is_subty = 0; - *isect = jl_type_intersection_env_s(t1, t2, NULL, &is_subty); - if (*isect == jl_bottom_type) - return 0; - if (is_subty) - return 1; - // TODO: sometimes type intersection returns types with free variables - if (jl_has_free_typevars(t1) || jl_has_free_typevars(t2)) - return 1; - // determine if type-intersection can be convinced to give a better, non-bad answer - // if the intersection was imprecise, see if we can do better by switching the types - *isect2 = jl_type_intersection(t2, t1); - if (*isect2 == jl_bottom_type) { - *isect = jl_bottom_type; - *isect2 = NULL; - return 0; - } - if (jl_types_egal(*isect2, *isect)) { - *isect2 = NULL; - } - return 1; -} - jl_typemap_entry_t *jl_method_table_add(jl_methtable_t *mt, jl_method_t *method, jl_tupletype_t *simpletype) { JL_TIMING(ADD_METHOD, ADD_METHOD); @@ -2277,30 +2432,32 @@ jl_typemap_entry_t *jl_method_table_add(jl_methtable_t *mt, jl_method_t *method, jl_timing_show_method(method, JL_TIMING_DEFAULT_BLOCK); jl_typemap_entry_t *newentry = NULL; JL_GC_PUSH1(&newentry); - JL_LOCK(&mt->writelock); // add our new entry assert(jl_atomic_load_relaxed(&method->primary_world) == ~(size_t)0); // min-world assert((jl_atomic_load_relaxed(&method->dispatch_status) & METHOD_SIG_LATEST_WHICH) == 0); assert((jl_atomic_load_relaxed(&method->dispatch_status) & METHOD_SIG_LATEST_ONLY) == 0); + JL_LOCK(&mt->cache->writelock); newentry = jl_typemap_alloc((jl_tupletype_t*)method->sig, simpletype, jl_emptysvec, (jl_value_t*)method, ~(size_t)0, 1); - jl_typemap_insert(&mt->defs, (jl_value_t*)mt, newentry, jl_cachearg_offset(mt)); - update_max_args(mt, method->sig); - JL_UNLOCK(&mt->writelock); + jl_typemap_insert(&mt->defs, (jl_value_t*)mt, newentry, 0); + + if (mt == jl_method_table) + update_max_args(method->sig); + JL_UNLOCK(&mt->cache->writelock); JL_GC_POP(); return newentry; } -void jl_method_table_activate(jl_methtable_t *mt, jl_typemap_entry_t *newentry) +void jl_method_table_activate(jl_typemap_entry_t *newentry) { JL_TIMING(ADD_METHOD, ADD_METHOD); jl_method_t *method = newentry->func.method; + jl_methtable_t *mt = jl_method_get_table(method); assert(jl_is_mtable(mt)); assert(jl_is_method(method)); jl_timing_show_method(method, JL_TIMING_DEFAULT_BLOCK); jl_value_t *type = (jl_value_t*)newentry->sig; jl_value_t *oldvalue = NULL; jl_array_t *oldmi = NULL; - JL_LOCK(&mt->writelock); size_t world = jl_atomic_load_relaxed(&method->primary_world); assert(world == jl_atomic_load_relaxed(&jl_world_counter) + 1); // min-world assert((jl_atomic_load_relaxed(&method->dispatch_status) & METHOD_SIG_LATEST_WHICH) == 0); @@ -2317,7 +2474,8 @@ void jl_method_table_activate(jl_methtable_t *mt, jl_typemap_entry_t *newentry) JL_GC_PUSH6(&oldvalue, &oldmi, &loctag, &isect, &isect2, &isect3); jl_typemap_entry_t *replaced = NULL; // then check what entries we replaced - oldvalue = get_intersect_matches(jl_atomic_load_relaxed(&mt->defs), newentry, &replaced, jl_cachearg_offset(mt), max_world); + oldvalue = get_intersect_matches(jl_atomic_load_relaxed(&mt->defs), newentry, &replaced, max_world); + int invalidated = 0; int only = !(jl_atomic_load_relaxed(&method->dispatch_status) & METHOD_SIG_PRECOMPILE_MANY); // will compute if this will be currently the only result that would returned from `ml_matches` given `sig` if (replaced) { @@ -2326,7 +2484,7 @@ void jl_method_table_activate(jl_methtable_t *mt, jl_typemap_entry_t *newentry) invalidated = 1; method_overwrite(newentry, m); // this is an optimized version of below, given we know the type-intersection is exact - jl_method_table_invalidate(mt, m, max_world); + jl_method_table_invalidate(m, max_world); int m_dispatch = jl_atomic_load_relaxed(&m->dispatch_status); jl_atomic_store_relaxed(&m->dispatch_status, 0); only = m_dispatch & METHOD_SIG_LATEST_ONLY; @@ -2342,60 +2500,7 @@ void jl_method_table_activate(jl_methtable_t *mt, jl_typemap_entry_t *newentry) assert(jl_is_array(oldvalue)); d = (jl_method_t**)jl_array_ptr_data(oldvalue); n = jl_array_nrows(oldvalue); - } - if (mt->backedges) { - jl_value_t **backedges = jl_array_ptr_data(mt->backedges); - size_t i, na = jl_array_nrows(mt->backedges); - size_t ins = 0; - for (i = 1; i < na; i += 2) { - jl_value_t *backedgetyp = backedges[i - 1]; - JL_GC_PROMISE_ROOTED(backedgetyp); - int missing = 0; - if (jl_type_intersection2(backedgetyp, (jl_value_t*)type, &isect, &isect2)) { - // See if the intersection was actually already fully - // covered, but that the new method is ambiguous. - // -> no previous method: now there is one, need to update the missing edge - // -> one+ previously matching method(s): - // -> more specific then all of them: need to update the missing edge - // -> some may have been ambiguous: now there is a replacement - // -> some may have been called: now there is a replacement (also will be detected in the loop later) - // -> less specific or ambiguous with any one of them: can ignore the missing edge (not missing) - // -> some may have been ambiguous: still are - // -> some may have been called: they may be partly replaced (will be detected in the loop later) - // c.f. `is_replacing`, which is a similar query, but with an existing method match to compare against - missing = 1; - size_t j; - for (j = 0; j < n; j++) { - jl_method_t *m = d[j]; - if (jl_subtype(isect, m->sig) || (isect2 && jl_subtype(isect2, m->sig))) { - // We now know that there actually was a previous - // method for this part of the type intersection. - if (!jl_type_morespecific(type, m->sig)) { - missing = 0; - break; - } - } - } - } - if (missing) { - jl_code_instance_t *backedge = (jl_code_instance_t*)backedges[i]; - JL_GC_PROMISE_ROOTED(backedge); - invalidate_code_instance(backedge, max_world, 0); - invalidated = 1; - if (_jl_debug_method_invalidation) - jl_array_ptr_1d_push(_jl_debug_method_invalidation, (jl_value_t*)backedgetyp); - } - else { - backedges[ins++] = backedges[i - 1]; - backedges[ins++] = backedges[i - 0]; - } - } - if (ins == 0) - mt->backedges = NULL; - else - jl_array_del_end(mt->backedges, na - ins); - } - if (oldvalue) { + oldmi = jl_alloc_vec_any(0); char *morespec = (char*)alloca(n); memset(morespec, morespec_unknown, n); @@ -2466,29 +2571,37 @@ void jl_method_table_activate(jl_methtable_t *mt, jl_typemap_entry_t *newentry) } } } - if (jl_array_nrows(oldmi)) { - // search mt->cache and leafcache and drop anything that might overlap with the new method - // this is very cheap, so we don't mind being fairly conservative at over-approximating this - struct invalidate_mt_env mt_cache_env; - mt_cache_env.max_world = max_world; - mt_cache_env.shadowed = oldmi; - mt_cache_env.newentry = newentry; - mt_cache_env.invalidated = 0; - - jl_typemap_visitor(jl_atomic_load_relaxed(&mt->cache), invalidate_mt_cache, (void*)&mt_cache_env); - jl_genericmemory_t *leafcache = jl_atomic_load_relaxed(&mt->leafcache); - size_t i, l = leafcache->length; - for (i = 1; i < l; i += 2) { - jl_value_t *entry = jl_genericmemory_ptr_ref(leafcache, i); - if (entry) { - while (entry != jl_nothing) { - invalidate_mt_cache((jl_typemap_entry_t*)entry, (void*)&mt_cache_env); - entry = (jl_value_t*)jl_atomic_load_relaxed(&((jl_typemap_entry_t*)entry)->next); - } + } + + jl_methcache_t *mc = jl_method_table->cache; + JL_LOCK(&mc->writelock); + struct _typename_invalidate_backedge typename_env = {type, &isect, &isect2, d, n, max_world, invalidated}; + jl_foreach_top_typename_for(_typename_invalidate_backedges, type, &typename_env); + invalidated |= typename_env.invalidated; + if (oldmi && jl_array_nrows(oldmi)) { + // search mc->cache and leafcache and drop anything that might overlap with the new method + // this is very cheap, so we don't mind being fairly conservative at over-approximating this + struct invalidate_mt_env mt_cache_env; + mt_cache_env.max_world = max_world; + mt_cache_env.shadowed = oldmi; + mt_cache_env.newentry = newentry; + mt_cache_env.invalidated = 0; + + jl_typemap_visitor(jl_atomic_load_relaxed(&mc->cache), invalidate_mt_cache, (void*)&mt_cache_env); + jl_genericmemory_t *leafcache = jl_atomic_load_relaxed(&mc->leafcache); + size_t i, l = leafcache->length; + for (i = 1; i < l; i += 2) { + jl_value_t *entry = jl_genericmemory_ptr_ref(leafcache, i); + if (entry) { + while (entry != jl_nothing) { + invalidate_mt_cache((jl_typemap_entry_t*)entry, (void*)&mt_cache_env); + entry = (jl_value_t*)jl_atomic_load_relaxed(&((jl_typemap_entry_t*)entry)->next); } } } + invalidated |= mt_cache_env.invalidated; } + JL_UNLOCK(&mc->writelock); } if (invalidated && _jl_debug_method_invalidation) { jl_array_ptr_1d_push(_jl_debug_method_invalidation, (jl_value_t*)method); @@ -2497,7 +2610,6 @@ void jl_method_table_activate(jl_methtable_t *mt, jl_typemap_entry_t *newentry) } jl_atomic_store_relaxed(&newentry->max_world, ~(size_t)0); jl_atomic_store_relaxed(&method->dispatch_status, METHOD_SIG_LATEST_WHICH | (only ? METHOD_SIG_LATEST_ONLY : 0)); // TODO: this should be sequenced fully after the world counter store - JL_UNLOCK(&mt->writelock); JL_GC_POP(); } @@ -2510,7 +2622,7 @@ JL_DLLEXPORT void jl_method_table_insert(jl_methtable_t *mt, jl_method_t *method jl_error("Method changes have been disabled via a call to disable_new_worlds."); size_t world = jl_atomic_load_relaxed(&jl_world_counter) + 1; jl_atomic_store_relaxed(&method->primary_world, world); - jl_method_table_activate(mt, newentry); + jl_method_table_activate(newentry); jl_atomic_store_release(&jl_world_counter, world); JL_UNLOCK(&world_counter_lock); JL_GC_POP(); @@ -2562,13 +2674,15 @@ static jl_tupletype_t *lookup_arg_type_tuple(jl_value_t *arg1 JL_PROPAGATES_ROOT JL_DLLEXPORT jl_value_t *jl_method_lookup_by_tt(jl_tupletype_t *tt, size_t world, jl_value_t *_mt) { jl_methtable_t *mt = NULL; - if (_mt == jl_nothing) - mt = jl_gf_ft_mtable(jl_tparam0(tt)); + if (_mt == jl_nothing) { + mt = jl_method_table; + } else { - assert(jl_isa(_mt, (jl_value_t*)jl_methtable_type)); + assert(jl_is_mtable(_mt)); mt = (jl_methtable_t*) _mt; } - jl_method_instance_t* mi = jl_mt_assoc_by_type(mt, tt, world); + jl_methcache_t *mc = mt->cache; + jl_method_instance_t *mi = jl_mt_assoc_by_type(mc, tt, world); if (!mi) return jl_nothing; return (jl_value_t*) mi; @@ -2577,13 +2691,13 @@ JL_DLLEXPORT jl_value_t *jl_method_lookup_by_tt(jl_tupletype_t *tt, size_t world JL_DLLEXPORT jl_method_instance_t *jl_method_lookup(jl_value_t **args, size_t nargs, size_t world) { assert(nargs > 0 && "expected caller to handle this case"); - jl_methtable_t *mt = jl_gf_mtable(args[0]); - jl_typemap_t *cache = jl_atomic_load_relaxed(&mt->cache); // XXX: gc root for this? - jl_typemap_entry_t *entry = jl_typemap_assoc_exact(cache, args[0], &args[1], nargs, jl_cachearg_offset(mt), world); + jl_methcache_t *mc = jl_method_table->cache; + jl_typemap_t *cache = jl_atomic_load_relaxed(&mc->cache); // XXX: gc root for this? + jl_typemap_entry_t *entry = jl_typemap_assoc_exact(cache, args[0], &args[1], nargs, jl_cachearg_offset(), world); if (entry) return entry->func.linfo; jl_tupletype_t *tt = arg_type_tuple(args[0], &args[1], nargs); - return jl_mt_assoc_by_type(mt, tt, world); + return jl_mt_assoc_by_type(mc, tt, world); } // return a Vector{Any} of svecs, each describing a method match: @@ -2606,10 +2720,9 @@ JL_DLLEXPORT jl_value_t *jl_matching_methods(jl_tupletype_t *types, jl_value_t * if (unw == (jl_value_t*)jl_emptytuple_type || jl_tparam0(unw) == jl_bottom_type) return (jl_value_t*)jl_an_empty_vec_any; if (mt == jl_nothing) - mt = (jl_value_t*)jl_method_table_for(unw); - if (mt == jl_nothing) - mt = NULL; - return ml_matches((jl_methtable_t*)mt, types, lim, include_ambiguous, 1, world, 1, min_valid, max_valid, ambig); + mt = (jl_value_t*)jl_method_table; + jl_methcache_t *mc = ((jl_methtable_t*)mt)->cache; + return ml_matches((jl_methtable_t*)mt, mc, types, lim, include_ambiguous, 1, world, 1, min_valid, max_valid, ambig); } JL_DLLEXPORT jl_method_instance_t *jl_get_unspecialized(jl_method_t *def JL_PROPAGATES_ROOT) @@ -3143,14 +3256,13 @@ JL_DLLEXPORT int32_t jl_invoke_api(jl_code_instance_t *codeinst) return -1; } -JL_DLLEXPORT jl_value_t *jl_normalize_to_compilable_sig(jl_methtable_t *mt, jl_tupletype_t *ti, jl_svec_t *env, jl_method_t *m, +JL_DLLEXPORT jl_value_t *jl_normalize_to_compilable_sig(jl_tupletype_t *ti, jl_svec_t *env, jl_method_t *m, int return_if_compileable) { jl_tupletype_t *tt = NULL; jl_svec_t *newparams = NULL; JL_GC_PUSH2(&tt, &newparams); - jl_methtable_t *kwmt = mt == jl_kwcall_mt ? jl_kwmethod_table_for(m->sig) : mt; - intptr_t max_varargs = get_max_varargs(m, kwmt, mt, NULL); + intptr_t max_varargs = get_max_varargs(m, NULL); jl_compilation_sig(ti, env, m, max_varargs, &newparams); int is_compileable = ((jl_datatype_t*)ti)->isdispatchtuple; if (newparams) { @@ -3176,10 +3288,7 @@ jl_method_instance_t *jl_normalize_to_compilable_mi(jl_method_instance_t *mi JL_ jl_method_t *def = mi->def.method; if (!jl_is_method(def) || !jl_is_datatype(mi->specTypes)) return mi; - jl_methtable_t *mt = jl_method_get_table(def); - if ((jl_value_t*)mt == jl_nothing) - return mi; - jl_value_t *compilationsig = jl_normalize_to_compilable_sig(mt, (jl_datatype_t*)mi->specTypes, mi->sparam_vals, def, 1); + jl_value_t *compilationsig = jl_normalize_to_compilable_sig((jl_datatype_t*)mi->specTypes, mi->sparam_vals, def, 1); if (compilationsig == jl_nothing || jl_egal(compilationsig, mi->specTypes)) return mi; jl_svec_t *env = NULL; @@ -3200,30 +3309,28 @@ JL_DLLEXPORT jl_method_instance_t *jl_method_match_to_mi(jl_method_match_t *matc jl_tupletype_t *ti = match->spec_types; jl_method_instance_t *mi = NULL; if (jl_is_datatype(ti)) { - jl_methtable_t *mt = jl_method_get_table(m); - assert(mt != NULL); - if ((jl_value_t*)mt != jl_nothing) { - // get the specialization, possibly also caching it - if (mt_cache && ((jl_datatype_t*)ti)->isdispatchtuple) { - // Since we also use this presence in the cache - // to trigger compilation when producing `.ji` files, - // inject it there now if we think it will be - // used via dispatch later (e.g. because it was hinted via a call to `precompile`) - JL_LOCK(&mt->writelock); - mi = cache_method(mt, &mt->cache, (jl_value_t*)mt, ti, m, world, min_valid, max_valid, env); - JL_UNLOCK(&mt->writelock); - } - else { - jl_value_t *tt = jl_normalize_to_compilable_sig(mt, ti, env, m, 1); - if (tt != jl_nothing) { - JL_GC_PUSH2(&tt, &env); - if (!jl_egal(tt, (jl_value_t*)ti)) { - jl_value_t *ti = jl_type_intersection_env((jl_value_t*)tt, (jl_value_t*)m->sig, &env); - assert(ti != jl_bottom_type); (void)ti; - } - mi = jl_specializations_get_linfo(m, (jl_value_t*)tt, env); - JL_GC_POP(); + // get the specialization, possibly also caching it + if (mt_cache && ((jl_datatype_t*)ti)->isdispatchtuple) { + // Since we also use this presence in the cache + // to trigger compilation when producing `.ji` files, + // inject it there now if we think it will be + // used via dispatch later (e.g. because it was hinted via a call to `precompile`) + jl_methcache_t *mc = jl_method_table->cache; + assert(mc); + JL_LOCK(&mc->writelock); + mi = cache_method(jl_method_get_table(m), mc, &mc->cache, (jl_value_t*)mc, ti, m, world, min_valid, max_valid, env); + JL_UNLOCK(&mc->writelock); + } + else { + jl_value_t *tt = jl_normalize_to_compilable_sig(ti, env, m, 1); + if (tt != jl_nothing) { + JL_GC_PUSH2(&tt, &env); + if (!jl_egal(tt, (jl_value_t*)ti)) { + jl_value_t *ti = jl_type_intersection_env((jl_value_t*)tt, (jl_value_t*)m->sig, &env); + assert(ti != jl_bottom_type); (void)ti; } + mi = jl_specializations_get_linfo(m, (jl_value_t*)tt, env); + JL_GC_POP(); } } } @@ -3598,7 +3705,6 @@ STATIC_INLINE jl_method_instance_t *jl_lookup_generic_(jl_value_t *F, jl_value_t (callsite >> 16) & (N_CALL_CACHE - 1), (callsite >> 24 | callsite << 8) & (N_CALL_CACHE - 1)}; jl_typemap_entry_t *entry = NULL; - jl_methtable_t *mt = NULL; int i; // check each cache entry to see if it matches //#pragma unroll @@ -3625,8 +3731,8 @@ STATIC_INLINE jl_method_instance_t *jl_lookup_generic_(jl_value_t *F, jl_value_t if (i == 4) { // if no method was found in the associative cache, check the full cache JL_TIMING(METHOD_LOOKUP_FAST, METHOD_LOOKUP_FAST); - mt = jl_gf_mtable(F); - jl_genericmemory_t *leafcache = jl_atomic_load_relaxed(&mt->leafcache); + jl_methcache_t *mc = jl_method_table->cache; + jl_genericmemory_t *leafcache = jl_atomic_load_relaxed(&mc->leafcache); entry = NULL; int cache_entry_count = jl_atomic_load_relaxed(&((jl_datatype_t*)FT)->name->cache_entry_count); if (leafcache != (jl_genericmemory_t*)jl_an_empty_memory_any && (cache_entry_count == 0 || cache_entry_count >= 8)) { @@ -3636,8 +3742,8 @@ STATIC_INLINE jl_method_instance_t *jl_lookup_generic_(jl_value_t *F, jl_value_t entry = lookup_leafcache(leafcache, (jl_value_t*)tt, world); } if (entry == NULL) { - jl_typemap_t *cache = jl_atomic_load_relaxed(&mt->cache); // XXX: gc root required? - entry = jl_typemap_assoc_exact(cache, F, args, nargs, jl_cachearg_offset(mt), world); + jl_typemap_t *cache = jl_atomic_load_relaxed(&mc->cache); // XXX: gc root required? + entry = jl_typemap_assoc_exact(cache, F, args, nargs, jl_cachearg_offset(), world); if (entry == NULL) { last_alloc = jl_options.malloc_log ? jl_gc_diff_total_bytes() : 0; if (tt == NULL) { @@ -3665,7 +3771,8 @@ STATIC_INLINE jl_method_instance_t *jl_lookup_generic_(jl_value_t *F, jl_value_t else { assert(tt); // cache miss case - mfunc = jl_mt_assoc_by_type(mt, tt, world); + jl_methcache_t *mc = jl_method_table->cache; + mfunc = jl_mt_assoc_by_type(mc, tt, world); if (jl_options.malloc_log) jl_gc_sync_total_bytes(last_alloc); // discard allocation count from compilation if (mfunc == NULL) { @@ -3706,18 +3813,15 @@ JL_DLLEXPORT jl_value_t *jl_apply_generic(jl_value_t *F, jl_value_t **args, uint return _jl_invoke(F, args, nargs, mfunc, world); } -static jl_method_match_t *_gf_invoke_lookup(jl_value_t *types JL_PROPAGATES_ROOT, jl_value_t *mt, size_t world, size_t *min_valid, size_t *max_valid) +static jl_method_match_t *_gf_invoke_lookup(jl_value_t *types JL_PROPAGATES_ROOT, jl_methtable_t *mt, size_t world, size_t *min_valid, size_t *max_valid) { jl_value_t *unw = jl_unwrap_unionall((jl_value_t*)types); if (!jl_is_tuple_type(unw)) return NULL; if (jl_tparam0(unw) == jl_bottom_type) return NULL; - if (mt == jl_nothing) - mt = (jl_value_t*)jl_method_table_for(unw); - if (mt == jl_nothing) - mt = NULL; - jl_value_t *matches = ml_matches((jl_methtable_t*)mt, (jl_tupletype_t*)types, 1, 0, 0, world, 1, min_valid, max_valid, NULL); + jl_methcache_t *mc = ((jl_methtable_t*)mt)->cache; + jl_value_t *matches = ml_matches((jl_methtable_t*)mt, mc, (jl_tupletype_t*)types, 1, 0, 0, world, 1, min_valid, max_valid, NULL); if (matches == jl_nothing || jl_array_nrows(matches) != 1) return NULL; jl_method_match_t *matc = (jl_method_match_t*)jl_array_ptr_ref(matches, 0); @@ -3729,7 +3833,9 @@ JL_DLLEXPORT jl_value_t *jl_gf_invoke_lookup(jl_value_t *types, jl_value_t *mt, // Deprecated: Use jl_gf_invoke_lookup_worlds for future development size_t min_valid = 0; size_t max_valid = ~(size_t)0; - jl_method_match_t *matc = _gf_invoke_lookup(types, mt, world, &min_valid, &max_valid); + if (mt == jl_nothing) + mt = (jl_value_t*)jl_method_table; + jl_method_match_t *matc = _gf_invoke_lookup(types, (jl_methtable_t*)mt, world, &min_valid, &max_valid); if (matc == NULL) return jl_nothing; return (jl_value_t*)matc->method; @@ -3738,7 +3844,9 @@ JL_DLLEXPORT jl_value_t *jl_gf_invoke_lookup(jl_value_t *types, jl_value_t *mt, JL_DLLEXPORT jl_value_t *jl_gf_invoke_lookup_worlds(jl_value_t *types, jl_value_t *mt, size_t world, size_t *min_world, size_t *max_world) { - jl_method_match_t *matc = _gf_invoke_lookup(types, mt, world, min_world, max_world); + if (mt == jl_nothing) + mt = (jl_value_t*)jl_method_table; + jl_method_match_t *matc = _gf_invoke_lookup(types, (jl_methtable_t*)mt, world, min_world, max_world); if (matc == NULL) return jl_nothing; return (jl_value_t*)matc; @@ -3801,7 +3909,7 @@ jl_value_t *jl_gf_invoke_by_method(jl_method_t *method, jl_value_t *gf, jl_value assert(sub); (void)sub; } - mfunc = cache_method(NULL, &method->invokes, (jl_value_t*)method, tt, method, 1, 1, ~(size_t)0, tpenv); + mfunc = cache_method(NULL, NULL, &method->invokes, (jl_value_t*)method, tt, method, 1, 1, ~(size_t)0, tpenv); } JL_UNLOCK(&method->writelock); JL_GC_POP(); @@ -3845,8 +3953,8 @@ jl_function_t *jl_new_generic_function_with_supertype(jl_sym_t *name, jl_module_ 0, 0, 0); assert(jl_is_datatype(ftype)); JL_GC_PUSH1(&ftype); - ftype->name->mt->name = name; - jl_gc_wb(ftype->name->mt, name); + ftype->name->singletonname = name; + jl_gc_wb(ftype->name, name); jl_declare_constant_val3(NULL, module, tname, (jl_value_t*)ftype, PARTITION_KIND_CONST, new_world); jl_value_t *f = jl_new_struct(ftype); ftype->instance = f; @@ -3947,7 +4055,7 @@ static int ml_matches_visitor(jl_typemap_entry_t *ml, struct typemap_intersectio static int ml_mtable_visitor(jl_methtable_t *mt, void *closure0) { struct typemap_intersection_env* env = (struct typemap_intersection_env*)closure0; - return jl_typemap_intersection_visitor(jl_atomic_load_relaxed(&mt->defs), jl_cachearg_offset(mt), env); + return jl_typemap_intersection_visitor(jl_atomic_load_relaxed(&mt->defs), 0, env); } // Visit the candidate methods, starting from t[idx], to determine a possible valid sort ordering, @@ -4230,7 +4338,7 @@ static int sort_mlmatches(jl_array_t *t, size_t idx, arraylist_t *visited, array // fully-covers is a Bool indicating subtyping, though temporarily it may be // tri-values, with `nothing` indicating a match that is not a subtype, but // which is dominated by one which is (and thus should be excluded unless ambiguous) -static jl_value_t *ml_matches(jl_methtable_t *mt, +static jl_value_t *ml_matches(jl_methtable_t *mt, jl_methcache_t *mc, jl_tupletype_t *type, int lim, int include_ambiguous, int intersections, size_t world, int cache_result, size_t *min_valid, size_t *max_valid, int *ambig) @@ -4259,10 +4367,10 @@ static jl_value_t *ml_matches(jl_methtable_t *mt, jl_value_t *isect2 = NULL; JL_GC_PUSH6(&env.t, &env.matc, &env.match.env, &search.env, &env.match.ti, &isect2); - if (mt) { + if (mc) { // check the leaf cache if this type can be in there if (((jl_datatype_t*)unw)->isdispatchtuple) { - jl_genericmemory_t *leafcache = jl_atomic_load_relaxed(&mt->leafcache); + jl_genericmemory_t *leafcache = jl_atomic_load_relaxed(&mc->leafcache); jl_typemap_entry_t *entry = lookup_leafcache(leafcache, (jl_value_t*)type, world); if (entry) { jl_method_instance_t *mi = entry->func.linfo; @@ -4295,7 +4403,7 @@ static jl_value_t *ml_matches(jl_methtable_t *mt, } // then check the full cache if it seems profitable if (((jl_datatype_t*)unw)->isdispatchtuple) { - jl_typemap_entry_t *entry = jl_typemap_assoc_by_type(jl_atomic_load_relaxed(&mt->cache), &search, jl_cachearg_offset(mt), /*subtype*/1); + jl_typemap_entry_t *entry = jl_typemap_assoc_by_type(jl_atomic_load_relaxed(&mc->cache), &search, jl_cachearg_offset(), /*subtype*/1); if (entry && (((jl_datatype_t*)unw)->isdispatchtuple || entry->guardsigs == jl_emptysvec)) { jl_method_instance_t *mi = entry->func.linfo; jl_method_t *meth = mi->def.method; @@ -4321,23 +4429,14 @@ static jl_value_t *ml_matches(jl_methtable_t *mt, return env.t; } } - if (!ml_mtable_visitor(mt, &env.match) && env.t == jl_an_empty_vec_any) { - JL_GC_POP(); - // if we return early without returning methods, set only the min/max valid collected from matching - *min_valid = env.match.min_valid; - *max_valid = env.match.max_valid; - return jl_nothing; - } } - else { - // else: scan everything - if (!jl_foreach_reachable_mtable(ml_mtable_visitor, &env.match) && env.t == jl_an_empty_vec_any) { - JL_GC_POP(); - // if we return early without returning methods, set only the min/max valid collected from matching - *min_valid = env.match.min_valid; - *max_valid = env.match.max_valid; - return jl_nothing; - } + // then scan everything + if (!ml_mtable_visitor(mt, &env.match) && env.t == jl_an_empty_vec_any) { + JL_GC_POP(); + // if we return early without returning methods, set only the min/max valid collected from matching + *min_valid = env.match.min_valid; + *max_valid = env.match.max_valid; + return jl_nothing; } // if we return early, set only the min/max valid collected from matching *min_valid = env.match.min_valid; @@ -4585,14 +4684,14 @@ static jl_value_t *ml_matches(jl_methtable_t *mt, if (env.match.min_valid < min_world) env.match.min_valid = min_world; } - if (mt && cache_result && ((jl_datatype_t*)unw)->isdispatchtuple) { // cache_result parameter keeps this from being recursive + if (mc && cache_result && ((jl_datatype_t*)unw)->isdispatchtuple) { // cache_result parameter keeps this from being recursive if (len == 1 && !has_ambiguity) { env.matc = (jl_method_match_t*)jl_array_ptr_ref(env.t, 0); jl_method_t *meth = env.matc->method; jl_svec_t *tpenv = env.matc->sparams; - JL_LOCK(&mt->writelock); - cache_method(mt, &mt->cache, (jl_value_t*)mt, (jl_tupletype_t*)unw, meth, world, env.match.min_valid, env.match.max_valid, tpenv); - JL_UNLOCK(&mt->writelock); + JL_LOCK(&mc->writelock); + cache_method(mt, mc, &mc->cache, (jl_value_t*)mc, (jl_tupletype_t*)unw, meth, world, env.match.min_valid, env.match.max_valid, tpenv); + JL_UNLOCK(&mc->writelock); } } *min_valid = env.match.min_valid; @@ -4672,7 +4771,7 @@ JL_DLLEXPORT void jl_extern_c(jl_value_t *name, jl_value_t *declrt, jl_tupletype } // save a record of this so that the alias is generated when we write an object file - jl_method_t *meth = (jl_method_t*)jl_methtable_lookup(ft->name->mt, (jl_value_t*)sigt, jl_atomic_load_acquire(&jl_world_counter)); + jl_method_t *meth = (jl_method_t*)jl_methtable_lookup((jl_value_t*)sigt, jl_atomic_load_acquire(&jl_world_counter)); if (!jl_is_method(meth)) jl_error("@ccallable: could not find requested method"); JL_GC_PUSH1(&meth); diff --git a/src/interpreter.c b/src/interpreter.c index 7ab284df78dff..f71e43757afd9 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -101,9 +101,8 @@ static jl_value_t *eval_methoddef(jl_expr_t *ex, interpreter_state *s) fname = eval_value(args[0], s); jl_methtable_t *mt = NULL; - if (jl_typetagis(fname, jl_methtable_type)) { + if (jl_is_mtable(fname)) mt = (jl_methtable_t*)fname; - } atypes = eval_value(args[1], s); meth = eval_value(args[2], s); jl_method_def((jl_svec_t*)atypes, mt, (jl_code_info_t*)meth, s->module); diff --git a/src/ircode.c b/src/ircode.c index ddd5bb29fdfac..9a94c4c62431a 100644 --- a/src/ircode.c +++ b/src/ircode.c @@ -1616,14 +1616,12 @@ void jl_init_serializer(void) jl_densearray_type, jl_function_type, jl_typename_type, jl_builtin_type, jl_task_type, jl_uniontype_type, jl_array_any_type, jl_intrinsic_type, - jl_methtable_type, jl_typemap_level_type, jl_voidpointer_type, jl_newvarnode_type, jl_abstractstring_type, jl_array_symbol_type, jl_anytuple_type, jl_tparam0(jl_anytuple_type), jl_emptytuple_type, jl_array_uint8_type, jl_array_uint32_type, jl_code_info_type, jl_typeofbottom_type, jl_typeofbottom_type->super, jl_namedtuple_type, jl_array_int32_type, jl_uint32_type, jl_uint64_type, - jl_type_type_mt, jl_nonfunction_mt, jl_opaque_closure_type, jl_memory_any_type, jl_memory_uint8_type, diff --git a/src/jl_exported_data.inc b/src/jl_exported_data.inc index df3b9c121837c..76e8368132424 100644 --- a/src/jl_exported_data.inc +++ b/src/jl_exported_data.inc @@ -65,7 +65,7 @@ XX(jl_interconditional_type) \ XX(jl_interrupt_exception) \ XX(jl_intrinsic_type) \ - XX(jl_kwcall_func) \ + XX(jl_kwcall_type) \ XX(jl_libdl_module) \ XX(jl_libdl_dlopen_func) \ XX(jl_lineinfonode_type) \ @@ -91,13 +91,13 @@ XX(jl_method_match_type) \ XX(jl_method_type) \ XX(jl_methtable_type) \ + XX(jl_methcache_type) \ XX(jl_missingcodeerror_type) \ XX(jl_module_type) \ XX(jl_n_threads_per_pool) \ XX(jl_namedtuple_type) \ XX(jl_namedtuple_typename) \ XX(jl_newvarnode_type) \ - XX(jl_nonfunction_mt) \ XX(jl_nothing) \ XX(jl_nothing_type) \ XX(jl_number_type) \ @@ -135,7 +135,6 @@ XX(jl_typename_type) \ XX(jl_typeofbottom_type) \ XX(jl_type_type) \ - XX(jl_type_type_mt) \ XX(jl_type_typename) \ XX(jl_uint16_type) \ XX(jl_uint32_type) \ diff --git a/src/jltypes.c b/src/jltypes.c index 52e707b618211..40dc55a4e3e54 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -2954,7 +2954,9 @@ void jl_init_types(void) JL_GC_DISABLED XX(symbol); jl_simplevector_type = jl_new_uninitialized_datatype(); XX(simplevector); + jl_methcache_type = jl_new_uninitialized_datatype(); jl_methtable_type = jl_new_uninitialized_datatype(); + jl_method_table = jl_new_method_table(jl_symbol("GlobalMethods"), core); jl_emptysvec = (jl_svec_t*)jl_gc_permobj(sizeof(void*), jl_simplevector_type); jl_set_typetagof(jl_emptysvec, jl_simplevector_tag, GC_OLD_MARKED); @@ -2962,14 +2964,10 @@ void jl_init_types(void) JL_GC_DISABLED jl_any_type = (jl_datatype_t*)jl_new_abstracttype((jl_value_t*)jl_symbol("Any"), core, NULL, jl_emptysvec); jl_any_type->super = jl_any_type; - jl_nonfunction_mt = jl_any_type->name->mt; - jl_any_type->name->mt = NULL; jl_datatype_t *type_type = jl_new_abstracttype((jl_value_t*)jl_symbol("Type"), core, jl_any_type, jl_emptysvec); jl_type_type = (jl_unionall_t*)type_type; jl_type_typename = type_type->name; - jl_type_type_mt = jl_new_method_table(jl_type_typename->name, core); - jl_type_typename->mt = jl_type_type_mt; // initialize them. lots of cycles. // NOTE: types are not actually mutable, but we want to ensure they are heap-allocated with stable addresses @@ -3004,56 +3002,60 @@ void jl_init_types(void) JL_GC_DISABLED jl_typename_type->name = jl_new_typename_in(jl_symbol("TypeName"), core, 0, 1); jl_typename_type->name->wrapper = (jl_value_t*)jl_typename_type; - jl_typename_type->name->mt = jl_nonfunction_mt; jl_typename_type->super = jl_any_type; jl_typename_type->parameters = jl_emptysvec; - jl_typename_type->name->n_uninitialized = 17 - 2; - jl_typename_type->name->names = jl_perm_symsvec(17, "name", "module", + jl_typename_type->name->n_uninitialized = 19 - 2; + jl_typename_type->name->names = jl_perm_symsvec(19, "name", "module", "singletonname", "names", "atomicfields", "constfields", "wrapper", "Typeofwrapper", "cache", "linearcache", - "mt", "partial", - "hash", "n_uninitialized", + "backedges", "partial", + "hash", "max_args", "n_uninitialized", "flags", // "abstract", "mutable", "mayinlinealloc", "cache_entry_count", "max_methods", "constprop_heuristic"); - const static uint32_t typename_constfields[1] = { 0b00011101000100111 }; // TODO: put back atomicfields and constfields in this list - const static uint32_t typename_atomicfields[1] = { 0b00100000110000000 }; + const static uint32_t typename_constfields[1] = { 0b0001101000001001011 }; // TODO: put back atomicfields and constfields in this list + const static uint32_t typename_atomicfields[1] = { 0b0010010001110000000 }; jl_typename_type->name->constfields = typename_constfields; jl_typename_type->name->atomicfields = typename_atomicfields; jl_precompute_memoized_dt(jl_typename_type, 1); - jl_typename_type->types = jl_svec(17, jl_symbol_type, jl_any_type /*jl_module_type*/, - jl_simplevector_type, jl_any_type/*jl_voidpointer_type*/, jl_any_type/*jl_voidpointer_type*/, + jl_typename_type->types = jl_svec(19, jl_symbol_type, jl_any_type /*jl_module_type*/, jl_symbol_type, + jl_simplevector_type, + jl_any_type/*jl_voidpointer_type*/, jl_any_type/*jl_voidpointer_type*/, jl_type_type, jl_type_type, jl_simplevector_type, jl_simplevector_type, - jl_methtable_type, jl_any_type, - jl_any_type /*jl_long_type*/, jl_any_type /*jl_int32_type*/, + jl_methcache_type, jl_any_type, + jl_any_type /*jl_long_type*/, + jl_any_type /*jl_int32_type*/, + jl_any_type /*jl_int32_type*/, jl_any_type /*jl_uint8_type*/, jl_any_type /*jl_uint8_type*/, jl_any_type /*jl_uint8_type*/, jl_any_type /*jl_uint8_type*/); + jl_methcache_type->name = jl_new_typename_in(jl_symbol("MethodCache"), core, 0, 1); + jl_methcache_type->name->wrapper = (jl_value_t*)jl_methcache_type; + jl_methcache_type->super = jl_any_type; + jl_methcache_type->parameters = jl_emptysvec; + jl_methcache_type->name->n_uninitialized = 4 - 2; + jl_methcache_type->name->names = jl_perm_symsvec(4, "leafcache", "cache", "", ""); + const static uint32_t methcache_atomicfields[1] = { 0b1111 }; + jl_methcache_type->name->atomicfields = methcache_atomicfields; + jl_precompute_memoized_dt(jl_methcache_type, 1); + jl_methcache_type->types = jl_svec(4, jl_any_type, jl_any_type, jl_any_type/*voidpointer*/, jl_any_type/*int32*/); + jl_methtable_type->name = jl_new_typename_in(jl_symbol("MethodTable"), core, 0, 1); jl_methtable_type->name->wrapper = (jl_value_t*)jl_methtable_type; - jl_methtable_type->name->mt = jl_nonfunction_mt; jl_methtable_type->super = jl_any_type; jl_methtable_type->parameters = jl_emptysvec; - jl_methtable_type->name->n_uninitialized = 11 - 6; - jl_methtable_type->name->names = jl_perm_symsvec(11, "name", "defs", - "leafcache", "cache", "max_args", - "module", "backedges", - "", "", "offs", ""); - const static uint32_t methtable_constfields[1] = { 0x00000020 }; // (1<<5); - const static uint32_t methtable_atomicfields[1] = { 0x0000001e }; // (1<<1)|(1<<2)|(1<<3)|(1<<4); + jl_methtable_type->name->n_uninitialized = 0; + jl_methtable_type->name->names = jl_perm_symsvec(4, "defs", "cache", "name", "module"); + const static uint32_t methtable_constfields[1] = { 0b1110 }; + const static uint32_t methtable_atomicfields[1] = { 0b0001 }; jl_methtable_type->name->constfields = methtable_constfields; jl_methtable_type->name->atomicfields = methtable_atomicfields; jl_precompute_memoized_dt(jl_methtable_type, 1); - jl_methtable_type->types = jl_svec(11, jl_symbol_type, jl_any_type, jl_any_type, - jl_any_type, jl_any_type/*jl_long*/, - jl_any_type/*module*/, jl_any_type/*any vector*/, - jl_any_type/*voidpointer*/, jl_any_type/*int32*/, - jl_any_type/*uint8*/, jl_any_type/*uint8*/); + jl_methtable_type->types = jl_svec(4, jl_any_type, jl_methcache_type, jl_symbol_type, jl_any_type /*jl_module_type*/); jl_symbol_type->name = jl_new_typename_in(jl_symbol("Symbol"), core, 0, 1); jl_symbol_type->name->wrapper = (jl_value_t*)jl_symbol_type; - jl_symbol_type->name->mt = jl_nonfunction_mt; jl_symbol_type->super = jl_any_type; jl_symbol_type->parameters = jl_emptysvec; jl_symbol_type->name->n_uninitialized = 0; @@ -3063,7 +3065,6 @@ void jl_init_types(void) JL_GC_DISABLED jl_simplevector_type->name = jl_new_typename_in(jl_symbol("SimpleVector"), core, 0, 1); jl_simplevector_type->name->wrapper = (jl_value_t*)jl_simplevector_type; - jl_simplevector_type->name->mt = jl_nonfunction_mt; jl_simplevector_type->super = jl_any_type; jl_simplevector_type->parameters = jl_emptysvec; jl_simplevector_type->name->n_uninitialized = 0; @@ -3249,8 +3250,6 @@ void jl_init_types(void) JL_GC_DISABLED jl_function_type = jl_new_abstracttype((jl_value_t*)jl_symbol("Function"), core, jl_any_type, jl_emptysvec); jl_builtin_type = jl_new_abstracttype((jl_value_t*)jl_symbol("Builtin"), core, jl_function_type, jl_emptysvec); - jl_function_type->name->mt = NULL; // subtypes of Function have independent method tables - jl_builtin_type->name->mt = NULL; // so they don't share the Any type table jl_svec_t *tv; @@ -3289,10 +3288,7 @@ void jl_init_types(void) JL_GC_DISABLED jl_svec(3, jl_module_type, jl_symbol_type, jl_binding_type), jl_emptysvec, 0, 0, 3); - core = jl_new_module(jl_symbol("Core"), NULL); - jl_type_typename->mt->module = core; - jl_core_module = core; - core = NULL; // not actually ready yet to use + jl_core_module = jl_new_module(jl_symbol("Core"), NULL); tv = jl_svec1(tvar("Backend")); jl_addrspace_typename = @@ -3376,11 +3372,11 @@ void jl_init_types(void) JL_GC_DISABLED jl_array_uint64_type = jl_apply_type2((jl_value_t*)jl_array_type, (jl_value_t*)jl_uint64_type, jl_box_long(1)); jl_an_empty_vec_any = (jl_value_t*)jl_alloc_vec_any(0); // used internally jl_an_empty_memory_any = (jl_value_t*)jl_alloc_memory_any(0); // used internally - jl_atomic_store_relaxed(&jl_nonfunction_mt->leafcache, (jl_genericmemory_t*)jl_an_empty_memory_any); - jl_atomic_store_relaxed(&jl_type_type_mt->leafcache, (jl_genericmemory_t*)jl_an_empty_memory_any); // finish initializing module Core core = jl_core_module; + jl_method_table->module = core; + jl_atomic_store_relaxed(&jl_method_table->cache->leafcache, (jl_genericmemory_t*)jl_an_empty_memory_any); jl_atomic_store_relaxed(&core->bindingkeyset, (jl_genericmemory_t*)jl_an_empty_memory_any); // export own name, so "using Foo" makes "Foo" itself visible jl_set_initial_const(core, core->name, (jl_value_t*)core, 1); @@ -3718,13 +3714,6 @@ void jl_init_types(void) JL_GC_DISABLED jl_svec(4, jl_type_type, jl_simplevector_type, jl_method_type, jl_bool_type), jl_emptysvec, 0, 0, 4); - // all Kinds share the Type method table (not the nonfunction one) - jl_unionall_type->name->mt = - jl_uniontype_type->name->mt = - jl_datatype_type->name->mt = - jl_typeofbottom_type->name->mt = - jl_type_type_mt; - jl_intrinsic_type = jl_new_primitivetype((jl_value_t*)jl_symbol("IntrinsicFunction"), core, jl_builtin_type, jl_emptysvec, 32); @@ -3848,23 +3837,20 @@ void jl_init_types(void) JL_GC_DISABLED jl_svecset(jl_datatype_type->types, 6, jl_int32_type); jl_svecset(jl_datatype_type->types, 7, jl_uint16_type); jl_svecset(jl_typename_type->types, 1, jl_module_type); - jl_svecset(jl_typename_type->types, 3, jl_voidpointer_type); jl_svecset(jl_typename_type->types, 4, jl_voidpointer_type); - jl_svecset(jl_typename_type->types, 5, jl_type_type); + jl_svecset(jl_typename_type->types, 5, jl_voidpointer_type); jl_svecset(jl_typename_type->types, 6, jl_type_type); - jl_svecset(jl_typename_type->types, 11, jl_long_type); - jl_svecset(jl_typename_type->types, 12, jl_int32_type); - jl_svecset(jl_typename_type->types, 13, jl_uint8_type); - jl_svecset(jl_typename_type->types, 14, jl_uint8_type); + jl_svecset(jl_typename_type->types, 7, jl_type_type); + jl_svecset(jl_typename_type->types, 12, jl_long_type); + jl_svecset(jl_typename_type->types, 13, jl_int32_type); + jl_svecset(jl_typename_type->types, 14, jl_int32_type); jl_svecset(jl_typename_type->types, 15, jl_uint8_type); jl_svecset(jl_typename_type->types, 16, jl_uint8_type); - jl_svecset(jl_methtable_type->types, 4, jl_long_type); - jl_svecset(jl_methtable_type->types, 5, jl_module_type); - jl_svecset(jl_methtable_type->types, 6, jl_array_any_type); - jl_svecset(jl_methtable_type->types, 7, jl_long_type); // voidpointer - jl_svecset(jl_methtable_type->types, 8, jl_long_type); // uint32_t plus alignment - jl_svecset(jl_methtable_type->types, 9, jl_uint8_type); - jl_svecset(jl_methtable_type->types, 10, jl_uint8_type); + jl_svecset(jl_typename_type->types, 17, jl_uint8_type); + jl_svecset(jl_typename_type->types, 18, jl_uint8_type); + jl_svecset(jl_methcache_type->types, 2, jl_long_type); // voidpointer + jl_svecset(jl_methcache_type->types, 3, jl_long_type); // uint32_t plus alignment + jl_svecset(jl_methtable_type->types, 3, jl_module_type); jl_svecset(jl_method_type->types, 13, jl_method_instance_type); //jl_svecset(jl_debuginfo_type->types, 0, jl_method_instance_type); // union(jl_method_instance_type, jl_method_type, jl_symbol_type) jl_svecset(jl_method_instance_type->types, 4, jl_code_instance_type); @@ -3879,6 +3865,7 @@ void jl_init_types(void) JL_GC_DISABLED jl_compute_field_offsets(jl_uniontype_type); jl_compute_field_offsets(jl_tvar_type); jl_compute_field_offsets(jl_methtable_type); + jl_compute_field_offsets(jl_methcache_type); jl_compute_field_offsets(jl_method_instance_type); jl_compute_field_offsets(jl_code_instance_type); jl_compute_field_offsets(jl_unionall_type); @@ -3966,9 +3953,9 @@ void post_boot_hooks(void) jl_trimfailure_type = (jl_datatype_t*)core("TrimFailure"); jl_pair_type = core("Pair"); - jl_kwcall_func = core("kwcall"); - jl_kwcall_mt = ((jl_datatype_t*)jl_typeof(jl_kwcall_func))->name->mt; - jl_atomic_store_relaxed(&jl_kwcall_mt->max_args, 0); + jl_value_t *kwcall_func = core("kwcall"); + jl_kwcall_type = (jl_datatype_t*)jl_typeof(kwcall_func); + jl_atomic_store_relaxed(&jl_kwcall_type->name->max_args, 0); jl_weakref_type = (jl_datatype_t*)core("WeakRef"); jl_vecelement_typename = ((jl_datatype_t*)jl_unwrap_unionall(core("VecElement")))->name; @@ -3976,27 +3963,6 @@ void post_boot_hooks(void) jl_abioverride_type = (jl_datatype_t*)core("ABIOverride"); jl_init_box_caches(); - - // set module field of primitive types - jl_svec_t *bindings = jl_atomic_load_relaxed(&jl_core_module->bindings); - jl_value_t **table = jl_svec_data(bindings); - for (size_t i = 0; i < jl_svec_len(bindings); i++) { - if (table[i] != jl_nothing) { - jl_binding_t *b = (jl_binding_t*)table[i]; - jl_value_t *v = jl_get_binding_value(b); - if (v) { - if (jl_is_unionall(v)) - v = jl_unwrap_unionall(v); - if (jl_is_datatype(v)) { - jl_datatype_t *tt = (jl_datatype_t*)v; - tt->name->module = jl_core_module; - if (tt->name->mt) - tt->name->mt->module = jl_core_module; - } - } - } - } - export_jl_small_typeof(); } diff --git a/src/julia.h b/src/julia.h index 1d7e599302e69..fdcc78f3b7a17 100644 --- a/src/julia.h +++ b/src/julia.h @@ -197,6 +197,7 @@ typedef struct _jl_datatype_t jl_tupletype_t; struct _jl_code_instance_t; typedef struct _jl_method_instance_t jl_method_instance_t; typedef struct _jl_globalref_t jl_globalref_t; +typedef struct _jl_typemap_entry_t jl_typemap_entry_t; // TypeMap is an implicitly defined type @@ -518,6 +519,7 @@ typedef struct { JL_DATA_TYPE jl_sym_t *name; struct _jl_module_t *module; + jl_sym_t *singletonname; // sometimes used for debug printing jl_svec_t *names; // field names const uint32_t *atomicfields; // if any fields are atomic, we record them here const uint32_t *constfields; // if any fields are const, we record them here @@ -527,15 +529,16 @@ typedef struct { _Atomic(jl_value_t*) Typeofwrapper; // cache for Type{wrapper} _Atomic(jl_svec_t*) cache; // sorted array _Atomic(jl_svec_t*) linearcache; // unsorted array - struct _jl_methtable_t *mt; + jl_array_t *backedges; // uncovered (sig => caller::CodeInstance) pairs with this type as the function jl_array_t *partial; // incomplete instantiations of this type intptr_t hash; + _Atomic(int32_t) max_args; // max # of non-vararg arguments in a signature with this type as the function int32_t n_uninitialized; // type properties uint8_t abstract:1; uint8_t mutabl:1; uint8_t mayinlinealloc:1; - uint8_t _reserved:5; + uint8_t _unused:5; _Atomic(uint8_t) cache_entry_count; // (approximate counter of TypeMapEntry for heuristics) uint8_t max_methods; // override for inference's max_methods setting (0 = no additional limit or relaxation) uint8_t constprop_heustic; // override for inference's constprop heuristic @@ -837,7 +840,7 @@ struct _jl_globalref_t { }; // one Type-to-Value entry -typedef struct _jl_typemap_entry_t { +struct _jl_typemap_entry_t { JL_DATA_TYPE _Atomic(struct _jl_typemap_entry_t*) next; // invasive linked list jl_tupletype_t *sig; // the type signature for this entry @@ -854,7 +857,7 @@ typedef struct _jl_typemap_entry_t { int8_t isleafsig; // isleaftype(sig) & !any(isType, sig) : unsorted and very fast int8_t issimplesig; // all(isleaftype | isAny | isType | isVararg, sig) : sorted and fast int8_t va; // isVararg(sig) -} jl_typemap_entry_t; +}; // one level in a TypeMap tree (each level splits on a type at a given offset) typedef struct _jl_typemap_level_t { @@ -874,19 +877,20 @@ typedef struct _jl_typemap_level_t { _Atomic(jl_typemap_t*) any; } jl_typemap_level_t; -// contains the TypeMap for one Type -typedef struct _jl_methtable_t { +typedef struct _jl_methcache_t { JL_DATA_TYPE - jl_sym_t *name; // sometimes used for debug printing - _Atomic(jl_typemap_t*) defs; _Atomic(jl_genericmemory_t*) leafcache; _Atomic(jl_typemap_t*) cache; - _Atomic(intptr_t) max_args; // max # of non-vararg arguments in a signature - jl_module_t *module; // sometimes used for debug printing - jl_array_t *backedges; // (sig, caller::CodeInstance) pairs jl_mutex_t writelock; - uint8_t offs; // 0, or 1 to skip splitting typemap on first (function) argument - uint8_t frozen; // whether this accepts adding new methods +} jl_methcache_t; + +// contains global MethodTable +typedef struct _jl_methtable_t { + JL_DATA_TYPE + _Atomic(jl_typemap_t*) defs; + jl_methcache_t *cache; + jl_sym_t *name; // sometimes used for debug printing + jl_module_t *module; // sometimes used for debug printing } jl_methtable_t; typedef struct { @@ -1109,16 +1113,17 @@ extern JL_DLLIMPORT jl_datatype_t *jl_upsilonnode_type JL_GLOBALLY_ROOTED; extern JL_DLLIMPORT jl_datatype_t *jl_quotenode_type JL_GLOBALLY_ROOTED; extern JL_DLLIMPORT jl_datatype_t *jl_newvarnode_type JL_GLOBALLY_ROOTED; extern JL_DLLIMPORT jl_datatype_t *jl_intrinsic_type JL_GLOBALLY_ROOTED; +extern JL_DLLIMPORT jl_datatype_t *jl_methcache_type JL_GLOBALLY_ROOTED; extern JL_DLLIMPORT jl_datatype_t *jl_methtable_type JL_GLOBALLY_ROOTED; extern JL_DLLIMPORT jl_datatype_t *jl_typemap_level_type JL_GLOBALLY_ROOTED; extern JL_DLLIMPORT jl_datatype_t *jl_typemap_entry_type JL_GLOBALLY_ROOTED; +extern JL_DLLIMPORT jl_datatype_t *jl_kwcall_type JL_GLOBALLY_ROOTED; extern JL_DLLIMPORT jl_svec_t *jl_emptysvec JL_GLOBALLY_ROOTED; extern JL_DLLIMPORT jl_value_t *jl_emptytuple JL_GLOBALLY_ROOTED; extern JL_DLLIMPORT jl_value_t *jl_true JL_GLOBALLY_ROOTED; extern JL_DLLIMPORT jl_value_t *jl_false JL_GLOBALLY_ROOTED; extern JL_DLLIMPORT jl_value_t *jl_nothing JL_GLOBALLY_ROOTED; -extern JL_DLLIMPORT jl_value_t *jl_kwcall_func JL_GLOBALLY_ROOTED; extern JL_DLLIMPORT jl_value_t *jl_libdl_dlopen_func JL_GLOBALLY_ROOTED; @@ -1475,9 +1480,7 @@ STATIC_INLINE void jl_array_uint32_set(void *a, size_t i, uint32_t x) JL_NOTSAFE #define jl_string_data(s) ((char*)s + sizeof(void*)) #define jl_string_len(s) (*(size_t*)s) -#define jl_gf_ft_mtable(ft) (((jl_datatype_t*)ft)->name->mt) -#define jl_gf_mtable(f) (jl_gf_ft_mtable(jl_typeof(f))) -#define jl_gf_name(f) (jl_gf_mtable(f)->name) +#define jl_gf_name(f) (((jl_datatype_t*)jl_typeof(f))->name->singletonname) // struct type info JL_DLLEXPORT jl_svec_t *jl_compute_fieldtypes(jl_datatype_t *st JL_PROPAGATES_ROOT, void *stack, int cacheable); @@ -1672,6 +1675,7 @@ static inline int jl_field_isconst(jl_datatype_t *st, int i) JL_NOTSAFEPOINT #define jl_is_method(v) jl_typetagis(v,jl_method_type) #define jl_is_module(v) jl_typetagis(v,jl_module_tag<<4) #define jl_is_mtable(v) jl_typetagis(v,jl_methtable_type) +#define jl_is_mcache(v) jl_typetagis(v,jl_methcache_type) #define jl_is_task(v) jl_typetagis(v,jl_task_tag<<4) #define jl_is_string(v) jl_typetagis(v,jl_string_tag<<4) #define jl_is_cpointer(v) jl_is_cpointer_type(jl_typeof(v)) diff --git a/src/julia_internal.h b/src/julia_internal.h index 4c424f04bf8f3..dd8c2ffe76cdd 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -388,9 +388,7 @@ static inline void memassign_safe(int hasptr, char *dst, const jl_value_t *src, #define GC_IN_IMAGE 4 // useful constants -extern JL_DLLIMPORT jl_methtable_t *jl_type_type_mt JL_GLOBALLY_ROOTED; -extern JL_DLLIMPORT jl_methtable_t *jl_nonfunction_mt JL_GLOBALLY_ROOTED; -extern jl_methtable_t *jl_kwcall_mt JL_GLOBALLY_ROOTED; +extern jl_methtable_t *jl_method_table JL_GLOBALLY_ROOTED; extern JL_DLLEXPORT jl_method_t *jl_opaque_closure_method JL_GLOBALLY_ROOTED; extern JL_DLLEXPORT _Atomic(size_t) jl_world_counter; extern jl_debuginfo_t *jl_nulldebuginfo JL_GLOBALLY_ROOTED; @@ -807,9 +805,9 @@ int jl_has_concrete_subtype(jl_value_t *typ); jl_tupletype_t *jl_inst_arg_tuple_type(jl_value_t *arg1, jl_value_t **args, size_t nargs, int leaf); jl_tupletype_t *jl_lookup_arg_tuple_type(jl_value_t *arg1 JL_PROPAGATES_ROOT, jl_value_t **args, size_t nargs, int leaf); JL_DLLEXPORT void jl_method_table_insert(jl_methtable_t *mt, jl_method_t *method, jl_tupletype_t *simpletype); -void jl_method_table_activate(jl_methtable_t *mt, jl_typemap_entry_t *newentry); +void jl_method_table_activate(jl_typemap_entry_t *newentry); jl_typemap_entry_t *jl_method_table_add(jl_methtable_t *mt, jl_method_t *method, jl_tupletype_t *simpletype); -void jl_mk_builtin_func(jl_datatype_t *dt, jl_sym_t *name, jl_fptr_args_t fptr) JL_GC_DISABLED; +jl_method_t *jl_mk_builtin_func(jl_datatype_t *dt, jl_sym_t *name, jl_fptr_args_t fptr) JL_GC_DISABLED; int jl_obviously_unequal(jl_value_t *a, jl_value_t *b); int jl_has_bound_typevars(jl_value_t *v, jl_typeenv_t *env) JL_NOTSAFEPOINT; JL_DLLEXPORT jl_array_t *jl_find_free_typevars(jl_value_t *v); @@ -859,7 +857,7 @@ int setonce_bits(jl_datatype_t *rty, char *p, jl_value_t *owner, jl_value_t *rhs jl_expr_t *jl_exprn(jl_sym_t *head, size_t n); jl_function_t *jl_new_generic_function(jl_sym_t *name, jl_module_t *module, size_t new_world); jl_function_t *jl_new_generic_function_with_supertype(jl_sym_t *name, jl_module_t *module, jl_datatype_t *st, size_t new_world); -int jl_foreach_reachable_mtable(int (*visit)(jl_methtable_t *mt, void *env), void *env); +int jl_foreach_reachable_mtable(int (*visit)(jl_methtable_t *mt, void *env), jl_array_t *mod_array, void *env); int foreach_mtable_in_module(jl_module_t *m, int (*visit)(jl_methtable_t *mt, void *env), void *env); void jl_init_main_module(void); JL_DLLEXPORT int jl_is_submodule(jl_module_t *child, jl_module_t *parent) JL_NOTSAFEPOINT; @@ -929,10 +927,17 @@ jl_datatype_t *jl_nth_argument_datatype(jl_value_t *argtypes JL_PROPAGATES_ROOT, JL_DLLEXPORT jl_value_t *jl_argument_datatype(jl_value_t *argt JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT; JL_DLLEXPORT jl_methtable_t *jl_method_table_for( jl_value_t *argtypes JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT; +JL_DLLEXPORT jl_methcache_t *jl_method_cache_for( + jl_value_t *argtypes JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT; jl_methtable_t *jl_kwmethod_table_for( jl_value_t *argtypes JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT; +jl_methcache_t *jl_kwmethod_cache_for( + jl_value_t *argtypes JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT; JL_DLLEXPORT jl_methtable_t *jl_method_get_table( jl_method_t *method JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT; +JL_DLLEXPORT jl_methcache_t *jl_method_get_cache( + jl_method_t *method JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT; +void jl_foreach_top_typename_for(void (*f)(jl_typename_t*, void*), jl_value_t *argtypes JL_PROPAGATES_ROOT, void *env); JL_DLLEXPORT int jl_pointer_egal(jl_value_t *t); JL_DLLEXPORT jl_value_t *jl_nth_slot_type(jl_value_t *sig JL_PROPAGATES_ROOT, size_t i) JL_NOTSAFEPOINT; @@ -1288,17 +1293,18 @@ JL_DLLEXPORT jl_method_t *jl_new_method_uninit(jl_module_t*); jl_module_t *jl_new_module_(jl_sym_t *name, jl_module_t *parent, uint8_t default_using_core, uint8_t self_name); jl_module_t *jl_add_standard_imports(jl_module_t *m); JL_DLLEXPORT jl_methtable_t *jl_new_method_table(jl_sym_t *name, jl_module_t *module); +JL_DLLEXPORT jl_methcache_t *jl_new_method_cache(void); JL_DLLEXPORT jl_method_instance_t *jl_get_specialization1(jl_tupletype_t *types JL_PROPAGATES_ROOT, size_t world, int mt_cache); jl_method_instance_t *jl_get_specialized(jl_method_t *m, jl_value_t *types, jl_svec_t *sp) JL_PROPAGATES_ROOT; JL_DLLEXPORT jl_value_t *jl_rettype_inferred(jl_value_t *owner, jl_method_instance_t *li JL_PROPAGATES_ROOT, size_t min_world, size_t max_world); JL_DLLEXPORT jl_value_t *jl_rettype_inferred_native(jl_method_instance_t *mi, size_t min_world, size_t max_world) JL_NOTSAFEPOINT; JL_DLLEXPORT jl_code_instance_t *jl_method_compiled(jl_method_instance_t *mi JL_PROPAGATES_ROOT, size_t world) JL_NOTSAFEPOINT; -JL_DLLEXPORT jl_value_t *jl_methtable_lookup(jl_methtable_t *mt JL_PROPAGATES_ROOT, jl_value_t *type, size_t world); +JL_DLLEXPORT jl_value_t *jl_methtable_lookup(jl_value_t *type, size_t world) JL_GLOBALLY_ROOTED; JL_DLLEXPORT jl_method_instance_t *jl_specializations_get_linfo( jl_method_t *m JL_PROPAGATES_ROOT, jl_value_t *type, jl_svec_t *sparams); jl_method_instance_t *jl_specializations_get_or_insert(jl_method_instance_t *mi_ins JL_PROPAGATES_ROOT); JL_DLLEXPORT void jl_method_instance_add_backedge(jl_method_instance_t *callee, jl_value_t *invokesig, jl_code_instance_t *caller); -JL_DLLEXPORT void jl_method_table_add_backedge(jl_methtable_t *mt, jl_value_t *typ, jl_code_instance_t *caller); +JL_DLLEXPORT void jl_method_table_add_backedge(jl_value_t *typ, jl_code_instance_t *caller); JL_DLLEXPORT void jl_mi_cache_insert(jl_method_instance_t *mi JL_ROOTING_ARGUMENT, jl_code_instance_t *ci JL_ROOTED_ARGUMENT JL_MAYBE_UNROOTED); JL_DLLEXPORT int jl_mi_try_insert(jl_method_instance_t *mi JL_ROOTING_ARGUMENT, diff --git a/src/method.c b/src/method.c index f71f09ceb83bc..77863b27e24b6 100644 --- a/src/method.c +++ b/src/method.c @@ -16,7 +16,6 @@ extern "C" { #endif -jl_methtable_t *jl_kwcall_mt; jl_method_t *jl_opaque_closure_method; static void check_c_types(const char *where, jl_value_t *rt, jl_value_t *at) @@ -803,7 +802,8 @@ JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *mi, size_t else if (jl_is_mtable(kind)) { assert(i < l); ex = data[i++]; - jl_method_table_add_backedge((jl_methtable_t*)kind, ex, ci); + if ((jl_methtable_t*)kind == jl_method_table) + jl_method_table_add_backedge(ex, ci); } else { assert(i < l); @@ -1154,54 +1154,71 @@ JL_DLLEXPORT jl_value_t *jl_declare_const_gf(jl_module_t *mod, jl_sym_t *name) return gf; } -static jl_methtable_t *nth_methtable(jl_value_t *a JL_PROPAGATES_ROOT, int n) JL_NOTSAFEPOINT +static void foreach_top_nth_typename(void (*f)(jl_typename_t*, void*), jl_value_t *a JL_PROPAGATES_ROOT, int n, void *env) { if (jl_is_datatype(a)) { if (n == 0) { - jl_methtable_t *mt = ((jl_datatype_t*)a)->name->mt; - if (mt != NULL) - return mt; + jl_datatype_t *dt = ((jl_datatype_t*)a); + jl_typename_t *tn = NULL; + while (1) { + if (dt != jl_any_type && dt != jl_function_type) + tn = dt->name; + if (dt->super == dt) + break; + dt = dt->super; + } + if (tn) + f(tn, env); } else if (jl_is_tuple_type(a)) { if (jl_nparams(a) >= n) - return nth_methtable(jl_tparam(a, n - 1), 0); + foreach_top_nth_typename(f, jl_tparam(a, n - 1), 0, env); } } else if (jl_is_typevar(a)) { - return nth_methtable(((jl_tvar_t*)a)->ub, n); + foreach_top_nth_typename(f, ((jl_tvar_t*)a)->ub, n, env); } else if (jl_is_unionall(a)) { - return nth_methtable(((jl_unionall_t*)a)->body, n); + foreach_top_nth_typename(f, ((jl_unionall_t*)a)->body, n, env); } else if (jl_is_uniontype(a)) { jl_uniontype_t *u = (jl_uniontype_t*)a; - jl_methtable_t *m1 = nth_methtable(u->a, n); - if ((jl_value_t*)m1 != jl_nothing) { - jl_methtable_t *m2 = nth_methtable(u->b, n); - if (m1 == m2) - return m1; - } + foreach_top_nth_typename(f, u->a, n, env); + foreach_top_nth_typename(f, u->b, n, env); } - return (jl_methtable_t*)jl_nothing; } // get the MethodTable for dispatch, or `nothing` if cannot be determined JL_DLLEXPORT jl_methtable_t *jl_method_table_for(jl_value_t *argtypes JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT { - return nth_methtable(argtypes, 1); + return jl_method_table; +} + +// get a MethodCache for dispatch +JL_DLLEXPORT jl_methcache_t *jl_method_cache_for(jl_value_t *argtypes JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT +{ + return jl_method_table->cache; +} + +void jl_foreach_top_typename_for(void (*f)(jl_typename_t*, void*), jl_value_t *argtypes JL_PROPAGATES_ROOT, void *env) +{ + foreach_top_nth_typename(f, argtypes, 1, env); } -jl_methtable_t *jl_kwmethod_table_for(jl_value_t *argtypes JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT +jl_methcache_t *jl_kwmethod_cache_for(jl_value_t *argtypes JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT { - jl_methtable_t *kwmt = nth_methtable(argtypes, 3); - if ((jl_value_t*)kwmt == jl_nothing) - return NULL; - return kwmt; + return jl_method_table->cache; } JL_DLLEXPORT jl_methtable_t *jl_method_get_table(jl_method_t *method JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT { - return method->external_mt ? (jl_methtable_t*)method->external_mt : jl_method_table_for(method->sig); + return method->external_mt ? (jl_methtable_t*)method->external_mt : jl_method_table; +} + +// get an arbitrary MethodCache for dispatch optimizations of method +JL_DLLEXPORT jl_methcache_t *jl_method_get_cache(jl_method_t *method JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT +{ + return jl_method_get_table(method)->cache; } JL_DLLEXPORT jl_method_t* jl_method_def(jl_svec_t *argdata, @@ -1218,25 +1235,29 @@ JL_DLLEXPORT jl_method_t* jl_method_def(jl_svec_t *argdata, size_t nargs = jl_svec_len(atypes); assert(nargs > 0); int isva = jl_is_vararg(jl_svecref(atypes, nargs - 1)); - if (!jl_is_type(jl_svecref(atypes, 0)) || (isva && nargs == 1)) + jl_value_t *ft = jl_svecref(atypes, 0); + if (!jl_is_type(ft) || (isva && nargs == 1)) jl_error("function type in method definition is not a type"); jl_sym_t *name; jl_method_t *m = NULL; jl_value_t *argtype = NULL; - JL_GC_PUSH3(&f, &m, &argtype); + JL_GC_PUSH4(&ft, &f, &m, &argtype); size_t i, na = jl_svec_len(atypes); argtype = jl_apply_tuple_type(atypes, 1); if (!jl_is_datatype(argtype)) jl_error("invalid type in method definition (Union{})"); - jl_methtable_t *external_mt = mt; if (!mt) - mt = jl_method_table_for(argtype); - if ((jl_value_t*)mt == jl_nothing) - jl_error("Method dispatch is unimplemented currently for this method signature"); - if (mt->frozen) - jl_error("cannot add methods to a builtin function"); + mt = jl_method_table; + jl_methtable_t *external_mt = mt == jl_method_table ? NULL : mt; + + //if (!external_mt) { + // jl_value_t **ttypes = { jl_builtin_type, jl_tparam0(jl_anytuple_type) }; + // jl_value_t *invalidt = jl_apply_tuple_type_v(ttypes, 2); // Tuple{Union{Builtin,OpaqueClosure}, Vararg} + // if (!jl_has_empty_intersection(argtype, invalidt)) + // jl_error("cannot add methods to a builtin function"); + //} assert(jl_is_linenode(functionloc)); jl_sym_t *file = (jl_sym_t*)jl_linenode_file(functionloc); @@ -1245,21 +1266,13 @@ JL_DLLEXPORT jl_method_t* jl_method_def(jl_svec_t *argdata, int32_t line = jl_linenode_line(functionloc); // TODO: derive our debug name from the syntax instead of the type - jl_methtable_t *kwmt = mt == jl_kwcall_mt ? jl_kwmethod_table_for(argtype) : mt; // if we have a kwcall, try to derive the name from the callee argument method table - name = (kwmt ? kwmt : mt)->name; - if (kwmt == jl_type_type_mt || kwmt == jl_nonfunction_mt || external_mt) { - // our value for `name` is bad, try to guess what the syntax might have had, - // like `jl_static_show_func_sig` might have come up with - jl_datatype_t *dt = jl_nth_argument_datatype(argtype, mt == jl_kwcall_mt ? 3 : 1); - if (dt != NULL) { - name = dt->name->name; - if (jl_is_type_type((jl_value_t*)dt)) { - dt = (jl_datatype_t*)jl_argument_datatype(jl_tparam0(dt)); - if ((jl_value_t*)dt != jl_nothing) { - name = dt->name->name; - } - } + jl_datatype_t *dtname = (jl_datatype_t*)jl_argument_datatype(jl_kwcall_type && ft == (jl_value_t*)jl_kwcall_type && nargs >= 3 ? jl_svecref(atypes, 2) : ft); + name = (jl_value_t*)dtname != jl_nothing ? dtname->name->singletonname : jl_any_type->name->singletonname; + if (jl_is_type_type((jl_value_t*)dtname)) { + dtname = (jl_datatype_t*)jl_argument_datatype(jl_tparam0(dtname)); + if ((jl_value_t*)dtname != jl_nothing) { + name = dtname->name->singletonname; } } @@ -1320,6 +1333,9 @@ JL_DLLEXPORT jl_method_t* jl_method_def(jl_svec_t *argdata, jl_symbol_name(file), line); } + ft = jl_rewrap_unionall(ft, argtype); + if (!external_mt && !jl_has_empty_intersection(ft, (jl_value_t*)jl_builtin_type)) // disallow adding methods to Any, Function, Builtin, and subtypes, or Unions of those + jl_error("cannot add methods to a builtin function"); m = jl_new_method_uninit(module); m->external_mt = (jl_value_t*)external_mt; diff --git a/src/module.c b/src/module.c index 0bfa2148f5465..884e55607665b 100644 --- a/src/module.c +++ b/src/module.c @@ -1157,14 +1157,14 @@ static void jl_binding_dep_message(jl_binding_t *b) jl_printf(JL_STDERR, " instead."); } else { - jl_methtable_t *mt = jl_gf_mtable(v); - if (mt != NULL) { + jl_typename_t *tn = ((jl_datatype_t*)jl_typeof(v))->name; + if (tn != NULL) { jl_printf(JL_STDERR, ", use "); - if (mt->module != jl_core_module) { - jl_static_show(JL_STDERR, (jl_value_t*)mt->module); + if (tn->module != jl_core_module) { + jl_static_show(JL_STDERR, (jl_value_t*)tn->module); jl_printf(JL_STDERR, "."); } - jl_printf(JL_STDERR, "%s", jl_symbol_name(mt->name)); + jl_printf(JL_STDERR, "%s", jl_symbol_name(tn->singletonname)); jl_printf(JL_STDERR, " instead."); } } diff --git a/src/precompile_utils.c b/src/precompile_utils.c index 295f91ad31e67..86bb723443925 100644 --- a/src/precompile_utils.c +++ b/src/precompile_utils.c @@ -159,12 +159,12 @@ static int compile_all_collect_(jl_methtable_t *mt, void *env) return 1; } -static void jl_compile_all_defs(jl_array_t *mis, int all) +static void jl_compile_all_defs(jl_array_t *mis, int all, jl_array_t *mod_array) { jl_array_t *allmeths = jl_alloc_vec_any(0); JL_GC_PUSH1(&allmeths); - jl_foreach_reachable_mtable(compile_all_collect_, allmeths); + jl_foreach_reachable_mtable(compile_all_collect_, mod_array, allmeths); size_t world = jl_atomic_load_acquire(&jl_world_counter); size_t i, l = jl_array_nrows(allmeths); @@ -224,38 +224,53 @@ static int precompile_enq_specialization_(jl_method_instance_t *mi, void *closur return 1; } -static int precompile_enq_all_specializations__(jl_typemap_entry_t *def, void *closure) +struct precompile_enq_all_specializations_env { + jl_array_t *worklist; + jl_array_t *m; +}; + +static int precompile_enq_all_specializations__(jl_typemap_entry_t *def, void *env) { jl_method_t *m = def->func.method; - if (m->external_mt) - return 1; + assert(!m->external_mt); + struct precompile_enq_all_specializations_env *closure = (struct precompile_enq_all_specializations_env*)env; + if (closure->worklist) { + size_t i, l = jl_array_nrows(closure->worklist); + for (i = 0; i < l; i++) { + if (m->module == (jl_module_t*)jl_array_ptr_ref(closure->worklist, i)) + break; + } + if (i == l) + return 1; + } if ((m->name == jl_symbol("__init__") || m->ccallable) && jl_is_dispatch_tupletype(m->sig)) { // ensure `__init__()` and @ccallables get strongly-hinted, specialized, and compiled jl_method_instance_t *mi = jl_specializations_get_linfo(m, m->sig, jl_emptysvec); - jl_array_ptr_1d_push((jl_array_t*)closure, (jl_value_t*)mi); + jl_array_ptr_1d_push(closure->m, (jl_value_t*)mi); } else { jl_value_t *specializations = jl_atomic_load_relaxed(&def->func.method->specializations); if (!jl_is_svec(specializations)) { - precompile_enq_specialization_((jl_method_instance_t*)specializations, closure); + precompile_enq_specialization_((jl_method_instance_t*)specializations, closure->m); } else { size_t i, l = jl_svec_len(specializations); for (i = 0; i < l; i++) { jl_value_t *mi = jl_svecref(specializations, i); if (mi != jl_nothing) - precompile_enq_specialization_((jl_method_instance_t*)mi, closure); + precompile_enq_specialization_((jl_method_instance_t*)mi, closure->m); } } } if (m->ccallable) - jl_array_ptr_1d_push((jl_array_t*)closure, (jl_value_t*)m->ccallable); + jl_array_ptr_1d_push(closure->m, (jl_value_t*)m->ccallable); return 1; } -static int precompile_enq_all_specializations_(jl_methtable_t *mt, void *env) +static int precompile_enq_all_specializations_(jl_array_t *worklist, jl_array_t *env) { - return jl_typemap_visitor(jl_atomic_load_relaxed(&mt->defs), precompile_enq_all_specializations__, env); + struct precompile_enq_all_specializations_env closure = {worklist, env}; + return jl_typemap_visitor(jl_atomic_load_relaxed(&jl_method_table->defs), precompile_enq_all_specializations__, &closure); } static void *jl_precompile_(jl_array_t *m, int external_linkage) @@ -284,13 +299,13 @@ static void *jl_precompile_(jl_array_t *m, int external_linkage) return native_code; } -static void *jl_precompile(int all) +static void *jl_precompile(int all, jl_array_t *mod_array) { // array of MethodInstances and ccallable aliases to include in the output jl_array_t *m = jl_alloc_vec_any(0); JL_GC_PUSH1(&m); - jl_compile_all_defs(m, all); - jl_foreach_reachable_mtable(precompile_enq_all_specializations_, m); + jl_compile_all_defs(m, all, mod_array); + precompile_enq_all_specializations_(NULL, m); void *native_code = jl_precompile_(m, 0); JL_GC_POP(); return native_code; @@ -311,13 +326,8 @@ static void *jl_precompile_worklist(jl_array_t *worklist, jl_array_t *extext_met jl_array_t *m = jl_alloc_vec_any(0); JL_GC_PUSH1(&m); if (!suppress_precompile) { - size_t i, n = jl_array_nrows(worklist); - for (i = 0; i < n; i++) { - jl_module_t *mod = (jl_module_t*)jl_array_ptr_ref(worklist, i); - assert(jl_is_module(mod)); - foreach_mtable_in_module(mod, precompile_enq_all_specializations_, m); - } - n = jl_array_nrows(extext_methods); + precompile_enq_all_specializations_(worklist, m); + size_t i, n = jl_array_nrows(extext_methods); for (i = 0; i < n; i++) { jl_method_t *method = (jl_method_t*)jl_array_ptr_ref(extext_methods, i); assert(jl_is_method(method)); @@ -350,21 +360,15 @@ static void *jl_precompile_worklist(jl_array_t *worklist, jl_array_t *extext_met static int enq_ccallable_entrypoints_(jl_typemap_entry_t *def, void *closure) { jl_method_t *m = def->func.method; - if (m->external_mt) - return 1; + assert(!m->external_mt); if (m->ccallable) jl_add_entrypoint((jl_tupletype_t*)jl_svecref(m->ccallable, 1)); return 1; } -static int enq_ccallable_entrypoints(jl_methtable_t *mt, void *env) -{ - return jl_typemap_visitor(jl_atomic_load_relaxed(&mt->defs), enq_ccallable_entrypoints_, env); -} - JL_DLLEXPORT void jl_add_ccallable_entrypoints(void) { - jl_foreach_reachable_mtable(enq_ccallable_entrypoints, NULL); + jl_typemap_visitor(jl_atomic_load_relaxed(&jl_method_table->defs), enq_ccallable_entrypoints_, NULL); } static void *jl_precompile_trimmed(size_t world) @@ -402,35 +406,39 @@ static void *jl_precompile_trimmed(size_t world) return native_code; } -static void jl_rebuild_methtables(arraylist_t* MIs, htable_t* mtables) +static void jl_rebuild_methtables(arraylist_t *MIs, htable_t *mtables) JL_GC_DISABLED { - size_t i; - for (i = 0; i < MIs->len; i++) { + // Rebuild MethodTable to contain only those methods for which we compiled code. + // This can have significant soundness problems if there previously existed + // any ambiguous methods, but it would probably be pretty hard to do this + // fully correctly (with the necessary inserted guard entries). + htable_t ms; + htable_new(&ms, 0); + for (size_t i = 0; i < MIs->len; i++) { jl_method_instance_t *mi = (jl_method_instance_t*)MIs->items[i]; jl_method_t *m = mi->def.method; + // Check if the method is already in the new table, if not then insert it there + void **inserted = ptrhash_bp(&ms, m); + if (*inserted != HT_NOTFOUND) + continue; + *inserted = (void*)m; jl_methtable_t *old_mt = jl_method_get_table(m); if ((jl_value_t *)old_mt == jl_nothing) continue; - jl_sym_t *name = old_mt->name; if (!ptrhash_has(mtables, old_mt)) - ptrhash_put(mtables, old_mt, jl_new_method_table(name, m->module)); + ptrhash_put(mtables, old_mt, jl_new_method_table(old_mt->name, old_mt->module)); jl_methtable_t *mt = (jl_methtable_t*)ptrhash_get(mtables, old_mt); - size_t world = jl_atomic_load_acquire(&jl_world_counter); - jl_value_t *lookup = jl_methtable_lookup(mt, m->sig, world); - // Check if the method is already in the new table, if not then insert it there - if (lookup == jl_nothing || (jl_method_t*)lookup != m) { - //TODO: should this be a function like unsafe_insert_method? - size_t min_world = jl_atomic_load_relaxed(&m->primary_world); - size_t max_world = ~(size_t)0; - assert(min_world == jl_atomic_load_relaxed(&m->primary_world)); - int dispatch_status = jl_atomic_load_relaxed(&m->dispatch_status); - jl_atomic_store_relaxed(&m->primary_world, ~(size_t)0); - jl_atomic_store_relaxed(&m->dispatch_status, 0); - jl_typemap_entry_t *newentry = jl_method_table_add(mt, m, NULL); - jl_atomic_store_relaxed(&m->primary_world, min_world); - jl_atomic_store_relaxed(&m->dispatch_status, dispatch_status); - jl_atomic_store_relaxed(&newentry->min_world, min_world); - jl_atomic_store_relaxed(&newentry->max_world, max_world); // short-circuit jl_method_table_insert - } + //TODO: should this be a function like unsafe_insert_method, since all that is wanted is the jl_typemap_insert on a copy of the existing entry + size_t min_world = jl_atomic_load_relaxed(&m->primary_world); + size_t max_world = ~(size_t)0; + int dispatch_status = jl_atomic_load_relaxed(&m->dispatch_status); + jl_atomic_store_relaxed(&m->primary_world, ~(size_t)0); + jl_atomic_store_relaxed(&m->dispatch_status, 0); + jl_typemap_entry_t *newentry = jl_method_table_add(mt, m, NULL); + jl_atomic_store_relaxed(&m->primary_world, min_world); + jl_atomic_store_relaxed(&m->dispatch_status, dispatch_status); + jl_atomic_store_relaxed(&newentry->min_world, min_world); + jl_atomic_store_relaxed(&newentry->max_world, max_world); // short-circuit jl_method_table_insert } + htable_free(&ms); } diff --git a/src/rtutils.c b/src/rtutils.c index 3b71a3ed42b59..286e0e147581c 100644 --- a/src/rtutils.c +++ b/src/rtutils.c @@ -673,7 +673,7 @@ JL_DLLEXPORT jl_value_t *jl_argument_datatype(jl_value_t *argt JL_PROPAGATES_ROO static int is_globname_binding(jl_value_t *v, jl_datatype_t *dv) JL_NOTSAFEPOINT { - jl_sym_t *globname = dv->name->mt != NULL ? dv->name->mt->name : NULL; + jl_sym_t *globname = dv->name->singletonname; if (globname && dv->name->module) { jl_binding_t *b = jl_get_module_binding(dv->name->module, globname, 0); jl_value_t *bv = jl_get_latest_binding_value_if_resolved_and_const_debug_only(b); @@ -685,7 +685,7 @@ static int is_globname_binding(jl_value_t *v, jl_datatype_t *dv) JL_NOTSAFEPOINT static int is_globfunction(jl_value_t *v, jl_datatype_t *dv, jl_sym_t **globname_out) JL_NOTSAFEPOINT { - jl_sym_t *globname = dv->name->mt != NULL ? dv->name->mt->name : NULL; + jl_sym_t *globname = dv->name->singletonname; *globname_out = globname; if (globname && !strchr(jl_symbol_name(globname), '#') && !strchr(jl_symbol_name(globname), '@')) { return 1; @@ -894,6 +894,9 @@ static size_t jl_static_show_x_(JL_STREAM *out, jl_value_t *v, jl_datatype_t *vt else if (v == (jl_value_t*)jl_methtable_type) { n += jl_printf(out, "Core.MethodTable"); } + else if (v == (jl_value_t*)jl_methcache_type) { + n += jl_printf(out, "Core.MethodCache"); + } else if (v == (jl_value_t*)jl_any_type) { n += jl_printf(out, "Any"); } @@ -1077,6 +1080,9 @@ static size_t jl_static_show_x_(JL_STREAM *out, jl_value_t *v, jl_datatype_t *vt else if (v == jl_nothing || (jl_nothing && (jl_value_t*)vt == jl_typeof(jl_nothing))) { n += jl_printf(out, "nothing"); } + else if (v == (jl_value_t*)jl_method_table) { + n += jl_printf(out, "Core.GlobalMethods"); + } else if (vt == jl_string_type) { n += jl_static_show_string(out, jl_string_data(v), jl_string_len(v), 1, 0); } @@ -1506,10 +1512,8 @@ size_t jl_static_show_func_sig_(JL_STREAM *s, jl_value_t *type, jl_static_show_c return n; } if ((jl_nparams(ftype) == 0 || ftype == ((jl_datatype_t*)ftype)->name->wrapper) && - ((jl_datatype_t*)ftype)->name->mt && - ((jl_datatype_t*)ftype)->name->mt != jl_type_type_mt && - ((jl_datatype_t*)ftype)->name->mt != jl_nonfunction_mt) { - n += jl_static_show_symbol(s, ((jl_datatype_t*)ftype)->name->mt->name); + !jl_is_type_type(ftype) && !jl_is_type_type((jl_value_t*)((jl_datatype_t*)ftype)->super)) { // aka !iskind + n += jl_static_show_symbol(s, ((jl_datatype_t*)ftype)->name->singletonname); } else { n += jl_printf(s, "(::"); diff --git a/src/staticdata.c b/src/staticdata.c index 05617ea3a087e..fa7551433f534 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -116,7 +116,7 @@ extern "C" { // TODO: put WeakRefs on the weak_refs list during deserialization // TODO: handle finalizers -#define NUM_TAGS 152 +#define NUM_TAGS 151 // An array of references that need to be restored from the sysimg // This is a manually constructed dual of the gvars array, which would be produced by codegen for Julia code, for C. @@ -182,6 +182,7 @@ static void get_tags(jl_value_t **tags[NUM_TAGS]) INSERT_TAG(jl_array_any_type); INSERT_TAG(jl_intrinsic_type); INSERT_TAG(jl_methtable_type); + INSERT_TAG(jl_methcache_type); INSERT_TAG(jl_typemap_level_type); INSERT_TAG(jl_typemap_entry_type); INSERT_TAG(jl_voidpointer_type); @@ -229,6 +230,7 @@ static void get_tags(jl_value_t **tags[NUM_TAGS]) INSERT_TAG(jl_addrspacecore_type); INSERT_TAG(jl_debuginfo_type); INSERT_TAG(jl_abioverride_type); + INSERT_TAG(jl_kwcall_type); // special typenames INSERT_TAG(jl_tuple_typename); @@ -277,12 +279,9 @@ static void get_tags(jl_value_t **tags[NUM_TAGS]) INSERT_TAG(jl_main_module); INSERT_TAG(jl_top_module); INSERT_TAG(jl_typeinf_func); - INSERT_TAG(jl_type_type_mt); - INSERT_TAG(jl_nonfunction_mt); - INSERT_TAG(jl_kwcall_mt); - INSERT_TAG(jl_kwcall_func); INSERT_TAG(jl_opaque_closure_method); INSERT_TAG(jl_nulldebuginfo); + INSERT_TAG(jl_method_table); // n.b. must update NUM_TAGS when you add something here #undef INSERT_TAG assert(i == NUM_TAGS - 1); @@ -785,12 +784,6 @@ static void jl_insert_into_serialization_queue(jl_serializer_state *s, jl_value_ } goto done_fields; // for now } - if (s->incremental && jl_is_mtable(v)) { - jl_methtable_t *mt = (jl_methtable_t *)v; - // Any back-edges will be re-validated and added by staticdata.jl, so - // drop them from the image here - record_field_change((jl_value_t**)&mt->backedges, NULL); - } if (jl_is_method_instance(v)) { jl_method_instance_t *mi = (jl_method_instance_t*)v; if (s->incremental) { @@ -836,24 +829,6 @@ static void jl_insert_into_serialization_queue(jl_serializer_state *s, jl_value_ } } } - if (jl_is_mtable(v)) { - jl_methtable_t *mt = (jl_methtable_t*)v; - if (jl_options.trim || jl_options.strip_ir) { - record_field_change((jl_value_t**)&mt->backedges, NULL); - } - else { - // don't recurse into all backedges memory (yet) - jl_value_t *backedges = get_replaceable_field((jl_value_t**)&mt->backedges, 1); - if (backedges) { - jl_queue_for_serialization_(s, (jl_value_t*)((jl_array_t*)backedges)->ref.mem, 0, 1); - for (size_t i = 0, n = jl_array_nrows(backedges); i < n; i += 2) { - jl_value_t *t = jl_array_ptr_ref(backedges, i); - assert(!jl_is_code_instance(t)); - jl_queue_for_serialization(s, t); - } - } - } - } if (jl_is_binding(v)) { jl_binding_t *b = (jl_binding_t*)v; if (s->incremental && needs_uniquing(v, s->query_cache)) { @@ -892,6 +867,23 @@ static void jl_insert_into_serialization_queue(jl_serializer_state *s, jl_value_ assert(!jl_object_in_image((jl_value_t*)tn->module)); assert(!jl_object_in_image((jl_value_t*)tn->wrapper)); } + // Any back-edges will be re-validated and added by staticdata.jl, so + // drop them from the image here + if (s->incremental || jl_options.trim || jl_options.strip_ir) { + record_field_change((jl_value_t**)&tn->backedges, NULL); + } + else { + // don't recurse into all backedges memory (yet) + jl_value_t *backedges = get_replaceable_field((jl_value_t**)&tn->backedges, 1); + if (backedges) { + jl_queue_for_serialization_(s, (jl_value_t*)((jl_array_t*)backedges)->ref.mem, 0, 1); + for (size_t i = 0, n = jl_array_nrows(backedges); i < n; i += 2) { + jl_value_t *t = jl_array_ptr_ref(backedges, i); + assert(!jl_is_code_instance(t)); + jl_queue_for_serialization(s, t); + } + } + } } if (s->incremental && jl_is_code_instance(v)) { jl_code_instance_t *ci = (jl_code_instance_t*)v; @@ -1013,7 +1005,7 @@ static void jl_insert_into_serialization_queue(jl_serializer_state *s, jl_value_ } } } - else if (jl_typetagis(v, jl_module_tag << 4)) { + else if (jl_is_module(v)) { jl_queue_module_for_serialization(s, (jl_module_t*)v); } else if (layout->nfields > 0) { @@ -1023,15 +1015,21 @@ static void jl_insert_into_serialization_queue(jl_serializer_state *s, jl_value_ if (jl_is_svec(jl_atomic_load_relaxed(&m->specializations))) jl_queue_for_serialization_(s, (jl_value_t*)jl_atomic_load_relaxed(&m->specializations), 0, 1); } - else if (jl_typetagis(v, jl_typename_type)) { - jl_typename_t *tn = (jl_typename_t*)v; - if (tn->mt != NULL && !tn->mt->frozen) { - jl_methtable_t * new_methtable = (jl_methtable_t *)ptrhash_get(&new_methtables, tn->mt); - if (new_methtable != HT_NOTFOUND) - record_field_change((jl_value_t **)&tn->mt, (jl_value_t*)new_methtable); - else - record_field_change((jl_value_t **)&tn->mt, NULL); + else if (jl_is_mtable(v)) { + jl_methtable_t *mt = (jl_methtable_t*)v; + jl_methtable_t *newmt = (jl_methtable_t*)ptrhash_get(&new_methtables, mt); + if (newmt != HT_NOTFOUND) + record_field_change((jl_value_t **)&mt->defs, (jl_value_t*)jl_atomic_load_relaxed(&newmt->defs)); + else + record_field_change((jl_value_t **)&mt->defs, jl_nothing); + } + else if (jl_is_mcache(v)) { + jl_methcache_t *mc = (jl_methcache_t*)v; + jl_value_t *cache = jl_atomic_load_relaxed(&mc->cache); + if (!jl_typetagis(cache, jl_typemap_entry_type) || ((jl_typemap_entry_t*)cache)->sig != jl_tuple_type) { // aka Builtins (maybe sometimes OpaqueClosure too) + record_field_change((jl_value_t **)&mc->cache, jl_nothing); } + record_field_change((jl_value_t **)&mc->leafcache, jl_an_empty_memory_any); } // TODO: prune any partitions and partition data that has been deleted in the current world //else if (jl_is_binding(v)) { @@ -1096,7 +1094,20 @@ static void jl_queue_for_serialization_(jl_serializer_state *s, jl_value_t *v, i if (!jl_needs_serialization(s, v)) return; - jl_value_t *t = jl_typeof(v); + jl_datatype_t *t = (jl_datatype_t*)jl_typeof(v); + // check early from errors, so we have a little bit of contextual state for debugging them + if (t == jl_task_type) { + jl_error("Task cannot be serialized"); + } + if (s->incremental && needs_uniquing(v, s->query_cache) && t == jl_binding_type) { + jl_binding_t *b = (jl_binding_t*)v; + if (b->globalref == NULL) + jl_error("Binding cannot be serialized"); // no way (currently) to recover its identity + } + if (jl_is_foreign_type(t) == 1) { + jl_error("Cannot serialize instances of foreign datatypes"); + } + // Items that require postorder traversal must visit their children prior to insertion into // the worklist/serialization_order (and also before their first use) if (s->incremental && !immediate) { @@ -1504,8 +1515,6 @@ static void jl_write_values(jl_serializer_state *s) JL_GC_DISABLED if (needs_uniquing(v, s->query_cache)) { if (jl_is_binding(v)) { jl_binding_t *b = (jl_binding_t*)v; - if (b->globalref == NULL) - jl_error("Binding cannot be serialized"); // no way (currently) to recover its identity write_pointerfield(s, (jl_value_t*)b->globalref->mod); write_pointerfield(s, (jl_value_t*)b->globalref->name); continue; @@ -1670,7 +1679,7 @@ static void jl_write_values(jl_serializer_state *s) JL_GC_DISABLED jl_write_module(s, item, (jl_module_t*)v); } else if (jl_typetagis(v, jl_task_tag << 4)) { - jl_error("Task cannot be serialized"); + abort(); // unreachable } else if (jl_is_svec(v)) { assert(f == s->s); @@ -1686,7 +1695,7 @@ static void jl_write_values(jl_serializer_state *s) JL_GC_DISABLED write_uint8(f, '\0'); // null-terminated strings for easier C-compatibility } else if (jl_is_foreign_type(t) == 1) { - jl_error("Cannot serialize instances of foreign datatypes"); + abort(); // unreachable } else if (jl_datatype_nfields(t) == 0) { // The object has no fields, so we just snapshot its byte representation @@ -2560,7 +2569,7 @@ static void jl_prune_mi_backedges(jl_array_t *backedges) jl_array_del_end(backedges, n - ins); } -static void jl_prune_mt_backedges(jl_array_t *backedges) +static void jl_prune_tn_backedges(jl_array_t *backedges) { if (backedges == NULL) return; @@ -2736,7 +2745,7 @@ static int strip_all_codeinfos__(jl_typemap_entry_t *def, void *_env) JL_GC_PUSH1(&slotnames); int tostrip = jl_array_len(slotnames); // for keyword methods, strip only nargs to keep the keyword names at the end for reflection - if (jl_tparam0(jl_unwrap_unionall(m->sig)) == jl_typeof(jl_kwcall_func)) + if (jl_tparam0(jl_unwrap_unionall(m->sig)) == (jl_value_t*)jl_kwcall_type) tostrip = m->nargs; strip_slotnames(slotnames, tostrip); m->slot_syms = jl_compress_argnames(slotnames); @@ -2768,14 +2777,14 @@ static int strip_all_codeinfos__(jl_typemap_entry_t *def, void *_env) return 1; } -static int strip_all_codeinfos_(jl_methtable_t *mt, void *_env) +static int strip_all_codeinfos_mt(jl_methtable_t *mt, void *_env) { return jl_typemap_visitor(jl_atomic_load_relaxed(&mt->defs), strip_all_codeinfos__, NULL); } -static void jl_strip_all_codeinfos(void) +static void jl_strip_all_codeinfos(jl_array_t *mod_array) { - jl_foreach_reachable_mtable(strip_all_codeinfos_, NULL); + jl_foreach_reachable_mtable(strip_all_codeinfos_mt, mod_array, NULL); } static int strip_module(jl_module_t *m, jl_sym_t *docmeta_sym) @@ -2980,15 +2989,7 @@ static void jl_prepare_serialization_data(jl_array_t *mod_array, jl_array_t *new *extext_methods = jl_alloc_vec_any(0); internal_methods = jl_alloc_vec_any(0); JL_GC_PUSH1(&internal_methods); - jl_collect_methtable_from_mod(jl_type_type_mt, *extext_methods); - jl_collect_methtable_from_mod(jl_nonfunction_mt, *extext_methods); - size_t i, len = jl_array_len(mod_array); - for (i = 0; i < len; i++) { - jl_module_t *m = (jl_module_t*)jl_array_ptr_ref(mod_array, i); - assert(jl_is_module(m)); - if (m->parent == m) // some toplevel modules (really just Base) aren't actually - jl_collect_extext_methods_from_mod(*extext_methods, m); - } + jl_collect_extext_methods(*extext_methods, mod_array); if (edges) { // Extract `edges` now (from info prepared by jl_collect_methcache_from_mod) @@ -3011,7 +3012,7 @@ static void jl_save_system_image_to_stream(ios_t *f, jl_array_t *mod_array, htable_new(&bits_replace, 0); // strip metadata and IR when requested if (jl_options.strip_metadata || jl_options.strip_ir) { - jl_strip_all_codeinfos(); + jl_strip_all_codeinfos(mod_array); jl_strip_all_docmeta(mod_array); } // collect needed methods and replace method tables that are in the tags array @@ -3068,31 +3069,11 @@ static void jl_save_system_image_to_stream(ios_t *f, jl_array_t *mod_array, size_t num_mis; jl_get_llvm_mis(native_functions, &num_mis, NULL); arraylist_grow(&MIs, num_mis); - jl_get_llvm_mis(native_functions, &num_mis, (jl_method_instance_t *)MIs.items); + jl_get_llvm_mis(native_functions, &num_mis, (jl_method_instance_t*)MIs.items); } } if (jl_options.trim) { jl_rebuild_methtables(&MIs, &new_methtables); - jl_methtable_t *mt = (jl_methtable_t *)ptrhash_get(&new_methtables, jl_type_type_mt); - JL_GC_PROMISE_ROOTED(mt); - if (mt != HT_NOTFOUND) - jl_type_type_mt = mt; - else - jl_type_type_mt = jl_new_method_table(jl_type_type_mt->name, jl_type_type_mt->module); - - mt = (jl_methtable_t *)ptrhash_get(&new_methtables, jl_kwcall_mt); - JL_GC_PROMISE_ROOTED(mt); - if (mt != HT_NOTFOUND) - jl_kwcall_mt = mt; - else - jl_kwcall_mt = jl_new_method_table(jl_kwcall_mt->name, jl_kwcall_mt->module); - - mt = (jl_methtable_t *)ptrhash_get(&new_methtables, jl_nonfunction_mt); - JL_GC_PROMISE_ROOTED(mt); - if (mt != HT_NOTFOUND) - jl_nonfunction_mt = mt; - else - jl_nonfunction_mt = jl_new_method_table(jl_nonfunction_mt->name, jl_nonfunction_mt->module); } nsym_tag = 0; @@ -3257,17 +3238,14 @@ static void jl_save_system_image_to_stream(ios_t *f, jl_array_t *mod_array, jl_prune_type_cache_hash(jl_atomic_load_relaxed(&tn->cache))); jl_gc_wb(tn, jl_atomic_load_relaxed(&tn->cache)); jl_prune_type_cache_linear(jl_atomic_load_relaxed(&tn->linearcache)); + jl_value_t *backedges = get_replaceable_field((jl_value_t**)&tn->backedges, 1); + jl_prune_tn_backedges((jl_array_t*)backedges); } else if (jl_is_method_instance(v)) { jl_method_instance_t *mi = (jl_method_instance_t*)v; jl_value_t *backedges = get_replaceable_field((jl_value_t**)&mi->backedges, 1); jl_prune_mi_backedges((jl_array_t*)backedges); } - else if (jl_is_mtable(v)) { - jl_methtable_t *mt = (jl_methtable_t*)v; - jl_value_t *backedges = get_replaceable_field((jl_value_t**)&mt->backedges, 1); - jl_prune_mt_backedges((jl_array_t*)backedges); - } else if (jl_is_binding(v)) { jl_binding_t *b = (jl_binding_t*)v; jl_value_t *backedges = get_replaceable_field((jl_value_t**)&b->backedges, 1); @@ -3520,7 +3498,7 @@ JL_DLLEXPORT void jl_create_system_image(void **_native_data, jl_array_t *workli if (jl_options.trim) *_native_data = jl_precompile_trimmed(precompilation_world); else - *_native_data = jl_precompile(jl_options.compile_enabled == JL_OPTIONS_COMPILE_ALL); + *_native_data = jl_precompile(jl_options.compile_enabled == JL_OPTIONS_COMPILE_ALL, mod_array); } // Make sure we don't run any Julia code concurrently after this point diff --git a/src/staticdata_utils.c b/src/staticdata_utils.c index 65f7dc59d9397..d699e0c262d26 100644 --- a/src/staticdata_utils.c +++ b/src/staticdata_utils.c @@ -332,9 +332,9 @@ static int jl_collect_methtable_from_mod(jl_methtable_t *mt, void *env) // Collect methods of external functions defined by modules in the worklist // "extext" = "extending external" // Also collect relevant backedges -static void jl_collect_extext_methods_from_mod(jl_array_t *s, jl_module_t *m) +static void jl_collect_extext_methods(jl_array_t *s, jl_array_t *mod_array) { - foreach_mtable_in_module(m, jl_collect_methtable_from_mod, s); + jl_foreach_reachable_mtable(jl_collect_methtable_from_mod, mod_array, s); } static void jl_record_edges(jl_method_instance_t *caller, jl_array_t *edges) @@ -727,9 +727,7 @@ static void jl_activate_methods(jl_array_t *external, jl_array_t *internal, size } for (i = 0; i < l; i++) { jl_typemap_entry_t *entry = (jl_typemap_entry_t*)jl_array_ptr_ref(external, i); - jl_methtable_t *mt = jl_method_get_table(entry->func.method); - assert((jl_value_t*)mt != jl_nothing); - jl_method_table_activate(mt, entry); + jl_method_table_activate(entry); } } } diff --git a/stdlib/Serialization/src/Serialization.jl b/stdlib/Serialization/src/Serialization.jl index 3362c9439d385..9437fedf649ec 100644 --- a/stdlib/Serialization/src/Serialization.jl +++ b/stdlib/Serialization/src/Serialization.jl @@ -467,6 +467,20 @@ function serialize(s::AbstractSerializer, meth::Method) nothing end +function serialize(s::AbstractSerializer, mt::Core.MethodTable) + serialize_type(s, typeof(mt)) + serialize(s, mt.cache) + nothing +end + +function serialize(s::AbstractSerializer, mc::Core.MethodCache) + serialize_type(s, typeof(mc)) + serialize(s, mc.name) + serialize(s, mc.module) + nothing +end + + function serialize(s::AbstractSerializer, linfo::Core.MethodInstance) serialize_cycle(s, linfo) && return writetag(s.io, METHODINSTANCE_TAG) @@ -536,11 +550,12 @@ function serialize_typename(s::AbstractSerializer, t::Core.TypeName) serialize(s, t.flags & 0x2 == 0x2) # .mutable serialize(s, Int32(length(primary.types) - t.n_uninitialized)) serialize(s, t.max_methods) - if isdefined(t, :mt) && t.mt !== Symbol.name.mt - serialize(s, t.mt.name) - serialize(s, collect(Base.MethodList(t.mt))) - serialize(s, t.mt.max_args) - kws = collect(methods(Core.kwcall, (Any, t.wrapper, Vararg))) + ms = Base.matches_to_methods(Base._methods_by_ftype(Tuple{t.wrapper, Vararg}, -1, Base.get_world_counter()), t, nothing).ms + if t.singletonname !== t.name || !isempty(ms) + serialize(s, t.singletonname) + serialize(s, ms) + serialize(s, t.max_args) + kws = Base.matches_to_methods(Base._methods_by_ftype(Tuple{typeof(Core.kwcall), Any, t.wrapper, Vararg}, -1, Base.get_world_counter()), t, nothing).ms if isempty(kws) writetag(s.io, UNDEFREF_TAG) else @@ -555,21 +570,17 @@ end # decide whether to send all data for a type (instead of just its name) function should_send_whole_type(s, t::DataType) tn = t.name - if isdefined(tn, :mt) - # TODO improve somehow - # send whole type for anonymous functions in Main - name = tn.mt.name - mod = tn.module - isanonfunction = mod === Main && # only Main - t.super === Function && # only Functions - unsafe_load(unsafe_convert(Ptr{UInt8}, tn.name)) == UInt8('#') && # hidden type - (!isdefined(mod, name) || t != typeof(getglobal(mod, name))) # XXX: 95% accurate test for this being an inner function - # TODO: more accurate test? (tn.name !== "#" name) - #TODO: iskw = startswith(tn.name, "#kw#") && ??? - #TODO: iskw && return send-as-kwftype - return mod === __deserialized_types__ || isanonfunction - end - return false + # TODO improve somehow? + # send whole type for anonymous functions in Main + name = tn.singletonname + mod = tn.module + mod === __deserialized_types__ && return true + isanonfunction = mod === Main && # only Main + t.super === Function && # only Functions + unsafe_load(unsafe_convert(Ptr{UInt8}, tn.name)) == UInt8('#') && # hidden type + (!isdefined(mod, name) || t != typeof(getglobal(mod, name))) # XXX: 95% accurate test for this being an inner function + # TODO: more accurate test? (tn.name !== "#" name) + return isanonfunction end function serialize_type_data(s, @nospecialize(t::DataType)) @@ -1112,8 +1123,8 @@ function deserialize(s::AbstractSerializer, ::Type{Method}) meth.recursion_relation = recursion_relation end if !is_for_opaque_closure - mt = ccall(:jl_method_table_for, Any, (Any,), sig) - if mt !== nothing && nothing === ccall(:jl_methtable_lookup, Any, (Any, Any, UInt), mt, sig, Base.get_world_counter()) + mt = Core.GlobalMethods + if nothing === ccall(:jl_methtable_lookup, Any, (Any, UInt), sig, Base.get_world_counter()) # XXX: quite sketchy? ccall(:jl_method_table_insert, Cvoid, (Any, Any, Ptr{Cvoid}), mt, meth, C_NULL) end end @@ -1122,6 +1133,19 @@ function deserialize(s::AbstractSerializer, ::Type{Method}) return meth end +function deserialize(s::AbstractSerializer, ::Type{Core.MethodTable}) + mc = deserialize(s)::Core.MethodCache + mc === Core.GlobalMethods.cache && return Core.GlobalMethods + return getglobal(mc.mod, mc.name)::Core.MethodTable +end + +function deserialize(s::AbstractSerializer, ::Type{Core.MethodCache}) + name = deserialize(s)::Symbol + mod = deserialize(s)::Module + f = Base.unwrap_unionall(getglobal(mod, name)) + return (f::Core.MethodTable).cache +end + function deserialize(s::AbstractSerializer, ::Type{Core.MethodInstance}) linfo = ccall(:jl_new_method_instance_uninit, Ref{Core.MethodInstance}, (Ptr{Cvoid},), C_NULL) deserialize_cycle(s, linfo) @@ -1471,20 +1495,10 @@ function deserialize_typename(s::AbstractSerializer, number) if tag != UNDEFREF_TAG mtname = handle_deserialize(s, tag) defs = deserialize(s) - maxa = deserialize(s)::Int + maxa = deserialize(s)::Union{Int,Int32} if makenew - mt = ccall(:jl_new_method_table, Any, (Any, Any), name, tn.module) - if !isempty(parameters) - mt.offs = 0 - end - mt.name = mtname - setfield!(mt, :max_args, maxa, :monotonic) - ccall(:jl_set_nth_field, Cvoid, (Any, Csize_t, Any), tn, Base.fieldindex(Core.TypeName, :mt)-1, mt) - for def in defs - if isdefined(def, :sig) - ccall(:jl_method_table_insert, Cvoid, (Any, Any, Ptr{Cvoid}), mt, def, C_NULL) - end - end + tn.singletonname = mtname + setfield!(tn, :max_args, Int32(maxa), :monotonic) end tag = Int32(read(s.io, UInt8)::UInt8) if tag != UNDEFREF_TAG @@ -1494,9 +1508,6 @@ function deserialize_typename(s::AbstractSerializer, number) @eval Core.kwcall(kwargs::NamedTuple, f::$ty, args...) = $kws(kwargs, f, args...) end end - elseif makenew - mt = Symbol.name.mt - ccall(:jl_set_nth_field, Cvoid, (Any, Csize_t, Any), tn, Base.fieldindex(Core.TypeName, :mt)-1, mt) end return tn end diff --git a/stdlib/Test/src/Test.jl b/stdlib/Test/src/Test.jl index e8d670b3d7d00..c96e33c434d52 100644 --- a/stdlib/Test/src/Test.jl +++ b/stdlib/Test/src/Test.jl @@ -2153,30 +2153,7 @@ function detect_ambiguities(mods::Module...; end end end - work = Base.loaded_modules_array() - filter!(mod -> mod === parentmodule(mod), work) # some items in loaded_modules_array are not top modules (really just Base) - while !isempty(work) - mod = pop!(work) - for n in names(mod, all = true) - Base.isdeprecated(mod, n) && continue - if !isdefined(mod, n) - if is_in_mods(mod, recursive, mods) - if allowed_undefineds === nothing || GlobalRef(mod, n) ∉ allowed_undefineds - println("Skipping ", mod, '.', n) # typically stale exports - end - end - continue - end - f = Base.unwrap_unionall(getfield(mod, n)) - if isa(f, Module) && f !== mod && parentmodule(f) === mod && nameof(f) === n - push!(work, f) - elseif isa(f, DataType) && isdefined(f.name, :mt) && parentmodule(f) === mod && nameof(f) === n && f.name.mt !== Symbol.name.mt && f.name.mt !== DataType.name.mt - examine(f.name.mt) - end - end - end - examine(Symbol.name.mt) - examine(DataType.name.mt) + examine(Core.GlobalMethods) return collect(ambs) end @@ -2224,30 +2201,7 @@ function detect_unbound_args(mods...; push!(ambs, m) end end - work = Base.loaded_modules_array() - filter!(mod -> mod === parentmodule(mod), work) # some items in loaded_modules_array are not top modules (really just Base) - while !isempty(work) - mod = pop!(work) - for n in names(mod, all = true) - Base.isdeprecated(mod, n) && continue - if !isdefined(mod, n) - if is_in_mods(mod, recursive, mods) - if allowed_undefineds === nothing || GlobalRef(mod, n) ∉ allowed_undefineds - println("Skipping ", mod, '.', n) # typically stale exports - end - end - continue - end - f = Base.unwrap_unionall(getfield(mod, n)) - if isa(f, Module) && f !== mod && parentmodule(f) === mod && nameof(f) === n - push!(work, f) - elseif isa(f, DataType) && isdefined(f.name, :mt) && parentmodule(f) === mod && nameof(f) === n && f.name.mt !== Symbol.name.mt && f.name.mt !== DataType.name.mt - examine(f.name.mt) - end - end - end - examine(Symbol.name.mt) - examine(DataType.name.mt) + examine(Core.GlobalMethods) return collect(ambs) end diff --git a/test/clangsa/MissingRoots.c b/test/clangsa/MissingRoots.c index 0a0d5369eba44..84341f9410e1e 100644 --- a/test/clangsa/MissingRoots.c +++ b/test/clangsa/MissingRoots.c @@ -277,20 +277,6 @@ void nonconst_loads2() static inline void look_at_value2(jl_value_t *v) { look_at_value(v); } -void mtable(jl_value_t *f) { - look_at_value2((jl_value_t*)jl_gf_mtable(f)); - jl_value_t *val = NULL; - JL_GC_PUSH1(&val); - val = (jl_value_t*)jl_gf_mtable(f); - JL_GC_POP(); -} - -void mtable2(jl_value_t **v) { - jl_value_t *val = NULL; - JL_GC_PUSH1(&val); - val = (jl_value_t*)jl_gf_mtable(v[2]); - JL_GC_POP(); -} void tparam0(jl_value_t *atype) { look_at_value(jl_tparam0(atype)); diff --git a/test/core.jl b/test/core.jl index 5f7f857ad6e35..d1b454db08009 100644 --- a/test/core.jl +++ b/test/core.jl @@ -17,10 +17,11 @@ for (T, c) in ( (Core.CodeInstance, [:def, :owner, :rettype, :exctype, :rettype_const, :analysis_results, :time_infer_total, :time_infer_cache_saved, :time_infer_self]), (Core.Method, [#=:name, :module, :file, :line, :primary_world, :sig, :slot_syms, :external_mt, :nargs, :called, :nospecialize, :nkw, :isva, :is_for_opaque_closure, :constprop=#]), (Core.MethodInstance, [#=:def, :specTypes, :sparam_vals=#]), - (Core.MethodTable, [:module]), + (Core.MethodTable, [:cache, :module, :name]), + (Core.MethodCache, []), (Core.TypeMapEntry, [:sig, :simplesig, :guardsigs, :func, :isleafsig, :issimplesig, :va]), (Core.TypeMapLevel, []), - (Core.TypeName, [:name, :module, :names, :wrapper, :mt, :hash, :n_uninitialized, :flags]), + (Core.TypeName, [:name, :module, :names, :wrapper, :hash, :n_uninitialized, :flags]), (DataType, [:name, :super, :parameters, :instance, :hash]), (TypeVar, [:name, :ub, :lb]), (Core.Memory, [:length, :ptr]), @@ -37,10 +38,11 @@ for (T, c) in ( (Core.CodeInstance, [:next, :min_world, :max_world, :inferred, :edges, :debuginfo, :ipo_purity_bits, :invoke, :specptr, :specsigflags, :precompile, :time_compile]), (Core.Method, [:primary_world, :dispatch_status]), (Core.MethodInstance, [:cache, :flags]), - (Core.MethodTable, [:defs, :leafcache, :cache, :max_args]), + (Core.MethodTable, [:defs]), + (Core.MethodCache, [:leafcache, :cache, :var""]), (Core.TypeMapEntry, [:next, :min_world, :max_world]), (Core.TypeMapLevel, [:arg1, :targ, :name1, :tname, :list, :any]), - (Core.TypeName, [:cache, :linearcache, :cache_entry_count]), + (Core.TypeName, [:cache, :linearcache, :Typeofwrapper, :max_args, :cache_entry_count]), (DataType, [:types, :layout]), (Core.Memory, []), (Core.GenericMemoryRef, []), @@ -2634,11 +2636,14 @@ struct D14919 <: Function; end @test B14919()() == "It's a brand new world" @test C14919()() == D14919()() == "Boo." -for f in (:Any, :Function, :(Core.Builtin), :(Union{Nothing, Type}), :(Union{typeof(+), Type}), :(Union{typeof(+), typeof(-)}), :(Base.Callable)) - @test_throws ErrorException("Method dispatch is unimplemented currently for this method signature") @eval (::$f)() = 1 -end -for f in (:(Core.getfield), :((::typeof(Core.getfield))), :((::Core.IntrinsicFunction))) - @test_throws ErrorException("cannot add methods to a builtin function") @eval $f() = 1 +let ex = ErrorException("cannot add methods to a builtin function") + for f in (:(Core.Any), :(Core.Function), :(Core.Builtin), :(Base.Callable), :(Union{Nothing,F} where F), :(typeof(Core.getfield)), :(Core.IntrinsicFunction)) + @test_throws ex @eval (::$f)() = 1 + end + @test_throws ex @eval (::Union{Nothing,F})() where {F<:Function} = 1 + for f in (:(Core.getfield),) + @test_throws ex @eval $f() = 1 + end end # issue #33370 @@ -5079,7 +5084,7 @@ function f16340(x::T) where T return g end let g = f16340(1) - @test isa(typeof(g).name.mt.defs.sig, UnionAll) + @test isa(only(methods(g)).sig, UnionAll) end # issue #16793 diff --git a/test/misc.jl b/test/misc.jl index 6c8d76fa1cd1a..ae5a193eb43fc 100644 --- a/test/misc.jl +++ b/test/misc.jl @@ -1614,10 +1614,10 @@ end let errs = IOBuffer() run(`$(Base.julia_cmd()) -e ' using Test - @test isdefined(DataType.name.mt, :backedges) + @test isdefined(Type.body.name, :backedges) Base.Experimental.disable_new_worlds() @test_throws "disable_new_worlds" @eval f() = 1 - @test !isdefined(DataType.name.mt, :backedges) + @test !isdefined(Type.body.name, :backedges) @test_throws "disable_new_worlds" Base.delete_method(which(+, (Int, Int))) @test 1+1 == 2 using Dates diff --git a/test/precompile.jl b/test/precompile.jl index c1ac8e03b2d1a..b98288af6e555 100644 --- a/test/precompile.jl +++ b/test/precompile.jl @@ -1932,8 +1932,12 @@ precompile_test_harness("PkgCacheInspector") do load_path end modules, init_order, edges, new_ext_cis, external_methods, new_method_roots, cache_sizes = sv - m = only(external_methods).func::Method - @test m.name == :repl_cmd && m.nargs < 2 + for m in external_methods + m = m.func::Method + if m.name !== :f + @test m.name == :repl_cmd && m.nargs == 1 + end + end @test new_ext_cis === nothing || any(new_ext_cis) do ci mi = ci.def::Core.MethodInstance mi.specTypes == Tuple{typeof(Base.repl_cmd), Int, String} diff --git a/test/reflection.jl b/test/reflection.jl index fdb3c329c58da..2afb37072f24a 100644 --- a/test/reflection.jl +++ b/test/reflection.jl @@ -523,13 +523,13 @@ test_typed_ir_printing(g15714, Tuple{Vector{Float32}}, #@test used_dup_var_tested15715 @test used_unique_var_tested15714 -let li = typeof(fieldtype).name.mt.cache.func::Core.MethodInstance, +let li = only(methods(fieldtype)).unspecialized, lrepr = string(li), mrepr = string(li.def), lmime = repr("text/plain", li), mmime = repr("text/plain", li.def) - @test lrepr == lmime == "MethodInstance for fieldtype(...)" + @test lrepr == lmime == "MethodInstance for fieldtype(::Vararg{Any})" @test mrepr == "fieldtype(...) @ Core none:0" # simple print @test mmime == "fieldtype(...)\n @ Core none:0" # verbose print end diff --git a/test/show.jl b/test/show.jl index ffc9e228f5b39..864fdce8b9e5d 100644 --- a/test/show.jl +++ b/test/show.jl @@ -858,7 +858,7 @@ struct S45879{P} end let ms = methods(S45879) @test ms isa Base.MethodList @test length(ms) == 0 - @test sprint(show, Base.MethodList(Method[], typeof(S45879).name.mt)) isa String + @test sprint(show, Base.MethodList(Method[], typeof(S45879).name)) isa String end function f49475(a=12.0; b) end @@ -1651,7 +1651,7 @@ struct f_with_params{t} <: Function end end let io = IOBuffer() - show(io, MIME"text/html"(), ModFWithParams.f_with_params.body.name.mt) + show(io, MIME"text/html"(), methods(ModFWithParams.f_with_params{Int}())) @test occursin("ModFWithParams.f_with_params", String(take!(io))) end @@ -1803,10 +1803,10 @@ end anonfn_type_repr = "$modname.var\"$(typeof(anonfn).name.name)\"" @test repr(typeof(anonfn)) == anonfn_type_repr @test repr(anonfn) == anonfn_type_repr * "()" - @test repr("text/plain", anonfn) == "$(typeof(anonfn).name.mt.name) (generic function with 1 method)" + @test repr("text/plain", anonfn) == "$(typeof(anonfn).name.singletonname) (generic function with 1 method)" mkclosure = x->y->x+y clo = mkclosure(10) - @test repr("text/plain", clo) == "$(typeof(clo).name.mt.name) (generic function with 1 method)" + @test repr("text/plain", clo) == "$(typeof(clo).name.singletonname) (generic function with 1 method)" @test repr(UnionAll) == "UnionAll" end diff --git a/test/stacktraces.jl b/test/stacktraces.jl index ca553c2a2e801..3df0998fe88f6 100644 --- a/test/stacktraces.jl +++ b/test/stacktraces.jl @@ -90,7 +90,7 @@ f(x) = (y = h(x); y) trace = (try; f(3); catch; stacktrace(catch_backtrace()); end)[1:3] can_inline = Bool(Base.JLOptions().can_inline) for (frame, func, inlined) in zip(trace, [g,h,f], (can_inline, can_inline, false)) - @test frame.func === typeof(func).name.mt.name + @test frame.func === typeof(func).name.singletonname # broken until #50082 can be addressed mi = isa(frame.linfo, Core.CodeInstance) ? frame.linfo.def : frame.linfo @test mi.def.module === which(func, (Any,)).module broken=inlined @@ -109,10 +109,10 @@ let src = Meta.lower(Main, quote let x = 1 end end).args[1]::Core.CodeInfo repr = string(sf) @test repr == "Toplevel MethodInstance thunk at b:3" end -let li = typeof(fieldtype).name.mt.cache.func::Core.MethodInstance, +let li = only(methods(fieldtype)).unspecialized, sf = StackFrame(:a, :b, 3, li, false, false, 0), repr = string(sf) - @test repr == "fieldtype(...) at b:3" + @test repr == "fieldtype(::Vararg{Any}) at b:3" end let ctestptr = cglobal((:ctest, "libccalltest")), diff --git a/test/syntax.jl b/test/syntax.jl index 9be2dff6c3cfa..9ced29245ea6b 100644 --- a/test/syntax.jl +++ b/test/syntax.jl @@ -592,10 +592,9 @@ let thismodule = @__MODULE__, @test !isdefined(M16096, :foo16096) @test !isdefined(M16096, :it) @test typeof(local_foo16096).name.module === thismodule - @test typeof(local_foo16096).name.mt.module === thismodule - @test getfield(thismodule, typeof(local_foo16096).name.mt.name) === local_foo16096 + @test getfield(thismodule, typeof(local_foo16096).name.singletonname) === local_foo16096 @test getfield(thismodule, typeof(local_foo16096).name.name) === typeof(local_foo16096) - @test !isdefined(M16096, typeof(local_foo16096).name.mt.name) + @test !isdefined(M16096, typeof(local_foo16096).name.singletonname) @test !isdefined(M16096, typeof(local_foo16096).name.name) end diff --git a/test/worlds.jl b/test/worlds.jl index 0ac54c3192b24..e99ab7189e25a 100644 --- a/test/worlds.jl +++ b/test/worlds.jl @@ -194,31 +194,26 @@ f_gen265(x::Type{Int}) = 3 # would have capped those specializations if they were still valid f26506(@nospecialize(x)) = 1 g26506(x) = Base.inferencebarrier(f26506)(x[1]) -z = Any["ABC"] +z26506 = Any["ABC"] f26506(x::Int) = 2 -g26506(z) # Places an entry for f26506(::String) in mt.name.cache +g26506(z26506) # Places an entry for f26506(::String) in MethodTable cache +w26506 = Base.get_world_counter() +cache26506 = ccall(:jl_mt_find_cache_entry, Any, (Any, Any, UInt), Core.GlobalMethods.cache, Tuple{typeof(f26506),String}, w26506)::Core.TypeMapEntry +@test cache26506.max_world === typemax(UInt) +w26506 = Base.get_world_counter() f26506(x::String) = 3 -let cache = typeof(f26506).name.mt.cache - # The entry we created above should have been truncated - @test cache.min_world == cache.max_world -end -c26506_1, c26506_2 = Condition(), Condition() -# Captures the world age -result26506 = Any[] -t = Task(()->begin - wait(c26506_1) - push!(result26506, g26506(z)) - notify(c26506_2) -end) -yield(t) +@test w26506+1 === Base.get_world_counter() +# The entry we created above should have been truncated +@test cache26506.max_world == w26506 +# Captures the world age on creation +t26506 = @task g26506(z26506) f26506(x::Float64) = 4 -let cache = typeof(f26506).name.mt.cache - # The entry we created above should have been truncated - @test cache.min_world == cache.max_world -end -notify(c26506_1) -wait(c26506_2) -@test result26506[1] == 3 +@test cache26506.max_world == w26506 +f26506(x::String) = 5 +# The entry we created above should not have been changed +@test cache26506.max_world == w26506 +@test fetch(schedule(t26506)) === 3 +@test g26506(z26506) === 5 # issue #38435 f38435(::Int, ::Any) = 1 From 7db505be0e6f9be2aa513ee793c7919d2a7b4e0f Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Thu, 29 May 2025 14:20:36 -0400 Subject: [PATCH 09/83] MethodTable/Cache PR updates (#58565) Missed updates from early designs in #58131. Fix #58557 (cherry picked from commit 8ce50a01e0306279b37c116520f02aaef8d54285) --- base/methodshow.jl | 4 +- doc/src/devdocs/functions.md | 62 +++++++---------------- doc/src/devdocs/types.md | 27 ++++++---- stdlib/Serialization/src/Serialization.jl | 17 ++----- 4 files changed, 40 insertions(+), 70 deletions(-) diff --git a/base/methodshow.jl b/base/methodshow.jl index dc3f564d70db7..dd391a46d170a 100644 --- a/base/methodshow.jl +++ b/base/methodshow.jl @@ -365,7 +365,7 @@ end show(io::IO, ms::MethodList) = show_method_table(io, ms) show(io::IO, ::MIME"text/plain", ms::MethodList) = show_method_table(io, ms) -show(io::IO, mt::Core.MethodTable) = show_method_table(io, MethodList(mt)) +show(io::IO, mt::Core.MethodTable) = print(io, mt.module, ".", mt.name, " is a Core.MethodTable with ", length(mt), " methods.") function inbase(m::Module) if m == Base @@ -470,8 +470,6 @@ function show(io::IO, mime::MIME"text/html", ms::MethodList) print(io, "
") end -show(io::IO, mime::MIME"text/html", mt::Core.MethodTable) = show(io, mime, MethodList(mt)) - # pretty-printing of AbstractVector{Method} function show(io::IO, mime::MIME"text/plain", mt::AbstractVector{Method}) last_shown_line_infos = get(io, :last_shown_line_infos, nothing) diff --git a/doc/src/devdocs/functions.md b/doc/src/devdocs/functions.md index cfaf40b96a595..0cbbb4623e9fa 100644 --- a/doc/src/devdocs/functions.md +++ b/doc/src/devdocs/functions.md @@ -6,21 +6,17 @@ This document will explain how functions, method definitions, and method tables ## Method Tables Every function in Julia is a generic function. A generic function is conceptually a single function, -but consists of many definitions, or methods. The methods of a generic function are stored in -a method table. Method tables (type `MethodTable`) are associated with `TypeName`s. A `TypeName` -describes a family of parameterized types. For example `Complex{Float32}` and `Complex{Float64}` -share the same `Complex` type name object. - -All objects in Julia are potentially callable, because every object has a type, which in turn -has a `TypeName`. +but consists of many definitions, or methods. The methods of a generic function are stored in a +method table. There is one global method table (type `MethodTable`) named `Core.GlobalMethods`. Any +default operation on methods (such as calls) uses that table. ## [Function calls](@id Function-calls) -Given the call `f(x, y)`, the following steps are performed: first, the method cache to use is -accessed as `typeof(f).name.mt`. Second, an argument tuple type is formed, `Tuple{typeof(f), typeof(x), typeof(y)}`. -Note that the type of the function itself is the first element. This is because the type might -have parameters, and so needs to take part in dispatch. This tuple type is looked up in the method -table. +Given the call `f(x, y)`, the following steps are performed: First, a tuple type is formed, +`Tuple{typeof(f), typeof(x), typeof(y)}`. Note that the type of the function itself is the first +element. This is because the function itself participates symmetrically in method lookup with the +other arguments. This tuple type is looked up in the global method table. However, the system can +then cache the results, so these steps can be skipped later for similar lookups. This dispatch process is performed by `jl_apply_generic`, which takes two arguments: a pointer to an array of the values `f`, `x`, and `y`, and the number of values (in this case 3). @@ -49,15 +45,6 @@ jl_value_t *jl_call(jl_function_t *f, jl_value_t **args, int32_t nargs); Given the above dispatch process, conceptually all that is needed to add a new method is (1) a tuple type, and (2) code for the body of the method. `jl_method_def` implements this operation. -`jl_method_table_for` is called to extract the relevant method table from what would be -the type of the first argument. This is much more complicated than the corresponding procedure -during dispatch, since the argument tuple type might be abstract. For example, we can define: - -```julia -(::Union{Foo{Int},Foo{Int8}})(x) = 0 -``` - -which works since all possible matching methods would belong to the same method table. ## Creating generic functions @@ -94,9 +81,7 @@ end ## Constructors -A constructor call is just a call to a type. The method table for `Type` contains all -constructor definitions. All subtypes of `Type` (`Type`, `UnionAll`, `Union`, and `DataType`) -currently share a method table via special arrangement. +A constructor call is just a call to a type, to a method defined on `Type{T}`. ## Builtins @@ -128,18 +113,14 @@ import Markdown Markdown.parse ``` -These are all singleton objects whose types are subtypes of `Builtin`, which is a subtype of -`Function`. Their purpose is to expose entry points in the run time that use the "jlcall" calling -convention: +These are mostly singleton objects all of whose types are subtypes of `Builtin`, which is a +subtype of `Function`. Their purpose is to expose entry points in the run time that use the +"jlcall" calling convention: ```c jl_value_t *(jl_value_t*, jl_value_t**, uint32_t) ``` -The method tables of builtins are empty. Instead, they have a single catch-all method cache entry -(`Tuple{Vararg{Any}}`) whose jlcall fptr points to the correct function. This is kind of a hack -but works reasonably well. - ## Keyword arguments Keyword arguments work by adding methods to the kwcall function. This function @@ -228,18 +209,13 @@ sees an argument in the `Function` type hierarchy passed to a slot declared as ` it behaves as if the `@nospecialize` annotation were applied. This heuristic seems to be extremely effective in practice. -The next issue concerns the structure of method cache hash tables. Empirical studies show that -the vast majority of dynamically-dispatched calls involve one or two arguments. In turn, many -of these cases can be resolved by considering only the first argument. (Aside: proponents of single -dispatch would not be surprised by this at all. However, this argument means "multiple dispatch -is easy to optimize in practice", and that we should therefore use it, *not* "we should use single -dispatch"!) So the method cache uses the type of the first argument as its primary key. Note, -however, that this corresponds to the *second* element of the tuple type for a function call (the -first element being the type of the function itself). Typically, type variation in head position -is extremely low -- indeed, the majority of functions belong to singleton types with no parameters. -However, this is not the case for constructors, where a single method table holds constructors -for every type. Therefore the `Type` method table is special-cased to use the *first* tuple type -element instead of the second. +The next issue concerns the structure of method tables. Empirical studies show that the vast +majority of dynamically-dispatched calls involve one or two arguments. In turn, many of these cases +can be resolved by considering only the first argument. (Aside: proponents of single dispatch would +not be surprised by this at all. However, this argument means "multiple dispatch is easy to optimize +in practice", and that we should therefore use it, *not* "we should use single dispatch"!). So the +method table and cache splits up on the structure based on a left-to-right decision tree so allow +efficient nearest-neighbor searches. The front end generates type declarations for all closures. Initially, this was implemented by generating normal type declarations. However, this produced an extremely large number of constructors, diff --git a/doc/src/devdocs/types.md b/doc/src/devdocs/types.md index b63f1c315f457..fc4a93b94ca3c 100644 --- a/doc/src/devdocs/types.md +++ b/doc/src/devdocs/types.md @@ -176,7 +176,12 @@ julia> dump(Array{Int,1}.name) TypeName name: Symbol Array module: Module Core - names: empty SimpleVector + singletonname: Symbol Array + names: SimpleVector + 1: Symbol ref + 2: Symbol size + atomicfields: Ptr{Nothing}(0x0000000000000000) + constfields: Ptr{Nothing}(0x0000000000000000) wrapper: UnionAll var: TypeVar name: Symbol T @@ -188,20 +193,20 @@ TypeName lb: Union{} ub: abstract type Any body: mutable struct Array{T, N} <: DenseArray{T, N} + Typeofwrapper: abstract type Type{Array} <: Any cache: SimpleVector ... - linearcache: SimpleVector ... - - hash: Int64 -7900426068641098781 - mt: MethodTable - name: Symbol Array - defs: Nothing nothing - cache: Nothing nothing - module: Module Core - : Int64 0 - : Int64 0 + hash: Int64 2594190783455944385 + backedges: #undef + partial: #undef + max_args: Int32 0 + n_uninitialized: Int32 0 + flags: UInt8 0x02 + cache_entry_count: UInt8 0x00 + max_methods: UInt8 0x00 + constprop_heuristic: UInt8 0x00 ``` In this case, the relevant field is `wrapper`, which holds a reference to the top-level type used diff --git a/stdlib/Serialization/src/Serialization.jl b/stdlib/Serialization/src/Serialization.jl index 9437fedf649ec..3c4152bf10598 100644 --- a/stdlib/Serialization/src/Serialization.jl +++ b/stdlib/Serialization/src/Serialization.jl @@ -469,15 +469,13 @@ end function serialize(s::AbstractSerializer, mt::Core.MethodTable) serialize_type(s, typeof(mt)) - serialize(s, mt.cache) + serialize(s, mt.name) + serialize(s, mt.module) nothing end function serialize(s::AbstractSerializer, mc::Core.MethodCache) - serialize_type(s, typeof(mc)) - serialize(s, mc.name) - serialize(s, mc.module) - nothing + error("cannot serialize MethodCache objects") end @@ -1134,16 +1132,9 @@ function deserialize(s::AbstractSerializer, ::Type{Method}) end function deserialize(s::AbstractSerializer, ::Type{Core.MethodTable}) - mc = deserialize(s)::Core.MethodCache - mc === Core.GlobalMethods.cache && return Core.GlobalMethods - return getglobal(mc.mod, mc.name)::Core.MethodTable -end - -function deserialize(s::AbstractSerializer, ::Type{Core.MethodCache}) name = deserialize(s)::Symbol mod = deserialize(s)::Module - f = Base.unwrap_unionall(getglobal(mod, name)) - return (f::Core.MethodTable).cache + return getglobal(mod, name)::Core.MethodTable end function deserialize(s::AbstractSerializer, ::Type{Core.MethodInstance}) From 54c51d93584300baa3708a1e8bda75ca5ca7a808 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Thu, 29 May 2025 14:53:54 -0400 Subject: [PATCH 10/83] fix breakage with `jl_get_global` (#58540) Introduce a new `jl_get_global_value` to do the new world-aware behavior, while preserving the old behavior for `jl_get_global`. Choose between `jl_get_global`, `jl_get_global_value`, and `jl_eval_global_var`, depending on what behavior is required. Also take this opportunity to fix some data race mistakes introduced by bindings (relaxed loads of jl_world_counter outside of assert) and lacking type asserts / unnecessary globals in precompile code. Fix #58097 Addresses post-review comment https://github.com/JuliaLang/julia/pull/57213#discussion_r1939814835, so this is already tested against by existing logic (cherry picked from commit 965d007479986e1c5f8c7f0e0b0fe17466ee4643) --- base/loading.jl | 8 ++-- src/gf.c | 7 ++-- src/init.c | 14 +++---- src/interpreter.c | 4 +- src/jl_uv.c | 4 +- src/jlapi.c | 4 +- src/julia.h | 8 +--- src/module.c | 41 ++++++++++++-------- src/precompile.c | 35 +++++++++-------- src/rtutils.c | 10 +++-- src/scheduler.c | 9 +++-- src/staticdata_utils.c | 85 +++++++++++++++++++++--------------------- src/task.c | 2 +- src/threading.c | 6 ++- src/toplevel.c | 21 +++++------ sysimage.mk | 6 +-- 16 files changed, 139 insertions(+), 125 deletions(-) diff --git a/base/loading.jl b/base/loading.jl index 49179fa73447d..de212f79e93b7 100644 --- a/base/loading.jl +++ b/base/loading.jl @@ -2213,7 +2213,7 @@ const include_callbacks = Any[] # used to optionally track dependencies when requiring a module: const _concrete_dependencies = Pair{PkgId,UInt128}[] # these dependency versions are "set in stone", because they are explicitly loaded, and the process should try to avoid invalidating them -const _require_dependencies = Any[] # a list of (mod, abspath, fsize, hash, mtime) tuples that are the file dependencies of the module currently being precompiled +const _require_dependencies = Any[] # a list of (mod::Module, abspath::String, fsize::UInt64, hash::UInt32, mtime::Float64) tuples that are the file dependencies of the module currently being precompiled const _track_dependencies = Ref(false) # set this to true to track the list of file dependencies function _include_dependency(mod::Module, _path::AbstractString; track_content::Bool=true, @@ -2239,9 +2239,9 @@ function _include_dependency!(dep_list::Vector{Any}, track_dependencies::Bool, else @lock require_lock begin if track_content - hash = isdir(path) ? _crc32c(join(readdir(path))) : open(_crc32c, path, "r") + hash = (isdir(path) ? _crc32c(join(readdir(path))) : open(_crc32c, path, "r"))::UInt32 # use mtime=-1.0 here so that fsize==0 && mtime==0.0 corresponds to a missing include_dependency - push!(dep_list, (mod, path, filesize(path), hash, -1.0)) + push!(dep_list, (mod, path, UInt64(filesize(path)), hash, -1.0)) else push!(dep_list, (mod, path, UInt64(0), UInt32(0), mtime(path))) end @@ -3337,7 +3337,7 @@ mutable struct CacheHeaderIncludes const modpath::Vector{String} # seemingly not needed in Base, but used by Revise end -function CacheHeaderIncludes(dep_tuple::Tuple{Module, String, Int64, UInt32, Float64}) +function CacheHeaderIncludes(dep_tuple::Tuple{Module, String, UInt64, UInt32, Float64}) return CacheHeaderIncludes(PkgId(dep_tuple[1]), dep_tuple[2:end]..., String[]) end diff --git a/src/gf.c b/src/gf.c index 07143d8902550..43aafa5094037 100644 --- a/src/gf.c +++ b/src/gf.c @@ -512,12 +512,13 @@ JL_DLLEXPORT jl_code_info_t *jl_gdbcodetyped1(jl_method_instance_t *mi, size_t w ct->world_age = jl_typeinf_world; jl_value_t **fargs; JL_GC_PUSHARGS(fargs, 4); - jl_module_t *CC = (jl_module_t*)jl_get_global(jl_core_module, jl_symbol("Compiler")); + jl_module_t *CC = (jl_module_t*)jl_get_global_value(jl_core_module, jl_symbol("Compiler")); if (CC != NULL && jl_is_module(CC)) { - fargs[0] = jl_get_global(CC, jl_symbol("NativeInterpreter"));; + JL_GC_PROMISE_ROOTED(CC); + fargs[0] = jl_get_global_value(CC, jl_symbol("NativeInterpreter"));; fargs[1] = jl_box_ulong(world); fargs[1] = jl_apply(fargs, 2); - fargs[0] = jl_get_global(CC, jl_symbol("typeinf_code")); + fargs[0] = jl_get_global_value(CC, jl_symbol("typeinf_code")); fargs[2] = (jl_value_t*)mi; fargs[3] = jl_true; ci = (jl_code_info_t*)jl_apply(fargs, 4); diff --git a/src/init.c b/src/init.c index c4388589dd581..da95cbd006e73 100644 --- a/src/init.c +++ b/src/init.c @@ -249,7 +249,7 @@ JL_DLLEXPORT void jl_atexit_hook(int exitcode) JL_NOTSAFEPOINT_ENTER if (jl_base_module) { size_t last_age = ct->world_age; ct->world_age = jl_get_world_counter(); - jl_value_t *f = jl_get_global(jl_base_module, jl_symbol("_atexit")); + jl_value_t *f = jl_get_global_value(jl_base_module, jl_symbol("_atexit")); if (f != NULL) { jl_value_t **fargs; JL_GC_PUSHARGS(fargs, 2); @@ -355,13 +355,14 @@ JL_DLLEXPORT void jl_postoutput_hook(void) if (jl_base_module) { jl_task_t *ct = jl_get_current_task(); - jl_value_t *f = jl_get_global(jl_base_module, jl_symbol("_postoutput")); + size_t last_age = ct->world_age; + ct->world_age = jl_get_world_counter(); + jl_value_t *f = jl_get_global_value(jl_base_module, jl_symbol("_postoutput")); if (f != NULL) { JL_TRY { - size_t last_age = ct->world_age; - ct->world_age = jl_get_world_counter(); + JL_GC_PUSH1(&f); jl_apply(&f, 1); - ct->world_age = last_age; + JL_GC_POP(); } JL_CATCH { jl_printf((JL_STREAM*)STDERR_FILENO, "\npostoutput hook threw an error: "); @@ -370,6 +371,7 @@ JL_DLLEXPORT void jl_postoutput_hook(void) jlbacktrace(); // written to STDERR_FILENO } } + ct->world_age = last_age; } return; } @@ -592,7 +594,6 @@ static NOINLINE void _finish_jl_init_(jl_image_buf_t sysimage, jl_ptls_t ptls, j jl_init_primitives(); jl_init_main_module(); jl_load(jl_core_module, "boot.jl"); - jl_current_task->world_age = jl_atomic_load_acquire(&jl_world_counter); post_boot_hooks(); } @@ -605,7 +606,6 @@ static NOINLINE void _finish_jl_init_(jl_image_buf_t sysimage, jl_ptls_t ptls, j jl_n_threads_per_pool[JL_THREADPOOL_ID_INTERACTIVE] = 0; jl_n_threads_per_pool[JL_THREADPOOL_ID_DEFAULT] = 1; } else { - jl_current_task->world_age = jl_atomic_load_acquire(&jl_world_counter); post_image_load_hooks(); } jl_start_threads(); diff --git a/src/interpreter.c b/src/interpreter.c index f71e43757afd9..5df79e77a92c1 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -161,14 +161,16 @@ static jl_value_t *do_invoke(jl_value_t **args, size_t nargs, interpreter_state return result; } +// get the global (throwing if null) in the current world jl_value_t *jl_eval_global_var(jl_module_t *m, jl_sym_t *e) { - jl_value_t *v = jl_get_global(m, e); + jl_value_t *v = jl_get_global_value(m, e); if (v == NULL) jl_undefined_var_error(e, (jl_value_t*)m); return v; } +// get the global (throwing if null) in the current world, optimized jl_value_t *jl_eval_globalref(jl_globalref_t *g) { jl_value_t *v = jl_get_globalref_value(g); diff --git a/src/jl_uv.c b/src/jl_uv.c index 3498952622dce..005d1ea727655 100644 --- a/src/jl_uv.c +++ b/src/jl_uv.c @@ -160,10 +160,10 @@ static void jl_uv_call_close_callback(jl_value_t *val) { jl_value_t **args; JL_GC_PUSHARGS(args, 2); // val is "rooted" in the finalizer list only right now - args[0] = jl_get_global(jl_base_relative_to(((jl_datatype_t*)jl_typeof(val))->name->module), + args[0] = jl_eval_global_var( + jl_base_relative_to(((jl_datatype_t*)jl_typeof(val))->name->module), jl_symbol("_uv_hook_close")); // topmod(typeof(val))._uv_hook_close args[1] = val; - assert(args[0]); jl_apply(args, 2); // TODO: wrap in try-catch? JL_GC_POP(); } diff --git a/src/jlapi.c b/src/jlapi.c index 47d5b84fa5606..0290f12cb1de9 100644 --- a/src/jlapi.c +++ b/src/jlapi.c @@ -951,12 +951,14 @@ static NOINLINE int true_main(int argc, char *argv[]) ct->world_age = jl_get_world_counter(); jl_function_t *start_client = jl_base_module ? - (jl_function_t*)jl_get_global(jl_base_module, jl_symbol("_start")) : NULL; + (jl_function_t*)jl_get_global_value(jl_base_module, jl_symbol("_start")) : NULL; if (start_client) { int ret = 1; JL_TRY { + JL_GC_PUSH1(&start_client); jl_value_t *r = jl_apply(&start_client, 1); + JL_GC_POP(); if (jl_typeof(r) != (jl_value_t*)jl_int32_type) jl_type_error("typeassert", (jl_value_t*)jl_int32_type, r); ret = jl_unbox_int32(r); diff --git a/src/julia.h b/src/julia.h index fdcc78f3b7a17..0fd0827f95f09 100644 --- a/src/julia.h +++ b/src/julia.h @@ -2119,6 +2119,7 @@ JL_DLLEXPORT int jl_is_const(jl_module_t *m, jl_sym_t *var); JL_DLLEXPORT int jl_globalref_is_const(jl_globalref_t *gr); JL_DLLEXPORT jl_value_t *jl_get_globalref_value(jl_globalref_t *gr); JL_DLLEXPORT jl_value_t *jl_get_global(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var); +JL_DLLEXPORT jl_value_t *jl_get_global_value(jl_module_t *m, jl_sym_t *var); JL_DLLEXPORT void jl_set_global(jl_module_t *m JL_ROOTING_ARGUMENT, jl_sym_t *var, jl_value_t *val JL_ROOTED_ARGUMENT); JL_DLLEXPORT void jl_set_const(jl_module_t *m JL_ROOTING_ARGUMENT, jl_sym_t *var, jl_value_t *val JL_ROOTED_ARGUMENT); void jl_set_initial_const(jl_module_t *m JL_ROOTING_ARGUMENT, jl_sym_t *var, jl_value_t *val JL_ROOTED_ARGUMENT, int exported); @@ -2724,12 +2725,7 @@ JL_DLLEXPORT jl_task_t *jl_get_current_task(void) JL_GLOBALLY_ROOTED JL_NOTSAFEP STATIC_INLINE jl_function_t *jl_get_function(jl_module_t *m, const char *name) { - jl_task_t *ct = jl_get_current_task(); - size_t last_world = ct->world_age; - ct->world_age = jl_get_world_counter(); - jl_value_t *r = jl_get_global(m, jl_symbol(name)); - ct->world_age = last_world; - return (jl_function_t*)r; + return (jl_function_t*)jl_get_global(m, jl_symbol(name)); } // TODO: we need to pin the task while using this (set pure bit) diff --git a/src/module.c b/src/module.c index 884e55607665b..da7b2e79f62d1 100644 --- a/src/module.c +++ b/src/module.c @@ -366,7 +366,7 @@ JL_DLLEXPORT jl_binding_partition_t *jl_maybe_reresolve_implicit(jl_binding_t *b JL_DLLEXPORT void jl_update_loaded_bpart(jl_binding_t *b, jl_binding_partition_t *bpart) { - struct implicit_search_resolution resolution = jl_resolve_implicit_import(b, NULL, jl_atomic_load_relaxed(&jl_world_counter), 0); + struct implicit_search_resolution resolution = jl_resolve_implicit_import(b, NULL, jl_atomic_load_acquire(&jl_world_counter), 0); jl_atomic_store_relaxed(&bpart->min_world, resolution.min_world); jl_atomic_store_relaxed(&bpart->max_world, resolution.max_world); bpart->restriction = resolution.binding_or_const; @@ -831,11 +831,12 @@ JL_DLLEXPORT jl_binding_t *jl_get_binding_wr(jl_module_t *m JL_PROPAGATES_ROOT, // return module of binding JL_DLLEXPORT jl_module_t *jl_get_module_of_binding(jl_module_t *m, jl_sym_t *var) { + size_t world = jl_current_task->world_age; jl_binding_t *b = jl_get_module_binding(m, var, 1); - jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); - jl_walk_binding_inplace(&b, &bpart, jl_current_task->world_age); + jl_binding_partition_t *bpart = jl_get_binding_partition(b, world); + jl_walk_binding_inplace(&b, &bpart, world); if (jl_binding_kind(bpart) == PARTITION_KIND_IMPLICIT_CONST) { - struct implicit_search_resolution resolution = jl_resolve_implicit_import(b, NULL, jl_current_task->world_age, 0); + struct implicit_search_resolution resolution = jl_resolve_implicit_import(b, NULL, world, 0); if (!resolution.debug_only_ultimate_binding) jl_error("Constant binding was imported from multiple modules"); b = resolution.debug_only_ultimate_binding; @@ -885,16 +886,17 @@ JL_DLLEXPORT jl_value_t *jl_get_binding_value_in_world(jl_binding_t *b, size_t w return jl_atomic_load_relaxed(&b->value); } -JL_DLLEXPORT jl_value_t *jl_get_binding_value_depwarn(jl_binding_t *b) +static jl_value_t *jl_get_binding_value_depwarn(jl_binding_t *b, size_t world) { - jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); + jl_binding_partition_t *bpart = jl_get_binding_partition(b, world); if (jl_options.depwarn) { int needs_depwarn = 0; - jl_walk_binding_inplace_depwarn(&b, &bpart, jl_current_task->world_age, &needs_depwarn); + jl_walk_binding_inplace_depwarn(&b, &bpart, world, &needs_depwarn); if (needs_depwarn) jl_binding_deprecation_warning(b); - } else { - jl_walk_binding_inplace(&b, &bpart, jl_current_task->world_age); + } + else { + jl_walk_binding_inplace(&b, &bpart, world); } enum jl_partition_kind kind = jl_binding_kind(bpart); if (jl_bkind_is_some_guard(kind)) @@ -907,11 +909,11 @@ JL_DLLEXPORT jl_value_t *jl_get_binding_value_depwarn(jl_binding_t *b) return jl_atomic_load_relaxed(&b->value); } - JL_DLLEXPORT jl_value_t *jl_get_binding_value_seqcst(jl_binding_t *b) { - jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); - jl_walk_binding_inplace(&b, &bpart, jl_current_task->world_age); + size_t world = jl_current_task->world_age; + jl_binding_partition_t *bpart = jl_get_binding_partition(b, world); + jl_walk_binding_inplace(&b, &bpart, world); enum jl_partition_kind kind = jl_binding_kind(bpart); if (jl_bkind_is_some_guard(kind)) return NULL; @@ -926,7 +928,7 @@ JL_DLLEXPORT jl_value_t *jl_get_binding_value_seqcst(jl_binding_t *b) JL_DLLEXPORT jl_value_t *jl_get_latest_binding_value_if_const(jl_binding_t *b) { // See note below. Note that this is for some deprecated uses, and should not be added to new code. - size_t world = jl_atomic_load_relaxed(&jl_world_counter); + size_t world = jl_atomic_load_acquire(&jl_world_counter); jl_binding_partition_t *bpart = jl_get_binding_partition(b, world); jl_walk_binding_inplace(&b, &bpart, world); enum jl_partition_kind kind = jl_binding_kind(bpart); @@ -1535,18 +1537,27 @@ JL_DLLEXPORT jl_binding_t *jl_get_module_binding(jl_module_t *m, jl_sym_t *var, } +// get the value (or null) in the current world JL_DLLEXPORT jl_value_t *jl_get_globalref_value(jl_globalref_t *gr) { jl_binding_t *b = gr->binding; if (!b) b = jl_get_module_binding(gr->mod, gr->name, 1); - return jl_get_binding_value_depwarn(b); + return jl_get_binding_value_depwarn(b, jl_current_task->world_age); +} + +// get the value (or null) in the current world +JL_DLLEXPORT jl_value_t *jl_get_global_value(jl_module_t *m, jl_sym_t *var) +{ + jl_binding_t *b = jl_get_module_binding(m, var, 1); + return jl_get_binding_value_depwarn(b, jl_current_task->world_age); } +// get the global (or null) in the latest world JL_DLLEXPORT jl_value_t *jl_get_global(jl_module_t *m, jl_sym_t *var) { jl_binding_t *b = jl_get_module_binding(m, var, 1); - return jl_get_binding_value_depwarn(b); + return jl_get_binding_value_depwarn(b, jl_atomic_load_acquire(&jl_world_counter)); } JL_DLLEXPORT void jl_set_global(jl_module_t *m JL_ROOTING_ARGUMENT, jl_sym_t *var, jl_value_t *val JL_ROOTED_ARGUMENT) diff --git a/src/precompile.c b/src/precompile.c index c21cf5367fba6..33b71d4605b30 100644 --- a/src/precompile.c +++ b/src/precompile.c @@ -36,27 +36,30 @@ void write_srctext(ios_t *f, jl_array_t *udeps, int64_t srctextpos) { // char*: src text // At the end we write int32(0) as a terminal sentinel. size_t len = jl_array_nrows(udeps); - static jl_value_t *replace_depot_func = NULL; - if (!replace_depot_func) - replace_depot_func = jl_get_global(jl_base_module, jl_symbol("replace_depot_path")); - static jl_value_t *normalize_depots_func = NULL; - if (!normalize_depots_func) - normalize_depots_func = jl_get_global(jl_base_module, jl_symbol("normalize_depots_for_relocation")); ios_t srctext; - jl_value_t *deptuple = NULL, *depots = NULL; - JL_GC_PUSH3(&deptuple, &udeps, &depots); + jl_value_t *replace_depot_func = NULL; + jl_value_t *normalize_depots_func = NULL; + jl_value_t *deptuple = NULL; + jl_value_t *depots = NULL; jl_task_t *ct = jl_current_task; size_t last_age = ct->world_age; ct->world_age = jl_atomic_load_acquire(&jl_world_counter); + JL_GC_PUSH4(&deptuple, &depots, &replace_depot_func, &normalize_depots_func); + replace_depot_func = jl_eval_global_var(jl_base_module, jl_symbol("replace_depot_path")); + normalize_depots_func = jl_eval_global_var(jl_base_module, jl_symbol("normalize_depots_for_relocation")); depots = jl_apply(&normalize_depots_func, 1); - ct->world_age = last_age; + jl_datatype_t *deptuple_p[5] = {jl_module_type, jl_string_type, jl_uint64_type, jl_uint32_type, jl_float64_type}; + jl_value_t *jl_deptuple_type = jl_apply_tuple_type_v((jl_value_t**)deptuple_p, 5); + JL_GC_PROMISE_ROOTED(jl_deptuple_type); +#define jl_is_deptuple(v) (jl_typeis((v), jl_deptuple_type)) for (size_t i = 0; i < len; i++) { deptuple = jl_array_ptr_ref(udeps, i); - jl_value_t *depmod = jl_fieldref(deptuple, 0); // module + jl_value_t *depmod = jl_fieldref_noalloc(deptuple, 0); // module // Dependencies declared with `include_dependency` are excluded // because these may not be Julia code (and could be huge) + JL_TYPECHK(write_srctext, deptuple, deptuple); if (depmod != (jl_value_t*)jl_main_module) { - jl_value_t *abspath = jl_fieldref(deptuple, 1); // file abspath + jl_value_t *abspath = jl_fieldref_noalloc(deptuple, 1); // file abspath const char *abspathstr = jl_string_data(abspath); if (!abspathstr[0]) continue; @@ -67,17 +70,11 @@ void write_srctext(ios_t *f, jl_array_t *udeps, int64_t srctextpos) { continue; } - jl_value_t **replace_depot_args; - JL_GC_PUSHARGS(replace_depot_args, 3); + jl_value_t *replace_depot_args[3]; replace_depot_args[0] = replace_depot_func; replace_depot_args[1] = abspath; replace_depot_args[2] = depots; - jl_task_t *ct = jl_current_task; - size_t last_age = ct->world_age; - ct->world_age = jl_atomic_load_acquire(&jl_world_counter); jl_value_t *depalias = (jl_value_t*)jl_apply(replace_depot_args, 3); - ct->world_age = last_age; - JL_GC_POP(); size_t slen = jl_string_len(depalias); write_int32(f, slen); @@ -91,6 +88,8 @@ void write_srctext(ios_t *f, jl_array_t *udeps, int64_t srctextpos) { ios_seek_end(f); } } + ct->world_age = last_age; +#undef jl_is_deptuple JL_GC_POP(); } write_int32(f, 0); // mark the end of the source text diff --git a/src/rtutils.c b/src/rtutils.c index 286e0e147581c..d5ec8a78b39ce 100644 --- a/src/rtutils.c +++ b/src/rtutils.c @@ -1589,15 +1589,17 @@ JL_DLLEXPORT void jl_test_failure_breakpoint(jl_value_t *v) // logging tools -------------------------------------------------------------- +// DO NOT USE THIS FUNCTION FOR NEW CODE +// The internal should not be doing anything that requires logging, which means most functions would trigger UB if calling this void jl_log(int level, jl_value_t *module, jl_value_t *group, jl_value_t *id, jl_value_t *file, jl_value_t *line, jl_value_t *kwargs, jl_value_t *msg) { - static jl_value_t *logmsg_func = NULL; - if (!logmsg_func && jl_base_module) { - jl_value_t *corelogging = jl_get_global(jl_base_module, jl_symbol("CoreLogging")); + jl_value_t *logmsg_func = NULL; + if (jl_base_module) { + jl_value_t *corelogging = jl_get_global_value(jl_base_module, jl_symbol("CoreLogging")); if (corelogging && jl_is_module(corelogging)) { - logmsg_func = jl_get_global((jl_module_t*)corelogging, jl_symbol("logmsg_shim")); + logmsg_func = jl_get_global_value((jl_module_t*)corelogging, jl_symbol("logmsg_shim")); } } if (!logmsg_func) { diff --git a/src/scheduler.c b/src/scheduler.c index 731a0c5146605..8e0202cc7a980 100644 --- a/src/scheduler.c +++ b/src/scheduler.c @@ -329,12 +329,15 @@ void jl_task_wait_empty(void) jl_task_t *ct = jl_current_task; if (jl_atomic_load_relaxed(&ct->tid) == 0 && jl_base_module) { jl_wait_empty_begin(); - jl_value_t *f = jl_get_global(jl_base_module, jl_symbol("wait")); - wait_empty = ct; size_t lastage = ct->world_age; ct->world_age = jl_atomic_load_acquire(&jl_world_counter); - if (f) + jl_value_t *f = jl_get_global_value(jl_base_module, jl_symbol("wait")); + wait_empty = ct; + if (f) { + JL_GC_PUSH1(&f); jl_apply_generic(f, NULL, 0); + JL_GC_POP(); + } // we are back from jl_task_get_next now ct->world_age = lastage; wait_empty = NULL; diff --git a/src/staticdata_utils.c b/src/staticdata_utils.c index d699e0c262d26..3f05de189c3ef 100644 --- a/src/staticdata_utils.c +++ b/src/staticdata_utils.c @@ -532,35 +532,40 @@ static int64_t write_dependency_list(ios_t *s, jl_array_t* worklist, jl_array_t { int64_t initial_pos = 0; int64_t pos = 0; - static jl_array_t *deps = NULL; - if (!deps) - deps = (jl_array_t*)jl_get_global(jl_base_module, jl_symbol("_require_dependencies")); - - // unique(deps) to eliminate duplicates while preserving order: - // we preserve order so that the topmost included .jl file comes first - static jl_value_t *unique_func = NULL; - if (!unique_func) - unique_func = jl_get_global(jl_base_module, jl_symbol("unique")); - jl_value_t *uniqargs[2] = {unique_func, (jl_value_t*)deps}; jl_task_t *ct = jl_current_task; size_t last_age = ct->world_age; ct->world_age = jl_atomic_load_acquire(&jl_world_counter); - jl_array_t *udeps = (*udepsp = deps && unique_func ? (jl_array_t*)jl_apply(uniqargs, 2) : NULL); - ct->world_age = last_age; + jl_value_t *depots = NULL, *prefs_hash = NULL, *prefs_list = NULL; + jl_value_t *unique_func = NULL; + jl_value_t *replace_depot_func = NULL; + jl_value_t *normalize_depots_func = NULL; + jl_value_t *toplevel = NULL; + jl_value_t *prefs_hash_func = NULL; + jl_value_t *get_compiletime_prefs_func = NULL; + JL_GC_PUSH8(&depots, &prefs_list, &unique_func, &replace_depot_func, &normalize_depots_func, &toplevel, &prefs_hash_func, &get_compiletime_prefs_func); + + jl_array_t *udeps = (jl_array_t*)jl_get_global_value(jl_base_module, jl_symbol("_require_dependencies")); + *udepsp = udeps; + + // unique(udeps) to eliminate duplicates while preserving order: + // we preserve order so that the topmost included .jl file comes first + if (udeps) { + unique_func = jl_eval_global_var(jl_base_module, jl_symbol("unique")); + jl_value_t *uniqargs[2] = {unique_func, (jl_value_t*)udeps}; + udeps = (jl_array_t*)jl_apply(uniqargs, 2); + *udepsp = udeps; + JL_TYPECHK(write_dependency_list, array_any, (jl_value_t*)udeps); + } - static jl_value_t *replace_depot_func = NULL; - if (!replace_depot_func) - replace_depot_func = jl_get_global(jl_base_module, jl_symbol("replace_depot_path")); - static jl_value_t *normalize_depots_func = NULL; - if (!normalize_depots_func) - normalize_depots_func = jl_get_global(jl_base_module, jl_symbol("normalize_depots_for_relocation")); + replace_depot_func = jl_get_global_value(jl_base_module, jl_symbol("replace_depot_path")); + normalize_depots_func = jl_eval_global_var(jl_base_module, jl_symbol("normalize_depots_for_relocation")); - jl_value_t *depots = NULL, *prefs_hash = NULL, *prefs_list = NULL; - JL_GC_PUSH2(&depots, &prefs_list); - last_age = ct->world_age; - ct->world_age = jl_atomic_load_acquire(&jl_world_counter); depots = jl_apply(&normalize_depots_func, 1); - ct->world_age = last_age; + + jl_datatype_t *deptuple_p[5] = {jl_module_type, jl_string_type, jl_uint64_type, jl_uint32_type, jl_float64_type}; + jl_value_t *jl_deptuple_type = jl_apply_tuple_type_v((jl_value_t**)deptuple_p, 5); + JL_GC_PROMISE_ROOTED(jl_deptuple_type); +#define jl_is_deptuple(v) (jl_typeis((v), jl_deptuple_type)) // write a placeholder for total size so that we can quickly seek past all of the // dependencies if we don't need them @@ -569,20 +574,16 @@ static int64_t write_dependency_list(ios_t *s, jl_array_t* worklist, jl_array_t size_t i, l = udeps ? jl_array_nrows(udeps) : 0; for (i = 0; i < l; i++) { jl_value_t *deptuple = jl_array_ptr_ref(udeps, i); - jl_value_t *deppath = jl_fieldref(deptuple, 1); + JL_TYPECHK(write_dependency_list, deptuple, deptuple); + jl_value_t *deppath = jl_fieldref_noalloc(deptuple, 1); if (replace_depot_func) { - jl_value_t **replace_depot_args; - JL_GC_PUSHARGS(replace_depot_args, 3); + jl_value_t *replace_depot_args[3]; replace_depot_args[0] = replace_depot_func; replace_depot_args[1] = deppath; replace_depot_args[2] = depots; - ct = jl_current_task; - size_t last_age = ct->world_age; - ct->world_age = jl_atomic_load_acquire(&jl_world_counter); deppath = (jl_value_t*)jl_apply(replace_depot_args, 3); - ct->world_age = last_age; - JL_GC_POP(); + JL_TYPECHK(write_dependency_list, string, deppath); } size_t slen = jl_string_len(deppath); @@ -591,7 +592,7 @@ static int64_t write_dependency_list(ios_t *s, jl_array_t* worklist, jl_array_t write_uint64(s, jl_unbox_uint64(jl_fieldref(deptuple, 2))); // fsize write_uint32(s, jl_unbox_uint32(jl_fieldref(deptuple, 3))); // hash write_float64(s, jl_unbox_float64(jl_fieldref(deptuple, 4))); // mtime - jl_module_t *depmod = (jl_module_t*)jl_fieldref(deptuple, 0); // evaluating module + jl_module_t *depmod = (jl_module_t*)jl_fieldref_noalloc(deptuple, 0); // evaluating module jl_module_t *depmod_top = depmod; while (!is_serialization_root_module(depmod_top)) depmod_top = depmod_top->parent; @@ -615,34 +616,31 @@ static int64_t write_dependency_list(ios_t *s, jl_array_t* worklist, jl_array_t // Calculate Preferences hash for current package. if (jl_base_module) { // Toplevel module is the module we're currently compiling, use it to get our preferences hash - jl_value_t * toplevel = (jl_value_t*)jl_get_global(jl_base_module, jl_symbol("__toplevel__")); - jl_value_t * prefs_hash_func = jl_get_global(jl_base_module, jl_symbol("get_preferences_hash")); - jl_value_t * get_compiletime_prefs_func = jl_get_global(jl_base_module, jl_symbol("get_compiletime_preferences")); - - if (toplevel && prefs_hash_func && get_compiletime_prefs_func) { - // Temporary invoke in newest world age - size_t last_age = ct->world_age; - ct->world_age = jl_atomic_load_acquire(&jl_world_counter); + toplevel = jl_get_global_value(jl_base_module, jl_symbol("__toplevel__")); + prefs_hash_func = jl_eval_global_var(jl_base_module, jl_symbol("get_preferences_hash")); + get_compiletime_prefs_func = jl_eval_global_var(jl_base_module, jl_symbol("get_compiletime_preferences")); + if (toplevel) { // call get_compiletime_prefs(__toplevel__) jl_value_t *args[3] = {get_compiletime_prefs_func, (jl_value_t*)toplevel, NULL}; prefs_list = (jl_value_t*)jl_apply(args, 2); + JL_TYPECHK(write_dependency_list, array, prefs_list); // Call get_preferences_hash(__toplevel__, prefs_list) args[0] = prefs_hash_func; args[2] = prefs_list; prefs_hash = (jl_value_t*)jl_apply(args, 3); - - // Reset world age to normal - ct->world_age = last_age; + JL_TYPECHK(write_dependency_list, uint64, prefs_hash); } } + ct->world_age = last_age; // If we successfully got the preferences, write it out, otherwise write `0` for this `.ji` file. if (prefs_hash != NULL && prefs_list != NULL) { size_t i, l = jl_array_nrows(prefs_list); for (i = 0; i < l; i++) { jl_value_t *pref_name = jl_array_ptr_ref(prefs_list, i); + JL_TYPECHK(write_dependency_list, string, pref_name); size_t slen = jl_string_len(pref_name); write_int32(s, slen); ios_write(s, jl_string_data(pref_name), slen); @@ -660,6 +658,7 @@ static int64_t write_dependency_list(ios_t *s, jl_array_t* worklist, jl_array_t write_uint64(s, 0); } JL_GC_POP(); // for depots, prefs_list +#undef jl_is_deptuple // write a dummy file position to indicate the beginning of the source-text pos = ios_pos(s); diff --git a/src/task.c b/src/task.c index 37e7f0e1f5440..c4976b5be0150 100644 --- a/src/task.c +++ b/src/task.c @@ -335,7 +335,7 @@ void JL_NORETURN jl_finish_task(jl_task_t *ct) // let the runtime know this task is dead and find a new task to run jl_function_t *done = jl_atomic_load_relaxed(&task_done_hook_func); if (done == NULL) { - done = (jl_function_t*)jl_get_global(jl_base_module, jl_symbol("task_done_hook")); + done = (jl_function_t*)jl_get_global_value(jl_base_module, jl_symbol("task_done_hook")); if (done != NULL) jl_atomic_store_release(&task_done_hook_func, done); } diff --git a/src/threading.c b/src/threading.c index 4ab0f7630f560..889a1c651d9c9 100644 --- a/src/threading.c +++ b/src/threading.c @@ -404,9 +404,11 @@ static _Atomic(jl_function_t*) init_task_lock_func JL_GLOBALLY_ROOTED = NULL; static void jl_init_task_lock(jl_task_t *ct) { + size_t last_age = ct->world_age; + ct->world_age = jl_get_world_counter(); jl_function_t *done = jl_atomic_load_relaxed(&init_task_lock_func); if (done == NULL) { - done = (jl_function_t*)jl_get_global(jl_base_module, jl_symbol("init_task_lock")); + done = (jl_function_t*)jl_get_global_value(jl_base_module, jl_symbol("init_task_lock")); if (done != NULL) jl_atomic_store_release(&init_task_lock_func, done); } @@ -419,6 +421,7 @@ static void jl_init_task_lock(jl_task_t *ct) jl_no_exc_handler(jl_current_exception(ct), ct); } } + ct->world_age = last_age; } JL_DLLEXPORT jl_gcframe_t **jl_adopt_thread(void) @@ -441,7 +444,6 @@ JL_DLLEXPORT jl_gcframe_t **jl_adopt_thread(void) JL_GC_PROMISE_ROOTED(ct); uv_random(NULL, NULL, &ct->rngState, sizeof(ct->rngState), 0, NULL); jl_atomic_fetch_add(&jl_gc_disable_counter, -1); - ct->world_age = jl_get_world_counter(); // root_task sets world_age to 1 jl_init_task_lock(ct); return &ct->gcstack; } diff --git a/src/toplevel.c b/src/toplevel.c index efdd29cb01030..21ac7cc716b6c 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -54,12 +54,6 @@ void jl_init_main_module(void) jl_set_initial_const(jl_main_module, jl_symbol("Core"), (jl_value_t*)jl_core_module, 0); // const Core.Main = Main } -static jl_function_t *jl_module_get_initializer(jl_module_t *m JL_PROPAGATES_ROOT) -{ - return (jl_function_t*)jl_get_global(m, jl_symbol("__init__")); -} - - void jl_module_run_initializer(jl_module_t *m) { JL_TIMING(INIT_MODULE, INIT_MODULE); @@ -68,9 +62,12 @@ void jl_module_run_initializer(jl_module_t *m) size_t last_age = ct->world_age; JL_TRY { ct->world_age = jl_atomic_load_acquire(&jl_world_counter); - jl_function_t *f = jl_module_get_initializer(m); - if (f != NULL) + jl_value_t *f = jl_get_global_value(m, jl_symbol("__init__")); + if (f != NULL) { + JL_GC_PUSH1(&f); jl_apply(&f, 1); + JL_GC_POP(); + } ct->world_age = last_age; } JL_CATCH { @@ -110,7 +107,7 @@ jl_array_t *jl_get_loaded_modules(void) static int jl_is__toplevel__mod(jl_module_t *mod) { return jl_base_module && - (jl_value_t*)mod == jl_get_global(jl_base_module, jl_symbol("__toplevel__")); + (jl_value_t*)mod == jl_get_global_value(jl_base_module, jl_symbol("__toplevel__")); } // TODO: add locks around global state mutation operations @@ -1091,7 +1088,7 @@ JL_DLLEXPORT jl_value_t *jl_toplevel_eval_in(jl_module_t *m, jl_value_t *ex) jl_filename = "none"; size_t last_age = ct->world_age; JL_TRY { - ct->world_age = jl_atomic_load_relaxed(&jl_world_counter); + ct->world_age = jl_atomic_load_acquire(&jl_world_counter); v = jl_toplevel_eval(m, ex); } JL_CATCH { @@ -1150,10 +1147,10 @@ static jl_value_t *jl_parse_eval_all(jl_module_t *module, jl_value_t *text, jl_lineno = lineno; continue; } - ct->world_age = jl_atomic_load_relaxed(&jl_world_counter); + ct->world_age = jl_atomic_load_acquire(&jl_world_counter); expression = jl_expand_with_loc_warn(expression, module, jl_string_data(filename), lineno); - ct->world_age = jl_atomic_load_relaxed(&jl_world_counter); + ct->world_age = jl_atomic_load_acquire(&jl_world_counter); result = jl_toplevel_eval_flex(module, expression, 1, 1, &filename_str, &lineno); } ct->world_age = last_age; diff --git a/sysimage.mk b/sysimage.mk index 55a28695acceb..abb5243de4275 100644 --- a/sysimage.mk +++ b/sysimage.mk @@ -70,14 +70,14 @@ RELDATADIR := $(call rel_path,$(JULIAHOME)/base,$(build_datarootdir))/ # <-- mak $(build_private_libdir)/basecompiler.ji: $(COMPILER_SRCS) @$(call PRINT_JULIA, cd $(JULIAHOME)/base && \ JULIA_NUM_THREADS=1 $(call spawn,$(JULIA_EXECUTABLE)) -C "$(JULIA_CPU_TARGET)" $(HEAPLIM) --output-ji $(call cygpath_w,$@).tmp \ - --startup-file=no --warn-overwrite=yes -g$(BOOTSTRAP_DEBUG_LEVEL) -O1 Base_compiler.jl --buildroot $(RELBUILDROOT) --dataroot $(RELDATADIR)) + --startup-file=no --warn-overwrite=yes --depwarn=error -g$(BOOTSTRAP_DEBUG_LEVEL) -O1 Base_compiler.jl --buildroot $(RELBUILDROOT) --dataroot $(RELDATADIR)) @mv $@.tmp $@ $(build_private_libdir)/sys.ji: $(build_private_libdir)/basecompiler.ji $(JULIAHOME)/VERSION $(BASE_SRCS) $(STDLIB_SRCS) @$(call PRINT_JULIA, cd $(JULIAHOME)/base && \ if ! JULIA_BINDIR=$(call cygpath_w,$(build_bindir)) WINEPATH="$(call cygpath_w,$(build_bindir));$$WINEPATH" \ JULIA_NUM_THREADS=1 $(call spawn, $(JULIA_EXECUTABLE)) -g1 -O1 -C "$(JULIA_CPU_TARGET)" $(HEAPLIM) --output-ji $(call cygpath_w,$@).tmp $(JULIA_SYSIMG_BUILD_FLAGS) \ - --startup-file=no --warn-overwrite=yes --sysimage $(call cygpath_w,$<) sysimg.jl --buildroot $(RELBUILDROOT) --dataroot $(RELDATADIR); then \ + --startup-file=no --warn-overwrite=yes --depwarn=error --sysimage $(call cygpath_w,$<) sysimg.jl --buildroot $(RELBUILDROOT) --dataroot $(RELDATADIR); then \ echo '*** This error might be fixed by running `make clean`. If the error persists$(COMMA) try `make cleanall`. ***'; \ false; \ fi ) @@ -93,7 +93,7 @@ $$(build_private_libdir)/sys$1-o.a $$(build_private_libdir)/sys$1-bc.a : $$(buil JULIA_DEPOT_PATH=':' \ JULIA_NUM_THREADS=1 \ $$(call spawn, $3) $2 -C "$$(JULIA_CPU_TARGET)" $$(HEAPLIM) --output-$$* $$(call cygpath_w,$$@).tmp $$(JULIA_SYSIMG_BUILD_FLAGS) \ - --startup-file=no --warn-overwrite=yes --sysimage $$(call cygpath_w,$$<) $$(call cygpath_w,$$(JULIAHOME)/contrib/generate_precompile.jl) $(JULIA_PRECOMPILE); then \ + --startup-file=no --warn-overwrite=yes --depwarn=error --sysimage $$(call cygpath_w,$$<) $$(call cygpath_w,$$(JULIAHOME)/contrib/generate_precompile.jl) $(JULIA_PRECOMPILE); then \ echo '*** This error is usually fixed by running `make clean`. If the error persists$$(COMMA) try `make cleanall`. ***'; \ false; \ fi ) From 2eb17ecaef7e93d377b462a26c8bd8ffe7424a93 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Thu, 5 Jun 2025 05:55:19 +0200 Subject: [PATCH 11/83] Detect Apple M4 and some related changes (#58301) The A15 was detected as M2; added codenames for easier future updates. Sources: - https://asahilinux.org/docs/hw/soc/soc-codenames/#socs - https://github.com/apple-oss-distributions/xnu/blob/main/osfmk/arm/cpuid.h - https://github.com/llvm/llvm-project/blob/main/llvm/lib/Target/AArch64/AArch64Processors.td#L428 Missing: - the M4 Pro and Max are missing (because they are missing from Apple's `cpuid.h`) Resolves #58278 --------- Co-authored-by: Christian Guinard <28689358+christiangnrd@users.noreply.github.com> (cherry picked from commit 7cb88d6951c9725f05426fcb110ee49bec4b147e) --- src/processor_arm.cpp | 79 +++++++++++++++++++++++++++++++------------ 1 file changed, 58 insertions(+), 21 deletions(-) diff --git a/src/processor_arm.cpp b/src/processor_arm.cpp index 66704a718a14d..b73f5c3e4bbac 100644 --- a/src/processor_arm.cpp +++ b/src/processor_arm.cpp @@ -166,9 +166,11 @@ enum class CPU : uint32_t { apple_a14, apple_a15, apple_a16, + apple_a17, apple_m1, apple_m2, apple_m3, + apple_m4, apple_s4, apple_s5, @@ -355,9 +357,11 @@ constexpr auto apple_a13 = armv8_4a_crypto | get_feature_masks(fp16fml, fullfp16 constexpr auto apple_a14 = armv8_5a_crypto | get_feature_masks(dotprod,fp16fml, fullfp16, sha3); constexpr auto apple_a15 = armv8_5a_crypto | get_feature_masks(dotprod,fp16fml, fullfp16, sha3, i8mm, bf16); constexpr auto apple_a16 = armv8_5a_crypto | get_feature_masks(dotprod,fp16fml, fullfp16, sha3, i8mm, bf16); +constexpr auto apple_a17 = armv8_5a_crypto | get_feature_masks(dotprod,fp16fml, fullfp16, sha3, i8mm, bf16); constexpr auto apple_m1 = armv8_5a_crypto | get_feature_masks(dotprod,fp16fml, fullfp16, sha3); constexpr auto apple_m2 = armv8_5a_crypto | get_feature_masks(dotprod,fp16fml, fullfp16, sha3, i8mm, bf16); constexpr auto apple_m3 = armv8_5a_crypto | get_feature_masks(dotprod,fp16fml, fullfp16, sha3, i8mm, bf16); +constexpr auto apple_m4 = armv8_5a_crypto | get_feature_masks(dotprod,fp16fml, fullfp16, sha3, i8mm, bf16); // Features based on https://github.com/llvm/llvm-project/blob/82507f1798768280cf5d5aab95caaafbc7fe6f47/llvm/include/llvm/Support/AArch64TargetParser.def // and sysctl -a hw.optional constexpr auto apple_s4 = apple_a12; @@ -441,9 +445,11 @@ static constexpr CPUSpec cpus[] = { {"apple-a14", CPU::apple_a14, CPU::apple_a13, 120000, Feature::apple_a14}, {"apple-a15", CPU::apple_a15, CPU::apple_a14, 160000, Feature::apple_a15}, {"apple-a16", CPU::apple_a16, CPU::apple_a14, 160000, Feature::apple_a16}, + {"apple-a17", CPU::apple_a17, CPU::apple_a16, 190000, Feature::apple_a17}, {"apple-m1", CPU::apple_m1, CPU::apple_a14, 130000, Feature::apple_m1}, {"apple-m2", CPU::apple_m2, CPU::apple_m1, 160000, Feature::apple_m2}, {"apple-m3", CPU::apple_m3, CPU::apple_m2, 180000, Feature::apple_m3}, + {"apple-m4", CPU::apple_m4, CPU::apple_m3, 190000, Feature::apple_m4}, {"apple-s4", CPU::apple_s4, CPU::generic, 100000, Feature::apple_s4}, {"apple-s5", CPU::apple_s5, CPU::generic, 100000, Feature::apple_s5}, {"thunderx3t110", CPU::marvell_thunderx3t110, CPU::cavium_thunderx2t99, 110000, @@ -722,6 +728,8 @@ static NOINLINE std::pair> _get_host_cpu() return std::make_pair((uint32_t)CPU::apple_m2, Feature::apple_m2); else if (cpu_name.find("M3") != StringRef ::npos) return std::make_pair((uint32_t)CPU::apple_m3, Feature::apple_m3); + else if (cpu_name.find("M4") != StringRef ::npos) + return std::make_pair((uint32_t)CPU::apple_m4, Feature::apple_m4); else return std::make_pair((uint32_t)CPU::apple_m1, Feature::apple_m1); } @@ -1042,7 +1050,10 @@ static CPU get_cpu_name(CPUID cpuid) default: return CPU::generic; } case 0x61: // 'a': Apple - // https://opensource.apple.com/source/xnu/xnu-7195.141.2/osfmk/arm/cpuid.h.auto.html + // Data here is partially based on these sources: + // https://github.com/apple-oss-distributions/xnu/blob/main/osfmk/arm/cpuid.h + // https://asahilinux.org/docs/hw/soc/soc-codenames/#socs + // https://github.com/llvm/llvm-project/blob/main/llvm/lib/Target/AArch64/AArch64Processors.td switch (cpuid.part) { case 0x0: // Swift return CPU::apple_swift; @@ -1067,31 +1078,57 @@ static CPU get_cpu_name(CPUID cpuid) return CPU::apple_a12; case 0xF: // Tempest M9 return CPU::apple_s4; - case 0x12: // Lightning - case 0x13: // Thunder + case 0x12: // H12 Cebu p-Core "Lightning" + case 0x13: // H12 Cebu e-Core "Thunder" return CPU::apple_a13; - case 0x20: // Icestorm - case 0x21: // Firestorm + case 0x20: // H13 Sicily e-Core "Icestorm" + case 0x21: // H13 Sicily p-Core "Firestorm" return CPU::apple_a14; - case 0x22: // Icestorm m1 - case 0x23: // Firestorm m1 - case 0x24: - case 0x25: // From https://github.com/AsahiLinux/m1n1/blob/3b9a71422e45209ef57c563e418f877bf54358be/src/chickens.c#L9 - case 0x28: - case 0x29: + case 0x22: // H13G Tonga e-Core "Icestorm" used in Apple M1 + case 0x23: // H13G Tonga p-Core "Firestorm" used in Apple M1 + case 0x24: // H13J Jade Chop e-Core "Icestorm" used in Apple M1 Pro + case 0x25: // H13J Jade Chop p-Core "Firestorm" used in Apple M1 Pro + case 0x28: // H13J Jade Die e-Core "Icestorm" used in Apple M1 Max / Ultra + case 0x29: // H13J Jade Die p-Core "Firestorm" used in Apple M1 Max / Ultra return CPU::apple_m1; - case 0x30: // Blizzard m2 - case 0x31: // Avalanche m2 - case 0x32: - case 0x33: - case 0x34: - case 0x35: - case 0x38: - case 0x39: + case 0x30: // H14 Ellis e-Core "Blizzard" used in Apple A15 + case 0x31: // H14 Ellis p-Core "Avalanche" used in Apple A15 + return CPU::apple_a15; + case 0x32: // H14G Staten e-Core "Blizzard" used in Apple M2 + case 0x33: // H14G Staten p-Core "Avalanche" used in Apple M2 + case 0x34: // H14S Rhodes Chop e-Core "Blizzard" used in Apple M2 Pro + case 0x35: // H14S Rhodes Chop p-Core "Avalanche" used in Apple M2 Pro + case 0x38: // H14C Rhodes Die e-Core "Blizzard" used in Apple M2 Max / Ultra + case 0x39: // H14C Rhodes Die p-Core "Avalanche" used in Apple M2 Max / Ultra return CPU::apple_m2; - case 0x49: // Everest m3 - case 0x48: // Sawtooth m3 + case 0x40: // H15 Crete e-Core "Sawtooth" used in Apple A16 + case 0x41: // H15 Crete p-Core "Everest" used in Apple A16 + return CPU::apple_a16; + case 0x42: // H15 Ibiza e-Core "Sawtooth" used in Apple M3 + case 0x43: // H15 Ibiza p-Core "Everest" used in Apple M3 + case 0x44: // H15 Lobos e-Core "Sawtooth" used in Apple M3 Pro + case 0x45: // H15 Lobos p-Core "Everest" used in Apple M3 Pro + case 0x49: // H15 Palma e-Core "Sawtooth" used in Apple M3 Max + case 0x48: // H15 Palma p-Core "Everest" used in Apple M3 Max return CPU::apple_m3; + //case 0x46: // M11 e-Core "Sawtooth" used in Apple S9 + //case 0x47: does not exist + //return CPU::apple_s9; + case 0x50: // H15 Coll e-Core "Sawtooth" used in Apple A17 Pro + case 0x51: // H15 Coll p-Core "Everest" used in Apple A17 Pro + return CPU::apple_a17; + case 0x52: // H16G Donan e-Core used in Apple M4 + case 0x53: // H16H Donan p-Core used in Apple M4 + case 0x54: // H16S Brava S e-Core used in Apple M4 Pro + case 0x55: // H16S Brava S p-Core used in Apple M4 Pro + case 0x58: // H16C Brava C e-Core used in Apple M4 Max + case 0x59: // H16C Brava C p-Core used in Apple M4 Max + return CPU::apple_m4; + //case 0x60: // H17P Tahiti e-Core used in Apple A18 Pro + //case 0x61: // H17P Tahiti p-Core used in Apple A18 Pro + //case 0x6a: // H17A Tupai e-Core used in Apple A18 + //case 0x6b: // H17A Tupai p-Core used in Apple A18 + //return CPU::apple_a18; default: return CPU::generic; } case 0x68: // 'h': Huaxintong Semiconductor From e66fbe4b01c26c894bb3480830d92c74b8e715ec Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Thu, 5 Jun 2025 08:49:12 -0400 Subject: [PATCH 12/83] Update install link in warning (#58638) (cherry picked from commit f5e983eafe6c879027217808a29a9c12bb27f5af) --- stdlib/InteractiveUtils/src/InteractiveUtils.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/InteractiveUtils/src/InteractiveUtils.jl b/stdlib/InteractiveUtils/src/InteractiveUtils.jl index 6b75a228b2761..c39112eded49a 100644 --- a/stdlib/InteractiveUtils/src/InteractiveUtils.jl +++ b/stdlib/InteractiveUtils/src/InteractiveUtils.jl @@ -120,7 +120,7 @@ function versioninfo(io::IO=stdout; verbose::Bool=false) Note: This is an unofficial build, please report bugs to the project responsible for this build and not to the Julia project unless you can - reproduce the issue using official builds available at https://julialang.org/downloads + reproduce the issue using official builds available at https://julialang.org """ ) end From bc65d98fb6f385a578448014d855509aaf2e94f5 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Thu, 5 Jun 2025 11:21:08 -0400 Subject: [PATCH 13/83] ircode: handle content outside of a module (#58639) Specifically, content in an `__init__` block is handled by secret duplicate precompile logic, and any content generated by it was previously not eligible to be included into cache files. Fix #58449 (cherry picked from commit 2e158a4d9a4c9600964168fd6243f9d7f224503f) --- src/precompile.c | 1 - src/staticdata.c | 6 ------ src/toplevel.c | 7 ++----- 3 files changed, 2 insertions(+), 12 deletions(-) diff --git a/src/precompile.c b/src/precompile.c index 33b71d4605b30..a627d102f7dab 100644 --- a/src/precompile.c +++ b/src/precompile.c @@ -139,7 +139,6 @@ JL_DLLEXPORT void jl_write_compiler_output(void) } } - assert(jl_precompile_toplevel_module == NULL); void *native_code = NULL; bool_t emit_native = jl_options.outputo || jl_options.outputbc || jl_options.outputunoptbc || jl_options.outputasm; diff --git a/src/staticdata.c b/src/staticdata.c index fa7551433f534..3350fbf5ee23a 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -3417,9 +3417,6 @@ static void jl_save_system_image_to_stream(ios_t *f, jl_array_t *mod_array, static void jl_write_header_for_incremental(ios_t *f, jl_array_t *worklist, jl_array_t *mod_array, jl_array_t **udeps, int64_t *srctextpos, int64_t *checksumpos) { - assert(jl_precompile_toplevel_module == NULL); - jl_precompile_toplevel_module = (jl_module_t*)jl_array_ptr_ref(worklist, jl_array_len(worklist)-1); - *checksumpos = write_header(f, 0); write_uint8(f, jl_cache_flags()); // write description of contents (name, uuid, buildid) @@ -3477,9 +3474,7 @@ JL_DLLEXPORT void jl_create_system_image(void **_native_data, jl_array_t *workli // Generate _native_data` if (_native_data != NULL) { jl_prepare_serialization_data(mod_array, newly_inferred, &extext_methods, &new_ext_cis, NULL, &query_cache); - jl_precompile_toplevel_module = (jl_module_t*)jl_array_ptr_ref(worklist, jl_array_len(worklist)-1); *_native_data = jl_precompile_worklist(worklist, extext_methods, new_ext_cis); - jl_precompile_toplevel_module = NULL; extext_methods = NULL; new_ext_cis = NULL; } @@ -3526,7 +3521,6 @@ JL_DLLEXPORT void jl_create_system_image(void **_native_data, jl_array_t *workli // Re-enable running julia code for postoutput hooks, atexit, etc. jl_gc_enable_finalizers(ct, 1); ct->reentrant_timing &= ~0b1000u; - jl_precompile_toplevel_module = NULL; if (worklist) { // Go back and update the checksum in the header diff --git a/src/toplevel.c b/src/toplevel.c index 21ac7cc716b6c..9e41fe5ac2e04 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -34,7 +34,7 @@ htable_t jl_current_modules; jl_mutex_t jl_modules_mutex; // During incremental compilation, the following gets set -jl_module_t *jl_precompile_toplevel_module = NULL; // the toplevel module currently being defined +jl_module_t *jl_precompile_toplevel_module = NULL; // the first toplevel module being defined jl_module_t *jl_add_standard_imports(jl_module_t *m) { @@ -172,7 +172,6 @@ static jl_value_t *jl_eval_module_expr(jl_module_t *parent_module, jl_expr_t *ex } } - jl_module_t *old_toplevel_module = jl_precompile_toplevel_module; size_t last_age = ct->world_age; if (parent_module == jl_main_module && name == jl_symbol("Base") && jl_base_module == NULL) { @@ -182,7 +181,7 @@ static jl_value_t *jl_eval_module_expr(jl_module_t *parent_module, jl_expr_t *ex if (is_parent__toplevel__) { jl_register_root_module(newm); - if (jl_options.incremental) { + if (jl_options.incremental && jl_precompile_toplevel_module == NULL) { jl_precompile_toplevel_module = newm; } } @@ -242,8 +241,6 @@ static jl_value_t *jl_eval_module_expr(jl_module_t *parent_module, jl_expr_t *ex } } - jl_precompile_toplevel_module = old_toplevel_module; - JL_GC_POP(); return (jl_value_t*)newm; } From 31bc1b7bd21990ee6c5a7577be07fcec2bd3df9f Mon Sep 17 00:00:00 2001 From: Mason Protter Date: Fri, 6 Jun 2025 14:49:18 +0200 Subject: [PATCH 14/83] Use type wrapper directly rather than typename in `FieldError` (#58507) (cherry picked from commit 347fb7c971df89116e92e0831ea2f5322865a411) --- base/errorshow.jl | 4 ++-- test/errorshow.jl | 21 ++++++++++++++++++++- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/base/errorshow.jl b/base/errorshow.jl index 69b13738d86e4..9df363a8c5e9f 100644 --- a/base/errorshow.jl +++ b/base/errorshow.jl @@ -378,7 +378,7 @@ end function showerror(io::IO, exc::FieldError) @nospecialize - print(io, "FieldError: type $(exc.type |> nameof) has no field `$(exc.field)`") + print(io, "FieldError: type $(exc.type.name.wrapper) has no field `$(exc.field)`") Base.Experimental.show_error_hints(io, exc) end @@ -1117,7 +1117,7 @@ Experimental.register_error_hint(fielderror_dict_hint_handler, FieldError) function fielderror_listfields_hint_handler(io, exc) fields = fieldnames(exc.type) if isempty(fields) - print(io, "; $(nameof(exc.type)) has no fields at all.") + print(io, "; $(exc.type.name.wrapper) has no fields at all.") else print(io, ", available fields: $(join(map(k -> "`$k`", fields), ", "))") end diff --git a/test/errorshow.jl b/test/errorshow.jl index bca5475b07901..d992d478c3978 100644 --- a/test/errorshow.jl +++ b/test/errorshow.jl @@ -852,7 +852,8 @@ end # Check error message first errorMsg = sprint(Base.showerror, ex) - @test occursin("FieldError: type FieldFoo has no field `c`", errorMsg) + @test occursin("FieldError: type", errorMsg) + @test occursin("FieldFoo has no field `c`", errorMsg) @test occursin("available fields: `a`, `b`", errorMsg) @test occursin("Available properties: `x`, `y`", errorMsg) @@ -877,6 +878,24 @@ end @test occursin(hintExpected, errorMsg) end +module FieldErrorTest +struct Point end +p = Point() +end + +@testset "FieldError with changing fields" begin + # https://discourse.julialang.org/t/better-error-message-for-modified-structs-in-julia-1-12/129265 + err_str1 = @except_str FieldErrorTest.p.x FieldError + @test occursin("FieldErrorTest.Point", err_str1) + @eval FieldErrorTest struct Point{T} + x::T + y::T + end + err_str2 = @except_str FieldErrorTest.p.x FieldError + @test occursin("@world", err_str2) + @test occursin("FieldErrorTest.Point", err_str2) +end + # UndefVar error hints module A53000 export f From 235a7dedc73178fffa67089337a27d548d6184ca Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Fri, 6 Jun 2025 13:27:54 -0400 Subject: [PATCH 15/83] module: Tweak backdate-warning-turned error (#58651) This makes two changes to the backdate-warning-turned-error (#58266): 1. Fix a bug where the error would only trigger the first time. We do only want to print once per process, but of course, we do want to error every time if enabled. 2. If we are in speculative execution context (generators and speculatively run functions during inference), always use the UndefVarError. Effects from these functions are not supposed to be observable, and it's very confusing if the printed warning goes away when depwarns are enabled. This is marginally more breaking, but the burden is on generated function authors (which already have to be world-age aware and are somewhat more regularly broken) and is consistent with other things that are stronger errors in pure context. Fixes #58648 (cherry picked from commit d2cc06193ef4161e4ac161bd4b5b57a51686a89a) --- src/module.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/module.c b/src/module.c index da7b2e79f62d1..bcb245cce10e1 100644 --- a/src/module.c +++ b/src/module.c @@ -846,8 +846,6 @@ JL_DLLEXPORT jl_module_t *jl_get_module_of_binding(jl_module_t *m, jl_sym_t *var static NOINLINE void print_backdate_admonition(jl_binding_t *b) JL_NOTSAFEPOINT { - if (jl_options.depwarn == JL_OPTIONS_DEPWARN_ERROR) - jl_undefined_var_error(b->globalref->name, (jl_value_t*)b->globalref->mod); jl_safe_printf( "WARNING: Detected access to binding `%s.%s` in a world prior to its definition world.\n" " Julia 1.12 has introduced more strict world age semantics for global bindings.\n" @@ -860,9 +858,13 @@ static NOINLINE void print_backdate_admonition(jl_binding_t *b) JL_NOTSAFEPOINT static inline void check_backdated_binding(jl_binding_t *b, enum jl_partition_kind kind) JL_NOTSAFEPOINT { - if (__unlikely(kind == PARTITION_KIND_BACKDATED_CONST) && - !(jl_atomic_fetch_or_relaxed(&b->flags, BINDING_FLAG_DID_PRINT_BACKDATE_ADMONITION) & BINDING_FLAG_DID_PRINT_BACKDATE_ADMONITION)) { - print_backdate_admonition(b); + if (__unlikely(kind == PARTITION_KIND_BACKDATED_CONST)) { + // We don't want functions that inference executes speculatively to print this warning, so turn those into + // an error for inference purposes. + if (jl_current_task->ptls->in_pure_callback || jl_options.depwarn == JL_OPTIONS_DEPWARN_ERROR) + jl_undefined_var_error(b->globalref->name, (jl_value_t*)b->globalref->mod); + if (!(jl_atomic_fetch_or_relaxed(&b->flags, BINDING_FLAG_DID_PRINT_BACKDATE_ADMONITION) & BINDING_FLAG_DID_PRINT_BACKDATE_ADMONITION)) + print_backdate_admonition(b); } } From dede289f3328922d2c5f1b46e1458c6cfec7e483 Mon Sep 17 00:00:00 2001 From: KristofferC Date: Wed, 11 Jun 2025 14:22:16 +0200 Subject: [PATCH 16/83] bump Pkg to latest 1.12 --- .../Pkg-7802601053e97179849ade041718a9c7f4009e97.tar.gz/md5 | 1 + .../Pkg-7802601053e97179849ade041718a9c7f4009e97.tar.gz/sha512 | 1 + .../Pkg-7aeec766cf637e2bc2af161eba8abd3a4b68d025.tar.gz/md5 | 1 - .../Pkg-7aeec766cf637e2bc2af161eba8abd3a4b68d025.tar.gz/sha512 | 1 - stdlib/Pkg.version | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 deps/checksums/Pkg-7802601053e97179849ade041718a9c7f4009e97.tar.gz/md5 create mode 100644 deps/checksums/Pkg-7802601053e97179849ade041718a9c7f4009e97.tar.gz/sha512 delete mode 100644 deps/checksums/Pkg-7aeec766cf637e2bc2af161eba8abd3a4b68d025.tar.gz/md5 delete mode 100644 deps/checksums/Pkg-7aeec766cf637e2bc2af161eba8abd3a4b68d025.tar.gz/sha512 diff --git a/deps/checksums/Pkg-7802601053e97179849ade041718a9c7f4009e97.tar.gz/md5 b/deps/checksums/Pkg-7802601053e97179849ade041718a9c7f4009e97.tar.gz/md5 new file mode 100644 index 0000000000000..0b4c2231e76e3 --- /dev/null +++ b/deps/checksums/Pkg-7802601053e97179849ade041718a9c7f4009e97.tar.gz/md5 @@ -0,0 +1 @@ +12d113a3b16a74ea2025bcd372fde850 diff --git a/deps/checksums/Pkg-7802601053e97179849ade041718a9c7f4009e97.tar.gz/sha512 b/deps/checksums/Pkg-7802601053e97179849ade041718a9c7f4009e97.tar.gz/sha512 new file mode 100644 index 0000000000000..63c416108b72b --- /dev/null +++ b/deps/checksums/Pkg-7802601053e97179849ade041718a9c7f4009e97.tar.gz/sha512 @@ -0,0 +1 @@ +541aa2a5743a5e3834cef3ec6e4e4ff359f9b16b3f8c1df1e9a2327ed108d512f484c17ded8481467fbfe18dc5915b0f00037f20add7878baceb8a3bdb47625c diff --git a/deps/checksums/Pkg-7aeec766cf637e2bc2af161eba8abd3a4b68d025.tar.gz/md5 b/deps/checksums/Pkg-7aeec766cf637e2bc2af161eba8abd3a4b68d025.tar.gz/md5 deleted file mode 100644 index 2574fca7dbe2b..0000000000000 --- a/deps/checksums/Pkg-7aeec766cf637e2bc2af161eba8abd3a4b68d025.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -d3e705f029ba3d81bd0725c2cb0b2e46 diff --git a/deps/checksums/Pkg-7aeec766cf637e2bc2af161eba8abd3a4b68d025.tar.gz/sha512 b/deps/checksums/Pkg-7aeec766cf637e2bc2af161eba8abd3a4b68d025.tar.gz/sha512 deleted file mode 100644 index 54276d232add9..0000000000000 --- a/deps/checksums/Pkg-7aeec766cf637e2bc2af161eba8abd3a4b68d025.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -ef8c37b056fb6dfc3c8b1b542d65d6ffdfdc1f41a08da5307ad1c3e7ce9fe0030ac4132c9d30af0e850964842d9b330e2f950bb49dd6dd0fd5b30592f8173477 diff --git a/stdlib/Pkg.version b/stdlib/Pkg.version index 63845886099aa..0b835147d2885 100644 --- a/stdlib/Pkg.version +++ b/stdlib/Pkg.version @@ -1,4 +1,4 @@ PKG_BRANCH = master -PKG_SHA1 = 7aeec766cf637e2bc2af161eba8abd3a4b68d025 +PKG_SHA1 = 7802601053e97179849ade041718a9c7f4009e97 PKG_GIT_URL := https://github.com/JuliaLang/Pkg.jl.git PKG_TAR_URL = https://api.github.com/repos/JuliaLang/Pkg.jl/tarball/$1 From eced41df71d767f31abfc714596cc6c718861aed Mon Sep 17 00:00:00 2001 From: Elliot Saba Date: Sat, 7 Jun 2025 23:10:32 -0700 Subject: [PATCH 17/83] Try workaround for https://github.com/JuliaLang/www.julialang.org/issues/2291 This dodges the issue on my machine, let's see if it works for everyone. (cherry picked from commit dda37f97d6d41c01ecea793e9603fc51ff4d6789) --- contrib/mac/app/startup.applescript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/mac/app/startup.applescript b/contrib/mac/app/startup.applescript index 9964049f34ed6..45ccbbb977d25 100644 --- a/contrib/mac/app/startup.applescript +++ b/contrib/mac/app/startup.applescript @@ -1,4 +1,4 @@ set RootPath to (path to me) set JuliaPath to POSIX path of ((RootPath as text) & "Contents:Resources:julia:bin:julia") set JuliaFile to POSIX file JuliaPath -tell application id "com.apple.finder" to open JuliaFile +do shell script "open -a Terminal '" & JuliaFile & "'" From 1aa7a502831e8345e6e9b4ffb3b641af5206514a Mon Sep 17 00:00:00 2001 From: Elliot Saba Date: Sun, 8 Jun 2025 16:25:59 -0700 Subject: [PATCH 18/83] Adjust applescript workaround It turns out that there are two path types in applescript, and I had mixed two of them in my previous patch. Annoyingly, things seemed to work when editing locally, unsure why. (cherry picked from commit c759aa933ed041e678d370dede7030c8893bbd10) --- contrib/mac/app/startup.applescript | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/contrib/mac/app/startup.applescript b/contrib/mac/app/startup.applescript index 45ccbbb977d25..d7b46cec1a89d 100644 --- a/contrib/mac/app/startup.applescript +++ b/contrib/mac/app/startup.applescript @@ -1,4 +1,3 @@ set RootPath to (path to me) set JuliaPath to POSIX path of ((RootPath as text) & "Contents:Resources:julia:bin:julia") -set JuliaFile to POSIX file JuliaPath -do shell script "open -a Terminal '" & JuliaFile & "'" +do shell script "open -a Terminal '" & JuliaPath & "'" From d87f8f9f4be7d99c6222b4ce7567888b8b8609c0 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 9 Jun 2025 16:30:46 -0400 Subject: [PATCH 19/83] better handling of missing backedges (#58636) Manage a single dictionary (keyed by TypeName) instead of scattering this info into each TypeName scattered across the system. This makes it much easier to scan the whole table when required and to split it up better, so that all kwcalls and all constructors don't end up stuck into just one table. While not enormous (or even the largest) just using the REPL and Pkg, they are clearly larger than intended for a linear scan: ``` julia> length(Type.body.name.backedges) 1024 julia> length(typeof(Core.kwcall).name.backedges) 196 julia> length(typeof(convert).name.backedges) 1510 ``` (cherry picked from commit 1c26f43717b613d639c2171a3f883a11bcb12196) --- src/datatype.c | 2 +- src/gf.c | 331 +++++++++++++++++++++++++++---------------- src/jltypes.c | 30 ++-- src/julia.h | 2 +- src/julia_internal.h | 2 - src/method.c | 38 ----- src/staticdata.c | 44 ++++-- test/misc.jl | 4 +- 8 files changed, 257 insertions(+), 196 deletions(-) diff --git a/src/datatype.c b/src/datatype.c index a886ba9845dbf..0dbba03e30343 100644 --- a/src/datatype.c +++ b/src/datatype.c @@ -62,6 +62,7 @@ JL_DLLEXPORT jl_methtable_t *jl_new_method_table(jl_sym_t *name, jl_module_t *mo mt->cache = mc; mt->name = name; mt->module = module; + mt->backedges = (jl_genericmemory_t*)jl_an_empty_memory_any; JL_GC_POP(); return mt; } @@ -88,7 +89,6 @@ JL_DLLEXPORT jl_typename_t *jl_new_typename_in(jl_sym_t *name, jl_module_t *modu tn->partial = NULL; tn->atomicfields = NULL; tn->constfields = NULL; - tn->backedges = NULL; tn->max_methods = 0; jl_atomic_store_relaxed(&tn->max_args, 0); jl_atomic_store_relaxed(&tn->cache_entry_count, 0); diff --git a/src/gf.c b/src/gf.c index 43aafa5094037..496e5b050392b 100644 --- a/src/gf.c +++ b/src/gf.c @@ -777,55 +777,117 @@ JL_DLLEXPORT int jl_mi_try_insert(jl_method_instance_t *mi JL_ROOTING_ARGUMENT, return ret; } -static int foreach_typename_in_module( - jl_module_t *m, - int (*visit)(jl_typename_t *tn, void *env), - void *env) +enum top_typename_facts { + EXACTLY_ANY = 1 << 0, + HAVE_TYPE = 1 << 1, + EXACTLY_TYPE = 1 << 2, + HAVE_FUNCTION = 1 << 3, + EXACTLY_FUNCTION = 1 << 4, + HAVE_KWCALL = 1 << 5, + EXACTLY_KWCALL = 1 << 6, + SHORT_TUPLE = 1 << 7, +}; + +static void foreach_top_nth_typename(void (*f)(jl_typename_t*, int, void*), jl_value_t *a JL_PROPAGATES_ROOT, int n, unsigned *facts, void *env) { - jl_svec_t *table = jl_atomic_load_relaxed(&m->bindings); - for (size_t i = 0; i < jl_svec_len(table); i++) { - jl_binding_t *b = (jl_binding_t*)jl_svecref(table, i); - if ((void*)b == jl_nothing) - break; - jl_sym_t *name = b->globalref->name; - jl_value_t *v = jl_get_latest_binding_value_if_const(b); - if (v) { - jl_value_t *uw = jl_unwrap_unionall(v); - if (jl_is_datatype(uw)) { - jl_typename_t *tn = ((jl_datatype_t*)uw)->name; - if (tn->module == m && tn->name == name && tn->wrapper == v) { - // this is the original/primary binding for the type (name/wrapper) - if (!visit(((jl_datatype_t*)uw)->name, env)) - return 0; - } + if (jl_is_datatype(a)) { + if (n <= 0) { + jl_datatype_t *dt = ((jl_datatype_t*)a); + if (dt->name == jl_type_typename) { // key Type{T} on T instead of Type + *facts |= HAVE_TYPE; + foreach_top_nth_typename(f, jl_tparam0(a), -1, facts, env); } - else if (jl_is_module(v)) { - jl_module_t *child = (jl_module_t*)v; - if (child != m && child->parent == m && child->name == name) { - // this is the original/primary binding for the submodule - if (!foreach_typename_in_module(child, visit, env)) - return 0; + else if (dt == jl_function_type) { + if (n == -1) // key Type{>:Function} as Type instead of Function + *facts |= EXACTLY_TYPE; // HAVE_TYPE is already set + else + *facts |= HAVE_FUNCTION | EXACTLY_FUNCTION; + } + else if (dt == jl_any_type) { + if (n == -1) // key Type{>:Any} and kinds as Type instead of Any + *facts |= EXACTLY_TYPE; // HAVE_TYPE is already set + else + *facts |= EXACTLY_ANY; + } + else if (dt == jl_kwcall_type) { + if (n == -1) // key Type{>:typeof(kwcall)} as exactly kwcall + *facts |= EXACTLY_KWCALL; + else + *facts |= HAVE_KWCALL; + } + else { + while (1) { + jl_datatype_t *super = dt->super; + if (super == jl_function_type) { + *facts |= HAVE_FUNCTION; + break; + } + if (super == jl_any_type || super->super == dt) + break; + dt = super; } + f(dt->name, 1, env); } } - table = jl_atomic_load_relaxed(&m->bindings); - } + else if (jl_is_tuple_type(a)) { + if (jl_nparams(a) >= n) + foreach_top_nth_typename(f, jl_tparam(a, n - 1), 0, facts, env); + else + *facts |= SHORT_TUPLE; + } + } + else if (jl_is_typevar(a)) { + foreach_top_nth_typename(f, ((jl_tvar_t*)a)->ub, n, facts, env); + } + else if (jl_is_unionall(a)) { + foreach_top_nth_typename(f, ((jl_unionall_t*)a)->body, n, facts, env); + } + else if (jl_is_uniontype(a)) { + jl_uniontype_t *u = (jl_uniontype_t*)a; + foreach_top_nth_typename(f, u->a, n, facts, env); + foreach_top_nth_typename(f, u->b, n, facts, env); + } +} + +// Inspect type `argtypes` for all backedge keys that might be relevant to it, splitting it +// up on some commonly observed patterns to make a better distribution. +// (It could do some of that balancing automatically, but for now just hard-codes kwcall.) +// Along the way, record some facts about what was encountered, so that those additional +// calls can be added later if needed for completeness. +// The `int explct` argument instructs the caller if the callback is due to an exactly +// encountered type or if it rather encountered a subtype. +// This is not capable of walking to all top-typenames for an explicitly encountered +// Function or Any, so the caller a fallback that can scan the entire in that case. +// We do not de-duplicate calls when encountering a Union. +static int jl_foreach_top_typename_for(void (*f)(jl_typename_t*, int, void*), jl_value_t *argtypes JL_PROPAGATES_ROOT, int all_subtypes, void *env) +{ + unsigned facts = 0; + foreach_top_nth_typename(f, argtypes, 1, &facts, env); + if (facts & HAVE_KWCALL) { + // split kwcall on the 3rd argument instead, using the same logic + unsigned kwfacts = 0; + foreach_top_nth_typename(f, argtypes, 3, &kwfacts, env); + // copy kwfacts to original facts + if (kwfacts & SHORT_TUPLE) + kwfacts |= (all_subtypes ? EXACTLY_ANY : EXACTLY_KWCALL); + facts |= kwfacts; + } + if (all_subtypes && (facts & (EXACTLY_FUNCTION | EXACTLY_TYPE | EXACTLY_ANY))) + // flag that we have an explct match than is necessitating a full table scan + return 0; + // or inform caller of only which supertypes are applicable + if (facts & HAVE_FUNCTION) + f(jl_function_type->name, facts & EXACTLY_FUNCTION ? 1 : 0, env); + if (facts & HAVE_TYPE) + f(jl_type_typename, facts & EXACTLY_TYPE ? 1 : 0, env); + if (facts & (HAVE_KWCALL | EXACTLY_KWCALL)) + f(jl_kwcall_type->name, facts & EXACTLY_KWCALL ? 1 : 0, env); + f(jl_any_type->name, facts & EXACTLY_ANY ? 1 : 0, env); return 1; } -static int jl_foreach_reachable_typename(int (*visit)(jl_typename_t *tn, void *env), jl_array_t *mod_array, void *env) -{ - for (size_t i = 0; i < jl_array_nrows(mod_array); i++) { - jl_module_t *m = (jl_module_t*)jl_array_ptr_ref(mod_array, i); - assert(jl_is_module(m)); - if (m->parent == m) // some toplevel modules (really just Base) aren't actually - if (!foreach_typename_in_module(m, visit, env)) - return 0; - } - return 1; -} -int foreach_mtable_in_module( +static int foreach_mtable_in_module( jl_module_t *m, int (*visit)(jl_methtable_t *mt, void *env), void *env) @@ -2089,41 +2151,56 @@ JL_DLLEXPORT void jl_method_instance_add_backedge(jl_method_instance_t *callee, } +static int jl_foreach_top_typename_for(void (*f)(jl_typename_t*, int, void*), jl_value_t *argtypes JL_PROPAGATES_ROOT, int all_subtypes, void *env); + struct _typename_add_backedge { jl_value_t *typ; jl_value_t *caller; }; -static void _typename_add_backedge(jl_typename_t *tn, void *env0) +static void _typename_add_backedge(jl_typename_t *tn, int explct, void *env0) { struct _typename_add_backedge *env = (struct _typename_add_backedge*)env0; JL_GC_PROMISE_ROOTED(env->typ); JL_GC_PROMISE_ROOTED(env->caller); - if (jl_atomic_load_relaxed(&allow_new_worlds)) { - if (!tn->backedges) { - // lazy-init the backedges array - tn->backedges = jl_alloc_vec_any(2); - jl_gc_wb(tn, tn->backedges); - jl_array_ptr_set(tn->backedges, 0, env->typ); - jl_array_ptr_set(tn->backedges, 1, env->caller); + if (!explct) + return; + jl_genericmemory_t *allbackedges = jl_method_table->backedges; + jl_array_t *backedges = (jl_array_t*)jl_eqtable_get(allbackedges, (jl_value_t*)tn, NULL); + if (backedges == NULL) { + backedges = jl_alloc_vec_any(2); + JL_GC_PUSH1(&backedges); + jl_array_del_end(backedges, 2); + jl_genericmemory_t *newtable = jl_eqtable_put(allbackedges, (jl_value_t*)tn, (jl_value_t*)backedges, NULL); + JL_GC_POP(); + if (newtable != allbackedges) { + jl_method_table->backedges = newtable; + jl_gc_wb(jl_method_table, newtable); } - else { - // check if the edge is already present and avoid adding a duplicate - size_t i, l = jl_array_nrows(tn->backedges); - // reuse an already cached instance of this type, if possible - // TODO: use jl_cache_type_(tt) like cache_method does, instead of this linear scan? - for (i = 1; i < l; i += 2) { - if (jl_array_ptr_ref(tn->backedges, i) != env->caller) { - if (jl_types_equal(jl_array_ptr_ref(tn->backedges, i - 1), env->typ)) { - env->typ = jl_array_ptr_ref(tn->backedges, i - 1); - break; - } - } + } + // check if the edge is already present and avoid adding a duplicate + size_t i, l = jl_array_nrows(backedges); + // reuse an already cached instance of this type, if possible + // TODO: use jl_cache_type_(tt) like cache_method does, instead of this linear scan? + // TODO: use as_global_root and de-dup edges array too + for (i = 1; i < l; i += 2) { + if (jl_array_ptr_ref(backedges, i) == env->caller) { + if (jl_types_equal(jl_array_ptr_ref(backedges, i - 1), env->typ)) { + env->typ = jl_array_ptr_ref(backedges, i - 1); + return; // this edge already recorded } - jl_array_ptr_1d_push(tn->backedges, env->typ); - jl_array_ptr_1d_push(tn->backedges, env->caller); } } + for (i = 1; i < l; i += 2) { + if (jl_array_ptr_ref(backedges, i) != env->caller) { + if (jl_types_equal(jl_array_ptr_ref(backedges, i - 1), env->typ)) { + env->typ = jl_array_ptr_ref(backedges, i - 1); + break; + } + } + } + jl_array_ptr_1d_push(backedges, env->typ); + jl_array_ptr_1d_push(backedges, env->caller); } // add a backedge from a non-existent signature to caller @@ -2133,11 +2210,13 @@ JL_DLLEXPORT void jl_method_table_add_backedge(jl_value_t *typ, jl_code_instance if (!jl_atomic_load_relaxed(&allow_new_worlds)) return; // try to pick the best cache(s) for this typ edge - struct _typename_add_backedge env = {typ, (jl_value_t*)caller}; - jl_methcache_t *mc = jl_method_table->cache; + jl_methtable_t *mt = jl_method_table; + jl_methcache_t *mc = mt->cache; JL_LOCK(&mc->writelock); - if (jl_atomic_load_relaxed(&allow_new_worlds)) - jl_foreach_top_typename_for(_typename_add_backedge, typ, &env); + if (jl_atomic_load_relaxed(&allow_new_worlds)) { + struct _typename_add_backedge env = {typ, (jl_value_t*)caller}; + jl_foreach_top_typename_for(_typename_add_backedge, typ, 0, &env); + } JL_UNLOCK(&mc->writelock); } @@ -2151,65 +2230,66 @@ struct _typename_invalidate_backedge { int invalidated; }; -static void _typename_invalidate_backedges(jl_typename_t *tn, void *env0) +static void _typename_invalidate_backedges(jl_typename_t *tn, int explct, void *env0) { struct _typename_invalidate_backedge *env = (struct _typename_invalidate_backedge*)env0; JL_GC_PROMISE_ROOTED(env->type); JL_GC_PROMISE_ROOTED(env->isect); // isJuliaType considers jl_value_t** to be a julia object too JL_GC_PROMISE_ROOTED(env->isect2); // isJuliaType considers jl_value_t** to be a julia object too - if (tn->backedges) { - jl_value_t **backedges = jl_array_ptr_data(tn->backedges); - size_t i, na = jl_array_nrows(tn->backedges); - size_t ins = 0; - for (i = 1; i < na; i += 2) { - jl_value_t *backedgetyp = backedges[i - 1]; - JL_GC_PROMISE_ROOTED(backedgetyp); - int missing = 0; - if (jl_type_intersection2(backedgetyp, (jl_value_t*)env->type, env->isect, env->isect2)) { - // See if the intersection was actually already fully - // covered, but that the new method is ambiguous. - // -> no previous method: now there is one, need to update the missing edge - // -> one+ previously matching method(s): - // -> more specific then all of them: need to update the missing edge - // -> some may have been ambiguous: now there is a replacement - // -> some may have been called: now there is a replacement (also will be detected in the loop later) - // -> less specific or ambiguous with any one of them: can ignore the missing edge (not missing) - // -> some may have been ambiguous: still are - // -> some may have been called: they may be partly replaced (will be detected in the loop later) - // c.f. `is_replacing`, which is a similar query, but with an existing method match to compare against - missing = 1; - for (size_t j = 0; j < env->n; j++) { - jl_method_t *m = env->d[j]; - JL_GC_PROMISE_ROOTED(m); - if (jl_subtype(*env->isect, m->sig) || (*env->isect2 && jl_subtype(*env->isect2, m->sig))) { - // We now know that there actually was a previous - // method for this part of the type intersection. - if (!jl_type_morespecific(env->type, m->sig)) { - missing = 0; - break; - } + jl_array_t *backedges = (jl_array_t*)jl_eqtable_get(jl_method_table->backedges, (jl_value_t*)tn, NULL); + if (backedges == NULL) + return; + jl_value_t **d = jl_array_ptr_data(backedges); + size_t i, na = jl_array_nrows(backedges); + size_t ins = 0; + for (i = 1; i < na; i += 2) { + jl_value_t *backedgetyp = d[i - 1]; + JL_GC_PROMISE_ROOTED(backedgetyp); + int missing = 0; + if (jl_type_intersection2(backedgetyp, (jl_value_t*)env->type, env->isect, env->isect2)) { + // See if the intersection was actually already fully + // covered, but that the new method is ambiguous. + // -> no previous method: now there is one, need to update the missing edge + // -> one+ previously matching method(s): + // -> more specific then all of them: need to update the missing edge + // -> some may have been ambiguous: now there is a replacement + // -> some may have been called: now there is a replacement (also will be detected in the loop later) + // -> less specific or ambiguous with any one of them: can ignore the missing edge (not missing) + // -> some may have been ambiguous: still are + // -> some may have been called: they may be partly replaced (will be detected in the loop later) + // c.f. `is_replacing`, which is a similar query, but with an existing method match to compare against + missing = 1; + for (size_t j = 0; j < env->n; j++) { + jl_method_t *m = env->d[j]; + JL_GC_PROMISE_ROOTED(m); + if (jl_subtype(*env->isect, m->sig) || (*env->isect2 && jl_subtype(*env->isect2, m->sig))) { + // We now know that there actually was a previous + // method for this part of the type intersection. + if (!jl_type_morespecific(env->type, m->sig)) { + missing = 0; + break; } } } - *env->isect = *env->isect2 = NULL; - if (missing) { - jl_code_instance_t *backedge = (jl_code_instance_t*)backedges[i]; - JL_GC_PROMISE_ROOTED(backedge); - invalidate_code_instance(backedge, env->max_world, 0); - env->invalidated = 1; - if (_jl_debug_method_invalidation) - jl_array_ptr_1d_push(_jl_debug_method_invalidation, (jl_value_t*)backedgetyp); - } - else { - backedges[ins++] = backedges[i - 1]; - backedges[ins++] = backedges[i - 0]; - } } - if (ins == 0) - tn->backedges = NULL; - else - jl_array_del_end(tn->backedges, na - ins); + *env->isect = *env->isect2 = NULL; + if (missing) { + jl_code_instance_t *backedge = (jl_code_instance_t*)d[i]; + JL_GC_PROMISE_ROOTED(backedge); + invalidate_code_instance(backedge, env->max_world, 0); + env->invalidated = 1; + if (_jl_debug_method_invalidation) + jl_array_ptr_1d_push(_jl_debug_method_invalidation, (jl_value_t*)backedgetyp); + } + else { + d[ins++] = d[i - 1]; + d[ins++] = d[i - 0]; + } } + if (ins == 0) + jl_eqtable_pop(jl_method_table->backedges, (jl_value_t*)tn, NULL, NULL); + else if (na != ins) + jl_array_del_end(backedges, na - ins); } struct invalidate_mt_env { @@ -2377,14 +2457,6 @@ static int erase_all_backedges(jl_methtable_t *mt, void *env) return jl_typemap_visitor(jl_atomic_load_relaxed(&mt->defs), erase_method_backedges, env); } -static int erase_all_mc_backedges(jl_typename_t *tn, void *env) -{ - tn->backedges = NULL; - return 1; -} - -static int jl_foreach_reachable_typename(int (*visit)(jl_typename_t *tn, void *env), jl_array_t *mod_array, void *env); - JL_DLLEXPORT void jl_disable_new_worlds(void) { if (jl_generating_output()) @@ -2397,7 +2469,7 @@ JL_DLLEXPORT void jl_disable_new_worlds(void) jl_foreach_reachable_mtable(erase_all_backedges, mod_array, (void*)NULL); JL_LOCK(&jl_method_table->cache->writelock); - jl_foreach_reachable_typename(erase_all_mc_backedges, mod_array, (void*)NULL); + jl_method_table->backedges = (jl_genericmemory_t*)jl_an_empty_memory_any; JL_UNLOCK(&jl_method_table->cache->writelock); JL_GC_POP(); } @@ -2577,7 +2649,16 @@ void jl_method_table_activate(jl_typemap_entry_t *newentry) jl_methcache_t *mc = jl_method_table->cache; JL_LOCK(&mc->writelock); struct _typename_invalidate_backedge typename_env = {type, &isect, &isect2, d, n, max_world, invalidated}; - jl_foreach_top_typename_for(_typename_invalidate_backedges, type, &typename_env); + if (!jl_foreach_top_typename_for(_typename_invalidate_backedges, type, 1, &typename_env)) { + // if the new method cannot be split into exact backedges, scan the whole table for anything that might be affected + jl_genericmemory_t *allbackedges = jl_method_table->backedges; + for (size_t i = 0, n = allbackedges->length; i < n; i += 2) { + jl_value_t *tn = jl_genericmemory_ptr_ref(allbackedges, i); + jl_value_t *backedges = jl_genericmemory_ptr_ref(allbackedges, i+1); + if (tn && tn != jl_nothing && backedges) + _typename_invalidate_backedges((jl_typename_t*)tn, 0, &typename_env); + } + } invalidated |= typename_env.invalidated; if (oldmi && jl_array_nrows(oldmi)) { // search mc->cache and leafcache and drop anything that might overlap with the new method diff --git a/src/jltypes.c b/src/jltypes.c index 40dc55a4e3e54..1c574a0fd5956 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -3004,23 +3004,22 @@ void jl_init_types(void) JL_GC_DISABLED jl_typename_type->name->wrapper = (jl_value_t*)jl_typename_type; jl_typename_type->super = jl_any_type; jl_typename_type->parameters = jl_emptysvec; - jl_typename_type->name->n_uninitialized = 19 - 2; - jl_typename_type->name->names = jl_perm_symsvec(19, "name", "module", "singletonname", + jl_typename_type->name->n_uninitialized = 18 - 2; + jl_typename_type->name->names = jl_perm_symsvec(18, "name", "module", "singletonname", "names", "atomicfields", "constfields", "wrapper", "Typeofwrapper", "cache", "linearcache", - "backedges", "partial", - "hash", "max_args", "n_uninitialized", + "partial", "hash", "max_args", "n_uninitialized", "flags", // "abstract", "mutable", "mayinlinealloc", "cache_entry_count", "max_methods", "constprop_heuristic"); - const static uint32_t typename_constfields[1] = { 0b0001101000001001011 }; // TODO: put back atomicfields and constfields in this list - const static uint32_t typename_atomicfields[1] = { 0b0010010001110000000 }; + const static uint32_t typename_constfields[1] = { 0b000110100001001011 }; // TODO: put back atomicfields and constfields in this list + const static uint32_t typename_atomicfields[1] = { 0b001001001110000000 }; jl_typename_type->name->constfields = typename_constfields; jl_typename_type->name->atomicfields = typename_atomicfields; jl_precompute_memoized_dt(jl_typename_type, 1); - jl_typename_type->types = jl_svec(19, jl_symbol_type, jl_any_type /*jl_module_type*/, jl_symbol_type, + jl_typename_type->types = jl_svec(18, jl_symbol_type, jl_any_type /*jl_module_type*/, jl_symbol_type, jl_simplevector_type, jl_any_type/*jl_voidpointer_type*/, jl_any_type/*jl_voidpointer_type*/, - jl_type_type, jl_type_type, jl_simplevector_type, jl_simplevector_type, + jl_type_type, jl_simplevector_type, jl_simplevector_type, jl_methcache_type, jl_any_type, jl_any_type /*jl_long_type*/, jl_any_type /*jl_int32_type*/, @@ -3046,13 +3045,13 @@ void jl_init_types(void) JL_GC_DISABLED jl_methtable_type->super = jl_any_type; jl_methtable_type->parameters = jl_emptysvec; jl_methtable_type->name->n_uninitialized = 0; - jl_methtable_type->name->names = jl_perm_symsvec(4, "defs", "cache", "name", "module"); - const static uint32_t methtable_constfields[1] = { 0b1110 }; - const static uint32_t methtable_atomicfields[1] = { 0b0001 }; + jl_methtable_type->name->names = jl_perm_symsvec(5, "defs", "cache", "name", "module", "backedges"); + const static uint32_t methtable_constfields[1] = { 0b01110 }; + const static uint32_t methtable_atomicfields[1] = { 0b00001 }; jl_methtable_type->name->constfields = methtable_constfields; jl_methtable_type->name->atomicfields = methtable_atomicfields; jl_precompute_memoized_dt(jl_methtable_type, 1); - jl_methtable_type->types = jl_svec(4, jl_any_type, jl_methcache_type, jl_symbol_type, jl_any_type /*jl_module_type*/); + jl_methtable_type->types = jl_svec(5, jl_any_type, jl_methcache_type, jl_symbol_type, jl_any_type /*jl_module_type*/, jl_any_type); jl_symbol_type->name = jl_new_typename_in(jl_symbol("Symbol"), core, 0, 1); jl_symbol_type->name->wrapper = (jl_value_t*)jl_symbol_type; @@ -3377,6 +3376,7 @@ void jl_init_types(void) JL_GC_DISABLED core = jl_core_module; jl_method_table->module = core; jl_atomic_store_relaxed(&jl_method_table->cache->leafcache, (jl_genericmemory_t*)jl_an_empty_memory_any); + jl_method_table->backedges = (jl_genericmemory_t*)jl_an_empty_memory_any; jl_atomic_store_relaxed(&core->bindingkeyset, (jl_genericmemory_t*)jl_an_empty_memory_any); // export own name, so "using Foo" makes "Foo" itself visible jl_set_initial_const(core, core->name, (jl_value_t*)core, 1); @@ -3841,13 +3841,13 @@ void jl_init_types(void) JL_GC_DISABLED jl_svecset(jl_typename_type->types, 5, jl_voidpointer_type); jl_svecset(jl_typename_type->types, 6, jl_type_type); jl_svecset(jl_typename_type->types, 7, jl_type_type); - jl_svecset(jl_typename_type->types, 12, jl_long_type); + jl_svecset(jl_typename_type->types, 11, jl_long_type); + jl_svecset(jl_typename_type->types, 12, jl_int32_type); jl_svecset(jl_typename_type->types, 13, jl_int32_type); - jl_svecset(jl_typename_type->types, 14, jl_int32_type); + jl_svecset(jl_typename_type->types, 14, jl_uint8_type); jl_svecset(jl_typename_type->types, 15, jl_uint8_type); jl_svecset(jl_typename_type->types, 16, jl_uint8_type); jl_svecset(jl_typename_type->types, 17, jl_uint8_type); - jl_svecset(jl_typename_type->types, 18, jl_uint8_type); jl_svecset(jl_methcache_type->types, 2, jl_long_type); // voidpointer jl_svecset(jl_methcache_type->types, 3, jl_long_type); // uint32_t plus alignment jl_svecset(jl_methtable_type->types, 3, jl_module_type); diff --git a/src/julia.h b/src/julia.h index 0fd0827f95f09..9d4d509e067f7 100644 --- a/src/julia.h +++ b/src/julia.h @@ -529,7 +529,6 @@ typedef struct { _Atomic(jl_value_t*) Typeofwrapper; // cache for Type{wrapper} _Atomic(jl_svec_t*) cache; // sorted array _Atomic(jl_svec_t*) linearcache; // unsorted array - jl_array_t *backedges; // uncovered (sig => caller::CodeInstance) pairs with this type as the function jl_array_t *partial; // incomplete instantiations of this type intptr_t hash; _Atomic(int32_t) max_args; // max # of non-vararg arguments in a signature with this type as the function @@ -891,6 +890,7 @@ typedef struct _jl_methtable_t { jl_methcache_t *cache; jl_sym_t *name; // sometimes used for debug printing jl_module_t *module; // sometimes used for debug printing + jl_genericmemory_t *backedges; // IdDict{top typenames, Vector{uncovered (sig => caller::CodeInstance)}} } jl_methtable_t; typedef struct { diff --git a/src/julia_internal.h b/src/julia_internal.h index dd8c2ffe76cdd..629fd8c385691 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -858,7 +858,6 @@ jl_expr_t *jl_exprn(jl_sym_t *head, size_t n); jl_function_t *jl_new_generic_function(jl_sym_t *name, jl_module_t *module, size_t new_world); jl_function_t *jl_new_generic_function_with_supertype(jl_sym_t *name, jl_module_t *module, jl_datatype_t *st, size_t new_world); int jl_foreach_reachable_mtable(int (*visit)(jl_methtable_t *mt, void *env), jl_array_t *mod_array, void *env); -int foreach_mtable_in_module(jl_module_t *m, int (*visit)(jl_methtable_t *mt, void *env), void *env); void jl_init_main_module(void); JL_DLLEXPORT int jl_is_submodule(jl_module_t *child, jl_module_t *parent) JL_NOTSAFEPOINT; jl_array_t *jl_get_loaded_modules(void); @@ -937,7 +936,6 @@ JL_DLLEXPORT jl_methtable_t *jl_method_get_table( jl_method_t *method JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT; JL_DLLEXPORT jl_methcache_t *jl_method_get_cache( jl_method_t *method JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT; -void jl_foreach_top_typename_for(void (*f)(jl_typename_t*, void*), jl_value_t *argtypes JL_PROPAGATES_ROOT, void *env); JL_DLLEXPORT int jl_pointer_egal(jl_value_t *t); JL_DLLEXPORT jl_value_t *jl_nth_slot_type(jl_value_t *sig JL_PROPAGATES_ROOT, size_t i) JL_NOTSAFEPOINT; diff --git a/src/method.c b/src/method.c index 77863b27e24b6..eba485ff9eb69 100644 --- a/src/method.c +++ b/src/method.c @@ -1154,39 +1154,6 @@ JL_DLLEXPORT jl_value_t *jl_declare_const_gf(jl_module_t *mod, jl_sym_t *name) return gf; } -static void foreach_top_nth_typename(void (*f)(jl_typename_t*, void*), jl_value_t *a JL_PROPAGATES_ROOT, int n, void *env) -{ - if (jl_is_datatype(a)) { - if (n == 0) { - jl_datatype_t *dt = ((jl_datatype_t*)a); - jl_typename_t *tn = NULL; - while (1) { - if (dt != jl_any_type && dt != jl_function_type) - tn = dt->name; - if (dt->super == dt) - break; - dt = dt->super; - } - if (tn) - f(tn, env); - } - else if (jl_is_tuple_type(a)) { - if (jl_nparams(a) >= n) - foreach_top_nth_typename(f, jl_tparam(a, n - 1), 0, env); - } - } - else if (jl_is_typevar(a)) { - foreach_top_nth_typename(f, ((jl_tvar_t*)a)->ub, n, env); - } - else if (jl_is_unionall(a)) { - foreach_top_nth_typename(f, ((jl_unionall_t*)a)->body, n, env); - } - else if (jl_is_uniontype(a)) { - jl_uniontype_t *u = (jl_uniontype_t*)a; - foreach_top_nth_typename(f, u->a, n, env); - foreach_top_nth_typename(f, u->b, n, env); - } -} // get the MethodTable for dispatch, or `nothing` if cannot be determined JL_DLLEXPORT jl_methtable_t *jl_method_table_for(jl_value_t *argtypes JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT @@ -1200,11 +1167,6 @@ JL_DLLEXPORT jl_methcache_t *jl_method_cache_for(jl_value_t *argtypes JL_PROPAGA return jl_method_table->cache; } -void jl_foreach_top_typename_for(void (*f)(jl_typename_t*, void*), jl_value_t *argtypes JL_PROPAGATES_ROOT, void *env) -{ - foreach_top_nth_typename(f, argtypes, 1, env); -} - jl_methcache_t *jl_kwmethod_cache_for(jl_value_t *argtypes JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT { return jl_method_table->cache; diff --git a/src/staticdata.c b/src/staticdata.c index 3350fbf5ee23a..dc2e5605d71e4 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -867,20 +867,30 @@ static void jl_insert_into_serialization_queue(jl_serializer_state *s, jl_value_ assert(!jl_object_in_image((jl_value_t*)tn->module)); assert(!jl_object_in_image((jl_value_t*)tn->wrapper)); } + } + if (jl_is_mtable(v)) { + jl_methtable_t *mt = (jl_methtable_t*)v; // Any back-edges will be re-validated and added by staticdata.jl, so // drop them from the image here if (s->incremental || jl_options.trim || jl_options.strip_ir) { - record_field_change((jl_value_t**)&tn->backedges, NULL); + record_field_change((jl_value_t**)&mt->backedges, jl_an_empty_memory_any); } else { // don't recurse into all backedges memory (yet) - jl_value_t *backedges = get_replaceable_field((jl_value_t**)&tn->backedges, 1); - if (backedges) { - jl_queue_for_serialization_(s, (jl_value_t*)((jl_array_t*)backedges)->ref.mem, 0, 1); - for (size_t i = 0, n = jl_array_nrows(backedges); i < n; i += 2) { - jl_value_t *t = jl_array_ptr_ref(backedges, i); - assert(!jl_is_code_instance(t)); - jl_queue_for_serialization(s, t); + jl_value_t *allbackedges = get_replaceable_field((jl_value_t**)&mt->backedges, 1); + jl_queue_for_serialization_(s, allbackedges, 0, 1); + for (size_t i = 0, n = ((jl_genericmemory_t*)allbackedges)->length; i < n; i += 2) { + jl_value_t *tn = jl_genericmemory_ptr_ref(allbackedges, i); + jl_queue_for_serialization(s, tn); + jl_value_t *backedges = jl_genericmemory_ptr_ref(allbackedges, i + 1); + if (backedges && backedges != jl_nothing) { + jl_queue_for_serialization_(s, (jl_value_t*)((jl_array_t*)backedges)->ref.mem, 0, 1); + jl_queue_for_serialization(s, backedges); + for (size_t i = 0, n = jl_array_nrows(backedges); i < n; i += 2) { + jl_value_t *t = jl_array_ptr_ref(backedges, i); + assert(!jl_is_code_instance(t)); + jl_queue_for_serialization(s, t); + } } } } @@ -2571,8 +2581,6 @@ static void jl_prune_mi_backedges(jl_array_t *backedges) static void jl_prune_tn_backedges(jl_array_t *backedges) { - if (backedges == NULL) - return; size_t i = 0, ins = 0, n = jl_array_nrows(backedges); for (i = 1; i < n; i += 2) { jl_value_t *ci = jl_array_ptr_ref(backedges, i); @@ -2584,6 +2592,15 @@ static void jl_prune_tn_backedges(jl_array_t *backedges) jl_array_del_end(backedges, n - ins); } +static void jl_prune_mt_backedges(jl_genericmemory_t *allbackedges) +{ + for (size_t i = 0, n = allbackedges->length; i < n; i += 2) { + jl_value_t *tn = jl_genericmemory_ptr_ref(allbackedges, i); + jl_value_t *backedges = jl_genericmemory_ptr_ref(allbackedges, i + 1); + if (tn && tn != jl_nothing && backedges) + jl_prune_tn_backedges((jl_array_t*)backedges); + } +} static void jl_prune_binding_backedges(jl_array_t *backedges) { @@ -3238,8 +3255,6 @@ static void jl_save_system_image_to_stream(ios_t *f, jl_array_t *mod_array, jl_prune_type_cache_hash(jl_atomic_load_relaxed(&tn->cache))); jl_gc_wb(tn, jl_atomic_load_relaxed(&tn->cache)); jl_prune_type_cache_linear(jl_atomic_load_relaxed(&tn->linearcache)); - jl_value_t *backedges = get_replaceable_field((jl_value_t**)&tn->backedges, 1); - jl_prune_tn_backedges((jl_array_t*)backedges); } else if (jl_is_method_instance(v)) { jl_method_instance_t *mi = (jl_method_instance_t*)v; @@ -3251,6 +3266,11 @@ static void jl_save_system_image_to_stream(ios_t *f, jl_array_t *mod_array, jl_value_t *backedges = get_replaceable_field((jl_value_t**)&b->backedges, 1); jl_prune_binding_backedges((jl_array_t*)backedges); } + else if (jl_is_mtable(v)) { + jl_methtable_t *mt = (jl_methtable_t*)v; + jl_value_t *backedges = get_replaceable_field((jl_value_t**)&mt->backedges, 1); + jl_prune_mt_backedges((jl_genericmemory_t*)backedges); + } } } diff --git a/test/misc.jl b/test/misc.jl index ae5a193eb43fc..b51c5a2553825 100644 --- a/test/misc.jl +++ b/test/misc.jl @@ -1614,10 +1614,10 @@ end let errs = IOBuffer() run(`$(Base.julia_cmd()) -e ' using Test - @test isdefined(Type.body.name, :backedges) + @test !isempty(Core.GlobalMethods.backedges) Base.Experimental.disable_new_worlds() @test_throws "disable_new_worlds" @eval f() = 1 - @test !isdefined(Type.body.name, :backedges) + @test isempty(Core.GlobalMethods.backedges) @test_throws "disable_new_worlds" Base.delete_method(which(+, (Int, Int))) @test 1+1 == 2 using Dates From 9c702e9497095f3e02fb75a969c0ac1c48ea3ae7 Mon Sep 17 00:00:00 2001 From: Neven Sajko <4944410+nsajko@users.noreply.github.com> Date: Mon, 9 Jun 2025 23:55:09 +0200 Subject: [PATCH 20/83] improve inferred effects for `reshape` for `Array` (#58672) (cherry picked from commit 1052201ff1b1844029c6a3274ea12755646ac597) --- base/reshapedarray.jl | 2 +- test/arrayops.jl | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/base/reshapedarray.jl b/base/reshapedarray.jl index f65a7d8c9561a..97c7a189f138b 100644 --- a/base/reshapedarray.jl +++ b/base/reshapedarray.jl @@ -36,7 +36,7 @@ length(R::ReshapedArrayIterator) = length(R.iter) eltype(::Type{<:ReshapedArrayIterator{I}}) where {I} = @isdefined(I) ? ReshapedIndex{eltype(I)} : Any @noinline throw_dmrsa(dims, len) = - throw(DimensionMismatch("new dimensions $(dims) must be consistent with array length $len")) + throw(DimensionMismatch(LazyString("new dimensions ", dims, " must be consistent with array length ", len))) ## reshape(::Array, ::Dims) returns a new Array (to avoid conditionally aliasing the structure, only the data) # reshaping to same # of dimensions diff --git a/test/arrayops.jl b/test/arrayops.jl index d5fba79c47017..836bbb1daec9a 100644 --- a/test/arrayops.jl +++ b/test/arrayops.jl @@ -100,6 +100,18 @@ using Dates @test Array{eltype(a)}(a) !== a @test Vector(a) !== a end +@testset "effect inference for `reshape` for `Array`" begin + for Arr ∈ (Array{<:Any, 0}, Vector, Matrix, Array{<:Any, 3}) + for Shape ∈ (Tuple{Int}, Tuple{Int, Int}) + effects = Base.infer_effects(reshape, Tuple{Arr{Float32}, Shape}) + @test Base.Compiler.is_effect_free(effects) + @test Base.Compiler.is_terminates(effects) + @test Base.Compiler.is_notaskstate(effects) + @test Base.Compiler.is_noub(effects) + @test Base.Compiler.is_nortcall(effects) + end + end +end @testset "reshaping SubArrays" begin a = Array(reshape(1:5, 1, 5)) @testset "linearfast" begin From 6a962010cc6b759c561015908320def582ee25df Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Tue, 10 Jun 2025 00:27:37 -0400 Subject: [PATCH 21/83] Unicode: Force-inline isgraphemebreak! (#58674) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When this API was added, this function inlined, which is important, because the API relies on the allocation of the `Ref` being elided. At some point (I went back to 1.8) this regressed. For example, it is currently responsible for substantially all non-Expr allocations in JuliaParser. Before (parsing all of Base with JuliaParser): ``` │ Memory estimate: 76.93 MiB, allocs estimate: 719922. ``` After: ``` │ Memory estimate: 53.31 MiB, allocs estimate: 156. ``` Also add a test to make sure this doesn't regress again. (cherry picked from commit d6294ba973db1dea9dc932779008fd66d27c4bd2) --- base/strings/unicode.jl | 2 +- stdlib/Unicode/test/runtests.jl | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/base/strings/unicode.jl b/base/strings/unicode.jl index f2938ba6021f2..4214028d83653 100644 --- a/base/strings/unicode.jl +++ b/base/strings/unicode.jl @@ -800,7 +800,7 @@ isgraphemebreak(c1::AbstractChar, c2::AbstractChar) = # Stateful grapheme break required by Unicode-9 rules: the string # must be processed in sequence, with state initialized to Ref{Int32}(0). # Requires utf8proc v2.0 or later. -function isgraphemebreak!(state::Ref{Int32}, c1::AbstractChar, c2::AbstractChar) +@inline function isgraphemebreak!(state::Ref{Int32}, c1::AbstractChar, c2::AbstractChar) if ismalformed(c1) || ismalformed(c2) state[] = 0 return true diff --git a/stdlib/Unicode/test/runtests.jl b/stdlib/Unicode/test/runtests.jl index 7fa57508cffbf..2af7015afa249 100644 --- a/stdlib/Unicode/test/runtests.jl +++ b/stdlib/Unicode/test/runtests.jl @@ -284,6 +284,8 @@ end @test_throws BoundsError graphemes("äöüx", 2:5) @test_throws BoundsError graphemes("äöüx", 5:5) @test_throws ArgumentError graphemes("äöüx", 0:1) + + @test @allocated(length(graphemes("äöüx"))) == 0 end @testset "#3721, #6939 up-to-date character widths" begin From 4479c55b40bc3ddcb0283064e7528bb9967aa2ad Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Wed, 11 Jun 2025 01:14:38 -0400 Subject: [PATCH 22/83] Test: Fix failfast for for loops (#58695) (cherry picked from commit 8567a3a10f4b746b91bf406bfe3171c3399aed8d) --- stdlib/Test/src/Test.jl | 10 ++++++++-- stdlib/Test/test/runtests.jl | 28 +++++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/stdlib/Test/src/Test.jl b/stdlib/Test/src/Test.jl index c96e33c434d52..08c1df44e818a 100644 --- a/stdlib/Test/src/Test.jl +++ b/stdlib/Test/src/Test.jl @@ -1664,6 +1664,10 @@ end trigger_test_failure_break(@nospecialize(err)) = ccall(:jl_test_failure_breakpoint, Cvoid, (Any,), err) +is_failfast_error(err::FailFastError) = true +is_failfast_error(err::LoadError) = is_failfast_error(err.error) # handle `include` barrier +is_failfast_error(err) = false + """ Generate the code for an `@testset` with a `let` argument. """ @@ -1775,7 +1779,7 @@ function testset_beginend_call(args, tests, source) # something in the test block threw an error. Count that as an # error in this test set trigger_test_failure_break(err) - if err isa FailFastError + if is_failfast_error(err) get_testset_depth() > 1 ? rethrow() : failfast_print() else record(ts, Error(:nontest_error, Expr(:tuple), err, Base.current_exceptions(), $(QuoteNode(source)))) @@ -1863,7 +1867,9 @@ function testset_forloop(args, testloop, source) # Something in the test block threw an error. Count that as an # error in this test set trigger_test_failure_break(err) - if !isa(err, FailFastError) + if is_failfast_error(err) + get_testset_depth() > 1 ? rethrow() : failfast_print() + else record(ts, Error(:nontest_error, Expr(:tuple), err, Base.current_exceptions(), $(QuoteNode(source)))) end end diff --git a/stdlib/Test/test/runtests.jl b/stdlib/Test/test/runtests.jl index 02523dc6fd911..66cab6c6aabbe 100644 --- a/stdlib/Test/test/runtests.jl +++ b/stdlib/Test/test/runtests.jl @@ -1348,7 +1348,7 @@ end @test occursin(expected, result) end end - @testset "failfast" begin + @testset "failfast begin-end" begin expected = r""" Test Summary: \| Fail Total +Time Foo \| 1 1 \s*\d*\.\ds @@ -1373,6 +1373,32 @@ end @test occursin(expected, result) end end + @testset "failfast for-loop" begin + expected = r""" + Test Summary: \| Fail Total +Time + Foo \| 1 1 \s*\d*\.\ds + 1 \| 1 1 \s*\d*\.\ds + """ + mktemp() do f, _ + write(f, + """ + using Test + + @testset "Foo" failfast=true begin + @testset "\$x" for x in 1:2 + @test false + end + @testset "Bar" begin + @test false + @test true + end + end + """) + cmd = `$(Base.julia_cmd()) --startup-file=no --color=no $f` + result = read(pipeline(ignorestatus(cmd), stderr=devnull), String) + @test occursin(expected, result) + end + end @testset "failfast passes to child testsets" begin expected = r""" Test Summary: \| Fail Total +Time From bb4a8901055d4d9df77f9c92599496e8e98e2abb Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Thu, 12 Jun 2025 14:31:02 -0400 Subject: [PATCH 23/83] restore fallback 3-arg `setprecision` method (#58586) (#58699) Manual backport of #58586 . Co-authored-by: Sukera <11753998+Seelengrab@users.noreply.github.com> --- NEWS.md | 5 +++++ base/mpfr.jl | 20 ++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/NEWS.md b/NEWS.md index f2e667378e5a0..9dee73bda6898 100644 --- a/NEWS.md +++ b/NEWS.md @@ -134,6 +134,8 @@ New library features * `Timer` now has readable `timeout` and `interval` properties, and a more descriptive `show` method ([#57081]). * `sort` now supports `NTuple`s ([#54494]). * `map!(f, A)` now stores the results in `A`, like `map!(f, A, A)` or `A .= f.(A)` ([#40632]). +* `setprecision` with a function argument (typically a `do` block) is now thread safe. Other forms + should be avoided, and types should switch to an implementation using `ScopedValue` ([#51362]). Standard library changes ------------------------ @@ -225,8 +227,10 @@ Tooling Improvements [#40989]: https://github.com/JuliaLang/julia/issues/40989 [#45793]: https://github.com/JuliaLang/julia/issues/45793 [#49355]: https://github.com/JuliaLang/julia/issues/49355 +[#49933]: https://github.com/JuliaLang/julia/issues/49933 [#50988]: https://github.com/JuliaLang/julia/issues/50988 [#51149]: https://github.com/JuliaLang/julia/issues/51149 +[#51362]: https://github.com/JuliaLang/julia/issues/51362 [#51810]: https://github.com/JuliaLang/julia/issues/51810 [#52103]: https://github.com/JuliaLang/julia/issues/52103 [#52999]: https://github.com/JuliaLang/julia/issues/52999 @@ -284,3 +288,4 @@ Tooling Improvements [#57087]: https://github.com/JuliaLang/julia/issues/57087 [#57109]: https://github.com/JuliaLang/julia/issues/57109 [#57253]: https://github.com/JuliaLang/julia/issues/57253 +[#57727]: https://github.com/JuliaLang/julia/issues/57727 diff --git a/base/mpfr.jl b/base/mpfr.jl index 0d52510447b2f..2175fb56cc526 100644 --- a/base/mpfr.jl +++ b/base/mpfr.jl @@ -1178,9 +1178,29 @@ Often used as `setprecision(T, precision) do ... end` Note: `nextfloat()`, `prevfloat()` do not use the precision mentioned by `setprecision`. +!!! warning + There is a fallback implementation of this method that calls `precision` + and `setprecision`, but it should no longer be relied on. Instead, you + should define the 3-argument form directly in a way that uses `ScopedValue`, + or recommend that callers use `ScopedValue` and `@with` themselves. + !!! compat "Julia 1.8" The `base` keyword requires at least Julia 1.8. """ +function setprecision(f::Function, ::Type{T}, prec::Integer; kws...) where T + depwarn(""" + The fallback `setprecision(::Function, ...)` method is deprecated. Packages overloading this method should + implement their own specialization using `ScopedValue` instead. + """, :setprecision) + old_prec = precision(T) + setprecision(T, prec; kws...) + try + return f() + finally + setprecision(T, old_prec) + end +end + function setprecision(f::Function, ::Type{BigFloat}, prec::Integer; base::Integer=2) Base.ScopedValues.@with(CURRENT_PRECISION => _convert_precision_from_base(prec, base), f()) end From fb1e0fef5ac3374674ab25321e9d6f6c5667845a Mon Sep 17 00:00:00 2001 From: Fredrik Ekre Date: Fri, 13 Jun 2025 15:46:08 +0200 Subject: [PATCH 24/83] Set the branch for SparseArrays to release-1.12 --- stdlib/SparseArrays.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/SparseArrays.version b/stdlib/SparseArrays.version index f690a34eb5ae4..e7703c0221971 100644 --- a/stdlib/SparseArrays.version +++ b/stdlib/SparseArrays.version @@ -1,4 +1,4 @@ -SPARSEARRAYS_BRANCH = main +SPARSEARRAYS_BRANCH = release-1.12 SPARSEARRAYS_SHA1 = 72c7cac6bbf21367a3c2fbc5c50e908aea5984bb SPARSEARRAYS_GIT_URL := https://github.com/JuliaSparse/SparseArrays.jl.git SPARSEARRAYS_TAR_URL = https://api.github.com/repos/JuliaSparse/SparseArrays.jl/tarball/$1 From 533f2b8e82fa688ce93b53b35051d9f97d2893f2 Mon Sep 17 00:00:00 2001 From: DilumAluthgeBot <43731525+DilumAluthgeBot@users.noreply.github.com> Date: Sat, 14 Jun 2025 07:00:27 -0400 Subject: [PATCH 25/83] =?UTF-8?q?=F0=9F=A4=96=20[backports-release-1.12]?= =?UTF-8?q?=20Bump=20the=20LinearAlgebra=20stdlib=20from=207264a49=20to=20?= =?UTF-8?q?6cc0405=20(#58725)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stdlib: LinearAlgebra URL: https://github.com/JuliaLang/LinearAlgebra.jl.git Stdlib branch: release-1.12 Julia branch: backports-release-1.12 Old commit: 7264a49 New commit: 6cc0405 Julia version: 1.12.0-beta4 LinearAlgebra version: 1.12.0 Bump invoked by: @jishnub Powered by: [BumpStdlibs.jl](https://github.com/JuliaLang/BumpStdlibs.jl) Diff: https://github.com/JuliaLang/LinearAlgebra.jl/compare/7264a497869f2232eaa3d740ba3b145ade3fc9f4...6cc040592fd509ee048658e9afb8a99a2dc20e1b ``` $ git log --oneline 7264a49..6cc0405 6cc0405 Backports release 1.12 (#1379) 73ff52d Change default symmetriceigen algorithm back to RobustRepresentations (#1363) 7194038 clarify eigen docstring (#1364) ``` Co-authored-by: jishnub <10461665+jishnub@users.noreply.github.com> --- .../md5 | 1 + .../sha512 | 1 + .../md5 | 1 - .../sha512 | 1 - stdlib/LinearAlgebra.version | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 deps/checksums/LinearAlgebra-6cc040592fd509ee048658e9afb8a99a2dc20e1b.tar.gz/md5 create mode 100644 deps/checksums/LinearAlgebra-6cc040592fd509ee048658e9afb8a99a2dc20e1b.tar.gz/sha512 delete mode 100644 deps/checksums/LinearAlgebra-7264a497869f2232eaa3d740ba3b145ade3fc9f4.tar.gz/md5 delete mode 100644 deps/checksums/LinearAlgebra-7264a497869f2232eaa3d740ba3b145ade3fc9f4.tar.gz/sha512 diff --git a/deps/checksums/LinearAlgebra-6cc040592fd509ee048658e9afb8a99a2dc20e1b.tar.gz/md5 b/deps/checksums/LinearAlgebra-6cc040592fd509ee048658e9afb8a99a2dc20e1b.tar.gz/md5 new file mode 100644 index 0000000000000..585185b3c2983 --- /dev/null +++ b/deps/checksums/LinearAlgebra-6cc040592fd509ee048658e9afb8a99a2dc20e1b.tar.gz/md5 @@ -0,0 +1 @@ +39c0cb64a6c4226f8cb07518f592a8bc diff --git a/deps/checksums/LinearAlgebra-6cc040592fd509ee048658e9afb8a99a2dc20e1b.tar.gz/sha512 b/deps/checksums/LinearAlgebra-6cc040592fd509ee048658e9afb8a99a2dc20e1b.tar.gz/sha512 new file mode 100644 index 0000000000000..41693dd5c7625 --- /dev/null +++ b/deps/checksums/LinearAlgebra-6cc040592fd509ee048658e9afb8a99a2dc20e1b.tar.gz/sha512 @@ -0,0 +1 @@ +31563375775a85fa5ae1f6584f0ebc1ffef8b66a2c76ea74111b21c5d6d171189768d40cf6a4decc203845c8d0c789da6688ad9a15ec9d5ee8e7700e1e08715b diff --git a/deps/checksums/LinearAlgebra-7264a497869f2232eaa3d740ba3b145ade3fc9f4.tar.gz/md5 b/deps/checksums/LinearAlgebra-7264a497869f2232eaa3d740ba3b145ade3fc9f4.tar.gz/md5 deleted file mode 100644 index 809e00b6e137d..0000000000000 --- a/deps/checksums/LinearAlgebra-7264a497869f2232eaa3d740ba3b145ade3fc9f4.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -1e348930bff6c7075dd4a5a29a24ab60 diff --git a/deps/checksums/LinearAlgebra-7264a497869f2232eaa3d740ba3b145ade3fc9f4.tar.gz/sha512 b/deps/checksums/LinearAlgebra-7264a497869f2232eaa3d740ba3b145ade3fc9f4.tar.gz/sha512 deleted file mode 100644 index 411324a140622..0000000000000 --- a/deps/checksums/LinearAlgebra-7264a497869f2232eaa3d740ba3b145ade3fc9f4.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -f362aa184dcfa71dbca347ae91784a83ec8317bef6b5a31ee9be9318f1d2a6cbc89283421661f916fc8478d9143f4d7f1a0ce3e54fbb64d7e98156050b80a333 diff --git a/stdlib/LinearAlgebra.version b/stdlib/LinearAlgebra.version index ae590e6655aa8..10e03e5e0f103 100644 --- a/stdlib/LinearAlgebra.version +++ b/stdlib/LinearAlgebra.version @@ -1,4 +1,4 @@ LINEARALGEBRA_BRANCH = release-1.12 -LINEARALGEBRA_SHA1 = 7264a497869f2232eaa3d740ba3b145ade3fc9f4 +LINEARALGEBRA_SHA1 = 6cc040592fd509ee048658e9afb8a99a2dc20e1b LINEARALGEBRA_GIT_URL := https://github.com/JuliaLang/LinearAlgebra.jl.git LINEARALGEBRA_TAR_URL = https://api.github.com/repos/JuliaLang/LinearAlgebra.jl/tarball/$1 From c283757bd2899a53ff0b1067f8742043f6938981 Mon Sep 17 00:00:00 2001 From: DilumAluthgeBot <43731525+DilumAluthgeBot@users.noreply.github.com> Date: Sat, 14 Jun 2025 07:00:50 -0400 Subject: [PATCH 26/83] =?UTF-8?q?=F0=9F=A4=96=20[backports-release-1.12]?= =?UTF-8?q?=20Bump=20the=20SparseArrays=20stdlib=20from=2072c7cac=20to=20c?= =?UTF-8?q?dbad55=20(#58724)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stdlib: SparseArrays URL: https://github.com/JuliaSparse/SparseArrays.jl.git Stdlib branch: release-1.12 Julia branch: backports-release-1.12 Old commit: 72c7cac New commit: cdbad55 Julia version: 1.12.0-beta4 SparseArrays version: 1.12.0 Bump invoked by: @fredrikekre Powered by: [BumpStdlibs.jl](https://github.com/JuliaLang/BumpStdlibs.jl) Diff: https://github.com/JuliaSparse/SparseArrays.jl/compare/72c7cac6bbf21367a3c2fbc5c50e908aea5984bb...cdbad55530fba0c7aa27d4bcc64dde2204ff133f ``` $ git log --oneline 72c7cac..cdbad55 cdbad55 Delete lock interface implementation from UmfpackLU (#617) 415bc9e [release-1.12] Run CI with Julia 1.12 (#635) d921308 fix libsuitesparseconfig bug f51dace Fix compat for SuiteSparse_jll fa9736c [release-1.12] Run CI with Julia 1.12 d1b0cd0 Backports for v1.12 (#624) e1817e8 Clarify pros, cons and limitations of Cholesky and LDLt (#621) b38f273 Use `libsuitesparseconfig` from JLL (#620) 66d65cc Relax `eltype` in `Diagonal` `ldiv!`/`rdiv!` (#616) 2ae8768 `ldiv!` for `Diagonal` and a sparse vector (#613) 08a15ca Replace `v == zero(v)` with `_iszero` (#610) 7ec2889 Fix `issymmetric` for matrices with empty columns (#606) f3610c0 SuiteSparse 7.10.1 wrappers and simpliefied wrapper generator process (#608) 9548149 Use `axes` instead of `1:size` (#602) ae727fe Explicitly import `Matrix` and `Vector` in CHOLMOD (#601) ce852af cleanup support for Float32 and ComplexF32 (#597) ``` Co-authored-by: fredrikekre <11698744+fredrikekre@users.noreply.github.com> --- .../md5 | 1 - .../sha512 | 1 - .../md5 | 1 + .../sha512 | 1 + stdlib/SparseArrays.version | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) delete mode 100644 deps/checksums/SparseArrays-72c7cac6bbf21367a3c2fbc5c50e908aea5984bb.tar.gz/md5 delete mode 100644 deps/checksums/SparseArrays-72c7cac6bbf21367a3c2fbc5c50e908aea5984bb.tar.gz/sha512 create mode 100644 deps/checksums/SparseArrays-cdbad55530fba0c7aa27d4bcc64dde2204ff133f.tar.gz/md5 create mode 100644 deps/checksums/SparseArrays-cdbad55530fba0c7aa27d4bcc64dde2204ff133f.tar.gz/sha512 diff --git a/deps/checksums/SparseArrays-72c7cac6bbf21367a3c2fbc5c50e908aea5984bb.tar.gz/md5 b/deps/checksums/SparseArrays-72c7cac6bbf21367a3c2fbc5c50e908aea5984bb.tar.gz/md5 deleted file mode 100644 index 12c4f2ff97697..0000000000000 --- a/deps/checksums/SparseArrays-72c7cac6bbf21367a3c2fbc5c50e908aea5984bb.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -3f25f8a47a7945b55c9cc53ef489a55f diff --git a/deps/checksums/SparseArrays-72c7cac6bbf21367a3c2fbc5c50e908aea5984bb.tar.gz/sha512 b/deps/checksums/SparseArrays-72c7cac6bbf21367a3c2fbc5c50e908aea5984bb.tar.gz/sha512 deleted file mode 100644 index 5daf7514ff4ed..0000000000000 --- a/deps/checksums/SparseArrays-72c7cac6bbf21367a3c2fbc5c50e908aea5984bb.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -5fd827602430e79846d974661b039902a5ab6495f94af8292a3d66c3c3a07a0c59858bfa5bfa941bf8bf6418af98d1dd41b88aad4cc7c7355a8e56cad7f1f3ac diff --git a/deps/checksums/SparseArrays-cdbad55530fba0c7aa27d4bcc64dde2204ff133f.tar.gz/md5 b/deps/checksums/SparseArrays-cdbad55530fba0c7aa27d4bcc64dde2204ff133f.tar.gz/md5 new file mode 100644 index 0000000000000..0cd5ebfb0fd87 --- /dev/null +++ b/deps/checksums/SparseArrays-cdbad55530fba0c7aa27d4bcc64dde2204ff133f.tar.gz/md5 @@ -0,0 +1 @@ +9f4376c0de171f481c153442dee250a4 diff --git a/deps/checksums/SparseArrays-cdbad55530fba0c7aa27d4bcc64dde2204ff133f.tar.gz/sha512 b/deps/checksums/SparseArrays-cdbad55530fba0c7aa27d4bcc64dde2204ff133f.tar.gz/sha512 new file mode 100644 index 0000000000000..207b0685cc2a5 --- /dev/null +++ b/deps/checksums/SparseArrays-cdbad55530fba0c7aa27d4bcc64dde2204ff133f.tar.gz/sha512 @@ -0,0 +1 @@ +ee756aa32d95849f728f7cfae8ba9cfce8ad51701cee6430e547f6b80b1f420e78d7d74471afc25ffc8cf6699cd5ae4e63cf38c32f3e8279179630074fda1830 diff --git a/stdlib/SparseArrays.version b/stdlib/SparseArrays.version index e7703c0221971..4e9de62c06d6f 100644 --- a/stdlib/SparseArrays.version +++ b/stdlib/SparseArrays.version @@ -1,4 +1,4 @@ SPARSEARRAYS_BRANCH = release-1.12 -SPARSEARRAYS_SHA1 = 72c7cac6bbf21367a3c2fbc5c50e908aea5984bb +SPARSEARRAYS_SHA1 = cdbad55530fba0c7aa27d4bcc64dde2204ff133f SPARSEARRAYS_GIT_URL := https://github.com/JuliaSparse/SparseArrays.jl.git SPARSEARRAYS_TAR_URL = https://api.github.com/repos/JuliaSparse/SparseArrays.jl/tarball/$1 From 6136581617e48ab618ae403a6325cc0a2083ab66 Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> Date: Tue, 17 Jun 2025 11:25:47 +0900 Subject: [PATCH 27/83] inference: improve `isdefined_tfunc` accuracy for `MustAlias` (#58743) --- Compiler/src/tfuncs.jl | 3 +++ Compiler/test/inference.jl | 19 +++++++++++++------ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/Compiler/src/tfuncs.jl b/Compiler/src/tfuncs.jl index 22a9658845fe3..fd378bcc3626c 100644 --- a/Compiler/src/tfuncs.jl +++ b/Compiler/src/tfuncs.jl @@ -405,6 +405,9 @@ end return isdefined_tfunc(𝕃, arg1, sym) end @nospecs function isdefined_tfunc(𝕃::AbstractLattice, arg1, sym) + if arg1 isa MustAlias + arg1 = widenmustalias(arg1) + end arg1t = arg1 isa Const ? typeof(arg1.val) : isconstType(arg1) ? typeof(arg1.parameters[1]) : widenconst(arg1) a1 = unwrap_unionall(arg1t) if isa(a1, DataType) && !isabstracttype(a1) diff --git a/Compiler/test/inference.jl b/Compiler/test/inference.jl index 7eba4b683463c..fb17f1991dc45 100644 --- a/Compiler/test/inference.jl +++ b/Compiler/test/inference.jl @@ -2310,12 +2310,6 @@ let 𝕃ᵢ = InferenceLattice(MustAliasesLattice(BaseInferenceLattice.instance) @test ifelse_tfunc(MustAlias(2, AliasableField{Any}, 1, Int), Int, Int) === Union{} end -@testset "issue #56913: `BoundsError` in type inference" begin - R = UnitRange{Int} - @test Type{AbstractVector} == Base.infer_return_type(Base.promote_typeof, Tuple{R, R, Vector{Any}, Vararg{R}}) - @test Type{AbstractVector} == Base.infer_return_type(Base.promote_typeof, Tuple{R, R, Vector{Any}, R, Vararg{R}}) -end - maybeget_mustalias_tmerge(x::AliasableField) = x.f maybeget_mustalias_tmerge(x) = x @test Base.return_types((Union{Nothing,AliasableField{Any}},); interp=MustAliasInterpreter()) do x @@ -2590,6 +2584,19 @@ end |> only === Compiler.InterMustAlias return 0 end == Integer +# `isdefined` accuracy for `MustAlias` +@test Base.infer_return_type((Any,); interp=MustAliasInterpreter()) do x + xx = Ref{Any}(x) + xxx = Some{Any}(xx) + Val(isdefined(xxx.value, :x)) +end == Val{true} + +@testset "issue #56913: `BoundsError` in type inference" begin + R = UnitRange{Int} + @test Type{AbstractVector} == Base.infer_return_type(Base.promote_typeof, Tuple{R, R, Vector{Any}, Vararg{R}}) + @test Type{AbstractVector} == Base.infer_return_type(Base.promote_typeof, Tuple{R, R, Vector{Any}, R, Vararg{R}}) +end + function f25579(g) h = g[] t = (h === nothing) From 870622a5ce0c059a432390c166b1369dad1e2086 Mon Sep 17 00:00:00 2001 From: Gabriel Baraldi Date: Tue, 17 Jun 2025 12:35:45 -0300 Subject: [PATCH 28/83] Bump llvm to 18.1.7+5 to fix memcpyopt issue (#58610) Fixes https://github.com/JuliaLang/julia/issues/58402 --- deps/checksums/clang | 224 ++++++++-------- deps/checksums/lld | 224 ++++++++-------- deps/checksums/llvm | 452 ++++++++++++++++---------------- deps/clang.version | 2 +- deps/lld.version | 2 +- deps/llvm-tools.version | 4 +- deps/llvm.version | 8 +- stdlib/LLD_jll/Project.toml | 2 +- stdlib/Manifest.toml | 4 +- stdlib/libLLVM_jll/Project.toml | 2 +- 10 files changed, 462 insertions(+), 462 deletions(-) diff --git a/deps/checksums/clang b/deps/checksums/clang index 2158589b5cef5..aad235644dfb1 100644 --- a/deps/checksums/clang +++ b/deps/checksums/clang @@ -1,112 +1,112 @@ -Clang.v18.1.7+3.aarch64-apple-darwin-llvm_version+18.asserts.tar.gz/md5/1dfebd0db436a282c2ccb01375e48419 -Clang.v18.1.7+3.aarch64-apple-darwin-llvm_version+18.asserts.tar.gz/sha512/d5a8fc8be8bdcfb98c3f868c1a08cb18bffaca0c9fc6efbb11beaadf40ed5ca7e2a70c3be783a7cc93b23f39e06167784f63e91abe726240ad62d11210337794 -Clang.v18.1.7+3.aarch64-apple-darwin-llvm_version+18.tar.gz/md5/f82250af13bd879486677cbf1ae0b7dd -Clang.v18.1.7+3.aarch64-apple-darwin-llvm_version+18.tar.gz/sha512/c4f67a59e30ea7bfb9ac83f07b1e07c856113dbc674d3a7d01cc7bbc326a1529f97d0e1a08a3aa60e110f901dba6d4888bae7060e24065444baaf633482108d7 -Clang.v18.1.7+3.aarch64-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/md5/2817b0eeb83eff4e1f580729e02564ab -Clang.v18.1.7+3.aarch64-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/sha512/88242559299836c7a7b7d3a216353fc6880a587a839793ed71d6d053318d6e2071ff218587a082f2b5dd9fb2b0952b4c60e62030d707435607303708bb1e6d81 -Clang.v18.1.7+3.aarch64-linux-gnu-cxx03-llvm_version+18.tar.gz/md5/d3f92998b7cc35a507cb1071baae8b02 -Clang.v18.1.7+3.aarch64-linux-gnu-cxx03-llvm_version+18.tar.gz/sha512/be22296623f604927e2e815a1cc149addda6d567270a50b2cdf77fe5b09f74313210a1ca7b1b3194592da23490ba1ccfdab9f520ce7219989e646f12208e418a -Clang.v18.1.7+3.aarch64-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/md5/716300acfdee4415f1afa3b5571b102b -Clang.v18.1.7+3.aarch64-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/sha512/b97efb3c461ea7d2736a3a8bb6b6b5c99f02df9a095f11291319c629d44f1fb934b124d38af6be3e5cc7103c6f85793d7f185c607383461de5d0c846560a1d1b -Clang.v18.1.7+3.aarch64-linux-gnu-cxx11-llvm_version+18.tar.gz/md5/034f44b2fc61791234d9580402002fb2 -Clang.v18.1.7+3.aarch64-linux-gnu-cxx11-llvm_version+18.tar.gz/sha512/0b4ff55afcec0b1e8fbd09fab57de8b44d5ded360d3b53132c7a7df8d3a3b83a495bf6e0c706784e678c6de46be3a72e8bfe562c7f8dfad90b82880849625e35 -Clang.v18.1.7+3.aarch64-linux-musl-cxx03-llvm_version+18.asserts.tar.gz/md5/54211070d63a2afac6350d06442cb145 -Clang.v18.1.7+3.aarch64-linux-musl-cxx03-llvm_version+18.asserts.tar.gz/sha512/a58f8afe9a20f202cf3956f758dc13a10be240d78877a02cd006d7e972751ed65623eef7e92a7256d9ed9157d6e277302f93b58f583d86d386ed4945f3c7d875 -Clang.v18.1.7+3.aarch64-linux-musl-cxx03-llvm_version+18.tar.gz/md5/7084567b3637fe64088fdce357a255de -Clang.v18.1.7+3.aarch64-linux-musl-cxx03-llvm_version+18.tar.gz/sha512/77ae83e159a814a7117cc859a0b2aa7a5d41f983d45b7eb1ce2fd2e93f8733ee067ac8c9fad9d5af90f852b8802043ef39c29b44430b2594892e57b61ccb680b -Clang.v18.1.7+3.aarch64-linux-musl-cxx11-llvm_version+18.asserts.tar.gz/md5/9e294d16a6e1c2c76c03f32cbbbfbe23 -Clang.v18.1.7+3.aarch64-linux-musl-cxx11-llvm_version+18.asserts.tar.gz/sha512/b8f83542b51f5cf953f6baed185550394744a8466307ee08525bf18a651fcecd7daafb98e75a0866b0e9a95a524e8940be7ae1878ba80d856182dcb7f7d2254e -Clang.v18.1.7+3.aarch64-linux-musl-cxx11-llvm_version+18.tar.gz/md5/70a41c2ffd55d2d87a7b8728287eb9fd -Clang.v18.1.7+3.aarch64-linux-musl-cxx11-llvm_version+18.tar.gz/sha512/44bb3dea7227ee991b2666c43a88613d5b5d382eb560b5ad1f1184d38680c85a2ef961bac6ad71c2b920702c1ec6e09296198e7ff5e2929f4ba7839e55896e3f -Clang.v18.1.7+3.aarch64-unknown-freebsd-llvm_version+18.asserts.tar.gz/md5/1f673de0cc2ec59cc62dee6040b2d6b7 -Clang.v18.1.7+3.aarch64-unknown-freebsd-llvm_version+18.asserts.tar.gz/sha512/9b2e64cd2cd510677375f3d07d434f46066adb7464751dfeaebb057129f6b092d8425b0728f60dd9a2ec4cb29625ffc5cda57acf1d5465d5f82765369954c58a -Clang.v18.1.7+3.aarch64-unknown-freebsd-llvm_version+18.tar.gz/md5/0d91f5a19060c6a1b1dadb3befa0fe6a -Clang.v18.1.7+3.aarch64-unknown-freebsd-llvm_version+18.tar.gz/sha512/9f9aaa36e1dab2d98a17602ed0b27163729928bfe4ac0f7b565cff1e0a653855b0f3e404830cb77ff35d93c0d5c42ed11d2506aecb5ec8d3752fbdfeb0ff5b4c -Clang.v18.1.7+3.armv6l-linux-gnueabihf-cxx03-llvm_version+18.asserts.tar.gz/md5/95ee1406f8575898eb52e2c86ae18992 -Clang.v18.1.7+3.armv6l-linux-gnueabihf-cxx03-llvm_version+18.asserts.tar.gz/sha512/4da66e4d397491836b3e539258844346fe50bff41e6c0628cbb5c0eac76147bd91d1720cec1523452efdb063adf6ef8792dc278244e1f8e194ef60a180442c56 -Clang.v18.1.7+3.armv6l-linux-gnueabihf-cxx03-llvm_version+18.tar.gz/md5/6c4e4e892b54ce81d73a8598728083e3 -Clang.v18.1.7+3.armv6l-linux-gnueabihf-cxx03-llvm_version+18.tar.gz/sha512/53d08fd8b6782867cfa6ce001b14a2fde38bc9ffc85c7e148aebf59dd9c1c535b54eaea816c39fcff42abc456c1047ed13d688917302bcc5a281abe368bd29bb -Clang.v18.1.7+3.armv6l-linux-gnueabihf-cxx11-llvm_version+18.asserts.tar.gz/md5/5acc5853111bcd529eeb06ea31b329e5 -Clang.v18.1.7+3.armv6l-linux-gnueabihf-cxx11-llvm_version+18.asserts.tar.gz/sha512/b1794f7cdfba838a7e43de8f66700ae44fd16d8f06300e8ab955044ae9bc96110c5ea72691841cd3787cdc93dfb91c6b257702c20390689a8d1b45a994db2fd8 -Clang.v18.1.7+3.armv6l-linux-gnueabihf-cxx11-llvm_version+18.tar.gz/md5/c4de50252e557fb126360001ddae6a97 -Clang.v18.1.7+3.armv6l-linux-gnueabihf-cxx11-llvm_version+18.tar.gz/sha512/9343a7272c76d5341bb49273ff8d43bed09ad99b2879ec51cfb8946174181b286af82d85e2d3a13a375c7e7859e51e4a4f06031a6a3fe7e540700cfc6a795741 -Clang.v18.1.7+3.armv6l-linux-musleabihf-cxx03-llvm_version+18.asserts.tar.gz/md5/af301478b20e56cb7fa1160cda2573a2 -Clang.v18.1.7+3.armv6l-linux-musleabihf-cxx03-llvm_version+18.asserts.tar.gz/sha512/8822c58df101c239221fead6fb523e677da04a065b42849a2e6ffff03dfd81e07f162a9bbdd29490ad9c0e0a33d362eec46608b9e6e42dfb4889da1c22191c91 -Clang.v18.1.7+3.armv6l-linux-musleabihf-cxx03-llvm_version+18.tar.gz/md5/901d2808599d5ac5ac7b5ca4bc39833d -Clang.v18.1.7+3.armv6l-linux-musleabihf-cxx03-llvm_version+18.tar.gz/sha512/820756cad00b1fe927801a253bd3077709c2b067ae79f9e1812f3cc9e85a0b7ac2ce1534031b7c6f7bda3364b7173c1c508e7c7d316920fb9bb901c16c1b18c7 -Clang.v18.1.7+3.armv6l-linux-musleabihf-cxx11-llvm_version+18.asserts.tar.gz/md5/d1f368604084e907c382aaf00efe452c -Clang.v18.1.7+3.armv6l-linux-musleabihf-cxx11-llvm_version+18.asserts.tar.gz/sha512/523b25f6b79e222eb65b5f4cd8f23b0d2c8b25b29af0df88efe45546ea57c7dabd88baef454fa0b76342d8d364739107271f25d3504380fdec5c9d225fcc2521 -Clang.v18.1.7+3.armv6l-linux-musleabihf-cxx11-llvm_version+18.tar.gz/md5/e57c116b2ad1cf32307eb4e600ac80be -Clang.v18.1.7+3.armv6l-linux-musleabihf-cxx11-llvm_version+18.tar.gz/sha512/63366b983c7aac9fe1246b25432b2200c8316f569f6930eb12de3c867f448ffccb8756d418f92eae7751d4c9ce6c42cee38237e429b81530819684fd5150c93a -Clang.v18.1.7+3.armv7l-linux-gnueabihf-cxx03-llvm_version+18.asserts.tar.gz/md5/645929ce42276db10ab79184a60cd6e3 -Clang.v18.1.7+3.armv7l-linux-gnueabihf-cxx03-llvm_version+18.asserts.tar.gz/sha512/65555ed26d9bd670b8363e5dad949822c2bf0e141a5418e1dc30c3f8a4733dd050620e40be2e7552c2551ecb30d4ef3e8f74cb240f1d441a9720a25f5a3bcaa7 -Clang.v18.1.7+3.armv7l-linux-gnueabihf-cxx03-llvm_version+18.tar.gz/md5/8424c6c6318dfa7bebeac33917b29453 -Clang.v18.1.7+3.armv7l-linux-gnueabihf-cxx03-llvm_version+18.tar.gz/sha512/6cf90c253f6b22358c2389a2347af2febd010117b22de0cc91ad713b8c8224627398004567c96b673650212eb5bd40bb97b9a637d46ddfeb3c72388d83445017 -Clang.v18.1.7+3.armv7l-linux-gnueabihf-cxx11-llvm_version+18.asserts.tar.gz/md5/ea8151dc1dc32befe579c7f9d7f13898 -Clang.v18.1.7+3.armv7l-linux-gnueabihf-cxx11-llvm_version+18.asserts.tar.gz/sha512/ed518423e9ec35afd7983471cf9ff1e971b840f637f34e0f62a1f6c7379ea59d4dafbeb9a311d39761733ecc98c0318ce3d8883298f8998e9c741441c7c9616b -Clang.v18.1.7+3.armv7l-linux-gnueabihf-cxx11-llvm_version+18.tar.gz/md5/70ed39b13bcb0435fee63bc30ae25a39 -Clang.v18.1.7+3.armv7l-linux-gnueabihf-cxx11-llvm_version+18.tar.gz/sha512/b2afa383346875514c62129c2991b3604c4fd3d507ecf4fc4244dec81d08b30218f5aa03dc4977185c2c9fb2d08848ddd373e448883ab472e5221ae5bf285c99 -Clang.v18.1.7+3.armv7l-linux-musleabihf-cxx03-llvm_version+18.asserts.tar.gz/md5/e6798835128f663f0c837aed4463e34b -Clang.v18.1.7+3.armv7l-linux-musleabihf-cxx03-llvm_version+18.asserts.tar.gz/sha512/c99856e16bd42ff967479e2c89690ea41268f1d1f868e2628482eafdfa53a0d69ed7c21ecc68ff0859eef07d9fe02f4844fad5f13df26cee6cea3a4254446096 -Clang.v18.1.7+3.armv7l-linux-musleabihf-cxx03-llvm_version+18.tar.gz/md5/92c1bd54b0474244e35c51952966a55b -Clang.v18.1.7+3.armv7l-linux-musleabihf-cxx03-llvm_version+18.tar.gz/sha512/2d7c3b60ba8b11cf903bc5ea720193852027cbe61ea0c8d6fac70be8f97691da3d36663aac6e61b68185dd83b42d09ad61dea973d9390271210d690295e4902c -Clang.v18.1.7+3.armv7l-linux-musleabihf-cxx11-llvm_version+18.asserts.tar.gz/md5/c495d594f8ce1f701d1bab54d0b60521 -Clang.v18.1.7+3.armv7l-linux-musleabihf-cxx11-llvm_version+18.asserts.tar.gz/sha512/0261bf45403daccf236723383341dc791e9cb3b291bde97812378d85aed785f083d5deea3bf806480a04ef1b972b00dccfd0537e43532a066c64733b817c3d77 -Clang.v18.1.7+3.armv7l-linux-musleabihf-cxx11-llvm_version+18.tar.gz/md5/41541de24d625271bdd5fad867b8eb0c -Clang.v18.1.7+3.armv7l-linux-musleabihf-cxx11-llvm_version+18.tar.gz/sha512/595226ad7ef75ab8ae03adb456b4ee9e884e9554c720b6c4ecbc38c75d446ddba7898be94630673074f09f40c6dc3e18fea9cee5a91b8b0e4727d20a180f670c -Clang.v18.1.7+3.i686-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/md5/8bd8ca0436611e78882939067f6277f7 -Clang.v18.1.7+3.i686-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/sha512/27c7b06e93fb0fb516b1b240e0df6c95e8bad6aea04d637ba065c6fafd087bfa94d9136afd39273c8d82d9c467395dcbd7b16f6a4b829acb0c0d4a5677676a5b -Clang.v18.1.7+3.i686-linux-gnu-cxx03-llvm_version+18.tar.gz/md5/424bfbd7b69ddf7b1199afaacde3e028 -Clang.v18.1.7+3.i686-linux-gnu-cxx03-llvm_version+18.tar.gz/sha512/9c48d949309aef6ee39371ff39a4f12c31bf3f25ddd288b317b2a17a803db73850cba2886598a1d10c4c154d511a4b79958d1acc012e92491a63f3925c522873 -Clang.v18.1.7+3.i686-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/md5/6b0b3e045ad64ecdc9848898f30d5f34 -Clang.v18.1.7+3.i686-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/sha512/6c0f4bdabbbc94fc9e1fedc138b0bce99d383e380ae7222fb70f5935f17701d549f6486956c8a21731061e4bf60bbc52794f6ce6858b4d2adb89bf80f88795c0 -Clang.v18.1.7+3.i686-linux-gnu-cxx11-llvm_version+18.tar.gz/md5/3b7a461ebf957756aeb2a2455b0a298c -Clang.v18.1.7+3.i686-linux-gnu-cxx11-llvm_version+18.tar.gz/sha512/74641a3636dd58c69415b19f0cb1de444215e22cfa9f0268fd549b5c53b206811d8beecdeb9692285613468d9a0569e836d225fb8361218438346914f6282839 -Clang.v18.1.7+3.i686-w64-mingw32-cxx03-llvm_version+18.asserts.tar.gz/md5/7533ca14f2932c35881ec05a5fb1e550 -Clang.v18.1.7+3.i686-w64-mingw32-cxx03-llvm_version+18.asserts.tar.gz/sha512/a1e55212b92c6b6dffc7e7b316c98e421e8384f65d4339455694c53643a3509b817d2ecb4e8dcd5f147dcf1be3920bcf82c1cb1732b23657bc7e36abb800d21e -Clang.v18.1.7+3.i686-w64-mingw32-cxx03-llvm_version+18.tar.gz/md5/5525f1e02315a128195cacb7f6cf7d44 -Clang.v18.1.7+3.i686-w64-mingw32-cxx03-llvm_version+18.tar.gz/sha512/9ee9fe4b1f52dc6533f177256e60b0579943e8bb5ba34118e5a02d25b6a4419133f3f819aae1e02d916cc17edd09330facdc6625d66564ad3cbd97ebfc439e32 -Clang.v18.1.7+3.i686-w64-mingw32-cxx11-llvm_version+18.asserts.tar.gz/md5/9f442a545e9c3fbb0898b7a233e5079f -Clang.v18.1.7+3.i686-w64-mingw32-cxx11-llvm_version+18.asserts.tar.gz/sha512/99cf06a5cda26001ed8d8bb4915a6a5993d4c9c5a7a038ccff99a3fa752f207b02095bdf1689f5cb9a2584a7e3ef26436b840896fe9a5b9b626980ebc7d85751 -Clang.v18.1.7+3.i686-w64-mingw32-cxx11-llvm_version+18.tar.gz/md5/9910ade7fdfc95ac2db3113fbfde42e0 -Clang.v18.1.7+3.i686-w64-mingw32-cxx11-llvm_version+18.tar.gz/sha512/6267f1b3dbbf7900bd72cd5700756e1e2c783157b87b1829af552f7dac36f749d9c7d2662235892105c959e1425914e944fbdd2f9521d2da7de321efe6c793a1 -Clang.v18.1.7+3.powerpc64le-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/md5/a6c7d64ede931fb19e066a1c191e2f6d -Clang.v18.1.7+3.powerpc64le-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/sha512/1a085a4ea1efb910f2b529f3c0e51be4a5e31debbefd00ceefeddc352b36bea6d0de5a06ea7d509098d16416b536ffed3da8485feefad7a2f11b1bc148a0c8c2 -Clang.v18.1.7+3.powerpc64le-linux-gnu-cxx03-llvm_version+18.tar.gz/md5/692af94ca3e5c3d229cbb459e266aadf -Clang.v18.1.7+3.powerpc64le-linux-gnu-cxx03-llvm_version+18.tar.gz/sha512/b27f05cfb0ada89cefc5a6f6527583b6b43d03525954d5b1ad1c807712efdb8750ea558a230b587a0c0d9e77c54d9f8978cc2f3884653808c7409eab1b32a055 -Clang.v18.1.7+3.powerpc64le-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/md5/3b59b6aa4b18b5dbbc632811f2ffa270 -Clang.v18.1.7+3.powerpc64le-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/sha512/f8c4b593f969c723ff1931c4875ed52497d83d74b94121890e10c9fcca5f6bddc5067555dee9949e61e426586ae3e568375fc44f318a07b70571ee34fdf7032c -Clang.v18.1.7+3.powerpc64le-linux-gnu-cxx11-llvm_version+18.tar.gz/md5/bc4be32ad57b13c3dabc80684a176ba7 -Clang.v18.1.7+3.powerpc64le-linux-gnu-cxx11-llvm_version+18.tar.gz/sha512/19a8346547b6c6adc2a9156e4b913b20137593752efa3648ad532b08de67cf015bba1eb023204755f48904c3381a3665c6c54fc8233c50e887a22ceebc652303 -Clang.v18.1.7+3.x86_64-apple-darwin-llvm_version+18.asserts.tar.gz/md5/13436ae410728f67c914fa7aed304736 -Clang.v18.1.7+3.x86_64-apple-darwin-llvm_version+18.asserts.tar.gz/sha512/3f83f1659580f4c5085b2da1c1a90581dcb3c45f5da1cf4d1801e230bb56fdb78a98cfe41b755949b34316ae08c55f5b2d558bb4026503ef2afa895b59dc861c -Clang.v18.1.7+3.x86_64-apple-darwin-llvm_version+18.tar.gz/md5/fa79485d88d173e15fb99b2f7fd793bc -Clang.v18.1.7+3.x86_64-apple-darwin-llvm_version+18.tar.gz/sha512/4886be75294979cdb55030747c664bd4cc2a2fa1489790d744e918a39fddcc5c214d4f39755d58206fd1bfd077774302b2be506ee80e4d0a2e2e2de642dbf124 -Clang.v18.1.7+3.x86_64-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/md5/4e5d1064d90f24d57d63f08b61baaab5 -Clang.v18.1.7+3.x86_64-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/sha512/cbfbe8b6f2be80e59b69d25d6af901ccb4807b12180208b69afa7223dd7d5249255265bc319c9402a1b0d1f0995940e3e72d7ecf1009f60d83021f8d35626a46 -Clang.v18.1.7+3.x86_64-linux-gnu-cxx03-llvm_version+18.tar.gz/md5/22fead15b4c45398ca869821d04ce015 -Clang.v18.1.7+3.x86_64-linux-gnu-cxx03-llvm_version+18.tar.gz/sha512/2ee7a7d3f293f7b63c89bbe3b541722c502a840883804ffe272848f4ac99b7a8ed350ebe92ec434dfdf03d1f4a5531c1367859f4a4603c98325abe5a0ad71177 -Clang.v18.1.7+3.x86_64-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/md5/46dd01b10377cc3d45c6a42cac0a07e5 -Clang.v18.1.7+3.x86_64-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/sha512/957677ce4251938d0c5e066448762b38a21bcce5ed424072ccd58085167d61b7e45a88fe32375f6bbd43dfb579b65a9afc09a886a650fc634a8fb9c81f27c9e3 -Clang.v18.1.7+3.x86_64-linux-gnu-cxx11-llvm_version+18.tar.gz/md5/bd9a61ea186a39162201341f0739fe84 -Clang.v18.1.7+3.x86_64-linux-gnu-cxx11-llvm_version+18.tar.gz/sha512/7a06d2a9ef20e88daa00d627d482ebbb6bf7223219d8b2a24aa60ac9eda24649d206b093d5bdb88b65c1e2b0d1ba0ad7dd927697e2bbac65bc9b42f9d14ad0d9 -Clang.v18.1.7+3.x86_64-linux-musl-cxx03-llvm_version+18.asserts.tar.gz/md5/60c98c6cc7d4446fb52b7585bc8709f3 -Clang.v18.1.7+3.x86_64-linux-musl-cxx03-llvm_version+18.asserts.tar.gz/sha512/4d55464b4499a45f774e1000a8b015326d114103a3d348fb263367e5506ca6659444ea6ee2767712903757e83939cd446aff6fe2351438b644f0057053422b58 -Clang.v18.1.7+3.x86_64-linux-musl-cxx03-llvm_version+18.tar.gz/md5/90a512d1881c4af1f1abfd5e90e37356 -Clang.v18.1.7+3.x86_64-linux-musl-cxx03-llvm_version+18.tar.gz/sha512/62d6d855aebd49f132d6470c7b0d5a0b965c6489b025046c1ea73fc53336030d6c5b4c867523a9206821f7fcf62fdb37ef0b7ff4b5eb04d07f40b65edd2c8e0f -Clang.v18.1.7+3.x86_64-linux-musl-cxx11-llvm_version+18.asserts.tar.gz/md5/c9eb9acb605d774db9636b82bf2e5f41 -Clang.v18.1.7+3.x86_64-linux-musl-cxx11-llvm_version+18.asserts.tar.gz/sha512/96e1440b3b0378edf8907d4cf779b1c53d63f6d00fa798efe1b6aaa289135aba8fd00a8d6f55d9678136e9e07d0c189293aec64f46e66788b938e1f8e1fc2199 -Clang.v18.1.7+3.x86_64-linux-musl-cxx11-llvm_version+18.tar.gz/md5/5837070450c81d44395468d8e3671dc7 -Clang.v18.1.7+3.x86_64-linux-musl-cxx11-llvm_version+18.tar.gz/sha512/0e8b674c0360f9586f03c7f5d0ffd5bc73dcde1e88eddf7d6360c1461adb8efffb104d8f454116a6a6cdc909973d0876745590b21009a9de56e12ce6e1c2e8fc -Clang.v18.1.7+3.x86_64-unknown-freebsd-llvm_version+18.asserts.tar.gz/md5/f94431ce7b8a12774925348a076e39e9 -Clang.v18.1.7+3.x86_64-unknown-freebsd-llvm_version+18.asserts.tar.gz/sha512/cdbcf5bd32a9fa4d5204e77f12d60b1fde540fc93243236f26896106d21f3b2106b0c3fcd93b1a7bbd6a9c4688200837f309b216ec9f334f8c8f28144b36d4ca -Clang.v18.1.7+3.x86_64-unknown-freebsd-llvm_version+18.tar.gz/md5/4ca4824a441d51cd4d1fe3516d7841fb -Clang.v18.1.7+3.x86_64-unknown-freebsd-llvm_version+18.tar.gz/sha512/ac0a046ede4b3c9bc75bbf7d1189e4679df6c35ca50e97fd6dadf437aba00816f66038db5dfddcfe2c49140c8416c79cfa4b67db371b4185ee897e0585b96301 -Clang.v18.1.7+3.x86_64-w64-mingw32-cxx03-llvm_version+18.asserts.tar.gz/md5/844031bd67137863f8e7dcd65aa6e45b -Clang.v18.1.7+3.x86_64-w64-mingw32-cxx03-llvm_version+18.asserts.tar.gz/sha512/56efe56f02f0d13e03ba029cc2ccf2aaf2d50479d8153b7922392ff90327e3cded2c1e7fc8cd799737cd988e64bb9c74f2c0ea6156a04fc08f22a4dbe6156cba -Clang.v18.1.7+3.x86_64-w64-mingw32-cxx03-llvm_version+18.tar.gz/md5/cc2705c3a856574835383aac7185ab32 -Clang.v18.1.7+3.x86_64-w64-mingw32-cxx03-llvm_version+18.tar.gz/sha512/eb037e996168d6d8987ff50c45e879f5e9779b044075f91cd8bbfe096260cd155b36f80bad840e88e1ab7970517e692875d5e84adc447153f167dfed886e0442 -Clang.v18.1.7+3.x86_64-w64-mingw32-cxx11-llvm_version+18.asserts.tar.gz/md5/2103b507b6aec55f8cb58a0c86aa461c -Clang.v18.1.7+3.x86_64-w64-mingw32-cxx11-llvm_version+18.asserts.tar.gz/sha512/d9a4d6eeec2aac1bc41a0be40526842e782d0796a306d3c1b5e53f7f146628ed974c8a4c4dce8baff5734d973966b4f3e1310be40b90ced9981ace4c4369a257 -Clang.v18.1.7+3.x86_64-w64-mingw32-cxx11-llvm_version+18.tar.gz/md5/daf3d83095fbad33bbb120314d6b53f7 -Clang.v18.1.7+3.x86_64-w64-mingw32-cxx11-llvm_version+18.tar.gz/sha512/e68a71d0d89d16e0c5c9182b8a3336c67179f37e247c8eef3f21e362a3258ff4815f258d2430ca3883a52a95bc26c8e2c42e3dd081f4998ed309813f3d0a4aa6 +Clang.v18.1.7+4.aarch64-apple-darwin-llvm_version+18.asserts.tar.gz/md5/d33fc7b8dad6ec4e7c3d407554004649 +Clang.v18.1.7+4.aarch64-apple-darwin-llvm_version+18.asserts.tar.gz/sha512/d2f9c58df58b520a955f2f3b867efbc0bc5acfbe4bb92b7fbd2ad88a7779b610c9afdef55bb9f29610fbcd08502a2cfe3170566fe28d24e78ba290c0e07bc3bf +Clang.v18.1.7+4.aarch64-apple-darwin-llvm_version+18.tar.gz/md5/be335c7b781138f1bf1716a57fb1a36f +Clang.v18.1.7+4.aarch64-apple-darwin-llvm_version+18.tar.gz/sha512/578caf4c00aa96328064424688bce976a29561886ff45634b44f0c17b952e825ad5136f3da3b76b59c73308e66efa7adeae0d463a091a41b23f247557881df8e +Clang.v18.1.7+4.aarch64-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/md5/bc2291806d2f778a26eb0d9bbbfb69df +Clang.v18.1.7+4.aarch64-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/sha512/682a39517d53ff1139d52cce12d08a687e37d57a0f02cabfbde901662ca6039a52f30a5d640a2bd85d3a08b8eb3d10f596e6fe6ced559527c02c2715948b04d6 +Clang.v18.1.7+4.aarch64-linux-gnu-cxx03-llvm_version+18.tar.gz/md5/cb0bf998272b6c21c3ca347a1405d5d2 +Clang.v18.1.7+4.aarch64-linux-gnu-cxx03-llvm_version+18.tar.gz/sha512/02f6c518e3a817b35459bd37de871b31f59fe05deb29a6cf969d2123b3c40a3b40f4fdf6f8b6e5476a705ee29308148777386e7edf07a300e0ba9726e04a955a +Clang.v18.1.7+4.aarch64-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/md5/d24dd31a7ce66e13abc0df85d371292c +Clang.v18.1.7+4.aarch64-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/sha512/d18712f49d5599397b8309c08aa133abd6cc31b4e44a7ee318afce345074f2e021a03287e7acd0394d3da1aa751f100b29510292073dd3503146f15a5dff7f4b +Clang.v18.1.7+4.aarch64-linux-gnu-cxx11-llvm_version+18.tar.gz/md5/dbdaa23478a49beb5e337dd8a0d18380 +Clang.v18.1.7+4.aarch64-linux-gnu-cxx11-llvm_version+18.tar.gz/sha512/9b4fc902bd433a4deba1ae80dbc6c5b0af9fb55ad2369c0155078c19905ad56bc703649f347e3ca5168a3e0f47252db5b24fca27e2e49d9a9300640dca33411e +Clang.v18.1.7+4.aarch64-linux-musl-cxx03-llvm_version+18.asserts.tar.gz/md5/883656cd00f127c9fe67cf52e1c0c6eb +Clang.v18.1.7+4.aarch64-linux-musl-cxx03-llvm_version+18.asserts.tar.gz/sha512/f78473efe02df6ec498a1c8046d6ff4f6a28df8681cb46887897566f10678cbe4b6d8da5bf566b32cc3a3ada12119efbe891d77645a9e57a32a7cf126859747f +Clang.v18.1.7+4.aarch64-linux-musl-cxx03-llvm_version+18.tar.gz/md5/ded96c4bc5ced9c54ad54ed1913aca8d +Clang.v18.1.7+4.aarch64-linux-musl-cxx03-llvm_version+18.tar.gz/sha512/b8bc33601c2db3b9b4fe1409dab5663d20ce0f0ff9a3c1177b2ab40309eec8c846e155c81d110cbe78c96f10cc95b38b06fa0558278342dcc36181d9f5ce3b89 +Clang.v18.1.7+4.aarch64-linux-musl-cxx11-llvm_version+18.asserts.tar.gz/md5/f6d3e2f0760e1669fd099902d80c8eb7 +Clang.v18.1.7+4.aarch64-linux-musl-cxx11-llvm_version+18.asserts.tar.gz/sha512/a4295c4bbfa7541bec11d51a797595405fbe6f7dd27f5feb9f5aba44a43343b1ec07dade9647c117e3cc822f6c16878e7cf4ec53838976456847958ff2c4fa0b +Clang.v18.1.7+4.aarch64-linux-musl-cxx11-llvm_version+18.tar.gz/md5/efea50a7bcfcfd479c56dfb5719f0182 +Clang.v18.1.7+4.aarch64-linux-musl-cxx11-llvm_version+18.tar.gz/sha512/eb8e78e25cfb52c4f035ee7880896827c48b900d8d5d6d6800295c9aced66d52974218a885139746f13da43e68408d44fd7da88071f26c21407226fb501baafd +Clang.v18.1.7+4.aarch64-unknown-freebsd-llvm_version+18.asserts.tar.gz/md5/3138f99666b75ef5304776263b19ee71 +Clang.v18.1.7+4.aarch64-unknown-freebsd-llvm_version+18.asserts.tar.gz/sha512/a6b9cd8874588024c7c5a28d2cd02ecc08a91617bcc98079078611c88b3821b053f3ed05b64a3129871778300544f51262cb80842ad1f56d0d7ef4bce8f311ce +Clang.v18.1.7+4.aarch64-unknown-freebsd-llvm_version+18.tar.gz/md5/65ea4e4b49ad2e131d897a7e3fef9a50 +Clang.v18.1.7+4.aarch64-unknown-freebsd-llvm_version+18.tar.gz/sha512/329da8a6cc14a4f4365cc98c97d19c0e0b79f994f279e279af20e92c12f482258f378007e3e8bb9542e2b4be352a5639e863cda2b03c9a6e6a35ebc979d4e613 +Clang.v18.1.7+4.armv6l-linux-gnueabihf-cxx03-llvm_version+18.asserts.tar.gz/md5/57a3cb518d3b97d78752d0e58c758f2c +Clang.v18.1.7+4.armv6l-linux-gnueabihf-cxx03-llvm_version+18.asserts.tar.gz/sha512/0359d1283c0bcec1932e40c00faa4571df6676af7c0ac1c7044da395b6240ae1d96e8566a15bc695339b1646910fc1edc9b60fb1c5339e8772b87ff0b38e7aa4 +Clang.v18.1.7+4.armv6l-linux-gnueabihf-cxx03-llvm_version+18.tar.gz/md5/135f3526951dcf3453a8f368dc203753 +Clang.v18.1.7+4.armv6l-linux-gnueabihf-cxx03-llvm_version+18.tar.gz/sha512/804fe6b5393d551a3278b3a8c17c06f23e8457225f0040a5179864bd814acdb4dd285203d2bd9c4a991d9ca45eb6ddc4e2a6ecf3d37cad5819f67dcc65057197 +Clang.v18.1.7+4.armv6l-linux-gnueabihf-cxx11-llvm_version+18.asserts.tar.gz/md5/48eee8f53f4cba55d7c178ff93c0bb97 +Clang.v18.1.7+4.armv6l-linux-gnueabihf-cxx11-llvm_version+18.asserts.tar.gz/sha512/944f03b54a8c4d185406f3d492aa6dbe6d2c6ea85e55fc8bdd9b1099f32478242e567175d587750d74ee9dc0cf88018ac07911e53e86c38eaa22e145ecb4f928 +Clang.v18.1.7+4.armv6l-linux-gnueabihf-cxx11-llvm_version+18.tar.gz/md5/b0887d9a754fcb9d69d57326e6bbadef +Clang.v18.1.7+4.armv6l-linux-gnueabihf-cxx11-llvm_version+18.tar.gz/sha512/ab01a41f0ef3444618e61d4e4a4a79236147026efc2909fda1c11bb622cb43178fc60ed494d4d480a1cad947d0b703fb8d6f39c5e3b503e246f2fea1c6a6fb24 +Clang.v18.1.7+4.armv6l-linux-musleabihf-cxx03-llvm_version+18.asserts.tar.gz/md5/86d8d2608c949d81eafdafe5566e5dea +Clang.v18.1.7+4.armv6l-linux-musleabihf-cxx03-llvm_version+18.asserts.tar.gz/sha512/d7b5c8c6d296883237bcdb7e1b3c14f486a689ecfbc323e9f21a3037f8349f67f8cc69ac842722544f0a51c589e970abbdcee4f7d6f62b624b8ff36c1810c739 +Clang.v18.1.7+4.armv6l-linux-musleabihf-cxx03-llvm_version+18.tar.gz/md5/3cbd719a2d2d9a5a221234acc259ae3d +Clang.v18.1.7+4.armv6l-linux-musleabihf-cxx03-llvm_version+18.tar.gz/sha512/3e6587a89880a4fa46e2488a2d825afb58fc747c17d854b71da15113d37f6d23213a8026a50fb3b7173a7cac6d8edd51837782971abc2a1b19c18645e97b1599 +Clang.v18.1.7+4.armv6l-linux-musleabihf-cxx11-llvm_version+18.asserts.tar.gz/md5/6f8373c6a149020f96abdbb55bc464e2 +Clang.v18.1.7+4.armv6l-linux-musleabihf-cxx11-llvm_version+18.asserts.tar.gz/sha512/a8e655239e436892250ca329ce682a924eed4dd85eb03cf29716f4606f8ade05e6e5808e2bdd69e3e0dc7f648b7ee318e1c966f9793cfd09099283ff58ff0a40 +Clang.v18.1.7+4.armv6l-linux-musleabihf-cxx11-llvm_version+18.tar.gz/md5/ad3f423db87f59f7dae16011e1d7e749 +Clang.v18.1.7+4.armv6l-linux-musleabihf-cxx11-llvm_version+18.tar.gz/sha512/613e5f4a5f00f67471cdf59df2ec8748301d781edb9a4122cb48a89805930ac681dc6962d629fca272b204751e8cdc3d4026d14f5209a85f007de458719d7b44 +Clang.v18.1.7+4.armv7l-linux-gnueabihf-cxx03-llvm_version+18.asserts.tar.gz/md5/8f62a3e5ee232df367ae24ef441262a7 +Clang.v18.1.7+4.armv7l-linux-gnueabihf-cxx03-llvm_version+18.asserts.tar.gz/sha512/fe058fca8c840f09acf853811c4b1c3360826150ad2b8c331e005fd7a3eee2967dcf59cbccd72e32e906490b208f48c91e9e0bd6d20e31f0fb9e002b964215d6 +Clang.v18.1.7+4.armv7l-linux-gnueabihf-cxx03-llvm_version+18.tar.gz/md5/a15a3f2724dc4f50de9b5471194b1b51 +Clang.v18.1.7+4.armv7l-linux-gnueabihf-cxx03-llvm_version+18.tar.gz/sha512/74a798b2c87ba66c049f25f25d14cd3682a4a3e515baa59c8c0207cef7f5496bbd98a5e3b292560c15fa8816569296bf82d5bde4c7e030308f9011a0c69c1840 +Clang.v18.1.7+4.armv7l-linux-gnueabihf-cxx11-llvm_version+18.asserts.tar.gz/md5/d4dd462dde96aabc2fd58dc142e8e37a +Clang.v18.1.7+4.armv7l-linux-gnueabihf-cxx11-llvm_version+18.asserts.tar.gz/sha512/a6e3816306d333e0ae01da09569fa7bf9c6af2b04e9f43be922ec6b70deab7607c928acf4bf64f27dd2d0a8811ac40c0334c432a2862895c2e34230592c66dde +Clang.v18.1.7+4.armv7l-linux-gnueabihf-cxx11-llvm_version+18.tar.gz/md5/a48d2577f84929236a41dbcedcfaa9d5 +Clang.v18.1.7+4.armv7l-linux-gnueabihf-cxx11-llvm_version+18.tar.gz/sha512/dc87739dc39864372cab02e4d6bbdda3fb7f10f51c2bc05a45e9debf58b81c80cebe95300d116f85b3838eabd8d157f7dd325f797147fb17d1578d0e27ee12d3 +Clang.v18.1.7+4.armv7l-linux-musleabihf-cxx03-llvm_version+18.asserts.tar.gz/md5/1f48da1003bb100eb7646ac587802dcb +Clang.v18.1.7+4.armv7l-linux-musleabihf-cxx03-llvm_version+18.asserts.tar.gz/sha512/9a5132ffbaa315ea03c220646886ac6775d07ed62cd94fa72b49a5eb64705ec701459a0894dfab13f895f39f12db740c2bfef61b23e5ef5d6879188f76c05f6f +Clang.v18.1.7+4.armv7l-linux-musleabihf-cxx03-llvm_version+18.tar.gz/md5/7904719daabee715eb119aabe407d821 +Clang.v18.1.7+4.armv7l-linux-musleabihf-cxx03-llvm_version+18.tar.gz/sha512/7060e68295d2c3709bc02ad369616323771d12c62dd58fb95cda09007dcb4983bde68150cc7190fa3d96cb8be96f6fe3cbf4d88178e847aef7406d7db3639d58 +Clang.v18.1.7+4.armv7l-linux-musleabihf-cxx11-llvm_version+18.asserts.tar.gz/md5/44f02b2fdfd7714b9eb4d9f2a3120994 +Clang.v18.1.7+4.armv7l-linux-musleabihf-cxx11-llvm_version+18.asserts.tar.gz/sha512/e71c06c472b5e5f08479c48d8520c4eccd44265b8f200b12268739da8c3c387a25bf5b7dd556da27cc5063fce5627d4507b6f5dc73781e21a16d59954979b4bf +Clang.v18.1.7+4.armv7l-linux-musleabihf-cxx11-llvm_version+18.tar.gz/md5/3654e21fd175679b200eed03ef251023 +Clang.v18.1.7+4.armv7l-linux-musleabihf-cxx11-llvm_version+18.tar.gz/sha512/6ec7478869b94b20e4069ff465253c6f8e66c8254a855423d43f288fcdaf3b283761660a395dac3227fd9eb3f10ffb7592ab709d15ee554d5ce35ec841a7a2a5 +Clang.v18.1.7+4.i686-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/md5/a22748f90259dcbb30bb95d6c468b93c +Clang.v18.1.7+4.i686-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/sha512/1a4728e6a43fb4e527ef3a1ce791f9c0f90f351bddc2b3e0a58b7ae68eeefd0007429e49e8d3b2f606acf1d75cdd74c7c17b7b2124d6d524bed46d800f3a3be6 +Clang.v18.1.7+4.i686-linux-gnu-cxx03-llvm_version+18.tar.gz/md5/a82d206cec9e650916da80480c7cb475 +Clang.v18.1.7+4.i686-linux-gnu-cxx03-llvm_version+18.tar.gz/sha512/ac15d4f641cb8410af7e66cbfa22a90d6772926f4a918f6a36dd80f30e3f5f226fcd13019b68891d7569cde1902b872e9e8426ee753bc64e7d3360b362bdb4d1 +Clang.v18.1.7+4.i686-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/md5/0a7fc5a1150c3f6890b6b445c577a737 +Clang.v18.1.7+4.i686-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/sha512/a1ab1a9fd500d2e97f95f01c9580c454e94f93c4e7cef3aa667c14e98465797b4d2f172ff2534f7eb0c05a94f03d8a4bfde0f0f56a46d2199163ff25f55cfae3 +Clang.v18.1.7+4.i686-linux-gnu-cxx11-llvm_version+18.tar.gz/md5/df70c6d93254aa1680138ec8a0758410 +Clang.v18.1.7+4.i686-linux-gnu-cxx11-llvm_version+18.tar.gz/sha512/49a297bc347ef68ef1fd1c331c1c91526ac618459d132f2404e62e42d6a31f9485be6500d41d332b740261b64a704ffa373ab2d9f455f637185e96d7345090b5 +Clang.v18.1.7+4.i686-w64-mingw32-cxx03-llvm_version+18.asserts.tar.gz/md5/613a1fd0ddbf4ef27848ddaef2525f9b +Clang.v18.1.7+4.i686-w64-mingw32-cxx03-llvm_version+18.asserts.tar.gz/sha512/6c5e544e400cdcd301515f7aaee5d24e46fe33ba8961795ac1e81a30403848ac23429903b999c32d0ac654ed6a4727cdddf3245f786cc26de54e437c721902ef +Clang.v18.1.7+4.i686-w64-mingw32-cxx03-llvm_version+18.tar.gz/md5/bb28c582b879422fee920ba57821b2f9 +Clang.v18.1.7+4.i686-w64-mingw32-cxx03-llvm_version+18.tar.gz/sha512/3b7efc14099222759c45f3ebe8289e5781c0ff92ec38da476100eb57c69be491e4536025ae8f4c427182628143422e0dbe2d16bc0bada70db69a466aa08412c8 +Clang.v18.1.7+4.i686-w64-mingw32-cxx11-llvm_version+18.asserts.tar.gz/md5/b291718251843b0141b72095953151d0 +Clang.v18.1.7+4.i686-w64-mingw32-cxx11-llvm_version+18.asserts.tar.gz/sha512/c2b631aac4f113c1fa8b2141d574abd6508eaaf1ed04037949cc731681c659f3a4150aa621225bbcdef32cafcea7cc756188cccc61a89f9f425d57a00cb823ba +Clang.v18.1.7+4.i686-w64-mingw32-cxx11-llvm_version+18.tar.gz/md5/e970211376c779e878cf378563f7325c +Clang.v18.1.7+4.i686-w64-mingw32-cxx11-llvm_version+18.tar.gz/sha512/9672440cd03ebf3b7a049c977c0391483095de69f641eded0979d6fbc67b7befb6a24176b0878efbf0c8856f0470c951d00a50355511378b5f6793387b42d7a4 +Clang.v18.1.7+4.powerpc64le-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/md5/860aa7dff4119e0b488bfe30be3255cc +Clang.v18.1.7+4.powerpc64le-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/sha512/92a40626eb48b70b89b53c81114bb8c022ce38d4582049e3a3520d396c22028e34229bf7d8a4cd6c840f979a4edf424c458ba33da15db5a4cf34b038ffae9389 +Clang.v18.1.7+4.powerpc64le-linux-gnu-cxx03-llvm_version+18.tar.gz/md5/892cd95401702eaa30d0b81b0b1921b7 +Clang.v18.1.7+4.powerpc64le-linux-gnu-cxx03-llvm_version+18.tar.gz/sha512/ebc9a819d352137b23338801c59df02afef86a780394397711a36291fc86e2e3128bde5386ced54142b297116b03af27bb9a5e6b890ba49d32a2e4a07730ad55 +Clang.v18.1.7+4.powerpc64le-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/md5/3dc49fdfb7a900f9ca0593eee6b2ab6e +Clang.v18.1.7+4.powerpc64le-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/sha512/a8970cf6f091833ab2dcc07711e2d6ca31c6ee71fc8487a24a88048db991c0beb5f175da676a3031e982357030cfe359e996af9da7e8ea88359d7314a114a304 +Clang.v18.1.7+4.powerpc64le-linux-gnu-cxx11-llvm_version+18.tar.gz/md5/52a9bd4fa31f79a4b3fafc32c087e7a2 +Clang.v18.1.7+4.powerpc64le-linux-gnu-cxx11-llvm_version+18.tar.gz/sha512/5befeb640f0d0200389c78f8c01835ea421d7705bd589f138acc2ae0b08d4f01614dfa4b165ea40dd6bd50c4f11c9252e507bcaf9767bb00c099d246770a9704 +Clang.v18.1.7+4.x86_64-apple-darwin-llvm_version+18.asserts.tar.gz/md5/229dd91f636793cc2d9cf940d2abd3a4 +Clang.v18.1.7+4.x86_64-apple-darwin-llvm_version+18.asserts.tar.gz/sha512/1ce5692bcb8ef1547479dbf9bf6d2abd5ec8f86ff28d3f7a9c79a314a0847437b18cc4f6a3b280c3dd01339130acd39f31cf21dc0911d5104ff1b465af05ddb7 +Clang.v18.1.7+4.x86_64-apple-darwin-llvm_version+18.tar.gz/md5/25b1b7a73c93e02879c4bfe665c1ad44 +Clang.v18.1.7+4.x86_64-apple-darwin-llvm_version+18.tar.gz/sha512/6f919c7b3c79046a1ec079334e827191a051f926e2385acb019e47a418002b1702a8b6e50cbb3d7a2be480dd942f93a740f5a34a878dd291ca1f27f59867d04f +Clang.v18.1.7+4.x86_64-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/md5/7b378124b57c43c59737adb0c25215bf +Clang.v18.1.7+4.x86_64-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/sha512/87597c30161ebaebcfd22ac8d032cedd35765e2d15e909857940ecd441430d9a47b9186b509390d1ceeace3d6701bc7dbd56bbc103ca568cc89bef20522af70f +Clang.v18.1.7+4.x86_64-linux-gnu-cxx03-llvm_version+18.tar.gz/md5/6224e76523b9a3c05ceb404452aa2a73 +Clang.v18.1.7+4.x86_64-linux-gnu-cxx03-llvm_version+18.tar.gz/sha512/8b99badd21d9931abad9ceae3036b7a4bd6a140440d4a9e550f5e7212fe5278fbf3e51018883423fa9b8b7d907067bf03045708272fae4ae252f37543775ce44 +Clang.v18.1.7+4.x86_64-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/md5/2b2eaf5af3f56281be586cdab0a75631 +Clang.v18.1.7+4.x86_64-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/sha512/7065cc65c9626a745a06d22b5a0bf7672be50caf9761953b3c631a5d20d3792a37090d106b967b4f74c4c4a7309bd7647487db6953ecdcd5dd2080fe81f9e93a +Clang.v18.1.7+4.x86_64-linux-gnu-cxx11-llvm_version+18.tar.gz/md5/073bbdd2a26d53c2a14c36a7fdfe739a +Clang.v18.1.7+4.x86_64-linux-gnu-cxx11-llvm_version+18.tar.gz/sha512/0dfbfe35be2775baa5737a7fb1bff55c5cb4158edb735d7191c1e2a9b08124f5a7949696371a2d1b3ea0cb1a0ce593e74a53ead86680675e2d54c9e16733dd90 +Clang.v18.1.7+4.x86_64-linux-musl-cxx03-llvm_version+18.asserts.tar.gz/md5/8b6e067d0b1cd9882207334269568a36 +Clang.v18.1.7+4.x86_64-linux-musl-cxx03-llvm_version+18.asserts.tar.gz/sha512/98f779e75614ba8ae2ae16d3d740ebbdc1428109d5716b51e53e8cf22bc4844bad47ac37a62b23c769dd0897581acd1e4e8c6f6f70db0043d73b2c5bd44216cc +Clang.v18.1.7+4.x86_64-linux-musl-cxx03-llvm_version+18.tar.gz/md5/b3a23a539915b32d2de6ad5ed073ea20 +Clang.v18.1.7+4.x86_64-linux-musl-cxx03-llvm_version+18.tar.gz/sha512/6cc5c7de57018ed61b7661965480b1e3e52c357e8a18c70aa17350613dc74df5cecfadc329536b8ce61e784eb3f327c0739f36c614af100c3b1550982b5b03fa +Clang.v18.1.7+4.x86_64-linux-musl-cxx11-llvm_version+18.asserts.tar.gz/md5/c269baae05161d61d6346dea052787be +Clang.v18.1.7+4.x86_64-linux-musl-cxx11-llvm_version+18.asserts.tar.gz/sha512/7a245fe24db9b9dfdf18e83fcdc1224329c6836bf02f6b21e6b8573e6d7fdcbc597300bb396ed71cbab6a8430a75e8e58be8b1130d01e476f5ab19969baf2551 +Clang.v18.1.7+4.x86_64-linux-musl-cxx11-llvm_version+18.tar.gz/md5/0c26d80c0202baadd22d18750bf83546 +Clang.v18.1.7+4.x86_64-linux-musl-cxx11-llvm_version+18.tar.gz/sha512/32ff9b8b395fa5b760b909331a4ef845b234d42ad37a5869a4a6e150ff74e1129588a38ce143ce08c5c326ba85b9bac6bd6dc3b763b72a609f65174e02a774b6 +Clang.v18.1.7+4.x86_64-unknown-freebsd-llvm_version+18.asserts.tar.gz/md5/8643b8eb284d1bc30ac7ee5395f98c58 +Clang.v18.1.7+4.x86_64-unknown-freebsd-llvm_version+18.asserts.tar.gz/sha512/35d4e724706395bc05ff02c5eabb938941e2b14fb7029b6cc170f3fa59af4d7f372eea23d3b43f899a109aefdf5689eabbe0a3dd2e5d8d9e74994f56115e08fa +Clang.v18.1.7+4.x86_64-unknown-freebsd-llvm_version+18.tar.gz/md5/f51d045b21cc4073fe6f4a1abf80f21e +Clang.v18.1.7+4.x86_64-unknown-freebsd-llvm_version+18.tar.gz/sha512/4d7d4222eca7dddb3c0804866dd7420742238b92369bea2c28f0e18c583ee22f2588724a5ea152ab7865399b5427cced9ad1ea58aa8c30e255b43a6c1e63c551 +Clang.v18.1.7+4.x86_64-w64-mingw32-cxx03-llvm_version+18.asserts.tar.gz/md5/670ac3b79ae1ac2285ee6f553338078b +Clang.v18.1.7+4.x86_64-w64-mingw32-cxx03-llvm_version+18.asserts.tar.gz/sha512/498cd3ba565f697a70a33a14bd56eaa492d9cc4f3451c1bf4a987c00fcf53b6a7542f321869ac35a0f42ebd6e261103e9cd6a60bcac9c15932accaf972f28b80 +Clang.v18.1.7+4.x86_64-w64-mingw32-cxx03-llvm_version+18.tar.gz/md5/7a8e855d96e33c53fb9e5940aca39763 +Clang.v18.1.7+4.x86_64-w64-mingw32-cxx03-llvm_version+18.tar.gz/sha512/d4e0c4efc943606092b98fd8718a6a27efb034a14a03c489c12de1abee6ad9c5567a3fa952ae183ba2b60221d70c401d658d3b6d236b28e7751ba2d3439cf81a +Clang.v18.1.7+4.x86_64-w64-mingw32-cxx11-llvm_version+18.asserts.tar.gz/md5/340fb259209e11bcb6ec15e0561b566d +Clang.v18.1.7+4.x86_64-w64-mingw32-cxx11-llvm_version+18.asserts.tar.gz/sha512/b4d173c20a85363c8f10170419ef59c1a23734c19a594bd5c0232f77d64947d9559ad124cad37024fb04c37f043115777d719e96521cfb27ecdbd9d193c76897 +Clang.v18.1.7+4.x86_64-w64-mingw32-cxx11-llvm_version+18.tar.gz/md5/9595c42011ce0c8156d6e8c2467304ab +Clang.v18.1.7+4.x86_64-w64-mingw32-cxx11-llvm_version+18.tar.gz/sha512/0c660e25f479ab0d01a607d1d1f59006b1504fea8b515b67726d1f4f2f4255cd9bfd5b8ae0c97d51f9bf57b619a2b1c5e9136f4a74927c55dfa127fa710108d8 diff --git a/deps/checksums/lld b/deps/checksums/lld index fff3140025e8d..660ec90c3a458 100644 --- a/deps/checksums/lld +++ b/deps/checksums/lld @@ -1,112 +1,112 @@ -LLD.v18.1.7+3.aarch64-apple-darwin-llvm_version+18.asserts.tar.gz/md5/229323a0b31c29b4221d79ace1a76820 -LLD.v18.1.7+3.aarch64-apple-darwin-llvm_version+18.asserts.tar.gz/sha512/c00fb8bf309f0cc6c8cb4465cc0062a8b1a848d9460c53241be654d88c598847b4590b4afa4b71c4859cfc67490942eddd79ae9ac4d75a9b0e392fbf67389a92 -LLD.v18.1.7+3.aarch64-apple-darwin-llvm_version+18.tar.gz/md5/ce7804a6a846d0d951aae34607c43bdc -LLD.v18.1.7+3.aarch64-apple-darwin-llvm_version+18.tar.gz/sha512/164adec7649a36b2967872884866de1c57f6f54e1c24f955593f9f6a10cd89c69493a64a37bf9f001ce3576baed867423d138dfb1df0139b4c1312e81001b167 -LLD.v18.1.7+3.aarch64-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/md5/cea134f347bae257cf5f55b6388cef81 -LLD.v18.1.7+3.aarch64-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/sha512/16b59143e929791b0c3e56cfb4970d8b3c87adf6e847fa9e2aac17c4ff2aa311ba2c7511c1b0ae2f39d9aa92f87ad4d99c042fe35bec391ac865fedb72bd3b1e -LLD.v18.1.7+3.aarch64-linux-gnu-cxx03-llvm_version+18.tar.gz/md5/5f903bab0e38fa608e8965acce6f020e -LLD.v18.1.7+3.aarch64-linux-gnu-cxx03-llvm_version+18.tar.gz/sha512/01e5f6a32958e04174c545f57c6c3b1bc88ccfd5ab18dcb9d67b92b55ebc7655a03bf963c4eaf7e5c3792d4691427a89db372e7534c6c8f965f8a715a32d9284 -LLD.v18.1.7+3.aarch64-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/md5/241a55374fd067f3736a2bb929e47015 -LLD.v18.1.7+3.aarch64-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/sha512/f1fedea4e6b5f6f3bbf4d705034d6c51b06f011c2ecec1ae49c5b7bd123891eee8b991462d60be7fffd58f7c773afe910a06ec0b55b37eed9b4d09b9fdbd5068 -LLD.v18.1.7+3.aarch64-linux-gnu-cxx11-llvm_version+18.tar.gz/md5/ff018c7448a7589935333e46739ee2c4 -LLD.v18.1.7+3.aarch64-linux-gnu-cxx11-llvm_version+18.tar.gz/sha512/b646c6a945b8f42b396164a8e87fc2e54b1ad05681f438dfba83fdd3712a60167aaffcb0300bc42d904eb4bd34c002a71642b59540ca01e64d6fecc6daaacdd8 -LLD.v18.1.7+3.aarch64-linux-musl-cxx03-llvm_version+18.asserts.tar.gz/md5/e6ee9423a82322b9233cafb1c92eed2d -LLD.v18.1.7+3.aarch64-linux-musl-cxx03-llvm_version+18.asserts.tar.gz/sha512/c915582a9ce2dfa8721741fb1ed19b719ba40f0092c2d29ebd68829ee558cef0b044a5e40985cff88e89129cbeed052d85fa5c6b6d87f9b3a68a6e89079ab4f3 -LLD.v18.1.7+3.aarch64-linux-musl-cxx03-llvm_version+18.tar.gz/md5/cc55112e2db358cf26d7bae3211d8e4f -LLD.v18.1.7+3.aarch64-linux-musl-cxx03-llvm_version+18.tar.gz/sha512/0ecb43045419020eea911f1767dae23a6b1e81bb155ec493e911a9412e45f7ec71461aea2e6fe346e641747139cae43d9435ccecaa7fd6a234e4d69bb06606ed -LLD.v18.1.7+3.aarch64-linux-musl-cxx11-llvm_version+18.asserts.tar.gz/md5/498b2909f80b20588135466d5211bc80 -LLD.v18.1.7+3.aarch64-linux-musl-cxx11-llvm_version+18.asserts.tar.gz/sha512/120fff24e85cf970670b20b5f4509475a3ae0d7621f8f67d018f3a7625548d736a3abc89f015966b1329c6b0a08a1db832e035ee3bae384e2c5864b73a856600 -LLD.v18.1.7+3.aarch64-linux-musl-cxx11-llvm_version+18.tar.gz/md5/1bcd298d5292f8e51f19b97fa4b27ab0 -LLD.v18.1.7+3.aarch64-linux-musl-cxx11-llvm_version+18.tar.gz/sha512/695c42557f9ee53b2e10bbf74653fbad4d02124b962a1f50cf719d2821607dfbb9c1bf638dbbc9e0e544f3020a9ef4a82decd13f886cc41ddf47c07a5e40eaa1 -LLD.v18.1.7+3.aarch64-unknown-freebsd-llvm_version+18.asserts.tar.gz/md5/f0e0668d29253cd834418c88ad63df31 -LLD.v18.1.7+3.aarch64-unknown-freebsd-llvm_version+18.asserts.tar.gz/sha512/f910fd8ca972b1cbe0704d4d73273e2d6911d31ae5fe842250802cd33453e4fa2ed03ae4b4df43ea4df13711cf2409c16b1c44832b44cb05f7681488c4402681 -LLD.v18.1.7+3.aarch64-unknown-freebsd-llvm_version+18.tar.gz/md5/84f79f1ce1fcd57ec4bd499a684da120 -LLD.v18.1.7+3.aarch64-unknown-freebsd-llvm_version+18.tar.gz/sha512/d0e4a7ecff0e3f499dc22a9409ab8bff9099d4fdf191916426be917695c7fd55043b41cb0fa21541c3d6a6c202736b5c7b8fce53244e3ac713560a47a0ed6588 -LLD.v18.1.7+3.armv6l-linux-gnueabihf-cxx03-llvm_version+18.asserts.tar.gz/md5/2323ff933feaf3754b442bee48a63607 -LLD.v18.1.7+3.armv6l-linux-gnueabihf-cxx03-llvm_version+18.asserts.tar.gz/sha512/47b8e490b89e04fb8886dae438e3ddcd53c4e98045de2b0def3988671827528c8e9ae296411464c0f17cc64bd3956644673f47a3817237f27e1c3ed16ac8ef01 -LLD.v18.1.7+3.armv6l-linux-gnueabihf-cxx03-llvm_version+18.tar.gz/md5/37cf8528666064a434296f2e0039e9c6 -LLD.v18.1.7+3.armv6l-linux-gnueabihf-cxx03-llvm_version+18.tar.gz/sha512/ea1504a859509f8a16030db7a65f42f0e78d67adf5946497f2178bf25456c0f2583af72c636881a4bdd1210dc0d377bdf300ef55aef5db8c56995424a1886059 -LLD.v18.1.7+3.armv6l-linux-gnueabihf-cxx11-llvm_version+18.asserts.tar.gz/md5/1c341f2b161e2320d3d1a74685887f54 -LLD.v18.1.7+3.armv6l-linux-gnueabihf-cxx11-llvm_version+18.asserts.tar.gz/sha512/4f6fc099293deb1a2cf729ea7edd6e17fea0dc8b9fae9acfe34e00b1f5c798933df9538c805c8d28c6279eb38f9ebae2a1aeb1a2f23087352c6eeb3b27b63ddc -LLD.v18.1.7+3.armv6l-linux-gnueabihf-cxx11-llvm_version+18.tar.gz/md5/e306d59c71b0958c77108e650fac2612 -LLD.v18.1.7+3.armv6l-linux-gnueabihf-cxx11-llvm_version+18.tar.gz/sha512/79fd7cec0e169a9555ec9b0acc3248991e2e37a1d5bb422808ffcfd4f47e79321560b7985c82dfe070fb0b5ded5c160d83e358399c6e7608eeb62cd4a1406f88 -LLD.v18.1.7+3.armv6l-linux-musleabihf-cxx03-llvm_version+18.asserts.tar.gz/md5/c1d080f1aebb58778d730578fb113290 -LLD.v18.1.7+3.armv6l-linux-musleabihf-cxx03-llvm_version+18.asserts.tar.gz/sha512/1f420da1897bd0a61413321aaaf032e8ed38d59e6dfe3313ca3a6ee6582ae6c566e3761ca8fcd1f5a964337ba8a9b3e73dc55ad68aca139beeb45e43d51e862b -LLD.v18.1.7+3.armv6l-linux-musleabihf-cxx03-llvm_version+18.tar.gz/md5/6f4e0c7d2fe9ac254650dcd2842dafa8 -LLD.v18.1.7+3.armv6l-linux-musleabihf-cxx03-llvm_version+18.tar.gz/sha512/bbc71b334250e5e6429766d88595adbb671a206630987ec2a27e05711ff0f844487dffc1c136052ec11394e9d5c51c70d1b75d5348f97d3bf7fab463291e9dc8 -LLD.v18.1.7+3.armv6l-linux-musleabihf-cxx11-llvm_version+18.asserts.tar.gz/md5/76925b9a7bc249b2227390c479c54f8d -LLD.v18.1.7+3.armv6l-linux-musleabihf-cxx11-llvm_version+18.asserts.tar.gz/sha512/20643ecb79732e3ae9666116dbd0763c18b808afa78e6a14998aadc7265cccd6efd28670592db61d3d27b8d3023be4c5f3df41fff9e1b38d61abf76829090b4f -LLD.v18.1.7+3.armv6l-linux-musleabihf-cxx11-llvm_version+18.tar.gz/md5/399b9aac140d9050088fdb187ed4645f -LLD.v18.1.7+3.armv6l-linux-musleabihf-cxx11-llvm_version+18.tar.gz/sha512/8bab65965670fe392e78d0b9dc78c92cdcf202898f6d5a3174eb89ca5cb95b995675c8a7d81bbc4e95e490ad1a43d9d29d7907b7006789c0143a1d8f24cccaeb -LLD.v18.1.7+3.armv7l-linux-gnueabihf-cxx03-llvm_version+18.asserts.tar.gz/md5/026a4f5ae9eb3ac05e5e8fa894d77a5b -LLD.v18.1.7+3.armv7l-linux-gnueabihf-cxx03-llvm_version+18.asserts.tar.gz/sha512/4bca8bd558619260cddf4e2f4593cbb2a0691b5ccc6d1dea6dfcc5a2b5f51d7d1a76c35e481244e211e2eacf32bd628df5ad0e6c75e5185bb1d9b569f6acbfd3 -LLD.v18.1.7+3.armv7l-linux-gnueabihf-cxx03-llvm_version+18.tar.gz/md5/f898ceabcba052b7e6713a2b2c208a92 -LLD.v18.1.7+3.armv7l-linux-gnueabihf-cxx03-llvm_version+18.tar.gz/sha512/92be1910f795390be5f15ba5b2c220a3209a5f7ac04fca3f5229486628bcf5d2f20cf6e4dda8b41d6beaaff42a68a9ddb95fdacc6eae33b9183b581e9a194895 -LLD.v18.1.7+3.armv7l-linux-gnueabihf-cxx11-llvm_version+18.asserts.tar.gz/md5/e366058cf69a4367945bdba9523f2a0b -LLD.v18.1.7+3.armv7l-linux-gnueabihf-cxx11-llvm_version+18.asserts.tar.gz/sha512/45a786e8d0162bd5bd01c029691d2928d3744ef4a7a1efc2e39755dee2f9a9ae23ee725f0454ca601cb9c082a342209e9129df851314b5757c74767b13508fc4 -LLD.v18.1.7+3.armv7l-linux-gnueabihf-cxx11-llvm_version+18.tar.gz/md5/665a8502170729c86ea95a7ea2fcce0f -LLD.v18.1.7+3.armv7l-linux-gnueabihf-cxx11-llvm_version+18.tar.gz/sha512/c1a2a85c9ce14af8c91bc9a599393c52c0b8a585057366b1ceeed34c5db44641ecd0c9b377bee80cb4951fc7102fbb4f21fd050126bfa5bb4e582ffefee17035 -LLD.v18.1.7+3.armv7l-linux-musleabihf-cxx03-llvm_version+18.asserts.tar.gz/md5/b90b2130262f63f5189cc8e4a65e4433 -LLD.v18.1.7+3.armv7l-linux-musleabihf-cxx03-llvm_version+18.asserts.tar.gz/sha512/c1cbfd38c82d676c3fdbec486691334cf7bf4115d9ef2665012b71725c28545a49f34edf5689ea0352822c811c24c89cc152d1fccd1586b17ae8e6b2503641df -LLD.v18.1.7+3.armv7l-linux-musleabihf-cxx03-llvm_version+18.tar.gz/md5/2d5360da4b2c9ffcea5d0a646a7c114b -LLD.v18.1.7+3.armv7l-linux-musleabihf-cxx03-llvm_version+18.tar.gz/sha512/73323e0937fe4423883480294c8df44744acde4f47380e35535cbe69c855c0e35e86a1eced3085ae0285f284f47af5ef237f4650bf2b6a8b9d5308efce88fa02 -LLD.v18.1.7+3.armv7l-linux-musleabihf-cxx11-llvm_version+18.asserts.tar.gz/md5/a9b9a65938a7701aaac6fa706481c867 -LLD.v18.1.7+3.armv7l-linux-musleabihf-cxx11-llvm_version+18.asserts.tar.gz/sha512/fe8243aa131ad8be54f0fca5754c2e68ec39049004ec8feed499731c5228a7a46e303ba866b9f9a55e5318c73d8a46d964673e111f6c60e5ae1628c568d7d894 -LLD.v18.1.7+3.armv7l-linux-musleabihf-cxx11-llvm_version+18.tar.gz/md5/0d9592a287c9231ae2db65000be2cea2 -LLD.v18.1.7+3.armv7l-linux-musleabihf-cxx11-llvm_version+18.tar.gz/sha512/4ee192dd33f518d2735a829ac8f822b5672b39e8c2254987aea6e5f2f0056213bd85d84c4050d52ba9ac8c35762521c324fe2d6e18db0396e7142af9cb61a561 -LLD.v18.1.7+3.i686-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/md5/d487598dec9969485dcf785fc0968bd4 -LLD.v18.1.7+3.i686-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/sha512/8d3117739919696b9b0c9ae398f1b1e9db8bd3e2e27839f62b3551c22ae2517f8abb69e57e23d125002bb466889b7352e69c1e9dfd9abf1c5433f274e928b341 -LLD.v18.1.7+3.i686-linux-gnu-cxx03-llvm_version+18.tar.gz/md5/943434b08dffb54e8cf04ae7bee34923 -LLD.v18.1.7+3.i686-linux-gnu-cxx03-llvm_version+18.tar.gz/sha512/77b7bbc5d988cf36ecd10609e091cf24dea134cd32c7ee96dec7bfe1a4942553b6205653edc16c8454261f621966daeb267f42562172bab4cec9693ad733d867 -LLD.v18.1.7+3.i686-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/md5/cb9e371947ad415de048636ed78ca48f -LLD.v18.1.7+3.i686-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/sha512/c00b696fa146e8c29b37f15f78ab3325db9b3f5b3514e615f145b4eb7c9c8788662cfb6255b7dead596cad8c576b378f7459c2c85d462b597ba5e21adbac0536 -LLD.v18.1.7+3.i686-linux-gnu-cxx11-llvm_version+18.tar.gz/md5/485f061ee8425f042e4dd3042388bf8a -LLD.v18.1.7+3.i686-linux-gnu-cxx11-llvm_version+18.tar.gz/sha512/845a47a36c61b305bb70b1249f6fb7c4e8f740acff90d3e850ab2e887f7d959ae263431a02305bf7587e4194463f9932769d500a19709bc479eb6e6168325421 -LLD.v18.1.7+3.i686-w64-mingw32-cxx03-llvm_version+18.asserts.tar.gz/md5/e4f97e8334e1f29ad9083d051a50eab9 -LLD.v18.1.7+3.i686-w64-mingw32-cxx03-llvm_version+18.asserts.tar.gz/sha512/13ff037881da8a2333129bb702f515a0eb1afb3e4f27298c035c133ce5c512fa643b2a90df38d6f61b1dd5e86e32998b9061241358b61be794caba2b989efb70 -LLD.v18.1.7+3.i686-w64-mingw32-cxx03-llvm_version+18.tar.gz/md5/570f50ef6523cb8133b160af8fa2057e -LLD.v18.1.7+3.i686-w64-mingw32-cxx03-llvm_version+18.tar.gz/sha512/69ec402469b2b2c85aabca1c8b36edd0c53b7e678e4c56fd96062b62a57b7ff1008f328d71e6aee36d4270a41a7bf84f62f934007398618b5426202d9614305d -LLD.v18.1.7+3.i686-w64-mingw32-cxx11-llvm_version+18.asserts.tar.gz/md5/0503dc3e4e69ca6fd7e2a5dac9c4ef3a -LLD.v18.1.7+3.i686-w64-mingw32-cxx11-llvm_version+18.asserts.tar.gz/sha512/9b6c851341c2642d5ed9169326b4de9eda50ea06b1270a721d2e85bce8ffe4c595cd491e0a218c3a418aed526f881737fbb44cb417cd5ba7db972bcbaa6ad0d1 -LLD.v18.1.7+3.i686-w64-mingw32-cxx11-llvm_version+18.tar.gz/md5/08b22e98c514d48ddb1039b44f64f480 -LLD.v18.1.7+3.i686-w64-mingw32-cxx11-llvm_version+18.tar.gz/sha512/5e5b7c66d5fec3ff1a9cb7989d62887699cc3e70ab36a94e6f157cb0b9adbe8d63f5f1a74cfb6765cf46851087019b12ccf09ea848ed6456d17cdc796a5bf2e8 -LLD.v18.1.7+3.powerpc64le-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/md5/7962fc6f08531f0dcfa44bd667f31582 -LLD.v18.1.7+3.powerpc64le-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/sha512/2c936064685f12ed6764c187192023118e97dcbff6ca1656f0304a40772b4ecf55ee0296b3c2a00760f5bb437162e2b737635fdd59b889d35756d697fc7e6b72 -LLD.v18.1.7+3.powerpc64le-linux-gnu-cxx03-llvm_version+18.tar.gz/md5/3eb4d78af670d446f696449a5e71e3ba -LLD.v18.1.7+3.powerpc64le-linux-gnu-cxx03-llvm_version+18.tar.gz/sha512/315dc76799f3e443fdb5ebbecf96a08070f8251930a26995de892b8e67bd35bbb365f2cc5fd93bc7cbcbc9edd08280ee8d2a36b28a704866dd3fdddae4969455 -LLD.v18.1.7+3.powerpc64le-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/md5/e73cadd0354897bd5bb611cc1c027858 -LLD.v18.1.7+3.powerpc64le-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/sha512/6f444a4ea22e7108ab75686ce9cd78c0db0a677e39e8434896fb1ec90b9dc013abf7de1024d329a9726dabf229a8a68c27a11f211092e676715d282efb7b8504 -LLD.v18.1.7+3.powerpc64le-linux-gnu-cxx11-llvm_version+18.tar.gz/md5/aeb310f106f31126dbe53459e36d33bd -LLD.v18.1.7+3.powerpc64le-linux-gnu-cxx11-llvm_version+18.tar.gz/sha512/cd18c115415dd92bc7fbb5c29cacc5848b1f3851c3a526ff9c0813ad46824df0a4f13a66b1e6641ed11b44b5b937390619f01666fe6d5a047f1772f0ad03c941 -LLD.v18.1.7+3.x86_64-apple-darwin-llvm_version+18.asserts.tar.gz/md5/9493a58ed62367b45a055c8880de0924 -LLD.v18.1.7+3.x86_64-apple-darwin-llvm_version+18.asserts.tar.gz/sha512/5a448c87ad627235d7d2c8f8f8866af0f6872c3f7775123edb09b23b772f165fa020fe0c592ad100f8c777213fe1346b642a556df66ed003771eb0e76345215a -LLD.v18.1.7+3.x86_64-apple-darwin-llvm_version+18.tar.gz/md5/d397b37abf0026ca69fa6657dd791e27 -LLD.v18.1.7+3.x86_64-apple-darwin-llvm_version+18.tar.gz/sha512/9e9fc915389bfa09cbe8b977f22a3466ccda052f415b3b5fdfc97a15e089d4f887fba97d6bfe6e17104f09bebe48c859bad25e9f2cabc179000247292eafca1b -LLD.v18.1.7+3.x86_64-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/md5/5dc96eef71dc28611bc998ef966371c6 -LLD.v18.1.7+3.x86_64-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/sha512/781993c75bb07db96d02b5a7e779116864730a9bb941b64420a435956a7ecd501b5b2673f1854c09ece5f0c73559d5723c271d6352be57ddae6801a695629362 -LLD.v18.1.7+3.x86_64-linux-gnu-cxx03-llvm_version+18.tar.gz/md5/8a1fe0ccf7699ab7a7a514b620112a70 -LLD.v18.1.7+3.x86_64-linux-gnu-cxx03-llvm_version+18.tar.gz/sha512/d002083045d3eb7c749f2e97527c1228cd317a8138ff254228e43594a6cabee47fa363785466ebc2874cc438457640ff08a836eec7334afac451506ea7bbed03 -LLD.v18.1.7+3.x86_64-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/md5/331be92bd3d76bb8e86991b7832ad41a -LLD.v18.1.7+3.x86_64-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/sha512/7b1c6df53311a17a92a41cb67ec476f947949c4ca5d15a643badaf9f01e76a186abbb6e156f95ad1605d83250df4e081164986a6b7fcb3238076b0ec5a3bb565 -LLD.v18.1.7+3.x86_64-linux-gnu-cxx11-llvm_version+18.tar.gz/md5/97c7f5267ad6927f699a25ce44f55a70 -LLD.v18.1.7+3.x86_64-linux-gnu-cxx11-llvm_version+18.tar.gz/sha512/7b847c6026fd7daeb17a4459b852562ce6664b2f406664be672bcc384dd5a79b9505561fc61dd8fb78a903a2ed4978f322cccad19f5a3966bac856e877c11ef7 -LLD.v18.1.7+3.x86_64-linux-musl-cxx03-llvm_version+18.asserts.tar.gz/md5/c86da6a396fcdddbd26cfd71c0f70458 -LLD.v18.1.7+3.x86_64-linux-musl-cxx03-llvm_version+18.asserts.tar.gz/sha512/8d5b75b43167080b8ea456e516c9ace02ee6066ce715a56f0b42cb8045b965b1cf8d4ebc0786c23be4544693ff858816a6257b0638ec11e077df32ead62f7efb -LLD.v18.1.7+3.x86_64-linux-musl-cxx03-llvm_version+18.tar.gz/md5/d72e175272ed893688d18e868120c575 -LLD.v18.1.7+3.x86_64-linux-musl-cxx03-llvm_version+18.tar.gz/sha512/9a46eeca8c7a8be65ed487a74227534e08a257e404814c44730f12a5bebc8cd160998cfd5ed30189aa606ddbe602e1b1788e465e4a210103c6726a7fd230abc3 -LLD.v18.1.7+3.x86_64-linux-musl-cxx11-llvm_version+18.asserts.tar.gz/md5/0206fdaa9582ae3bddaed1b6fd7a8cb5 -LLD.v18.1.7+3.x86_64-linux-musl-cxx11-llvm_version+18.asserts.tar.gz/sha512/584a67f603f656ca5d27aa0ef2e425ad385612aff06cdc1d534b5944939a09246c93954fc153b8a89acff721e657a8903af9a640abc252d4e452f348781bca98 -LLD.v18.1.7+3.x86_64-linux-musl-cxx11-llvm_version+18.tar.gz/md5/0dd14af342467eac2e13cad4acbc881f -LLD.v18.1.7+3.x86_64-linux-musl-cxx11-llvm_version+18.tar.gz/sha512/918f2c66898f828414009fa6ee273da5bd654e4b787ebb4d703f0be27e388b46870d68bd58c4f45638d276c61c1bfe2f3c67fbf34dfb5578158d072f82d927de -LLD.v18.1.7+3.x86_64-unknown-freebsd-llvm_version+18.asserts.tar.gz/md5/d1862068a670d4c04887513b914e11a8 -LLD.v18.1.7+3.x86_64-unknown-freebsd-llvm_version+18.asserts.tar.gz/sha512/c5a91657667394e468e71d9c07df0c71918d63d094d2598875f75cf3830d8502e70f59fba59b07a2d1e0551f58d0487521c856e68e4122fd6a6f7ebd1c7c0f58 -LLD.v18.1.7+3.x86_64-unknown-freebsd-llvm_version+18.tar.gz/md5/8dc0ec01029765dbfdd28d63bea8cfca -LLD.v18.1.7+3.x86_64-unknown-freebsd-llvm_version+18.tar.gz/sha512/234e9db1177003a074c6ca7236c589424b4617d1a359f5f9e2ba6095a7f317d62ac731319b4b4513c523e80c15b82c99ff0fc9df5f76fad452955492e9935b1d -LLD.v18.1.7+3.x86_64-w64-mingw32-cxx03-llvm_version+18.asserts.tar.gz/md5/7beb510d766ac1e16017aa6924e88659 -LLD.v18.1.7+3.x86_64-w64-mingw32-cxx03-llvm_version+18.asserts.tar.gz/sha512/bd18b733a6b2fbbeef7f8af2f13dade0330a525c83b4faed5a5d2507007be2f2f7be70f99d05524fa94ae1dca524be64adbb9dc87485477f62109f44cbae95fe -LLD.v18.1.7+3.x86_64-w64-mingw32-cxx03-llvm_version+18.tar.gz/md5/9ecca76cea81cd1d0fd3470778145371 -LLD.v18.1.7+3.x86_64-w64-mingw32-cxx03-llvm_version+18.tar.gz/sha512/d1548402dfcb4aa0cf3c9e445a9810e5d8bc2411de9943b57e892ec82af29e214f6d93c58af9cd0de9b4fa5a0438e4c1fe0b9591a9582143d470e7a42e685f4a -LLD.v18.1.7+3.x86_64-w64-mingw32-cxx11-llvm_version+18.asserts.tar.gz/md5/b1de7acc21fe51c1486854cd46b71bae -LLD.v18.1.7+3.x86_64-w64-mingw32-cxx11-llvm_version+18.asserts.tar.gz/sha512/9f8457c12801584340b3fbf846920299756359016d151018562f8c14e0a03f657fdb6eb1d7418fdfbf586c59e670d866384e822de9bde15b2dbd031ce5e6af8d -LLD.v18.1.7+3.x86_64-w64-mingw32-cxx11-llvm_version+18.tar.gz/md5/373a7007eb8b526811604fb0161f73af -LLD.v18.1.7+3.x86_64-w64-mingw32-cxx11-llvm_version+18.tar.gz/sha512/b586815621f698c7d6ff995c93e11ea1ec55e7e7c0e34ad874f64b942ecd73685cce150d51804bdd371ec42671e7814e364944276ec91282b9b8b8226a6d5786 +LLD.v18.1.7+5.aarch64-apple-darwin-llvm_version+18.asserts.tar.gz/md5/229323a0b31c29b4221d79ace1a76820 +LLD.v18.1.7+5.aarch64-apple-darwin-llvm_version+18.asserts.tar.gz/sha512/c00fb8bf309f0cc6c8cb4465cc0062a8b1a848d9460c53241be654d88c598847b4590b4afa4b71c4859cfc67490942eddd79ae9ac4d75a9b0e392fbf67389a92 +LLD.v18.1.7+5.aarch64-apple-darwin-llvm_version+18.tar.gz/md5/ce7804a6a846d0d951aae34607c43bdc +LLD.v18.1.7+5.aarch64-apple-darwin-llvm_version+18.tar.gz/sha512/164adec7649a36b2967872884866de1c57f6f54e1c24f955593f9f6a10cd89c69493a64a37bf9f001ce3576baed867423d138dfb1df0139b4c1312e81001b167 +LLD.v18.1.7+5.aarch64-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/md5/cea134f347bae257cf5f55b6388cef81 +LLD.v18.1.7+5.aarch64-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/sha512/16b59143e929791b0c3e56cfb4970d8b3c87adf6e847fa9e2aac17c4ff2aa311ba2c7511c1b0ae2f39d9aa92f87ad4d99c042fe35bec391ac865fedb72bd3b1e +LLD.v18.1.7+5.aarch64-linux-gnu-cxx03-llvm_version+18.tar.gz/md5/5f903bab0e38fa608e8965acce6f020e +LLD.v18.1.7+5.aarch64-linux-gnu-cxx03-llvm_version+18.tar.gz/sha512/01e5f6a32958e04174c545f57c6c3b1bc88ccfd5ab18dcb9d67b92b55ebc7655a03bf963c4eaf7e5c3792d4691427a89db372e7534c6c8f965f8a715a32d9284 +LLD.v18.1.7+5.aarch64-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/md5/241a55374fd067f3736a2bb929e47015 +LLD.v18.1.7+5.aarch64-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/sha512/f1fedea4e6b5f6f3bbf4d705034d6c51b06f011c2ecec1ae49c5b7bd123891eee8b991462d60be7fffd58f7c773afe910a06ec0b55b37eed9b4d09b9fdbd5068 +LLD.v18.1.7+5.aarch64-linux-gnu-cxx11-llvm_version+18.tar.gz/md5/ff018c7448a7589935333e46739ee2c4 +LLD.v18.1.7+5.aarch64-linux-gnu-cxx11-llvm_version+18.tar.gz/sha512/b646c6a945b8f42b396164a8e87fc2e54b1ad05681f438dfba83fdd3712a60167aaffcb0300bc42d904eb4bd34c002a71642b59540ca01e64d6fecc6daaacdd8 +LLD.v18.1.7+5.aarch64-linux-musl-cxx03-llvm_version+18.asserts.tar.gz/md5/e6ee9423a82322b9233cafb1c92eed2d +LLD.v18.1.7+5.aarch64-linux-musl-cxx03-llvm_version+18.asserts.tar.gz/sha512/c915582a9ce2dfa8721741fb1ed19b719ba40f0092c2d29ebd68829ee558cef0b044a5e40985cff88e89129cbeed052d85fa5c6b6d87f9b3a68a6e89079ab4f3 +LLD.v18.1.7+5.aarch64-linux-musl-cxx03-llvm_version+18.tar.gz/md5/cc55112e2db358cf26d7bae3211d8e4f +LLD.v18.1.7+5.aarch64-linux-musl-cxx03-llvm_version+18.tar.gz/sha512/0ecb43045419020eea911f1767dae23a6b1e81bb155ec493e911a9412e45f7ec71461aea2e6fe346e641747139cae43d9435ccecaa7fd6a234e4d69bb06606ed +LLD.v18.1.7+5.aarch64-linux-musl-cxx11-llvm_version+18.asserts.tar.gz/md5/498b2909f80b20588135466d5211bc80 +LLD.v18.1.7+5.aarch64-linux-musl-cxx11-llvm_version+18.asserts.tar.gz/sha512/120fff24e85cf970670b20b5f4509475a3ae0d7621f8f67d018f3a7625548d736a3abc89f015966b1329c6b0a08a1db832e035ee3bae384e2c5864b73a856600 +LLD.v18.1.7+5.aarch64-linux-musl-cxx11-llvm_version+18.tar.gz/md5/1bcd298d5292f8e51f19b97fa4b27ab0 +LLD.v18.1.7+5.aarch64-linux-musl-cxx11-llvm_version+18.tar.gz/sha512/695c42557f9ee53b2e10bbf74653fbad4d02124b962a1f50cf719d2821607dfbb9c1bf638dbbc9e0e544f3020a9ef4a82decd13f886cc41ddf47c07a5e40eaa1 +LLD.v18.1.7+5.aarch64-unknown-freebsd-llvm_version+18.asserts.tar.gz/md5/5e0c29963d8f132b57cc5f7440b0a6a5 +LLD.v18.1.7+5.aarch64-unknown-freebsd-llvm_version+18.asserts.tar.gz/sha512/7521d79bb1bb993fc088fc72cddc468c10b9c07f8732f2de12debd9f1454e8f8f6a330957b3285473dc7c5d2379ac46ddf279174f6cef04a8bb549490caa6599 +LLD.v18.1.7+5.aarch64-unknown-freebsd-llvm_version+18.tar.gz/md5/8255acef157147cfdf3fc94b9cc2bda0 +LLD.v18.1.7+5.aarch64-unknown-freebsd-llvm_version+18.tar.gz/sha512/98dbf592022f7eb2db42a2349d1cc0cf3cf07f40f5ba37dfe6e1622dc86e6bd1080a860f018636401a88ab0b5098dbb863bcfc6cbb3f0213423ebcc0abd3311f +LLD.v18.1.7+5.armv6l-linux-gnueabihf-cxx03-llvm_version+18.asserts.tar.gz/md5/2323ff933feaf3754b442bee48a63607 +LLD.v18.1.7+5.armv6l-linux-gnueabihf-cxx03-llvm_version+18.asserts.tar.gz/sha512/47b8e490b89e04fb8886dae438e3ddcd53c4e98045de2b0def3988671827528c8e9ae296411464c0f17cc64bd3956644673f47a3817237f27e1c3ed16ac8ef01 +LLD.v18.1.7+5.armv6l-linux-gnueabihf-cxx03-llvm_version+18.tar.gz/md5/37cf8528666064a434296f2e0039e9c6 +LLD.v18.1.7+5.armv6l-linux-gnueabihf-cxx03-llvm_version+18.tar.gz/sha512/ea1504a859509f8a16030db7a65f42f0e78d67adf5946497f2178bf25456c0f2583af72c636881a4bdd1210dc0d377bdf300ef55aef5db8c56995424a1886059 +LLD.v18.1.7+5.armv6l-linux-gnueabihf-cxx11-llvm_version+18.asserts.tar.gz/md5/1c341f2b161e2320d3d1a74685887f54 +LLD.v18.1.7+5.armv6l-linux-gnueabihf-cxx11-llvm_version+18.asserts.tar.gz/sha512/4f6fc099293deb1a2cf729ea7edd6e17fea0dc8b9fae9acfe34e00b1f5c798933df9538c805c8d28c6279eb38f9ebae2a1aeb1a2f23087352c6eeb3b27b63ddc +LLD.v18.1.7+5.armv6l-linux-gnueabihf-cxx11-llvm_version+18.tar.gz/md5/e306d59c71b0958c77108e650fac2612 +LLD.v18.1.7+5.armv6l-linux-gnueabihf-cxx11-llvm_version+18.tar.gz/sha512/79fd7cec0e169a9555ec9b0acc3248991e2e37a1d5bb422808ffcfd4f47e79321560b7985c82dfe070fb0b5ded5c160d83e358399c6e7608eeb62cd4a1406f88 +LLD.v18.1.7+5.armv6l-linux-musleabihf-cxx03-llvm_version+18.asserts.tar.gz/md5/c1d080f1aebb58778d730578fb113290 +LLD.v18.1.7+5.armv6l-linux-musleabihf-cxx03-llvm_version+18.asserts.tar.gz/sha512/1f420da1897bd0a61413321aaaf032e8ed38d59e6dfe3313ca3a6ee6582ae6c566e3761ca8fcd1f5a964337ba8a9b3e73dc55ad68aca139beeb45e43d51e862b +LLD.v18.1.7+5.armv6l-linux-musleabihf-cxx03-llvm_version+18.tar.gz/md5/6f4e0c7d2fe9ac254650dcd2842dafa8 +LLD.v18.1.7+5.armv6l-linux-musleabihf-cxx03-llvm_version+18.tar.gz/sha512/bbc71b334250e5e6429766d88595adbb671a206630987ec2a27e05711ff0f844487dffc1c136052ec11394e9d5c51c70d1b75d5348f97d3bf7fab463291e9dc8 +LLD.v18.1.7+5.armv6l-linux-musleabihf-cxx11-llvm_version+18.asserts.tar.gz/md5/76925b9a7bc249b2227390c479c54f8d +LLD.v18.1.7+5.armv6l-linux-musleabihf-cxx11-llvm_version+18.asserts.tar.gz/sha512/20643ecb79732e3ae9666116dbd0763c18b808afa78e6a14998aadc7265cccd6efd28670592db61d3d27b8d3023be4c5f3df41fff9e1b38d61abf76829090b4f +LLD.v18.1.7+5.armv6l-linux-musleabihf-cxx11-llvm_version+18.tar.gz/md5/399b9aac140d9050088fdb187ed4645f +LLD.v18.1.7+5.armv6l-linux-musleabihf-cxx11-llvm_version+18.tar.gz/sha512/8bab65965670fe392e78d0b9dc78c92cdcf202898f6d5a3174eb89ca5cb95b995675c8a7d81bbc4e95e490ad1a43d9d29d7907b7006789c0143a1d8f24cccaeb +LLD.v18.1.7+5.armv7l-linux-gnueabihf-cxx03-llvm_version+18.asserts.tar.gz/md5/026a4f5ae9eb3ac05e5e8fa894d77a5b +LLD.v18.1.7+5.armv7l-linux-gnueabihf-cxx03-llvm_version+18.asserts.tar.gz/sha512/4bca8bd558619260cddf4e2f4593cbb2a0691b5ccc6d1dea6dfcc5a2b5f51d7d1a76c35e481244e211e2eacf32bd628df5ad0e6c75e5185bb1d9b569f6acbfd3 +LLD.v18.1.7+5.armv7l-linux-gnueabihf-cxx03-llvm_version+18.tar.gz/md5/f898ceabcba052b7e6713a2b2c208a92 +LLD.v18.1.7+5.armv7l-linux-gnueabihf-cxx03-llvm_version+18.tar.gz/sha512/92be1910f795390be5f15ba5b2c220a3209a5f7ac04fca3f5229486628bcf5d2f20cf6e4dda8b41d6beaaff42a68a9ddb95fdacc6eae33b9183b581e9a194895 +LLD.v18.1.7+5.armv7l-linux-gnueabihf-cxx11-llvm_version+18.asserts.tar.gz/md5/e366058cf69a4367945bdba9523f2a0b +LLD.v18.1.7+5.armv7l-linux-gnueabihf-cxx11-llvm_version+18.asserts.tar.gz/sha512/45a786e8d0162bd5bd01c029691d2928d3744ef4a7a1efc2e39755dee2f9a9ae23ee725f0454ca601cb9c082a342209e9129df851314b5757c74767b13508fc4 +LLD.v18.1.7+5.armv7l-linux-gnueabihf-cxx11-llvm_version+18.tar.gz/md5/665a8502170729c86ea95a7ea2fcce0f +LLD.v18.1.7+5.armv7l-linux-gnueabihf-cxx11-llvm_version+18.tar.gz/sha512/c1a2a85c9ce14af8c91bc9a599393c52c0b8a585057366b1ceeed34c5db44641ecd0c9b377bee80cb4951fc7102fbb4f21fd050126bfa5bb4e582ffefee17035 +LLD.v18.1.7+5.armv7l-linux-musleabihf-cxx03-llvm_version+18.asserts.tar.gz/md5/b90b2130262f63f5189cc8e4a65e4433 +LLD.v18.1.7+5.armv7l-linux-musleabihf-cxx03-llvm_version+18.asserts.tar.gz/sha512/c1cbfd38c82d676c3fdbec486691334cf7bf4115d9ef2665012b71725c28545a49f34edf5689ea0352822c811c24c89cc152d1fccd1586b17ae8e6b2503641df +LLD.v18.1.7+5.armv7l-linux-musleabihf-cxx03-llvm_version+18.tar.gz/md5/2d5360da4b2c9ffcea5d0a646a7c114b +LLD.v18.1.7+5.armv7l-linux-musleabihf-cxx03-llvm_version+18.tar.gz/sha512/73323e0937fe4423883480294c8df44744acde4f47380e35535cbe69c855c0e35e86a1eced3085ae0285f284f47af5ef237f4650bf2b6a8b9d5308efce88fa02 +LLD.v18.1.7+5.armv7l-linux-musleabihf-cxx11-llvm_version+18.asserts.tar.gz/md5/a9b9a65938a7701aaac6fa706481c867 +LLD.v18.1.7+5.armv7l-linux-musleabihf-cxx11-llvm_version+18.asserts.tar.gz/sha512/fe8243aa131ad8be54f0fca5754c2e68ec39049004ec8feed499731c5228a7a46e303ba866b9f9a55e5318c73d8a46d964673e111f6c60e5ae1628c568d7d894 +LLD.v18.1.7+5.armv7l-linux-musleabihf-cxx11-llvm_version+18.tar.gz/md5/0d9592a287c9231ae2db65000be2cea2 +LLD.v18.1.7+5.armv7l-linux-musleabihf-cxx11-llvm_version+18.tar.gz/sha512/4ee192dd33f518d2735a829ac8f822b5672b39e8c2254987aea6e5f2f0056213bd85d84c4050d52ba9ac8c35762521c324fe2d6e18db0396e7142af9cb61a561 +LLD.v18.1.7+5.i686-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/md5/d487598dec9969485dcf785fc0968bd4 +LLD.v18.1.7+5.i686-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/sha512/8d3117739919696b9b0c9ae398f1b1e9db8bd3e2e27839f62b3551c22ae2517f8abb69e57e23d125002bb466889b7352e69c1e9dfd9abf1c5433f274e928b341 +LLD.v18.1.7+5.i686-linux-gnu-cxx03-llvm_version+18.tar.gz/md5/943434b08dffb54e8cf04ae7bee34923 +LLD.v18.1.7+5.i686-linux-gnu-cxx03-llvm_version+18.tar.gz/sha512/77b7bbc5d988cf36ecd10609e091cf24dea134cd32c7ee96dec7bfe1a4942553b6205653edc16c8454261f621966daeb267f42562172bab4cec9693ad733d867 +LLD.v18.1.7+5.i686-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/md5/cb9e371947ad415de048636ed78ca48f +LLD.v18.1.7+5.i686-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/sha512/c00b696fa146e8c29b37f15f78ab3325db9b3f5b3514e615f145b4eb7c9c8788662cfb6255b7dead596cad8c576b378f7459c2c85d462b597ba5e21adbac0536 +LLD.v18.1.7+5.i686-linux-gnu-cxx11-llvm_version+18.tar.gz/md5/485f061ee8425f042e4dd3042388bf8a +LLD.v18.1.7+5.i686-linux-gnu-cxx11-llvm_version+18.tar.gz/sha512/845a47a36c61b305bb70b1249f6fb7c4e8f740acff90d3e850ab2e887f7d959ae263431a02305bf7587e4194463f9932769d500a19709bc479eb6e6168325421 +LLD.v18.1.7+5.i686-w64-mingw32-cxx03-llvm_version+18.asserts.tar.gz/md5/91ff693c2af0f7621b2f9060df25b2f6 +LLD.v18.1.7+5.i686-w64-mingw32-cxx03-llvm_version+18.asserts.tar.gz/sha512/f15f7979db0b0f575cd6f8d9c052cd4faab663cb184ed3fb74f68734bc7c2e41c251ad893c3a0abe8c546a9ccfe73e177c92d28a892e5a3887ab8d8ef27327e7 +LLD.v18.1.7+5.i686-w64-mingw32-cxx03-llvm_version+18.tar.gz/md5/32d0692c49e490481a6feb672dcc6516 +LLD.v18.1.7+5.i686-w64-mingw32-cxx03-llvm_version+18.tar.gz/sha512/f336b14dc27bb0db25e1af267d9b6c21580f9b01a610d08d15cfed47c77a5be0664d473e21b910754d82a2e7b3b68607c50a227b4c40b48a5f6ea6d23fe12638 +LLD.v18.1.7+5.i686-w64-mingw32-cxx11-llvm_version+18.asserts.tar.gz/md5/1d9612a61214b47d466a97e929ff5b20 +LLD.v18.1.7+5.i686-w64-mingw32-cxx11-llvm_version+18.asserts.tar.gz/sha512/d38f71363ba0274f32221e42e655f27a1c40ee9e22c3cbf1c478e58fdbad040dca529bc6d74fff82c171825aa091ed39a8c043f9291fbe66a6c3ad4c6032a1d0 +LLD.v18.1.7+5.i686-w64-mingw32-cxx11-llvm_version+18.tar.gz/md5/21f4b3cbf1bd87843f73ccfe053d75b2 +LLD.v18.1.7+5.i686-w64-mingw32-cxx11-llvm_version+18.tar.gz/sha512/fe730959877ad78e6c5d5ce72d52fc5639357436ff396bc2dfe0488c1a8a5da512fe418705741bd6868b4e497cfd4fbaa024f9a2d49034d6801170db09081872 +LLD.v18.1.7+5.powerpc64le-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/md5/7962fc6f08531f0dcfa44bd667f31582 +LLD.v18.1.7+5.powerpc64le-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/sha512/2c936064685f12ed6764c187192023118e97dcbff6ca1656f0304a40772b4ecf55ee0296b3c2a00760f5bb437162e2b737635fdd59b889d35756d697fc7e6b72 +LLD.v18.1.7+5.powerpc64le-linux-gnu-cxx03-llvm_version+18.tar.gz/md5/3eb4d78af670d446f696449a5e71e3ba +LLD.v18.1.7+5.powerpc64le-linux-gnu-cxx03-llvm_version+18.tar.gz/sha512/315dc76799f3e443fdb5ebbecf96a08070f8251930a26995de892b8e67bd35bbb365f2cc5fd93bc7cbcbc9edd08280ee8d2a36b28a704866dd3fdddae4969455 +LLD.v18.1.7+5.powerpc64le-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/md5/e73cadd0354897bd5bb611cc1c027858 +LLD.v18.1.7+5.powerpc64le-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/sha512/6f444a4ea22e7108ab75686ce9cd78c0db0a677e39e8434896fb1ec90b9dc013abf7de1024d329a9726dabf229a8a68c27a11f211092e676715d282efb7b8504 +LLD.v18.1.7+5.powerpc64le-linux-gnu-cxx11-llvm_version+18.tar.gz/md5/aeb310f106f31126dbe53459e36d33bd +LLD.v18.1.7+5.powerpc64le-linux-gnu-cxx11-llvm_version+18.tar.gz/sha512/cd18c115415dd92bc7fbb5c29cacc5848b1f3851c3a526ff9c0813ad46824df0a4f13a66b1e6641ed11b44b5b937390619f01666fe6d5a047f1772f0ad03c941 +LLD.v18.1.7+5.x86_64-apple-darwin-llvm_version+18.asserts.tar.gz/md5/9493a58ed62367b45a055c8880de0924 +LLD.v18.1.7+5.x86_64-apple-darwin-llvm_version+18.asserts.tar.gz/sha512/5a448c87ad627235d7d2c8f8f8866af0f6872c3f7775123edb09b23b772f165fa020fe0c592ad100f8c777213fe1346b642a556df66ed003771eb0e76345215a +LLD.v18.1.7+5.x86_64-apple-darwin-llvm_version+18.tar.gz/md5/d397b37abf0026ca69fa6657dd791e27 +LLD.v18.1.7+5.x86_64-apple-darwin-llvm_version+18.tar.gz/sha512/9e9fc915389bfa09cbe8b977f22a3466ccda052f415b3b5fdfc97a15e089d4f887fba97d6bfe6e17104f09bebe48c859bad25e9f2cabc179000247292eafca1b +LLD.v18.1.7+5.x86_64-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/md5/5dc96eef71dc28611bc998ef966371c6 +LLD.v18.1.7+5.x86_64-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/sha512/781993c75bb07db96d02b5a7e779116864730a9bb941b64420a435956a7ecd501b5b2673f1854c09ece5f0c73559d5723c271d6352be57ddae6801a695629362 +LLD.v18.1.7+5.x86_64-linux-gnu-cxx03-llvm_version+18.tar.gz/md5/8a1fe0ccf7699ab7a7a514b620112a70 +LLD.v18.1.7+5.x86_64-linux-gnu-cxx03-llvm_version+18.tar.gz/sha512/d002083045d3eb7c749f2e97527c1228cd317a8138ff254228e43594a6cabee47fa363785466ebc2874cc438457640ff08a836eec7334afac451506ea7bbed03 +LLD.v18.1.7+5.x86_64-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/md5/331be92bd3d76bb8e86991b7832ad41a +LLD.v18.1.7+5.x86_64-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/sha512/7b1c6df53311a17a92a41cb67ec476f947949c4ca5d15a643badaf9f01e76a186abbb6e156f95ad1605d83250df4e081164986a6b7fcb3238076b0ec5a3bb565 +LLD.v18.1.7+5.x86_64-linux-gnu-cxx11-llvm_version+18.tar.gz/md5/97c7f5267ad6927f699a25ce44f55a70 +LLD.v18.1.7+5.x86_64-linux-gnu-cxx11-llvm_version+18.tar.gz/sha512/7b847c6026fd7daeb17a4459b852562ce6664b2f406664be672bcc384dd5a79b9505561fc61dd8fb78a903a2ed4978f322cccad19f5a3966bac856e877c11ef7 +LLD.v18.1.7+5.x86_64-linux-musl-cxx03-llvm_version+18.asserts.tar.gz/md5/c86da6a396fcdddbd26cfd71c0f70458 +LLD.v18.1.7+5.x86_64-linux-musl-cxx03-llvm_version+18.asserts.tar.gz/sha512/8d5b75b43167080b8ea456e516c9ace02ee6066ce715a56f0b42cb8045b965b1cf8d4ebc0786c23be4544693ff858816a6257b0638ec11e077df32ead62f7efb +LLD.v18.1.7+5.x86_64-linux-musl-cxx03-llvm_version+18.tar.gz/md5/d72e175272ed893688d18e868120c575 +LLD.v18.1.7+5.x86_64-linux-musl-cxx03-llvm_version+18.tar.gz/sha512/9a46eeca8c7a8be65ed487a74227534e08a257e404814c44730f12a5bebc8cd160998cfd5ed30189aa606ddbe602e1b1788e465e4a210103c6726a7fd230abc3 +LLD.v18.1.7+5.x86_64-linux-musl-cxx11-llvm_version+18.asserts.tar.gz/md5/0206fdaa9582ae3bddaed1b6fd7a8cb5 +LLD.v18.1.7+5.x86_64-linux-musl-cxx11-llvm_version+18.asserts.tar.gz/sha512/584a67f603f656ca5d27aa0ef2e425ad385612aff06cdc1d534b5944939a09246c93954fc153b8a89acff721e657a8903af9a640abc252d4e452f348781bca98 +LLD.v18.1.7+5.x86_64-linux-musl-cxx11-llvm_version+18.tar.gz/md5/0dd14af342467eac2e13cad4acbc881f +LLD.v18.1.7+5.x86_64-linux-musl-cxx11-llvm_version+18.tar.gz/sha512/918f2c66898f828414009fa6ee273da5bd654e4b787ebb4d703f0be27e388b46870d68bd58c4f45638d276c61c1bfe2f3c67fbf34dfb5578158d072f82d927de +LLD.v18.1.7+5.x86_64-unknown-freebsd-llvm_version+18.asserts.tar.gz/md5/d209b46c3919a674da300effa7fb2c8e +LLD.v18.1.7+5.x86_64-unknown-freebsd-llvm_version+18.asserts.tar.gz/sha512/d56ec5a6e4cbcfd3ba4c4c9549fa9f39fca262c5ef238fb338548d4df35f277f3e266ed5112f8ad056a6ad18eb0258afe79ba1b9d391468059f9c40b9981dddf +LLD.v18.1.7+5.x86_64-unknown-freebsd-llvm_version+18.tar.gz/md5/e22a96444d1b00a86b592b30dbf925eb +LLD.v18.1.7+5.x86_64-unknown-freebsd-llvm_version+18.tar.gz/sha512/acfef951e6e0d0bbd343eeb4bd9c5485696916780c73d5eb81a76ea440ff97e2577205c85c789d0e92e6048a1595670b31e47d56caf5d02c5d423990246d8840 +LLD.v18.1.7+5.x86_64-w64-mingw32-cxx03-llvm_version+18.asserts.tar.gz/md5/312c816be2aa7f123a387905f580eae4 +LLD.v18.1.7+5.x86_64-w64-mingw32-cxx03-llvm_version+18.asserts.tar.gz/sha512/7778a5efe3edc1faba62236f9a940c1c3c2ed1743fd89b6f18162dbebd4a25a04dc9ddf25788d9a47292f44ede44a06d31a9194b79df873967b1fb6f5fef23f3 +LLD.v18.1.7+5.x86_64-w64-mingw32-cxx03-llvm_version+18.tar.gz/md5/e50cd7ea46f14f2237455c5b015c16e1 +LLD.v18.1.7+5.x86_64-w64-mingw32-cxx03-llvm_version+18.tar.gz/sha512/03b4612e4a1f9449598f0de0c526bf82e7d1aa25a41800263c5dc78edb7d71dd5a46694ad164f6ede66bdb887fa821bba20b2b04e6af8f228451243928f54842 +LLD.v18.1.7+5.x86_64-w64-mingw32-cxx11-llvm_version+18.asserts.tar.gz/md5/3a7f1029c8dcb80486174f24e29a097a +LLD.v18.1.7+5.x86_64-w64-mingw32-cxx11-llvm_version+18.asserts.tar.gz/sha512/df217f008e81142a5cab4a9a2f51164d14f2021a8847136317b6ed7fb2b354f194407e2320843758c76d5e178f7bce92f7ca3e7cfec482908ac102b6dffe3fe9 +LLD.v18.1.7+5.x86_64-w64-mingw32-cxx11-llvm_version+18.tar.gz/md5/9467b4c03398cecc20cd1d60068e415d +LLD.v18.1.7+5.x86_64-w64-mingw32-cxx11-llvm_version+18.tar.gz/sha512/a49068058becde369c83f1a42bcd77db9dfc62744b43abd4ab1be66a47e127dde78446501ed5f4b74e8ea6bbf3c72a2c251dfd5103118253694d48ce82d1e617 diff --git a/deps/checksums/llvm b/deps/checksums/llvm index ac8c678bdf653..a408ffa8d9664 100644 --- a/deps/checksums/llvm +++ b/deps/checksums/llvm @@ -1,115 +1,115 @@ -LLVM.v18.1.7+3.aarch64-apple-darwin-llvm_version+18.asserts.tar.gz/md5/f8c2d285a6db7c3b89d295b32b78f07b -LLVM.v18.1.7+3.aarch64-apple-darwin-llvm_version+18.asserts.tar.gz/sha512/99d923fff09b70093962cb32d2a12a2d2355824c1c3404900d593cfd0e95a4b52744e7d3fcd22407651916adc2e1534637437630843762c3f2c0c650881aa0e6 -LLVM.v18.1.7+3.aarch64-apple-darwin-llvm_version+18.tar.gz/md5/2ad6bf2ab91cb75bc3bb627b1859997b -LLVM.v18.1.7+3.aarch64-apple-darwin-llvm_version+18.tar.gz/sha512/bd06a3adcae64700f4051a18705e7937539b3cdfa61dda38260398a8896401a267b718594631d71afc68a3b273b0d05f6018927c3a08c070bd6c45d53b19c78a -LLVM.v18.1.7+3.aarch64-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/md5/7bc3125dd810bcc44ea2d454b6caa683 -LLVM.v18.1.7+3.aarch64-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/sha512/86742a4476481b14145855ead8a5acc6397782f6d3445f900ac2de0570f1fcf53563cf5e1f3cb59886282083ce63756604f1ca2434e9e427cdc1bd1f68373581 -LLVM.v18.1.7+3.aarch64-linux-gnu-cxx03-llvm_version+18.tar.gz/md5/4eae06d9e6272aef23afc191501810fd -LLVM.v18.1.7+3.aarch64-linux-gnu-cxx03-llvm_version+18.tar.gz/sha512/fb75927982b1428b05b765bd5ac017b2c15d89990b7e6cb582b9e1a3ec04d09801d25d5cc6c037a12c205edb7c0f7a2d33832a2d1de7920711e9720dc3ca3655 -LLVM.v18.1.7+3.aarch64-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/md5/cd86e18a63cd6e84a1493acf0df4e267 -LLVM.v18.1.7+3.aarch64-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/sha512/1dfefc4600368467ab90ccb527a9fdb012b9b7f485d932a0db8c4b1b81985fad931b74494b76ef2162e46280447d39a055b5681b33a17c564c50094de29aeb13 -LLVM.v18.1.7+3.aarch64-linux-gnu-cxx11-llvm_version+18.tar.gz/md5/c7cf7daa7c11827ae4f9fb2e16f3cce3 -LLVM.v18.1.7+3.aarch64-linux-gnu-cxx11-llvm_version+18.tar.gz/sha512/dabe2940606a671a8e3b4f28bb9e813d000650203c382372142457020f2ccd498534903aa99320afb7ff960a62d752ee6cb724e74745bc1bad1051e12cf78ab4 -LLVM.v18.1.7+3.aarch64-linux-musl-cxx03-llvm_version+18.asserts.tar.gz/md5/62e575b89fd92d9206abebc19b084abf -LLVM.v18.1.7+3.aarch64-linux-musl-cxx03-llvm_version+18.asserts.tar.gz/sha512/7ac029567fd68fee82b7096e2fe278ee5cd2935494433b1faace036469c54bc471d614d0bb339750429dd88f3e723165d2dacaa627f73c3647c6f3b51a4a3034 -LLVM.v18.1.7+3.aarch64-linux-musl-cxx03-llvm_version+18.tar.gz/md5/5d39ef811bc78204ebfc7e98111469cf -LLVM.v18.1.7+3.aarch64-linux-musl-cxx03-llvm_version+18.tar.gz/sha512/10fc9a64d63351e168bc79fa63bcaa6fd49c8483e5ecc40a66216192588367e9b47ec3ea2c047e88f39ea8f1caf8052726f4bc8858223f7744606156b4133970 -LLVM.v18.1.7+3.aarch64-linux-musl-cxx11-llvm_version+18.asserts.tar.gz/md5/f072fe487e5d1b717aec49a6244adf05 -LLVM.v18.1.7+3.aarch64-linux-musl-cxx11-llvm_version+18.asserts.tar.gz/sha512/42b03a2562728ac86e751abab2e8233d583baf006e69b107d002a9258844ad53f62e6332eab3790364940d478c7ebab6d3e0e2194220e8436f40e6b75063d1a2 -LLVM.v18.1.7+3.aarch64-linux-musl-cxx11-llvm_version+18.tar.gz/md5/eabf0239298f13ff4893011e75828bdf -LLVM.v18.1.7+3.aarch64-linux-musl-cxx11-llvm_version+18.tar.gz/sha512/34724d9c9a550c85d406021d7265e1848b002b8f212427eebff6e8f03ec6acc336efb0c2cd9d9e1c76329e7c84a84a9d852b8de5897550d957e0e9385129033d -LLVM.v18.1.7+3.aarch64-unknown-freebsd-llvm_version+18.asserts.tar.gz/md5/8b736710b2c749fccf0a782f3b887ec2 -LLVM.v18.1.7+3.aarch64-unknown-freebsd-llvm_version+18.asserts.tar.gz/sha512/d7458ead5a604781a117e54a03dc6f3fc47e932298c68af425a6725ef4767bb512c910316818081d5e27d9d08b4ce1792d684c0014271fd492eedaf47acc5eb3 -LLVM.v18.1.7+3.aarch64-unknown-freebsd-llvm_version+18.tar.gz/md5/ed0487ad3494352ffebfac51ef947168 -LLVM.v18.1.7+3.aarch64-unknown-freebsd-llvm_version+18.tar.gz/sha512/e13082056be94335b1f4253afe3c4a25555b6bd10c5d68052f01117415dab344a3f883a9f25ff4ac630262756dd15825e74395650d80181c85c0663d7028a9f5 -LLVM.v18.1.7+3.armv6l-linux-gnueabihf-cxx03-llvm_version+18.asserts.tar.gz/md5/1910b5daa31db6542f0c762901ab7d43 -LLVM.v18.1.7+3.armv6l-linux-gnueabihf-cxx03-llvm_version+18.asserts.tar.gz/sha512/c43e8091e9946ba1d8849734a25b258df95b4759a79676565b624930d4a19805a78b66b1d193e528f95174d909d7895d4a4e49fe8ca298a24dc40d25c95900b1 -LLVM.v18.1.7+3.armv6l-linux-gnueabihf-cxx03-llvm_version+18.tar.gz/md5/a5198b13dc75ad3454e05aa6cdaca48f -LLVM.v18.1.7+3.armv6l-linux-gnueabihf-cxx03-llvm_version+18.tar.gz/sha512/9ec8078a1a7246f1545fe074783d6b88ce9b50f62b0438ff5637f6dedf5bcac427cc252c350354b7063f79f4e31a19f699c168c15bc6547a207da497026c2827 -LLVM.v18.1.7+3.armv6l-linux-gnueabihf-cxx11-llvm_version+18.asserts.tar.gz/md5/f569654ecdd8ec2a50986ccac8388c69 -LLVM.v18.1.7+3.armv6l-linux-gnueabihf-cxx11-llvm_version+18.asserts.tar.gz/sha512/9b50e3be1577a753f0ce42704846bd126229d8dd9f28bfcbda58c4f18e4b9ca4ec6bb9b57de61b3b9af8157a2983aeffb8af782a073e5e19a8ccc261cbea9601 -LLVM.v18.1.7+3.armv6l-linux-gnueabihf-cxx11-llvm_version+18.tar.gz/md5/496de8c9e2361f44ac6933480620d07f -LLVM.v18.1.7+3.armv6l-linux-gnueabihf-cxx11-llvm_version+18.tar.gz/sha512/02a8ecfb6e81e0fe07fb0d616a84a590e23e944588c18348c32265bf6bf19196beec189a0bc40514e379e97a9c8bef83557260839800fabe9f8e39e96689713d -LLVM.v18.1.7+3.armv6l-linux-musleabihf-cxx03-llvm_version+18.asserts.tar.gz/md5/05bc7406fd0a703edbc912bb3230eb37 -LLVM.v18.1.7+3.armv6l-linux-musleabihf-cxx03-llvm_version+18.asserts.tar.gz/sha512/898dd4c19dd0f22dcd1bd44264daa8dc64340c890c3368fac7451da1ac872a687d55b5eb50ae4e156c2dc4ece226ec05775daebafe9d8b53eb83b72d2986ff92 -LLVM.v18.1.7+3.armv6l-linux-musleabihf-cxx03-llvm_version+18.tar.gz/md5/d6ca30fc3a2796ebda2451f80846883d -LLVM.v18.1.7+3.armv6l-linux-musleabihf-cxx03-llvm_version+18.tar.gz/sha512/d7dc96e1bbca38272b1ca78b3ff995fc30434937a58815c63d0a9b4a017964cfb269a1f3203ad8374870257152229941d420f098644375b5f4d1b88fe39e0dff -LLVM.v18.1.7+3.armv6l-linux-musleabihf-cxx11-llvm_version+18.asserts.tar.gz/md5/6eb1a197150ad6c165b82c5e0e0db102 -LLVM.v18.1.7+3.armv6l-linux-musleabihf-cxx11-llvm_version+18.asserts.tar.gz/sha512/a159598c2bf351ea79d01e8a454a82bbd9823c080399520af3182e57259957ad07834b03c336e6225857da365e8ec1aa9f65b0ddd0821883ae817cb81f8e6dab -LLVM.v18.1.7+3.armv6l-linux-musleabihf-cxx11-llvm_version+18.tar.gz/md5/116d849cb2fb4b1c8c517397b2b04192 -LLVM.v18.1.7+3.armv6l-linux-musleabihf-cxx11-llvm_version+18.tar.gz/sha512/7b2596c76d2814fc30992ba78e5c8f93519442fa76004187de9830732b80bfc6c77f5d7aca042c20d8f868cd682bb6f71e3fa32940bc8c7b401753dc4ac2f331 -LLVM.v18.1.7+3.armv7l-linux-gnueabihf-cxx03-llvm_version+18.asserts.tar.gz/md5/27837dc854a173bd37a20f92383f6913 -LLVM.v18.1.7+3.armv7l-linux-gnueabihf-cxx03-llvm_version+18.asserts.tar.gz/sha512/1719205cba6de969e8724a99444bf958d5a7943ae90ee2dd11193f56ddfd4f0edf6d9af6da2e67787a64b91d994fee76bd8ffde36486c5229a980c2c4ef07e29 -LLVM.v18.1.7+3.armv7l-linux-gnueabihf-cxx03-llvm_version+18.tar.gz/md5/f0016c21c045e205131ea22dc711acaf -LLVM.v18.1.7+3.armv7l-linux-gnueabihf-cxx03-llvm_version+18.tar.gz/sha512/6d192b7e21c7ee3327d288b890f4c5dd03e5f53dcba6905a34cab96b7ad0ab6364f5271af88d95e60aab8f569a8840d17e16f27f6fcdafcaf537d5d4a651dca7 -LLVM.v18.1.7+3.armv7l-linux-gnueabihf-cxx11-llvm_version+18.asserts.tar.gz/md5/9a2bad4518966db29e37e7c88388e779 -LLVM.v18.1.7+3.armv7l-linux-gnueabihf-cxx11-llvm_version+18.asserts.tar.gz/sha512/b9a10af9dcbacf1f129d4e9b4cf562a6a4687252cc8a0fcd78f52d75c0c20be0ff32e67413a7902a628b04e7fac1091d35b64b145e33814899796009b6ed2853 -LLVM.v18.1.7+3.armv7l-linux-gnueabihf-cxx11-llvm_version+18.tar.gz/md5/77c4e24c1e44ce14bc6476954f294a15 -LLVM.v18.1.7+3.armv7l-linux-gnueabihf-cxx11-llvm_version+18.tar.gz/sha512/d9d90a4ac788dbbc1b532623a380d4cca8813ecdf8b7b4a8cfff769499e50a1433bac618234bd0765d8a4f50aafb3fa724d16ac71baf75ae5a2b4396fa2bd017 -LLVM.v18.1.7+3.armv7l-linux-musleabihf-cxx03-llvm_version+18.asserts.tar.gz/md5/b29e36dcf5a0aa05734f1d6a0afd6944 -LLVM.v18.1.7+3.armv7l-linux-musleabihf-cxx03-llvm_version+18.asserts.tar.gz/sha512/ab46a835f9843c5b3427101bcd0c5d2b8acf79693aa9b8d4282d499f25df4ca248a81fc94ddd96c75d69d3c6b3814b225eed81bec32fbe9199bffdd605f7fec8 -LLVM.v18.1.7+3.armv7l-linux-musleabihf-cxx03-llvm_version+18.tar.gz/md5/a411269f925cc968a0438562262e6d97 -LLVM.v18.1.7+3.armv7l-linux-musleabihf-cxx03-llvm_version+18.tar.gz/sha512/04f275603134b0ea0f23da377e4983765885f2b1954d5c617134af9f103470a5e50dfda18bcddb836852db2382f1c134db40df00b36c8bd00e7a9e6ff1a9e684 -LLVM.v18.1.7+3.armv7l-linux-musleabihf-cxx11-llvm_version+18.asserts.tar.gz/md5/841921e33407e15eeeaa76354aa2b737 -LLVM.v18.1.7+3.armv7l-linux-musleabihf-cxx11-llvm_version+18.asserts.tar.gz/sha512/e1fb8b75e141cc90916c5c81c31ee91336911983c525f38eab86682ba69679dfbe1f10c9b673323632fc75f38cacc2af47a3d5d5d1031ec9a2a60cebd68d501b -LLVM.v18.1.7+3.armv7l-linux-musleabihf-cxx11-llvm_version+18.tar.gz/md5/7342a1d7b1d2c0fed7f5edf1c331ffa8 -LLVM.v18.1.7+3.armv7l-linux-musleabihf-cxx11-llvm_version+18.tar.gz/sha512/dae8ca11fa8d34f99ee19a95bcd108a65b9e6a6ddf2e5a9b126f2ba1b1cdff6b7ec21e9590d70b3785593435bb71e47703d9765811db814a90aa8a47940421ff -LLVM.v18.1.7+3.i686-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/md5/10aac489dfa10a77427a82958f525da2 -LLVM.v18.1.7+3.i686-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/sha512/a87f721df4fc5f6e929a54d8e41e55fb366a051a610836923213bfa42a7f1593de880391131619653cc3571bb76a4c82e011852ee5a6005523957c9f0937e6ba -LLVM.v18.1.7+3.i686-linux-gnu-cxx03-llvm_version+18.tar.gz/md5/7f231fd359f9297261c22f95d8f738c8 -LLVM.v18.1.7+3.i686-linux-gnu-cxx03-llvm_version+18.tar.gz/sha512/fdd6441011609ef341108ff2d108c6f320d415b621a69922aeacc555c3d1ae6090a0f600f24e229a609b88ba9c1868900791a6590033b7dad333ad11f8a6365b -LLVM.v18.1.7+3.i686-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/md5/c4523a485082044553e1a89049dc4734 -LLVM.v18.1.7+3.i686-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/sha512/db365e63bbb5189f7f348e2fd51e627ddfebf838ca9dfc6c0f8a7bbf6b8a2a03d78ea3ccdf08b0c2674f4cf5a0979506efa643554091ba751f16051bdf42ca9f -LLVM.v18.1.7+3.i686-linux-gnu-cxx11-llvm_version+18.tar.gz/md5/bcd10e4f3e5a4b00d52441e0094de1c9 -LLVM.v18.1.7+3.i686-linux-gnu-cxx11-llvm_version+18.tar.gz/sha512/b17fae89a3dfaa9428cf48c9c0866477cc75edda6aa3800702227cc9e3d6ebaacbd60cccc96acb4ccde56a2de531dea5a436bac8e6c450a4674daae23b878037 -LLVM.v18.1.7+3.i686-w64-mingw32-cxx03-llvm_version+18.asserts.tar.gz/md5/6bb986b1c9b66ca24c976e6534726b00 -LLVM.v18.1.7+3.i686-w64-mingw32-cxx03-llvm_version+18.asserts.tar.gz/sha512/1fd7cf1c80594561a8b83cf993192299e8a96046bd1e2f6eb330898c5e2dd0fc7c6ee0e3115d4e4049b83c71e724fab19a5d468e72fd141d8a2c4c02d831b71a -LLVM.v18.1.7+3.i686-w64-mingw32-cxx03-llvm_version+18.tar.gz/md5/c44aad21aef3b92fa0b1543ab9e4b93a -LLVM.v18.1.7+3.i686-w64-mingw32-cxx03-llvm_version+18.tar.gz/sha512/1aed6fb716a576b132d13397c927b36f00d78a42e5273168f1eacd208e366c55328286c56bae0abaf2c7ee424e7f19f4e096cd53f7d7caf863a0d58de1a2386e -LLVM.v18.1.7+3.i686-w64-mingw32-cxx11-llvm_version+18.asserts.tar.gz/md5/c3494f146906e178c5e5e32c10f6fec6 -LLVM.v18.1.7+3.i686-w64-mingw32-cxx11-llvm_version+18.asserts.tar.gz/sha512/a0fe26f88492ce8416257e76a5938a65b4911822c9c3e3bd0e3455adae1beaa952a769d616e8f8525c3bac64a6e3cd7f1dfd68800b5e7db94ad63320a2716e2b -LLVM.v18.1.7+3.i686-w64-mingw32-cxx11-llvm_version+18.tar.gz/md5/4644616c2e8937169500c200fb56322a -LLVM.v18.1.7+3.i686-w64-mingw32-cxx11-llvm_version+18.tar.gz/sha512/1250c5c9541782dabb5f0063bb2a18ee15a5dcd0e8b675e78474fa7dce2d51dd97e1bc4eee0a526a73f7812c57e41faa85e021fea4de74d33c62ae67ca555d73 -LLVM.v18.1.7+3.powerpc64le-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/md5/b39ce0b0f143c3bef4dade99251003bc -LLVM.v18.1.7+3.powerpc64le-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/sha512/62148e1e0a31d6b28effda0a5016d9335005b27ffdc5be1d184efcbb13f13e29eca52eca19cc6800d1d0421c0e67a36027e05d5fdc967dae686b5bfd112fb2b6 -LLVM.v18.1.7+3.powerpc64le-linux-gnu-cxx03-llvm_version+18.tar.gz/md5/9475748210eb5b1947fe3aa6673b6c29 -LLVM.v18.1.7+3.powerpc64le-linux-gnu-cxx03-llvm_version+18.tar.gz/sha512/54320295e59e5903db558b6be0220442dbaf7ea78e1612d54a35cbe014541b354ea708679da00851b962140b6da77301e27b656fd478666d3f0f710382c13a85 -LLVM.v18.1.7+3.powerpc64le-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/md5/6a533054ccfc3d1b0920eabcfb45ee03 -LLVM.v18.1.7+3.powerpc64le-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/sha512/3871620aeea2ccaf6e4b17a675c5504624fc6d8ed57bf4e5b66e0372b7124e4f3d1e0f10baa1018d5a1ac5bc4bf0e9d2143e84827712fda1f512fed24829f1b9 -LLVM.v18.1.7+3.powerpc64le-linux-gnu-cxx11-llvm_version+18.tar.gz/md5/3fc6d1b7d59b98823d6016f97835b7c5 -LLVM.v18.1.7+3.powerpc64le-linux-gnu-cxx11-llvm_version+18.tar.gz/sha512/745942235e40f2ab71a5eaef2768842823620d4a4dc7454a7512fb2bd95bc8a74323eec6a4b33edf1ef935151c18a20172f60fcca2fca1ff3a37b1e019ea4640 -LLVM.v18.1.7+3.x86_64-apple-darwin-llvm_version+18.asserts.tar.gz/md5/4bf72195bb2b3fafd98bd3f1966dfd0a -LLVM.v18.1.7+3.x86_64-apple-darwin-llvm_version+18.asserts.tar.gz/sha512/6554fd0374875428d0479e192ac3c70823a1143ac9acf0fafb3332f6c03e7fc8d14513512152bc995c186024bc36de77c5e7895ac1382f962b22b1089c3cf176 -LLVM.v18.1.7+3.x86_64-apple-darwin-llvm_version+18.tar.gz/md5/5631a8736cab900c3fcfeb559abc54a2 -LLVM.v18.1.7+3.x86_64-apple-darwin-llvm_version+18.tar.gz/sha512/55d93ffcc0125720f7db379396c5a79e98408225aebebc72fdd05b38605e73481eef46c219f59088b3bdea6257a7a7e369e6e0110019164374ac35bb49897738 -LLVM.v18.1.7+3.x86_64-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/md5/28ae362155ce224cef605cee53e36d0b -LLVM.v18.1.7+3.x86_64-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/sha512/d90f25e57f92a9da68245ceb15316e3868bf657d7e744f37cce5ccb4945777ec82fc5d470ba4fc104fe7aaabfff7b0dc260838a45331e4360b0fd14c59a55666 -LLVM.v18.1.7+3.x86_64-linux-gnu-cxx03-llvm_version+18.tar.gz/md5/d10ec63510dc1a043ee0a4e37b49eacd -LLVM.v18.1.7+3.x86_64-linux-gnu-cxx03-llvm_version+18.tar.gz/sha512/54c393208d1f51661e631cba62a21c0685fb58827067d5ea7c42fb3d6dd8c8db99d8ee1b3c304abc25510bcb0265d86ca03e1ce19be4faa252d97cfc8a1b52cb -LLVM.v18.1.7+3.x86_64-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/md5/2c1e000206c9e7c6c8e7515eb8115e3e -LLVM.v18.1.7+3.x86_64-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/sha512/12c0ead798e43448a30699b5386b3d88aac49aaef9bae283ea6d089a1c66df7293f4f220a2b5c3d96e73e556e37e745f38d81f5c68e09a86a2b19a6695eff460 -LLVM.v18.1.7+3.x86_64-linux-gnu-cxx11-llvm_version+18.tar.gz/md5/21d6c5d5e422412b88ffce50862efb29 -LLVM.v18.1.7+3.x86_64-linux-gnu-cxx11-llvm_version+18.tar.gz/sha512/5e8e17ba79134e9752c7fbd28b62e4616574a5e1dfcb0980160a3aad28a2f6cec4e48ed1acf73ca1f94d74397f7ee3eba53cb1280699e40c451295590ede3fe3 -LLVM.v18.1.7+3.x86_64-linux-musl-cxx03-llvm_version+18.asserts.tar.gz/md5/293fdc43431493f915a3e0a5b3c6d587 -LLVM.v18.1.7+3.x86_64-linux-musl-cxx03-llvm_version+18.asserts.tar.gz/sha512/27e13a4334a3bfb3c91fd06abcc4eca7a347f4bffcbce40834302d153ef29756295121b42ac433c266668af1428ffa08ed12ce75f21fef44cd7ac1d8bdfd155a -LLVM.v18.1.7+3.x86_64-linux-musl-cxx03-llvm_version+18.tar.gz/md5/2825dac8280d0563b7f521a9eb8c0563 -LLVM.v18.1.7+3.x86_64-linux-musl-cxx03-llvm_version+18.tar.gz/sha512/7f4549ac7b63e58d8c149f6b22bd997545713477a1df3b32adf640f3951580df1645f08756d9ba80c479160cf5759e3f9372396655a35cdca14f4be4afc4ae22 -LLVM.v18.1.7+3.x86_64-linux-musl-cxx11-llvm_version+18.asserts.tar.gz/md5/0c0da0eccec4a092fc0e9a915716ed6f -LLVM.v18.1.7+3.x86_64-linux-musl-cxx11-llvm_version+18.asserts.tar.gz/sha512/e538e29c4d52d9aaf151670619702541fed8231ae4c7fb9431a425d10eea95433087034a37da8fe468bd27a1c882f6f8eb9549ef71964124db10e99f4b402ba5 -LLVM.v18.1.7+3.x86_64-linux-musl-cxx11-llvm_version+18.tar.gz/md5/6b4fd19277c978306441da3b58ab86a1 -LLVM.v18.1.7+3.x86_64-linux-musl-cxx11-llvm_version+18.tar.gz/sha512/6216b3e1dc6aea979d8b5abc4cc0faf510e4e64441b1d18b4b36c45d65e874e9046e14eea67efb88f3219449ef048d34fcb751b15c59f8a299aa822b426d50ae -LLVM.v18.1.7+3.x86_64-unknown-freebsd-llvm_version+18.asserts.tar.gz/md5/689ce55ca1eb1be8090a7dad2e5f1a86 -LLVM.v18.1.7+3.x86_64-unknown-freebsd-llvm_version+18.asserts.tar.gz/sha512/a2ebd80e71375abafdaa45d4d104c1822d2205bd680b8c8541aa90dbc54d530e348a64a18acfba14cb66c078f0386d54375bf26cddef935a348e874b99609312 -LLVM.v18.1.7+3.x86_64-unknown-freebsd-llvm_version+18.tar.gz/md5/dbb26e6bd19d71607248446d38ea0a42 -LLVM.v18.1.7+3.x86_64-unknown-freebsd-llvm_version+18.tar.gz/sha512/eecaafa95e1df14f57f93e44732a23b1fb734af73bb533c8b4662dd0ddcfe696271571b97e2a5346581c000336f9fa0b28bf1c92535490e5174649a7e01b6019 -LLVM.v18.1.7+3.x86_64-w64-mingw32-cxx03-llvm_version+18.asserts.tar.gz/md5/51981c5aac875046101670896de92c2d -LLVM.v18.1.7+3.x86_64-w64-mingw32-cxx03-llvm_version+18.asserts.tar.gz/sha512/466da0868068d27dfa8284a3431925c9cfed9314f681bbadd0c331ae67a1acb975015a739abfea239e7f93a2fd7d439601f5d8421d7fa4fcceec5730649686a7 -LLVM.v18.1.7+3.x86_64-w64-mingw32-cxx03-llvm_version+18.tar.gz/md5/65da06ac7ef16d3e3ea6137cb9a943f4 -LLVM.v18.1.7+3.x86_64-w64-mingw32-cxx03-llvm_version+18.tar.gz/sha512/6c70bcd54d1cbe502b7d9db50a59a62a8a10e4e90d7d607d61ed7737a70474aba2db5f5151b1dc03f965a84d8770d4be6f248ed1f4bc6c9e63298abecb936f1e -LLVM.v18.1.7+3.x86_64-w64-mingw32-cxx11-llvm_version+18.asserts.tar.gz/md5/0a4cefbd15c37cb418cfaac56b789146 -LLVM.v18.1.7+3.x86_64-w64-mingw32-cxx11-llvm_version+18.asserts.tar.gz/sha512/7fd5c69bfde6264ae4e548ec9c399dd09b1a5fe4b9cced23d6bc4257f0f67874b838d53ee8d6eef7fc01ee9d086758e06f00bb0a0388b97de2eb85143a47192a -LLVM.v18.1.7+3.x86_64-w64-mingw32-cxx11-llvm_version+18.tar.gz/md5/da2430483844823d31bcc5f302252ac2 -LLVM.v18.1.7+3.x86_64-w64-mingw32-cxx11-llvm_version+18.tar.gz/sha512/19e9168b44d40acdc0d924e16f93c315237207a4441ae78997c511135872e557f654236bc859453069671145e81e961ac93c9dfa601d1b6631b9ccfa09b929b3 +LLVM.v18.1.7+4.aarch64-apple-darwin-llvm_version+18.asserts.tar.gz/md5/d2ff48876c4d883f430b27328c8c7520 +LLVM.v18.1.7+4.aarch64-apple-darwin-llvm_version+18.asserts.tar.gz/sha512/327b6651dbf039638fdf4920832ebfe19a6448226e1afed2f9052a338f7c71264616efad32843fa9372bde03db6b61964d814319e2c495381a4f024fef7ae7c5 +LLVM.v18.1.7+4.aarch64-apple-darwin-llvm_version+18.tar.gz/md5/4763334eeb55148f50415c2fb41c56d6 +LLVM.v18.1.7+4.aarch64-apple-darwin-llvm_version+18.tar.gz/sha512/5cee3c928743d319eeb767e5b581b17c36e9daa5787970ebcce41a83575b1db67012513fb51f4c877022d732a6893dd3fb8f6912698a215d833ebc0d246c5f1b +LLVM.v18.1.7+4.aarch64-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/md5/1909f5e4d3f8ba6f2350f500e2610d01 +LLVM.v18.1.7+4.aarch64-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/sha512/a9883aaac56058c29e4b67c202b53da7b9ab28cdec6a8c3aa75952bd327b6712c743f4db039985f6584a7537f8d8c8a8f183ff4453f6674af19ae685274eee54 +LLVM.v18.1.7+4.aarch64-linux-gnu-cxx03-llvm_version+18.tar.gz/md5/1a2804d3db38017049530614ee4b4c2a +LLVM.v18.1.7+4.aarch64-linux-gnu-cxx03-llvm_version+18.tar.gz/sha512/b969f83495f808888b20f0eb53b5ef5a2b921abf64153f0dee7ae1133b9c974f226846c30f28d9db9512c18753ced7ec8ba104bd4512f3d92e789f4e2732c712 +LLVM.v18.1.7+4.aarch64-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/md5/b0e3dabffe2e4f2691520163cab614e0 +LLVM.v18.1.7+4.aarch64-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/sha512/eb7bf45feb60b2845b08beaeef53db8af7cf7a2f4358cbacd26ec4df67ca2f929150dbba67d0214190cd415f89780916a8c1d6dfa1ffcae682afce7ef5754d0c +LLVM.v18.1.7+4.aarch64-linux-gnu-cxx11-llvm_version+18.tar.gz/md5/3ccfcca025dda5415548edb605a5915f +LLVM.v18.1.7+4.aarch64-linux-gnu-cxx11-llvm_version+18.tar.gz/sha512/6b7bc5e2dce6c06006968b5a4c1aeca6241800dc2c457989c4ce4e4078b811ea9d73ad35b8b28798bc423124d05da5cadb62dcea70ee8040852140d109f06cad +LLVM.v18.1.7+4.aarch64-linux-musl-cxx03-llvm_version+18.asserts.tar.gz/md5/3df8f5dac037a7a0a13e8ddccc43c09f +LLVM.v18.1.7+4.aarch64-linux-musl-cxx03-llvm_version+18.asserts.tar.gz/sha512/06b977792c934a611ac1a1631ca531aeb567dd9bbcf7b7d7d70ac39c079ee4e635840b09dc7e99702122ed467adcf653192987ee6f7b120dac020cdde2d4fa86 +LLVM.v18.1.7+4.aarch64-linux-musl-cxx03-llvm_version+18.tar.gz/md5/3c158389fc53e608a768390df871295f +LLVM.v18.1.7+4.aarch64-linux-musl-cxx03-llvm_version+18.tar.gz/sha512/d4cd188dff4a7eecbd9a885e711f6ed399d89e7420d6eb4b8dc7d5fd1c7aa5caed38eac2f986f0fb992d6881bd7a1fde3f62c1b8dcbb4ae505ecd33a1ea56d0e +LLVM.v18.1.7+4.aarch64-linux-musl-cxx11-llvm_version+18.asserts.tar.gz/md5/8c6dd5e1fe5eb9548c27ac28a0293eaf +LLVM.v18.1.7+4.aarch64-linux-musl-cxx11-llvm_version+18.asserts.tar.gz/sha512/5d2d7681661af8c592dba3330aab7cefde4a3220e6f18a0fc75f582c8f3025ff8a65fe6e8bf547f81a7d937b3a18bc1392c5dd3198cdde7f06bd12d85e5c090e +LLVM.v18.1.7+4.aarch64-linux-musl-cxx11-llvm_version+18.tar.gz/md5/a5d4ba849d0607fbd73139b16bc16c5d +LLVM.v18.1.7+4.aarch64-linux-musl-cxx11-llvm_version+18.tar.gz/sha512/f2e1fbc104b63e8ef5632c02274eebfea6b1dc14c6919f0e066dfee4c1f3687ee451694ac11c74b1f57f3987e0553edbccd1efb2615ab179ff6ea342a7ae481b +LLVM.v18.1.7+4.aarch64-unknown-freebsd-llvm_version+18.asserts.tar.gz/md5/da8f2ac10baf2f5792efac8f396d958e +LLVM.v18.1.7+4.aarch64-unknown-freebsd-llvm_version+18.asserts.tar.gz/sha512/b99138074e41dc534ed64cec0ad3337640bcbdf68b8738c9d5cfd5eba3574388c5a47fe76b967212a6e013bd7c09c3c0ceefc2c18a66302e2be7ffcc719e9cc0 +LLVM.v18.1.7+4.aarch64-unknown-freebsd-llvm_version+18.tar.gz/md5/f69bedc9c68b53e45684a81067c684e9 +LLVM.v18.1.7+4.aarch64-unknown-freebsd-llvm_version+18.tar.gz/sha512/fc5a01f36ed0aee53a3d90f6b07b7dbbc73f40bc2613faacdee7f3b0e86f0f449502de6a47949245a85869b7c1415ab49193f346c496d034a33090445d83b5a0 +LLVM.v18.1.7+4.armv6l-linux-gnueabihf-cxx03-llvm_version+18.asserts.tar.gz/md5/86190d010c3bf5a4a940a24d59a22cc0 +LLVM.v18.1.7+4.armv6l-linux-gnueabihf-cxx03-llvm_version+18.asserts.tar.gz/sha512/1c29ae7322f7e7c0ea47c165e239833d815482919322e9d8ea217dd6dc304884e844d82523d75e34964d1fbaff1106bac1008a4330f35ad00ca84676f4ab9907 +LLVM.v18.1.7+4.armv6l-linux-gnueabihf-cxx03-llvm_version+18.tar.gz/md5/49e37626fd1a23eb2edf130db61433c9 +LLVM.v18.1.7+4.armv6l-linux-gnueabihf-cxx03-llvm_version+18.tar.gz/sha512/16fb2104375c06f6a69b1bce4f63f04d4989982ace593e3539966a19e23156f0a01ab375c2f060225a76de3496ec84a8d5bb129789ccbc38c7e69402f313e2c5 +LLVM.v18.1.7+4.armv6l-linux-gnueabihf-cxx11-llvm_version+18.asserts.tar.gz/md5/dfa42f2505a81f71e8c96bb1ae8c040a +LLVM.v18.1.7+4.armv6l-linux-gnueabihf-cxx11-llvm_version+18.asserts.tar.gz/sha512/1de7804eb2d8cec8283cdca49fea44dcad73a5e1578ed6923a4534d84d0c4c34d6662141e68dbc045e9a06448e30c5c9096b0c149bae351f51e3d6c2111c0690 +LLVM.v18.1.7+4.armv6l-linux-gnueabihf-cxx11-llvm_version+18.tar.gz/md5/ec4c23a7c635588d0f6b622a23ad7b60 +LLVM.v18.1.7+4.armv6l-linux-gnueabihf-cxx11-llvm_version+18.tar.gz/sha512/77e6af72ada7ff6d5622eb71b7b899bd3a15e8dab09bc1d996aee68d1e7794781a628643d823a69e61bfac272ef4ece5f01f92f77892d680da457e9a42aa5a68 +LLVM.v18.1.7+4.armv6l-linux-musleabihf-cxx03-llvm_version+18.asserts.tar.gz/md5/4be5d6998e7b9e365ece12a89eab85d7 +LLVM.v18.1.7+4.armv6l-linux-musleabihf-cxx03-llvm_version+18.asserts.tar.gz/sha512/5846110206146899ada791c0accbb65ab5c167998a46533423ca31cb581cfa5765459455710f4fd8e918b1836d3eda4950a862ea4482179e960cac4bd997668a +LLVM.v18.1.7+4.armv6l-linux-musleabihf-cxx03-llvm_version+18.tar.gz/md5/c2b4455d8d7148d375db2cf31bfa8972 +LLVM.v18.1.7+4.armv6l-linux-musleabihf-cxx03-llvm_version+18.tar.gz/sha512/1105d8dd5535db5401cfb644532563486e4a06191e9c440b4a64282b7288f20feafa90ae01be0311b9947fffdad17483b38c74bd513406cc0dfa3d5390da7d2b +LLVM.v18.1.7+4.armv6l-linux-musleabihf-cxx11-llvm_version+18.asserts.tar.gz/md5/20cbd4764f1641ac36ef4e91bb0a3443 +LLVM.v18.1.7+4.armv6l-linux-musleabihf-cxx11-llvm_version+18.asserts.tar.gz/sha512/19ad90604d5af3579fc826d9061e327ad9c073642092d5d00f54d93e35b7888a55a64bf3a23f069ed4526bcfc6d0e0ba394f9f7cc982a49be1c41d2076b2f119 +LLVM.v18.1.7+4.armv6l-linux-musleabihf-cxx11-llvm_version+18.tar.gz/md5/42ab86133333da71b036d2aea0ab7e7f +LLVM.v18.1.7+4.armv6l-linux-musleabihf-cxx11-llvm_version+18.tar.gz/sha512/a31ba5a95f4e1abeaf4ff86d07777716658ae79e1ab6cefbbe42c85beb66e39fa7627c8d794fd8d8e595ad6d20a3200b54c16e946166da50e41e78d51ba3f3b4 +LLVM.v18.1.7+4.armv7l-linux-gnueabihf-cxx03-llvm_version+18.asserts.tar.gz/md5/9a5df42c54a585fe87c6ad00460e8c26 +LLVM.v18.1.7+4.armv7l-linux-gnueabihf-cxx03-llvm_version+18.asserts.tar.gz/sha512/297c717f00735b7d6daedd364695c657330645b803a29701b6331acc9558494896448e0529118e2b571bf137a7ad539fa33d707928c913d132a5ee086f3f93a3 +LLVM.v18.1.7+4.armv7l-linux-gnueabihf-cxx03-llvm_version+18.tar.gz/md5/5c0c5d27b4055ede2c2c366c5cd37401 +LLVM.v18.1.7+4.armv7l-linux-gnueabihf-cxx03-llvm_version+18.tar.gz/sha512/6dfedc56c7a46f233e689c80740e6222242c595fc7030fdb853855c8e0be333351cc2db784eab43bb0a83bb42b06bcdae907af2f66815763461895d9395bc70c +LLVM.v18.1.7+4.armv7l-linux-gnueabihf-cxx11-llvm_version+18.asserts.tar.gz/md5/64a5039fa3870fe66938167ba37719b4 +LLVM.v18.1.7+4.armv7l-linux-gnueabihf-cxx11-llvm_version+18.asserts.tar.gz/sha512/ddb6ee3e97c6cdb2c1f05d0ca05ad9720b964a0ebd5344f395b23f6e20aeff15cd7ef1bae38f067f3dadb26624498de9256167e2407d73737e39be09a77d7a36 +LLVM.v18.1.7+4.armv7l-linux-gnueabihf-cxx11-llvm_version+18.tar.gz/md5/130e4ca797e14dad6aa0bc6a9d1f8f10 +LLVM.v18.1.7+4.armv7l-linux-gnueabihf-cxx11-llvm_version+18.tar.gz/sha512/d0b0725df6bf6e1ba530fa8844d45787c76608f11a9a16822825186df5f9d62021f9640ec9d6a5c4220a9efefb687e612e4f6400430d2de9888e93bdc2c53ffd +LLVM.v18.1.7+4.armv7l-linux-musleabihf-cxx03-llvm_version+18.asserts.tar.gz/md5/f0301ea8d84567ebc5caed562b277e74 +LLVM.v18.1.7+4.armv7l-linux-musleabihf-cxx03-llvm_version+18.asserts.tar.gz/sha512/3adefc0b7e15cfd18f86531984bf677f19617b52716028c05351e00ad60a88096ea958d4889e98e12e87f1f869df9614092764ba819611d5aafaeec24001c906 +LLVM.v18.1.7+4.armv7l-linux-musleabihf-cxx03-llvm_version+18.tar.gz/md5/25a12d9e28753979d282212e6e31906a +LLVM.v18.1.7+4.armv7l-linux-musleabihf-cxx03-llvm_version+18.tar.gz/sha512/9cccaf08dedec278ab71f1f910be41daeb6bfcc23ba629503b2ecdb4667de080fa237da046295e2d219f48e7639f7a923db65c1f1e0a07211bcb6614f767880e +LLVM.v18.1.7+4.armv7l-linux-musleabihf-cxx11-llvm_version+18.asserts.tar.gz/md5/66afe4276ab27fab5b782af20c7de1e9 +LLVM.v18.1.7+4.armv7l-linux-musleabihf-cxx11-llvm_version+18.asserts.tar.gz/sha512/2dc373dc06969a7e3b52265341f93ad8ca4a8c80676fb6155405a18ab6577ab03ed39ccae28220497b78b133dce2ca65f0d3b68278f350c217cdb396287fc09a +LLVM.v18.1.7+4.armv7l-linux-musleabihf-cxx11-llvm_version+18.tar.gz/md5/df2bb1a9461190a8def39f77c827c615 +LLVM.v18.1.7+4.armv7l-linux-musleabihf-cxx11-llvm_version+18.tar.gz/sha512/d9d2093fc52ce7b016d9e392cd068b12ea820467fa0c31c7e9da18baf3d736b7c7b49050957c202232cc6a6fe4fac5aba23c1c5d8ae2d1e21bededa525ae791f +LLVM.v18.1.7+4.i686-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/md5/6c2b730a3056f9fc4e48ba9caa0959bb +LLVM.v18.1.7+4.i686-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/sha512/9c71497c6480b66f1bc2d77f72b12a7120746f35b823af6b999e0e8576d2371097b76d87d927b8eae00090ea9553f822b78548768fbb73c1c895d4ac8709c75f +LLVM.v18.1.7+4.i686-linux-gnu-cxx03-llvm_version+18.tar.gz/md5/81c3bf18dac5f9a6e1670f62f044dba2 +LLVM.v18.1.7+4.i686-linux-gnu-cxx03-llvm_version+18.tar.gz/sha512/074beb7a543407168b2f42b3c29063cf0a43d0b98e2919a7826f200cd7082a734c96304d0dfc604803f187980d79bf4501eb291f66d92b7e2f9fa9a2dcc7e4a4 +LLVM.v18.1.7+4.i686-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/md5/14b99a0abc5b26b0cdd8bee2fc66f5d5 +LLVM.v18.1.7+4.i686-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/sha512/1397a732b1a55f39033930add4357e894da5a3f8fdf8e71afb7ad05d74a2d3fe895aabae2de8d14588fe01d0fe676fd3d4f8a8777645fc13c49672d5493bb4ca +LLVM.v18.1.7+4.i686-linux-gnu-cxx11-llvm_version+18.tar.gz/md5/d1e0b91f6d3dbcf94be3ff8f8e83f761 +LLVM.v18.1.7+4.i686-linux-gnu-cxx11-llvm_version+18.tar.gz/sha512/249fa874921f1b3088afb01667863a2a5de5a8d26ad5b439c09484472492c607c98df2b52556399d3319e7add198446aa871dd00fed1843b966bdbfbb35acb71 +LLVM.v18.1.7+4.i686-w64-mingw32-cxx03-llvm_version+18.asserts.tar.gz/md5/a2f5c38be76b35ca02c6b1ce87f873f9 +LLVM.v18.1.7+4.i686-w64-mingw32-cxx03-llvm_version+18.asserts.tar.gz/sha512/c83665cf6a25f675b45b54a7346dd8ff6ad0cdaa197a68ac3cb1eb73afd7e75ebffe9aa31047ca7f36d50f0d9187865ba872c7ad7f705823400bbbcf4ac7bbbb +LLVM.v18.1.7+4.i686-w64-mingw32-cxx03-llvm_version+18.tar.gz/md5/6fa91c4a862b114926118cd1992c36f5 +LLVM.v18.1.7+4.i686-w64-mingw32-cxx03-llvm_version+18.tar.gz/sha512/319fe078adaf3101d7c8e4502bf4f30617c858f254af4fab40913e4d8aacca54fbacf121ec43fcdb07f8f92d788c92ceda89d8fbc50d033c6b1fdfef7b8b3d3f +LLVM.v18.1.7+4.i686-w64-mingw32-cxx11-llvm_version+18.asserts.tar.gz/md5/fac4b602f1658964a3157d7870e391a8 +LLVM.v18.1.7+4.i686-w64-mingw32-cxx11-llvm_version+18.asserts.tar.gz/sha512/07c4b9cc5c4843025fc8da3f9db80253933fd6e05d9f781539025a922de2bcb62250c893f551fba1676785a53faf768d767080a7a59e80b051d4c61cd9a697b9 +LLVM.v18.1.7+4.i686-w64-mingw32-cxx11-llvm_version+18.tar.gz/md5/faeeee316451a553e499a850f4927153 +LLVM.v18.1.7+4.i686-w64-mingw32-cxx11-llvm_version+18.tar.gz/sha512/b6d9a425907260293e0fb9a7e38e1cebbb8176452f5754bd226736e711056452b6da8b7584ddd13219f088c59f8acfebb0f05ab2966e662936b45027d8248ad1 +LLVM.v18.1.7+4.powerpc64le-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/md5/b4b66836f9156fc61ecb296ba09339ef +LLVM.v18.1.7+4.powerpc64le-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/sha512/b310dc8d8863c0da72d5c1e0b094542b1d8a8b2696999eba38a13a8962c5972e2cc682e62c627de8b2c0565624e0c283aa877473f803d4ea25e2a69d1895e369 +LLVM.v18.1.7+4.powerpc64le-linux-gnu-cxx03-llvm_version+18.tar.gz/md5/ad15a8c23753c91a4cddd15504d077b0 +LLVM.v18.1.7+4.powerpc64le-linux-gnu-cxx03-llvm_version+18.tar.gz/sha512/24560043f2de1baeaf3343814ec9cca1c3c9de514586f2449e1f1766f4ebda11dd7bb49bf95959c027d3ce845124bd38ed41907cf1cb31f1e02851d6a85f23da +LLVM.v18.1.7+4.powerpc64le-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/md5/7b6e45ef10fe03a30186ce84b2900b55 +LLVM.v18.1.7+4.powerpc64le-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/sha512/f193a596a4bdc4b0d4656b2dac4a16e08d1274f1ca3ac1400f7ae19c045876c0cdfeaf7f853c2dec89931274bdce8d1a59aa31125c266ca2e66ef739ff2012c8 +LLVM.v18.1.7+4.powerpc64le-linux-gnu-cxx11-llvm_version+18.tar.gz/md5/1710dc4978f1c66ca1ece6415942f2f2 +LLVM.v18.1.7+4.powerpc64le-linux-gnu-cxx11-llvm_version+18.tar.gz/sha512/eeab3db272f72626c3f5aeb2ae9917fe0837dffa0d35f2c66ac2befbca0544f22ebc639de79f2b27ea9ac0354855867febcad700a60c9a6d26a463cdebafdeef +LLVM.v18.1.7+4.x86_64-apple-darwin-llvm_version+18.asserts.tar.gz/md5/f939452c4251f79bf798c043cf18579d +LLVM.v18.1.7+4.x86_64-apple-darwin-llvm_version+18.asserts.tar.gz/sha512/3799a37feec6845240b7ffac3006c82f7206315b6bee52e35f7d5001c7658b552e951e3c82118bc9c31eb414f148a1d2f94aa39bc0fd8c7e3d474bb660b50e3f +LLVM.v18.1.7+4.x86_64-apple-darwin-llvm_version+18.tar.gz/md5/daa29a91e0bb0a5217277b549754f5ab +LLVM.v18.1.7+4.x86_64-apple-darwin-llvm_version+18.tar.gz/sha512/77ee4bb3df16e7e8b09da71811c9e333131b2bb6202b247383b7eed129d51e643a83359cb4b34ee27eda4a0c61235661d01a5b8362292e3fb82feca7e0bc1aae +LLVM.v18.1.7+4.x86_64-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/md5/e9acc5388bb91de5bd5677d0261e64a9 +LLVM.v18.1.7+4.x86_64-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/sha512/3bf168ecb2163b896dcd6eeec06aafc9f072b6ffc2cb458ee16f44fb0a3b8aff8f7a9a78c7d8e56133c108820f01ccf747c800205cd17bd220037109b0085758 +LLVM.v18.1.7+4.x86_64-linux-gnu-cxx03-llvm_version+18.tar.gz/md5/5bbd2421abcb5aee53bb9dfe349f85b4 +LLVM.v18.1.7+4.x86_64-linux-gnu-cxx03-llvm_version+18.tar.gz/sha512/5e172445793d0f02bed170f58473bae10fb6dac3734d7e5a362ea03a607b918636b688990c33b6a9392e50da3a90f0fa1f82fa5bfd3d00f9ac032244b72b10f4 +LLVM.v18.1.7+4.x86_64-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/md5/79188f344f825f0d25ea43221757788e +LLVM.v18.1.7+4.x86_64-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/sha512/264010b23484c5fed36557c8a2abe49c4628d24230265487f64a5a3318d53845439796c6f4cb231712dd92f5ea210ce2362e6d69135df6b1566e9670aa51843d +LLVM.v18.1.7+4.x86_64-linux-gnu-cxx11-llvm_version+18.tar.gz/md5/5e45fd8bff4f0f60ad5acdb929d422e3 +LLVM.v18.1.7+4.x86_64-linux-gnu-cxx11-llvm_version+18.tar.gz/sha512/1faedb56a9cf919e53270fdeb0417a27345cedcd9974c82a0edaa4de5e99e2592faf02522952353b1f2bedd8c03a4f38466ede7f829d6555526665a66141017f +LLVM.v18.1.7+4.x86_64-linux-musl-cxx03-llvm_version+18.asserts.tar.gz/md5/4723d91f315cd44b4d53e4790f20831b +LLVM.v18.1.7+4.x86_64-linux-musl-cxx03-llvm_version+18.asserts.tar.gz/sha512/92b10a8729fa0cdc10690ca743d41f6c2bb7cec7b134b1b0ed216e75360f59d461af51d86212967e86bcd9473d561916a27d8da281d5e446d05ef92582ad152a +LLVM.v18.1.7+4.x86_64-linux-musl-cxx03-llvm_version+18.tar.gz/md5/468c76c8a239aef2a85f99ce53a3a9e7 +LLVM.v18.1.7+4.x86_64-linux-musl-cxx03-llvm_version+18.tar.gz/sha512/e1cadb25b5c06d5f3807251adbf5d8f9d34c8f7bcda229e8a4d01f76fd820a71c7e472fb1c7877941b2ba9b4b17a3d227ca28ad71e51e2ca6d71c6d124d640c0 +LLVM.v18.1.7+4.x86_64-linux-musl-cxx11-llvm_version+18.asserts.tar.gz/md5/cbbbdd8781c5bac3b43b5736c26f5142 +LLVM.v18.1.7+4.x86_64-linux-musl-cxx11-llvm_version+18.asserts.tar.gz/sha512/621f81114ac516516f7cd7f43480285f70780202a29baafff4b883b5df3e293ab5a5788951dc3b2dc29bc8fd6fa66a07637833ace4eacba6162648d1987505fe +LLVM.v18.1.7+4.x86_64-linux-musl-cxx11-llvm_version+18.tar.gz/md5/46bb4ce575cf0b640bb6b5a2a606b327 +LLVM.v18.1.7+4.x86_64-linux-musl-cxx11-llvm_version+18.tar.gz/sha512/385218b95dba66d9bf1448c5e6e75678b4537083d13f4457e127f460abf14836fa5711159a3e12c61c93dd81fdc5cf6f1ca855b56ff968b697818b639b7a32be +LLVM.v18.1.7+4.x86_64-unknown-freebsd-llvm_version+18.asserts.tar.gz/md5/6e6e79c0ac1afc889cd46eade345154e +LLVM.v18.1.7+4.x86_64-unknown-freebsd-llvm_version+18.asserts.tar.gz/sha512/d01b62f114afc49c7cc69a27aa454e8940d224609995ff2ae7731f34a2652ff37b8ff203eee4a0966ff4c86e1fba4d2f699d9c510b83b1f2775451a174ed3bc8 +LLVM.v18.1.7+4.x86_64-unknown-freebsd-llvm_version+18.tar.gz/md5/f3c87420e35c24b50161adb7aa111670 +LLVM.v18.1.7+4.x86_64-unknown-freebsd-llvm_version+18.tar.gz/sha512/64aca33f22ff15f236f5b3514208477b3eafddf309f21bf29c634430bed4b1aa27e22a1798e4e1a33364db7a36e80c89dde4605db9d62f686d4a5d008091b382 +LLVM.v18.1.7+4.x86_64-w64-mingw32-cxx03-llvm_version+18.asserts.tar.gz/md5/4228a2ce55a4beb2c3609d0703f87bc1 +LLVM.v18.1.7+4.x86_64-w64-mingw32-cxx03-llvm_version+18.asserts.tar.gz/sha512/7d412e51499f2cf864f5c0e668aa8b4faaf3ee2b79f362d54e612147b9be9ff642280b3a59363ded48be685c5f0c3e322e38fe9e15b1595961d3ed9c872e0326 +LLVM.v18.1.7+4.x86_64-w64-mingw32-cxx03-llvm_version+18.tar.gz/md5/6b7bf112cacd833d79904b31ebb17d7e +LLVM.v18.1.7+4.x86_64-w64-mingw32-cxx03-llvm_version+18.tar.gz/sha512/49487f7f8baf310e13c4269c1fa2e90c8227902ce4b4578e5695e11bceae2ed626e49a944a4e50d23ab7309fae96f347a2cb7530f2074b4119d1cf7c825efd87 +LLVM.v18.1.7+4.x86_64-w64-mingw32-cxx11-llvm_version+18.asserts.tar.gz/md5/71b6dfae49fb6abba57bb2ea5f5ced10 +LLVM.v18.1.7+4.x86_64-w64-mingw32-cxx11-llvm_version+18.asserts.tar.gz/sha512/b152aa0be9814d733b892b9d316aee8e47b8fc034fd3190251e45a1ace828b893614a2735d2d71dccb1edd56c47bc9cacfa2044fb67927beb0daa20054dc6dcf +LLVM.v18.1.7+4.x86_64-w64-mingw32-cxx11-llvm_version+18.tar.gz/md5/e8f344f933ea61d6a75028c735a625e0 +LLVM.v18.1.7+4.x86_64-w64-mingw32-cxx11-llvm_version+18.tar.gz/sha512/9fc38dc52b007ac71c826856ebb88a4700c23ac5d70510bde62ea41ee90eee100c20abf1ff488fc0091eb59a2c5a5191e304b723b45042a6497a93b57a8bcbc3 LLVMLibUnwind.v19.1.4+0.aarch64-apple-darwin.tar.gz/md5/aace388fc1ece82ea524c582506ae931 LLVMLibUnwind.v19.1.4+0.aarch64-apple-darwin.tar.gz/sha512/c0211340a05630bcfcf9e3bab97da3e9f07e596e8d391427fa919c99502ab0a09878eda379254f379511884347f7e742872e8589f9b6ccbc2d126a5dfe0a350f LLVMLibUnwind.v19.1.4+0.aarch64-linux-gnu.tar.gz/md5/942d0b4ffb8bfd743cdafebf5bdfdbb3 @@ -144,119 +144,119 @@ LLVMLibUnwind.v19.1.4+0.x86_64-unknown-freebsd.tar.gz/md5/05f5b916fa639a68096cc7 LLVMLibUnwind.v19.1.4+0.x86_64-unknown-freebsd.tar.gz/sha512/0a137168c466861fdbdbef86dec96ece0d4c10f87fdc2dd729b445deb0fd59b214241b62644da77581a0100826e07dacf81fa060e67e35ff38df0d6807cb618b LLVMLibUnwind.v19.1.4+0.x86_64-w64-mingw32.tar.gz/md5/bb073cb86c821a70b845bd5de0edc2d9 LLVMLibUnwind.v19.1.4+0.x86_64-w64-mingw32.tar.gz/sha512/24d206c65c7be34485a1492250a9ca958e70be7057b981940bc24c4822e50e3963c9f88f42892ba2ea6df17fedb2783ace1693aeac74f200a5ca6033a14d6cb9 -libLLVM.v18.1.7+4.aarch64-apple-darwin-llvm_version+18.asserts.tar.gz/md5/9f0f5961fd1b7459b7cc6b535c49b9cc -libLLVM.v18.1.7+4.aarch64-apple-darwin-llvm_version+18.asserts.tar.gz/sha512/5a72510ab3b0b56ad478aaa49deffb809f0f1f3939cb6b7a899110249c95391fcf77108e3c60295c26d87c75ccd0fd548b9cbd5a528b4371eddd4b2f428d2af1 -libLLVM.v18.1.7+4.aarch64-apple-darwin-llvm_version+18.tar.gz/md5/6f4c4802055e49efb045a18b3a18c3c1 -libLLVM.v18.1.7+4.aarch64-apple-darwin-llvm_version+18.tar.gz/sha512/c5d17d6c8782b2de3c69942bab8a972e29bd7f262662d41475202ca6436202b01c9dcc2cde9b09f39473159c9da8cbb1b4db7717f0f701469dfe6f363ef62d45 -libLLVM.v18.1.7+4.aarch64-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/md5/4cd6ea39664d09051d12767ea53e14b1 -libLLVM.v18.1.7+4.aarch64-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/sha512/6cc3b443c5e4ac71d81bce312af48b663b5b20e10a874a171faf9f7cee65f37a0ddba41a13b6eb61e07a84d8bd2058e5748969bbfa8a59b01a94867dadf6f5c2 -libLLVM.v18.1.7+4.aarch64-linux-gnu-cxx03-llvm_version+18.tar.gz/md5/1ae79bb7cba1fd6a898f3cb86563337c -libLLVM.v18.1.7+4.aarch64-linux-gnu-cxx03-llvm_version+18.tar.gz/sha512/c4b714b4aeea418c988bbc91911ae226fc8e2301bcc00efa34d703ff91f28b20b2a15647612651cc346ef2508280492497035a43ebd2f62b062800216bd023ef -libLLVM.v18.1.7+4.aarch64-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/md5/29804b49dceb444d71c4b9110b3b9141 -libLLVM.v18.1.7+4.aarch64-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/sha512/bb15cdcb3aa10067d52bccfc89a1bf0141501c6f54eea4e2bfe094f463d5041dead84ab5d613a0250a86258d33df530b9b2b8636e5335963c8874ac00b5191c1 -libLLVM.v18.1.7+4.aarch64-linux-gnu-cxx11-llvm_version+18.tar.gz/md5/d37118f2ebf692b2b48995fa7567f3ec -libLLVM.v18.1.7+4.aarch64-linux-gnu-cxx11-llvm_version+18.tar.gz/sha512/3f4f88c82137c11f70cfee1998ebd8d7b8507d8164ca61a425b0bdd9d724ac0476eb61582408171ac104aa4692f38da4b8522182ac50c6d4c239dce7e5116d7e -libLLVM.v18.1.7+4.aarch64-linux-musl-cxx03-llvm_version+18.asserts.tar.gz/md5/da62e799a788ef941b60c474c80fbc16 -libLLVM.v18.1.7+4.aarch64-linux-musl-cxx03-llvm_version+18.asserts.tar.gz/sha512/b2b87955bb0628fff800245ba8785ff1c57fa6b82263094c8207aba1cfe8b3c60d8816700c722606feed7db50635fca0ecb7e2f7f3cdaa2bcbee0cb7995f960c -libLLVM.v18.1.7+4.aarch64-linux-musl-cxx03-llvm_version+18.tar.gz/md5/07dcc3b96e32f4c845b8bd6d4bb3f6be -libLLVM.v18.1.7+4.aarch64-linux-musl-cxx03-llvm_version+18.tar.gz/sha512/7e785c1f1ccef610b5129985a4250102f3d3592848404fcd0e07293e7fc4836189165deec650286be82f4a14a719720580bc2c80168a0648c26cbbe99734ebae -libLLVM.v18.1.7+4.aarch64-linux-musl-cxx11-llvm_version+18.asserts.tar.gz/md5/fe4dba386d61114ab035009f5d973534 -libLLVM.v18.1.7+4.aarch64-linux-musl-cxx11-llvm_version+18.asserts.tar.gz/sha512/8fa0a8027f64f382735757eed2b66b4be20a065c6f9714c7ffb10d643d491a8682927f5113a2e3e2cfc151101d3b48f4c3905a8ab6cde58d76fa1c2af7cabe36 -libLLVM.v18.1.7+4.aarch64-linux-musl-cxx11-llvm_version+18.tar.gz/md5/3c0deeb5750ccc5e74904eb4cdb1059d -libLLVM.v18.1.7+4.aarch64-linux-musl-cxx11-llvm_version+18.tar.gz/sha512/2956cd529e2bbec075bdf398ed44fd9e31861e08803beae454f9d8f1a85cc38aa41e36535f1f02940abf48f6f8a31f6663470e057065827ed174edd1f063a999 -libLLVM.v18.1.7+4.aarch64-unknown-freebsd-llvm_version+18.asserts.tar.gz/md5/840ddff37d9b3fb591052882a2f3daaf -libLLVM.v18.1.7+4.aarch64-unknown-freebsd-llvm_version+18.asserts.tar.gz/sha512/73b1ee831c455f447a3e603d5c9c333e89fd367c2692f1aa1d3063b8dd60a514565b3abbd79902e4ed5ee800146dd3e92b5dedb5092ad9520b325dca8da77b1f -libLLVM.v18.1.7+4.aarch64-unknown-freebsd-llvm_version+18.tar.gz/md5/73608188562e1e315a489d0772ccb2d6 -libLLVM.v18.1.7+4.aarch64-unknown-freebsd-llvm_version+18.tar.gz/sha512/08c10107a22f4bba18b6bd108a8821e81699f6be0495356f69b6c53d1f2033b4e37a7d9bcba01d28586ccd067028baeb549e671794cc7dd4d3791026690ff721 -libLLVM.v18.1.7+4.armv6l-linux-gnueabihf-cxx03-llvm_version+18.asserts.tar.gz/md5/d6821537e94a38482271ff68c8e3f992 -libLLVM.v18.1.7+4.armv6l-linux-gnueabihf-cxx03-llvm_version+18.asserts.tar.gz/sha512/2616e190c2765b43e4c3304029e849e5360555e5e1dc0059f6c3294d2797bef102a1c1ecdaf1eb9ff78aaf62e23525e0a3bac998ed92a4d14774dbe8923c50b6 -libLLVM.v18.1.7+4.armv6l-linux-gnueabihf-cxx03-llvm_version+18.tar.gz/md5/ebc37e019458e57824d3868a5caadb05 -libLLVM.v18.1.7+4.armv6l-linux-gnueabihf-cxx03-llvm_version+18.tar.gz/sha512/f835fd254c746621d5e9e12fee0a2bbb4c1954fd357a140208912552701d0e17005a4b5bbe5675f9526778c6b3bd3e5fae510e312dd48e07fe376da0c5d40899 -libLLVM.v18.1.7+4.armv6l-linux-gnueabihf-cxx11-llvm_version+18.asserts.tar.gz/md5/7f3d5b242f875bd2da988fd8e83cafb6 -libLLVM.v18.1.7+4.armv6l-linux-gnueabihf-cxx11-llvm_version+18.asserts.tar.gz/sha512/e763e99ff7356d03564215b5b3ff747a6e78a91dc62fa9d6c09cdb091efa4dad7cf8f88565f0d01dc35f6485aa3c2d513fcc91dd93051f3233b7dd551f8474ac -libLLVM.v18.1.7+4.armv6l-linux-gnueabihf-cxx11-llvm_version+18.tar.gz/md5/e4045d26a8878a4e7f51a31e761a537d -libLLVM.v18.1.7+4.armv6l-linux-gnueabihf-cxx11-llvm_version+18.tar.gz/sha512/025045a9491aa9ffce618f191d9c3d87310a956b6e23abd32f64116eccc52df6958e3135720a05ddcc37231e707fde541d1715f212eec0cadbce14397098d6b6 -libLLVM.v18.1.7+4.armv6l-linux-musleabihf-cxx03-llvm_version+18.asserts.tar.gz/md5/2bf265fcf032fb1dcd670a535c36a57f -libLLVM.v18.1.7+4.armv6l-linux-musleabihf-cxx03-llvm_version+18.asserts.tar.gz/sha512/7c77257585829e4022767ca3f4ace0dfb56e60179d2ddaed76ed9df329b8a5f227507f8565dbf8d5df8869bec2677089ec1565c5a0f94238a6ba01b2a696d8c3 -libLLVM.v18.1.7+4.armv6l-linux-musleabihf-cxx03-llvm_version+18.tar.gz/md5/6c8ecc36f4b34045bf7750a8ce8893b4 -libLLVM.v18.1.7+4.armv6l-linux-musleabihf-cxx03-llvm_version+18.tar.gz/sha512/cdf31871986baebfc11437743f15f133fb987784bc6a98ae0a6fff30c2e954cc6affc0c7a513b364c458c4279f7ed80486eacc0d1a5950a935bcc7158a176660 -libLLVM.v18.1.7+4.armv6l-linux-musleabihf-cxx11-llvm_version+18.asserts.tar.gz/md5/ce67eeb02f9b12bfd89b6bc6b2079969 -libLLVM.v18.1.7+4.armv6l-linux-musleabihf-cxx11-llvm_version+18.asserts.tar.gz/sha512/8c7feb74068f6a5df9d7f4d4fe719779ba9d4682606fcd170c1fdc2be1fdd963882d7092a42a00ab84a91e71962428964334db90de45adee9e4ba93c14fe1174 -libLLVM.v18.1.7+4.armv6l-linux-musleabihf-cxx11-llvm_version+18.tar.gz/md5/4e1faf56780903a64e88cdda15b8bf5b -libLLVM.v18.1.7+4.armv6l-linux-musleabihf-cxx11-llvm_version+18.tar.gz/sha512/9bbf6fba0f6a236d68dd228b933cf0cf1687b02397d8959a93ad59f0cc72f5a769670efd4aa48c2374e1368d900f2ed5a2ba0a5b795cf16f457a33b5162a9136 -libLLVM.v18.1.7+4.armv7l-linux-gnueabihf-cxx03-llvm_version+18.asserts.tar.gz/md5/85451952680acb73bd57c6093211443d -libLLVM.v18.1.7+4.armv7l-linux-gnueabihf-cxx03-llvm_version+18.asserts.tar.gz/sha512/b8e4180a312e68538af2057582c409387684ccd7320514def933df8dd7c1258f08a18dca339c9b6eb78c4c2a14eb11c2fb25e6f96da83515f465eed5c500d1c7 -libLLVM.v18.1.7+4.armv7l-linux-gnueabihf-cxx03-llvm_version+18.tar.gz/md5/c02f109693eb630d20b9c2aba03ff07b -libLLVM.v18.1.7+4.armv7l-linux-gnueabihf-cxx03-llvm_version+18.tar.gz/sha512/4162bc3aeadca88f81816b1ad84582dbe680f54d88d76285caab686c2c00d0a30346f1d6d0958fd1b5f8a296679605560ec37569e399574f2ab3110656fad74f -libLLVM.v18.1.7+4.armv7l-linux-gnueabihf-cxx11-llvm_version+18.asserts.tar.gz/md5/01fcecf3adb17ed0358d854eece4b79a -libLLVM.v18.1.7+4.armv7l-linux-gnueabihf-cxx11-llvm_version+18.asserts.tar.gz/sha512/eb140c0c7a18de4a58b2467dc359cb2c1ffe34264ca358573ba90cfa8651f9d770fa8c067b618d045699f1420e3b29489b71aae087c47eb4114039b4979fbc8a -libLLVM.v18.1.7+4.armv7l-linux-gnueabihf-cxx11-llvm_version+18.tar.gz/md5/861c096f87bbc516a8cfdca2bd8f9cc0 -libLLVM.v18.1.7+4.armv7l-linux-gnueabihf-cxx11-llvm_version+18.tar.gz/sha512/fc65b7b5206ee9e5f579bd0a34cbff93f47b93ad7ae6c2ee14a7b446dd9489db8b02df85587b5d4867ac82a30823633d52e2b0cadf94e4ae4d1cef7c33ccce48 -libLLVM.v18.1.7+4.armv7l-linux-musleabihf-cxx03-llvm_version+18.asserts.tar.gz/md5/9b6639379b74e4c3d0aa288abd433e53 -libLLVM.v18.1.7+4.armv7l-linux-musleabihf-cxx03-llvm_version+18.asserts.tar.gz/sha512/261ec83cdbf2b2a75926a632a748c0db14b0be37175bdaa610997df8e3611f08689509b93ca483c8b8b6a11c90a2fdaa5dee6cc9c2245672cb83922ce650b725 -libLLVM.v18.1.7+4.armv7l-linux-musleabihf-cxx03-llvm_version+18.tar.gz/md5/5b9687dbe8576a9881c24bb2541edbd2 -libLLVM.v18.1.7+4.armv7l-linux-musleabihf-cxx03-llvm_version+18.tar.gz/sha512/39cf2b39e20fbc63dd4746be92b09aef91e9386c94d3e0b0100bced398eb071953f103f55f3668e48801fa8ef0af14c5184a75eceb10f840982591fa8c6c2f59 -libLLVM.v18.1.7+4.armv7l-linux-musleabihf-cxx11-llvm_version+18.asserts.tar.gz/md5/fbcac757c4b5d86446e70ff3e0b6c2ff -libLLVM.v18.1.7+4.armv7l-linux-musleabihf-cxx11-llvm_version+18.asserts.tar.gz/sha512/1285e54eb0973eb97f457667fa92365fd3775a9691ea949a966f56d29f5770c88b6912d286d4ab3ccabe6a8bfb2e1b87e22b636323110d69994ff65e6504896b -libLLVM.v18.1.7+4.armv7l-linux-musleabihf-cxx11-llvm_version+18.tar.gz/md5/b77f996fbc03bfdb944c7ea630867cdc -libLLVM.v18.1.7+4.armv7l-linux-musleabihf-cxx11-llvm_version+18.tar.gz/sha512/b40dff6e56f9e3bcee67e8e65bd79685f63475fe21f2760a7cb79604268cd97f9eb602c2aa163a7ecc3ba2645a088e1911d2719d18cdd8daf6643db8f54352f0 -libLLVM.v18.1.7+4.i686-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/md5/afcfc9e4d4a04abc0c69361f8ba43598 -libLLVM.v18.1.7+4.i686-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/sha512/5d5137f1c4e7ae998629c5bb076051683f88e62688683d76ca2742aa723a80edd2c63b1ae6ff0bce81602c96b69ff99d804857f60939bfa59393e6d250ab07a2 -libLLVM.v18.1.7+4.i686-linux-gnu-cxx03-llvm_version+18.tar.gz/md5/0bf97c7ac35c1a68c69ed2bba861924b -libLLVM.v18.1.7+4.i686-linux-gnu-cxx03-llvm_version+18.tar.gz/sha512/e6cc1d6294fdbb0dbd424d60c459cdb497e0118b1da1144ddbed64f7e5dd58fb01911eb6a9ffec24e0e27cc4c593b0c4bbfa38497ed446a8040e6f85b2911b8b -libLLVM.v18.1.7+4.i686-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/md5/64bf5c29c94d8ba4577e2d73e99d2a94 -libLLVM.v18.1.7+4.i686-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/sha512/eb0690538cc1aa0b321f95117cd61426c47b6bc31117216b1daea6bbc691dd9ed68cb3aa41485ae1925358849e749110f273338a515822765557df2f3d258348 -libLLVM.v18.1.7+4.i686-linux-gnu-cxx11-llvm_version+18.tar.gz/md5/5a7e644087ff78651ce07160f5a98f91 -libLLVM.v18.1.7+4.i686-linux-gnu-cxx11-llvm_version+18.tar.gz/sha512/de9c8be69fcf6dc6f564e0440f5e2c08deb9da2b75b5a702e936b988e9c9ac8a9392f540c752f163ce80f80870b236a421f79229b148f460498b779f963b1d54 -libLLVM.v18.1.7+4.i686-w64-mingw32-cxx03-llvm_version+18.asserts.tar.gz/md5/ee33a06fda2bf953b255ddbffde1284e -libLLVM.v18.1.7+4.i686-w64-mingw32-cxx03-llvm_version+18.asserts.tar.gz/sha512/45d41cb2018f37c1ce8f28b9a81b8a9bd2b7282e70c9f5be4246d7fe6b44a439340485ad472c8eb837b6c80653dfda3cbb5c2d35fce13e9046431fe0271290a8 -libLLVM.v18.1.7+4.i686-w64-mingw32-cxx03-llvm_version+18.tar.gz/md5/f26af4c3ac08df8eea7c9856a7583ddd -libLLVM.v18.1.7+4.i686-w64-mingw32-cxx03-llvm_version+18.tar.gz/sha512/b3fbd17c5aac722620da44cb1c6f84fe1220d07997e028c21f0360f5f7844b953d9e4a500b2e743adac1f9d2ad61a522b0e44621845ad9fc4c7587456a1de278 -libLLVM.v18.1.7+4.i686-w64-mingw32-cxx11-llvm_version+18.asserts.tar.gz/md5/5149f99d2b29dcfb70e845c4810b64ea -libLLVM.v18.1.7+4.i686-w64-mingw32-cxx11-llvm_version+18.asserts.tar.gz/sha512/7cf494ae8cfd7ce780f7fc000c910af441a19c7633682655c30633e9131ff2be710851e3f1c582ca4898378749fcfb6a678ecfc1b35d97797e9832e1ea2e4ff4 -libLLVM.v18.1.7+4.i686-w64-mingw32-cxx11-llvm_version+18.tar.gz/md5/46fbebdccad778e953c02c82ae77de7c -libLLVM.v18.1.7+4.i686-w64-mingw32-cxx11-llvm_version+18.tar.gz/sha512/46735b1dabd675440591a44e8ddb94cec066b9f90c7579e9b8327e3079d94709aa14a6cc9f523f5ab14296e9d04ec38e2b3265b91c39d8115f43cd2e43af4436 -libLLVM.v18.1.7+4.powerpc64le-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/md5/7aa31bd01782ee5a3e8ead1983cdb9fa -libLLVM.v18.1.7+4.powerpc64le-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/sha512/8411ef4fb32344f9c511b77963953e117fa3424b9e4c27640c97861612c3e465f0508b762ea5dd70a0e453f71d1070e5d88a169b357c8d6aab4e04ba5cff268d -libLLVM.v18.1.7+4.powerpc64le-linux-gnu-cxx03-llvm_version+18.tar.gz/md5/68d8ad81493ff8951b752a4bbe7d7050 -libLLVM.v18.1.7+4.powerpc64le-linux-gnu-cxx03-llvm_version+18.tar.gz/sha512/1e4ccd4ef2f2784a7cfeb2721f2e13db52365b8af3bbdb552c72474f18fa5681e6aa0188f69dc2bce218f9e395a4873b61f73f35d10b5f21c9acea1f3e461c77 -libLLVM.v18.1.7+4.powerpc64le-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/md5/1b50987bd4fa05f020c3795c60c0b1cc -libLLVM.v18.1.7+4.powerpc64le-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/sha512/7271b5e17e759deb7d0f75c4c01c28b9fe83adb9564b389b6e44d131570f8d0eb942e9c645042b8ea6a07dc49d537c38035e176ff9ab08c92cfd1a44338a8a48 -libLLVM.v18.1.7+4.powerpc64le-linux-gnu-cxx11-llvm_version+18.tar.gz/md5/0f485d054050e1dcdfb8f01b4efef86a -libLLVM.v18.1.7+4.powerpc64le-linux-gnu-cxx11-llvm_version+18.tar.gz/sha512/153e77cdb946b545247cbd8c682e07226a85c092dd415deb6f4cce6a3d4a731b42a20cb88dbbb8220b7d8c298a3b3fddf1dec3ad5ccdc87dc286e10cd54a052f -libLLVM.v18.1.7+4.x86_64-apple-darwin-llvm_version+18.asserts.tar.gz/md5/4fbb5ecb088a636d7f3979cdc0d19508 -libLLVM.v18.1.7+4.x86_64-apple-darwin-llvm_version+18.asserts.tar.gz/sha512/6c64e28c867ce9d0bb5f19235b51c537de38907ac2e84d16bce1b2f18e5c1d02760e9ed8bab73fd78b551267e31872bf2ca59df164de6bc7cb8fcc5f05ba5989 -libLLVM.v18.1.7+4.x86_64-apple-darwin-llvm_version+18.tar.gz/md5/cdc1786080c6dcd3b29251d92e110aae -libLLVM.v18.1.7+4.x86_64-apple-darwin-llvm_version+18.tar.gz/sha512/1ee211fe903577c351c5bd84461b47b2570209960b8f218f92503b1e2a9c95a8b74ce083ac4da5ee66000f3da0f7804a07ef655f5560b396baf291f5f5fe8b1c -libLLVM.v18.1.7+4.x86_64-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/md5/50f41cd5d8f789175d10498f7762bbbf -libLLVM.v18.1.7+4.x86_64-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/sha512/31095dcc4b29cb840a8429a97e8ee916fe95802419d94d26dd6cbd7693a66af881cc82615ff71350bb4e24a5ce42156ee086fbc044c51e83b41b54a86004d985 -libLLVM.v18.1.7+4.x86_64-linux-gnu-cxx03-llvm_version+18.tar.gz/md5/8355ee35aab8205ce83d62b57bc1c8f9 -libLLVM.v18.1.7+4.x86_64-linux-gnu-cxx03-llvm_version+18.tar.gz/sha512/3704ca4bbcba6123f20943dc35194e4a666fae1822279dbe2851ccf620683bebd8f92fa98e84e302c54cd23546b1521ee37f900645e1427e2700e2d928211cae -libLLVM.v18.1.7+4.x86_64-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/md5/745b55591cd0c0530ab36b3b6303de86 -libLLVM.v18.1.7+4.x86_64-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/sha512/7701289fc8ad175f4f264eea07e19f8f19cc8263876f14dc5d2cf35e3170b0bbea54558eec07e9cf175f9127029aac13754eae45e42ab1e1f31f2e5287857296 -libLLVM.v18.1.7+4.x86_64-linux-gnu-cxx11-llvm_version+18.tar.gz/md5/c5784fdc403b8002b88482e5dac9c910 -libLLVM.v18.1.7+4.x86_64-linux-gnu-cxx11-llvm_version+18.tar.gz/sha512/710376e2f13461e6c629bf53185f834d16f1854c9fb284eaa5b55249d9289b23fccc8a9f7f8fc00e74d93fa13b86782a360a3394d247942bff72bdcf6f926781 -libLLVM.v18.1.7+4.x86_64-linux-musl-cxx03-llvm_version+18.asserts.tar.gz/md5/f50abc149a6e7bae03a0a568d2915b4a -libLLVM.v18.1.7+4.x86_64-linux-musl-cxx03-llvm_version+18.asserts.tar.gz/sha512/206bb3db48bd5408f227c48e9282f8f215988c17f498f41768c1f1659ce81f6ab1c26229079bb78326e9640266b94e5e1337dfc06e6e2c6c406e6b3b55089fa0 -libLLVM.v18.1.7+4.x86_64-linux-musl-cxx03-llvm_version+18.tar.gz/md5/e9ebabbef45e39a344b84284b0e62c96 -libLLVM.v18.1.7+4.x86_64-linux-musl-cxx03-llvm_version+18.tar.gz/sha512/dc986a3e55990d6b885bef493a9526bfb16b8ceb1e3dc62b00a7e6d6aa8fd749cbb2690f061559d6b0b7fc74fc58b7eb289bee6e528d3add90f4db94d1218c60 -libLLVM.v18.1.7+4.x86_64-linux-musl-cxx11-llvm_version+18.asserts.tar.gz/md5/9c1e44db7c2e259529982336e29e7de1 -libLLVM.v18.1.7+4.x86_64-linux-musl-cxx11-llvm_version+18.asserts.tar.gz/sha512/ea8ab32de84ff2c1e37bf17cab026d331c4d5c065d2ad52fede1fd9bc8138b4b9532011e57d52e5dae2455363dbbe196310529a4090a834c1bed354e8032971b -libLLVM.v18.1.7+4.x86_64-linux-musl-cxx11-llvm_version+18.tar.gz/md5/dee60d75932b1327118b4115ff2d710d -libLLVM.v18.1.7+4.x86_64-linux-musl-cxx11-llvm_version+18.tar.gz/sha512/b1b46fa9fa16c8822a06ae116376f7d60846b67756066ae716f20cc2fe22c0976726bd1efeb4ea0a9fd52e9a7c7b3f24944ccbebc155fbe4480790e22b140d67 -libLLVM.v18.1.7+4.x86_64-unknown-freebsd-llvm_version+18.asserts.tar.gz/md5/5c670329435e934957e3025b9dc7325d -libLLVM.v18.1.7+4.x86_64-unknown-freebsd-llvm_version+18.asserts.tar.gz/sha512/b51bd90a1f175e7b5c8f24f63daac8075b41134a5b5477610f433bf3d7ffa144b6ba0684540014967bd9021cb4d0c95c5dd7bc22d54da7a79f73e0326c0e65c5 -libLLVM.v18.1.7+4.x86_64-unknown-freebsd-llvm_version+18.tar.gz/md5/0d6f6974a8a82d224669e1f5c2a45d99 -libLLVM.v18.1.7+4.x86_64-unknown-freebsd-llvm_version+18.tar.gz/sha512/9bb7fee05f0fb449316f746b27a06fbd14579eef70a2bf39332e5a406a35aa1b1bc362d74a41774d65781cfcb49743f940c25fc734a531db5d94c03869626de0 -libLLVM.v18.1.7+4.x86_64-w64-mingw32-cxx03-llvm_version+18.asserts.tar.gz/md5/83aef3200c39e359b805d9200b5fe4df -libLLVM.v18.1.7+4.x86_64-w64-mingw32-cxx03-llvm_version+18.asserts.tar.gz/sha512/5648cd248851af495ab4548b01adfa71826aa41353ee1a6199c55e20d406d0bca8aef29482668a2f7a6ed5e2e2d3c2241c5e8cd4022692de813f2a615296df86 -libLLVM.v18.1.7+4.x86_64-w64-mingw32-cxx03-llvm_version+18.tar.gz/md5/9539f763d6ca37b9930ddee290a32cb2 -libLLVM.v18.1.7+4.x86_64-w64-mingw32-cxx03-llvm_version+18.tar.gz/sha512/0831d52bc9c134a666151ed2743e2b9471b58cf51dd2cc67c8f30fde1a142cfd4bf52cbf3845dc86fe7184457ff7adb1c2c31fdf5a9f15cdf55691580dde5f3c -libLLVM.v18.1.7+4.x86_64-w64-mingw32-cxx11-llvm_version+18.asserts.tar.gz/md5/fa169a8fb12a8ab69e08abaa7ba71c86 -libLLVM.v18.1.7+4.x86_64-w64-mingw32-cxx11-llvm_version+18.asserts.tar.gz/sha512/7554a970b31140a57f625df23cee8d3653c4f24fae020197c9e777f92d9c60b268dfa6bc60d3d895dc9ecb9a182269ea4b512d7bafa9218a72c81c8b39f83f6b -libLLVM.v18.1.7+4.x86_64-w64-mingw32-cxx11-llvm_version+18.tar.gz/md5/c8883304bc0f8defbd8117ebb9b6721b -libLLVM.v18.1.7+4.x86_64-w64-mingw32-cxx11-llvm_version+18.tar.gz/sha512/01abcc346cdd6f4a09ec4954b2b47e7e506e7aa51f69060389e3426101acef46e6d84c049b62b933d52cea3cc859b03de09843091c441f0a4091c962d59b4a30 -llvm-julia-18.1.7-3.tar.gz/md5/82e931476ec0e953022d3958bd3b1f8a -llvm-julia-18.1.7-3.tar.gz/sha512/683c28e68d354b3200d451004201a16737d8e52b20cee0f1e2fb8621301de34f23444c60636a79056d865dbcc6a59422458596d52797b0fa67c90620f864bd9d +libLLVM.v18.1.7+5.aarch64-apple-darwin-llvm_version+18.asserts.tar.gz/md5/614c4f2cf80128a345a1d3632f2adfa5 +libLLVM.v18.1.7+5.aarch64-apple-darwin-llvm_version+18.asserts.tar.gz/sha512/a8c5169dda4394c1cdab569ae6132ae3e69aacf281cb7a52e59dd930f08b6a32a3957314386d073ee7ede877732861e3359b59a322f875d237a22a5ed458d665 +libLLVM.v18.1.7+5.aarch64-apple-darwin-llvm_version+18.tar.gz/md5/702923c46893d9d1394a4520d94acee2 +libLLVM.v18.1.7+5.aarch64-apple-darwin-llvm_version+18.tar.gz/sha512/8ae620e1cc1cfddecd1d1230f509072ddcaf8fc1258addc1ff51d788b66b5e709d05093a29c45ac413ba61ca1c437d2408f481e2bb4d926cbeb433b1d23098e3 +libLLVM.v18.1.7+5.aarch64-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/md5/0f94779b455b80f60c8e8380f94519b9 +libLLVM.v18.1.7+5.aarch64-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/sha512/7611f7970885bb1a7e57afc3d571025ed9c344ab4045a9febcd50a026a6473d35676eb8eee06fe7a6a4828f7f9654d3c6d36aea7b609a6af88eb15d8306232d1 +libLLVM.v18.1.7+5.aarch64-linux-gnu-cxx03-llvm_version+18.tar.gz/md5/4e9b7af9743d73adaf235ed0f4695947 +libLLVM.v18.1.7+5.aarch64-linux-gnu-cxx03-llvm_version+18.tar.gz/sha512/d02e260109727686cc06005a4cc57a513ac27498c302e3fc2a656dda1e38f51a818ae58fe817c22bc797bf3dac6f9e915f5e6229320b867262188763652a82cd +libLLVM.v18.1.7+5.aarch64-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/md5/1407e50419e476d0f8ff16367a13f306 +libLLVM.v18.1.7+5.aarch64-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/sha512/c03e30bca892d2eba104ca525aa4524b5014367771a53caf0a276b075e109fee4e4b237d0689474c2aff26acac01dc096663449a9d64df23579b1552797ff997 +libLLVM.v18.1.7+5.aarch64-linux-gnu-cxx11-llvm_version+18.tar.gz/md5/7f5c127f0ac374801c67afd9efc91de4 +libLLVM.v18.1.7+5.aarch64-linux-gnu-cxx11-llvm_version+18.tar.gz/sha512/e53e0f9d7225eface37bc04dd03ef0d8d760e12470cfb4d744387979bb28731511d979bccb69e61f8d8e88a7885113070827a947c13029b05b674274bd64e573 +libLLVM.v18.1.7+5.aarch64-linux-musl-cxx03-llvm_version+18.asserts.tar.gz/md5/b6862585ea1bda09a1221bea8041662b +libLLVM.v18.1.7+5.aarch64-linux-musl-cxx03-llvm_version+18.asserts.tar.gz/sha512/72e1a8d0a06f24b30057e403519c6f6ad64d2955b809a142bcc31f5960fd62455b01f10c4aff8e0fb05d93f720b54bed8240040954ca46d0df647cc130160018 +libLLVM.v18.1.7+5.aarch64-linux-musl-cxx03-llvm_version+18.tar.gz/md5/f0cc1309cfa700f8dde09979d7262606 +libLLVM.v18.1.7+5.aarch64-linux-musl-cxx03-llvm_version+18.tar.gz/sha512/238ff54b91ed8e21e73cfa06dd0cc406d64d263d3df0cfa20fec0b6fe7ab5106d3c9a7faebdc8ccc9cd9e5ee74cfdafeba410ff7ea03337b67fa052d38499413 +libLLVM.v18.1.7+5.aarch64-linux-musl-cxx11-llvm_version+18.asserts.tar.gz/md5/baf59bf8e5ecfc7b042d71829fd4b6f3 +libLLVM.v18.1.7+5.aarch64-linux-musl-cxx11-llvm_version+18.asserts.tar.gz/sha512/c34e7ba26ada00bf727e84e15fad4e2cfcf90f86880a458686f44cc127c49c00de1e3f78bd71b480b4c6cfc6a6516d495cba46f1f675f9487132c150fca419dd +libLLVM.v18.1.7+5.aarch64-linux-musl-cxx11-llvm_version+18.tar.gz/md5/6864ba9219b57cee5c4adfa34408542f +libLLVM.v18.1.7+5.aarch64-linux-musl-cxx11-llvm_version+18.tar.gz/sha512/4308479ebd399eb9fd5cc82c0b4a3cb4f9de047b66575284b148e0fa9b71d8c0ed838aa08ff518c75c4f0df81a23604705e69f9b8f455b1cc0d9bec5309f39e5 +libLLVM.v18.1.7+5.aarch64-unknown-freebsd-llvm_version+18.asserts.tar.gz/md5/846c59a5a4eec694c094beb3701fbafb +libLLVM.v18.1.7+5.aarch64-unknown-freebsd-llvm_version+18.asserts.tar.gz/sha512/33ebff717bb0c0b2a918fafab6d3a7485ee9cd2c6624281154f8d116e1b65dec955bab1fdb7491535641f0306444278f4b2d19c2852f920c2a01610dc52c4581 +libLLVM.v18.1.7+5.aarch64-unknown-freebsd-llvm_version+18.tar.gz/md5/236c2c016eacd64b6278e67057aa8a62 +libLLVM.v18.1.7+5.aarch64-unknown-freebsd-llvm_version+18.tar.gz/sha512/4baec6cebb6975bc76fa55f785c1edc1cd6b51f284d0205aeaf22a453e52df728eb7a5bbc4d6ed55ee256ce65474b3faae961dac0208256c1eca57cdc7ffb470 +libLLVM.v18.1.7+5.armv6l-linux-gnueabihf-cxx03-llvm_version+18.asserts.tar.gz/md5/5de4e3558dc54696172405efb55f832a +libLLVM.v18.1.7+5.armv6l-linux-gnueabihf-cxx03-llvm_version+18.asserts.tar.gz/sha512/38941739db5d1d49f87fe402c4caa2ddc1139569f97a4ed858d2d29c91acb4d208e2223af8495ac243087ab459a168279d988a8a6957bcf2c535c4d79f301037 +libLLVM.v18.1.7+5.armv6l-linux-gnueabihf-cxx03-llvm_version+18.tar.gz/md5/9bb7aca392fe906aa7b70cd6d8a0611a +libLLVM.v18.1.7+5.armv6l-linux-gnueabihf-cxx03-llvm_version+18.tar.gz/sha512/d12cd2b0d2e918a5c9102e650a563918051feab012993066df9a0eb4e6abb3587090b82c4621bafd618ebc477c2db2f55f647a7092103a3c539e503494443fd7 +libLLVM.v18.1.7+5.armv6l-linux-gnueabihf-cxx11-llvm_version+18.asserts.tar.gz/md5/617c8996fa61ab17a8b3a2280b20e910 +libLLVM.v18.1.7+5.armv6l-linux-gnueabihf-cxx11-llvm_version+18.asserts.tar.gz/sha512/4d96846c0766187e08663bf7aaf15673f2b05180f59069008d974f1b81be90c4652588781942f65e31d5c4ce24d84792a490369d2d521e1463625e587a1af414 +libLLVM.v18.1.7+5.armv6l-linux-gnueabihf-cxx11-llvm_version+18.tar.gz/md5/52c10f854291b4574e0d3f39af6e87cb +libLLVM.v18.1.7+5.armv6l-linux-gnueabihf-cxx11-llvm_version+18.tar.gz/sha512/4f4449f555023ec8706cdfd48ae9cfdcbf06dd034c42de9db76addf31f507330baf366c411caab1c5ead811c89b1aff51973bfa220b00af9166570a34d870549 +libLLVM.v18.1.7+5.armv6l-linux-musleabihf-cxx03-llvm_version+18.asserts.tar.gz/md5/2c50c1857373b4caa6e8d6a1dff2adf3 +libLLVM.v18.1.7+5.armv6l-linux-musleabihf-cxx03-llvm_version+18.asserts.tar.gz/sha512/693f74f6f8b3d9c264298f9725d9fd5704304a7d3fb7ae010db4f4a60d2d3ca951e83e9eaf1ea34f3c4a1aa5250657d3bfa2367fe11164a7401623bffa39848f +libLLVM.v18.1.7+5.armv6l-linux-musleabihf-cxx03-llvm_version+18.tar.gz/md5/06da4e466c5cc3518bb8396d304d86e9 +libLLVM.v18.1.7+5.armv6l-linux-musleabihf-cxx03-llvm_version+18.tar.gz/sha512/edc7717bfcf55e0e828c5c1cfe57f82f925dc3a29d8d2c0829688b554c2e8a3ae7a60de35fec7e93bf9ba47dc64265a91753c25ebdadb18bf31cdd63dacf4f3e +libLLVM.v18.1.7+5.armv6l-linux-musleabihf-cxx11-llvm_version+18.asserts.tar.gz/md5/e6adb4e03d54249d7148fcd5f0d2ab65 +libLLVM.v18.1.7+5.armv6l-linux-musleabihf-cxx11-llvm_version+18.asserts.tar.gz/sha512/02e41826135a7ae279cdb7169f7969942e5142a8e77a99f0e590a87b8a4633fcaeda2590e23b1598449672b3f00650cd69526f20dd1be2ad98595a27ae359a64 +libLLVM.v18.1.7+5.armv6l-linux-musleabihf-cxx11-llvm_version+18.tar.gz/md5/714db0b44c5d2e31a3fefada500af4d3 +libLLVM.v18.1.7+5.armv6l-linux-musleabihf-cxx11-llvm_version+18.tar.gz/sha512/933c84e79d15c13b4becbf6ae3c5cd3b5ab3d29fe678c40e7e8e6a7581658e24263cb901381795443072cac382e4c75c90f34a7b8ef2c7aa53f675e4fe2a957c +libLLVM.v18.1.7+5.armv7l-linux-gnueabihf-cxx03-llvm_version+18.asserts.tar.gz/md5/ff39f8e44e85beed03d3c1561e12feb5 +libLLVM.v18.1.7+5.armv7l-linux-gnueabihf-cxx03-llvm_version+18.asserts.tar.gz/sha512/dd25a5f962960577c9e18dd7bc1c61b8ba252cb1f3ec2b06f82aee3a75bcc37b0f337ac6aa8c04d3fd5bb1689889881b8ac1e7a2cbeb974dbeb30dd14b4952bc +libLLVM.v18.1.7+5.armv7l-linux-gnueabihf-cxx03-llvm_version+18.tar.gz/md5/887d1219e2d850752647ea6930393659 +libLLVM.v18.1.7+5.armv7l-linux-gnueabihf-cxx03-llvm_version+18.tar.gz/sha512/b90031987fd32cdbba488dc579fed6bec2ad0ebe22c7fce99115214cee9bfcf17f0a71b2bdd940983c4f47fd4ffd8d16d2cc0749f7c42307960fb8a2c5a6e0d9 +libLLVM.v18.1.7+5.armv7l-linux-gnueabihf-cxx11-llvm_version+18.asserts.tar.gz/md5/51674de63294e1644acd6d76863f4a03 +libLLVM.v18.1.7+5.armv7l-linux-gnueabihf-cxx11-llvm_version+18.asserts.tar.gz/sha512/949763f9f28ea1f807bb3f89a5a919e1c62ffc57f80a1c60e998f3840400e1ebdc521e884a378f6a104cd6911a6aa74075338baf8f246057fd2b465a865652b0 +libLLVM.v18.1.7+5.armv7l-linux-gnueabihf-cxx11-llvm_version+18.tar.gz/md5/494e0b31ac708167ea1c3e7424d2a939 +libLLVM.v18.1.7+5.armv7l-linux-gnueabihf-cxx11-llvm_version+18.tar.gz/sha512/881dc6767cb0ecf6e13eb5102f5cbd69aea1bcc005097151ad38ba4ebfefe7ea399338ccd36b0755b443a96364d9ee7305a9d82616271490346269dbb076081c +libLLVM.v18.1.7+5.armv7l-linux-musleabihf-cxx03-llvm_version+18.asserts.tar.gz/md5/c50ec7ed8ea740e59a9a9b854c62e551 +libLLVM.v18.1.7+5.armv7l-linux-musleabihf-cxx03-llvm_version+18.asserts.tar.gz/sha512/c8fcb46aa12c7624ac929b58e1b9041ce0c66151912e15889ed1f35d8f5b5a021ef62d22142d1b46e7ae219d38980106a4efdf2863261dcb64bd2d75b2bd3d60 +libLLVM.v18.1.7+5.armv7l-linux-musleabihf-cxx03-llvm_version+18.tar.gz/md5/8f770e875820d320bb838375f4a76ed8 +libLLVM.v18.1.7+5.armv7l-linux-musleabihf-cxx03-llvm_version+18.tar.gz/sha512/22d3e1e5026c770438642b6fd2e58550fc58d59caa546fc8dfb72ee91b16f713160fcb928988a2229a2960327c1088bef32f09a9525ad30b6dc1de51567c691b +libLLVM.v18.1.7+5.armv7l-linux-musleabihf-cxx11-llvm_version+18.asserts.tar.gz/md5/6f4ea685a2f61365a4584dfd7ed1d48f +libLLVM.v18.1.7+5.armv7l-linux-musleabihf-cxx11-llvm_version+18.asserts.tar.gz/sha512/3046c2e05e57b0255a7afafafafed4cf60a6231882541ea2b0d4ecfe959e43adf792bf02dd0eaa18b395b6dea6e85c5118fbc1c3a24432a73257e7fd0c4d3b7e +libLLVM.v18.1.7+5.armv7l-linux-musleabihf-cxx11-llvm_version+18.tar.gz/md5/97585c0a6be92891a9bf0b2abf8498e9 +libLLVM.v18.1.7+5.armv7l-linux-musleabihf-cxx11-llvm_version+18.tar.gz/sha512/be31a9d03a6cebde2319593a14572b906c37113d46b4d74c869581ee7bb04855ae12c5f381c77eb78be9e019ab45d42da29a649f0799771b55d29cfda4037441 +libLLVM.v18.1.7+5.i686-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/md5/27e80a7f447540261234fa7682f640d6 +libLLVM.v18.1.7+5.i686-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/sha512/065ea890b83b5e7be1e053018a3578a298e8b2552608f4d5e0cf2f127bfe25fcbfe588642b08e7891a57265043d6b8c0d35d4c3da49d320db103d7eb80ab9ff0 +libLLVM.v18.1.7+5.i686-linux-gnu-cxx03-llvm_version+18.tar.gz/md5/7f04972f69e6d18fc33c683ab9c04f7d +libLLVM.v18.1.7+5.i686-linux-gnu-cxx03-llvm_version+18.tar.gz/sha512/22a5edd6ea35385e2535c1a3f4ef5044e5a84cc2a0185e7e46289418f424955a3ae2e35c22628b52ab5ca12fbb21b77d924e170eb56968ee946a6b5f2d0a33b4 +libLLVM.v18.1.7+5.i686-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/md5/fec8498206f1d9a42be6359c5cd95466 +libLLVM.v18.1.7+5.i686-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/sha512/eda50e64c2219e73a7d3565d6ab90b6102da3c2c4168b2e5218cdea5e51573b5dbdc121eb2189dc3c7775f77c6bc340c5c004af27699f94317b52a98c95cc51d +libLLVM.v18.1.7+5.i686-linux-gnu-cxx11-llvm_version+18.tar.gz/md5/7a347dceefa924dbe36de2a50050abe0 +libLLVM.v18.1.7+5.i686-linux-gnu-cxx11-llvm_version+18.tar.gz/sha512/6e4d9b097efc5a63562bc11a23e93d385379ce4baac77c65677e610d1824cc8fe9019048e2dd8e25caf976f2023df8f7b85ca7c8a9c3d2b6c1ac9b2a5dfa3845 +libLLVM.v18.1.7+5.i686-w64-mingw32-cxx03-llvm_version+18.asserts.tar.gz/md5/6cf0604857ce7dbebe4e805ab13f2ebc +libLLVM.v18.1.7+5.i686-w64-mingw32-cxx03-llvm_version+18.asserts.tar.gz/sha512/8d257fa81af8418ecd1f7f0cea88b969b970b1973c8764422f211ea183fc7f6fc177e2c2189892a19d2289ef026c6ec3f74059d6edddca0b3846b9a2c126ad84 +libLLVM.v18.1.7+5.i686-w64-mingw32-cxx03-llvm_version+18.tar.gz/md5/850f0a17f7ae56d693c66d032801d97e +libLLVM.v18.1.7+5.i686-w64-mingw32-cxx03-llvm_version+18.tar.gz/sha512/e42b12097d002306d734b49983261c7b9dadd7273862aeba09f6994832db9da65835ab86294e57265028fd4a8b7a544f8a3dd48bf3c23e45b2de4eec87d44160 +libLLVM.v18.1.7+5.i686-w64-mingw32-cxx11-llvm_version+18.asserts.tar.gz/md5/221e2a112359ed954ad721fc76f5b13c +libLLVM.v18.1.7+5.i686-w64-mingw32-cxx11-llvm_version+18.asserts.tar.gz/sha512/a94d68718254da9043aa45f22f49a3bb6cd768e32cdc14402f2ee12ed7c48c8c8ede9163808bffa451d7d1e7d4a6c1390956ff9d6f4461fea5a83e7187a82698 +libLLVM.v18.1.7+5.i686-w64-mingw32-cxx11-llvm_version+18.tar.gz/md5/264057f43126283102b00def81b17ea3 +libLLVM.v18.1.7+5.i686-w64-mingw32-cxx11-llvm_version+18.tar.gz/sha512/5de5d22f1685ac3183568f9c2f330c1de9912d81e5f4cc58a03d430960fbbccb812c17730c3782a00ff7327500fc4a501a7cf999de93932338fe93f68c7680f3 +libLLVM.v18.1.7+5.powerpc64le-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/md5/45d2a5957d1aca883046e5c95cd1c494 +libLLVM.v18.1.7+5.powerpc64le-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/sha512/354407da4e50d15340abd8f3ae5ef029314cc4be78777a14e2e89bacf9014562e423b1ccb595794cdcc608a01420595dbbf3f1c6ab284969a3588cd972a40fa8 +libLLVM.v18.1.7+5.powerpc64le-linux-gnu-cxx03-llvm_version+18.tar.gz/md5/4fe886695db26d9360df8e76508cda88 +libLLVM.v18.1.7+5.powerpc64le-linux-gnu-cxx03-llvm_version+18.tar.gz/sha512/0978223ab4fcd157ddadd9c0656748e5ce011ab7d07b980c1f09dcbc2fbf67b21055f18be623e498265c305817dfd5cde057b71b046e88871a1523484ad489a4 +libLLVM.v18.1.7+5.powerpc64le-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/md5/d96ed9650675ccb49e52aead0482a49c +libLLVM.v18.1.7+5.powerpc64le-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/sha512/6bd83eb1f636bc294c0e6088d215054dc896779f93d1e3df2fc32835778db2f02a75264ef274ec054fd3f604386f97746ba20ab1187296a5445f5647a4a13604 +libLLVM.v18.1.7+5.powerpc64le-linux-gnu-cxx11-llvm_version+18.tar.gz/md5/ac6fd6d5a07084e4cae2314a2cd9adfb +libLLVM.v18.1.7+5.powerpc64le-linux-gnu-cxx11-llvm_version+18.tar.gz/sha512/852f613fc8b78511d9f53484b2bf544230939750e659da7aa5179dccb8662fd61a4f36086104a20b367dee74990980fff0a4f7bcb8b0ea8ad987f309337c42b1 +libLLVM.v18.1.7+5.x86_64-apple-darwin-llvm_version+18.asserts.tar.gz/md5/3f7fb351702456f897486cc02540184c +libLLVM.v18.1.7+5.x86_64-apple-darwin-llvm_version+18.asserts.tar.gz/sha512/7b3951189c2f1f9b8d3d60dc7fda46537ed6d7c06b6be698d6df37157c39d8294d1048d7cdec5fd4ad54cc9b597268cd802c2bc8e5a5c6f3b6461d50c2a9f773 +libLLVM.v18.1.7+5.x86_64-apple-darwin-llvm_version+18.tar.gz/md5/ed26db445a214d2570f732933a0c8e51 +libLLVM.v18.1.7+5.x86_64-apple-darwin-llvm_version+18.tar.gz/sha512/ff7dce53822518132608d1ae6e454c99fbe88a7108b7ac676f57cd3832df2761de460e2f2c4f4ff32bc4279f01bb4c1d0a4b67ebd24fc4551c955677eae91303 +libLLVM.v18.1.7+5.x86_64-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/md5/c2037083649784ac685aae6be5d643be +libLLVM.v18.1.7+5.x86_64-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/sha512/82787adcb833510fa0f2dc89dc8bc8721d4d4d28c1b753a669be2fcd23db1789ae77e6c774b4d8101fa07e8e0018fe12b1022b40d6226e831035abfcaa2243cf +libLLVM.v18.1.7+5.x86_64-linux-gnu-cxx03-llvm_version+18.tar.gz/md5/194a410598ae3c6fd2f94ece77613e29 +libLLVM.v18.1.7+5.x86_64-linux-gnu-cxx03-llvm_version+18.tar.gz/sha512/a224855c0bad5cd9c86373f2e5cbc1c6c12efa2b7fa897d75e1401dae2eea1dcb75004e423b771346fbed083846fe57ce9349c79e1e871bf0ca7fbb1cf0d4c83 +libLLVM.v18.1.7+5.x86_64-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/md5/6aef022fe6057e71d84a469de39f1df6 +libLLVM.v18.1.7+5.x86_64-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/sha512/646aa726e2d745ca8d01cc24265d73ac7e8b0e8a818dfdf7ba17984f82ca3ba697e237eb685c36e2fd29f6a649316e5769cd677f15d861b0f66ca848ca7b3619 +libLLVM.v18.1.7+5.x86_64-linux-gnu-cxx11-llvm_version+18.tar.gz/md5/b3c4d1bd69eb0ef24e244a2c53d4482e +libLLVM.v18.1.7+5.x86_64-linux-gnu-cxx11-llvm_version+18.tar.gz/sha512/4814a550f6d7fb5cb975c403b0b06e910aec4ae13d007428ad507c3a9e69a628e1e6d09ec4b933909fbb59cfb8f4755003527584afce813625cf56f432873a87 +libLLVM.v18.1.7+5.x86_64-linux-musl-cxx03-llvm_version+18.asserts.tar.gz/md5/3558bdf495c90df4666324927b25fb7c +libLLVM.v18.1.7+5.x86_64-linux-musl-cxx03-llvm_version+18.asserts.tar.gz/sha512/a746ab1c229d9fe995258915757dd4b2f05f23b34710f9e198ad25e2202216ced254978376f7a1bd05196da5f1b893f1b86143d7107ef1885349950ed7fdcedf +libLLVM.v18.1.7+5.x86_64-linux-musl-cxx03-llvm_version+18.tar.gz/md5/de1ec2406a8f5642157ed8a01a3c10ab +libLLVM.v18.1.7+5.x86_64-linux-musl-cxx03-llvm_version+18.tar.gz/sha512/d937ebaa5780b7d9a404055d991456e6d5de3c56f133f4c8377acea98f033fca5a836b661da18bb58b0122e9702ad7969456b9695594bfee9ce8eb9e77a6b1b0 +libLLVM.v18.1.7+5.x86_64-linux-musl-cxx11-llvm_version+18.asserts.tar.gz/md5/5ebeb59d5398edd3a53b976ead0500e3 +libLLVM.v18.1.7+5.x86_64-linux-musl-cxx11-llvm_version+18.asserts.tar.gz/sha512/a3c5cc63d1972970b3d03a4b58298f33ec66ed739564862223987947287e97a85342ac5f70d0c197086dad74b69eeaba47baf15dbb49f6f2744318c430bc6dc5 +libLLVM.v18.1.7+5.x86_64-linux-musl-cxx11-llvm_version+18.tar.gz/md5/8862f2f7ee02f39339811c1b0741d7c0 +libLLVM.v18.1.7+5.x86_64-linux-musl-cxx11-llvm_version+18.tar.gz/sha512/f1866e04a290e69d0e3fcf906f2053aa8ed2c51ac0ba6fc621799a75984a9cd38d763126b9f8ca726cdbb7d2a2b686ed0df9780caa3276ed02ec889da3f37f31 +libLLVM.v18.1.7+5.x86_64-unknown-freebsd-llvm_version+18.asserts.tar.gz/md5/7977ab6cb209a4b8569ee13f9462c24c +libLLVM.v18.1.7+5.x86_64-unknown-freebsd-llvm_version+18.asserts.tar.gz/sha512/5f2f6a9588704fa0870f51a609938f4a26fb6bdae5158285b5d222a0649b7e2086bd4fbb3892914b0322ef7ee1848164f0e5e39fb2c5d8ba2febbd903a49dad4 +libLLVM.v18.1.7+5.x86_64-unknown-freebsd-llvm_version+18.tar.gz/md5/7b5d194d4747f1a1b4e348ed2bc0f8a9 +libLLVM.v18.1.7+5.x86_64-unknown-freebsd-llvm_version+18.tar.gz/sha512/d0e9b608c8bf914b3e7cac3d75cd340e703695cad113604e9bd6a6ad9fc40db2d5eae7ae7287f726ace098fec92253c551366b5294728aa28ab96c55faeda3d5 +libLLVM.v18.1.7+5.x86_64-w64-mingw32-cxx03-llvm_version+18.asserts.tar.gz/md5/7807e53cfb230f22c52fd0bdf3c204c5 +libLLVM.v18.1.7+5.x86_64-w64-mingw32-cxx03-llvm_version+18.asserts.tar.gz/sha512/c601e229f16e848362d22653cf56228d34a94be2d713d403daeae8a57e86ead6d02e1bd8d7e015e4a1431823f029d2d3502c703d1cd43b09cff093b35f65dc16 +libLLVM.v18.1.7+5.x86_64-w64-mingw32-cxx03-llvm_version+18.tar.gz/md5/0a6ce9706165364620ca3285c5a028ff +libLLVM.v18.1.7+5.x86_64-w64-mingw32-cxx03-llvm_version+18.tar.gz/sha512/cc1a13c043b79c047097b0c9179e24e793448eb46929860a97e37287e32733b9bdc77cf35de4b0617da8228c4321eca747bbc9c2bfd3d0a14de7de301f81bb3f +libLLVM.v18.1.7+5.x86_64-w64-mingw32-cxx11-llvm_version+18.asserts.tar.gz/md5/78a1ae46a856d695314e2d1c5ec32648 +libLLVM.v18.1.7+5.x86_64-w64-mingw32-cxx11-llvm_version+18.asserts.tar.gz/sha512/46eb78cf06070003d3db9468dd0f7eb7182ab0e2aab5382c084a50c998f1f88feac4b6b7865c0a3ac68789749580f6363cc4658d89e97a67a1980b5632501aa0 +libLLVM.v18.1.7+5.x86_64-w64-mingw32-cxx11-llvm_version+18.tar.gz/md5/2fa953aa26fb40a38e0e22b23d93c0e7 +libLLVM.v18.1.7+5.x86_64-w64-mingw32-cxx11-llvm_version+18.tar.gz/sha512/a6aacd7bb74424ba5bc84b3201f9e6965a929090a60ed61b19fd516d8073fee259cde368201ba2d6296fac6fa805c3ec7aa94f6434cc35c3457c7b3aa0e57744 +llvm-julia-18.1.7-4.tar.gz/md5/ddd227220baeac9ac36ee2fcbb098905 +llvm-julia-18.1.7-4.tar.gz/sha512/a356c3189b30c0fd9c7a527f2b55ef7b95584355f5bbbf284fd59ddbe91af1bcfa57c30303e15884e80ace4792e7899f89d9dae25b97c40ae2cd3618a7ff024a llvm-project-19.1.4.tar.xz/md5/1e13043b18558e4346ea3769094c9737 llvm-project-19.1.4.tar.xz/sha512/a586f8a41dde5e0d9ca6d8c58e9ef2a2e59b70a86d2e2c46106dc31b5c096bb80af0cdbdb486179e9cc676a540099f49a1c2db9e5e84c50362db1f72e9af6906 diff --git a/deps/clang.version b/deps/clang.version index 0f49ecdd649f0..f8531d0d96286 100644 --- a/deps/clang.version +++ b/deps/clang.version @@ -3,4 +3,4 @@ ## jll artifact # Clang (paired with LLVM, only here as a JLL download) CLANG_JLL_NAME := Clang -CLANG_JLL_VER := 18.1.7+3 +CLANG_JLL_VER := 18.1.7+4 diff --git a/deps/lld.version b/deps/lld.version index 8c7008fc93d7d..84ebd52bfd273 100644 --- a/deps/lld.version +++ b/deps/lld.version @@ -2,4 +2,4 @@ ## jll artifact LLD_JLL_NAME := LLD -LLD_JLL_VER := 18.1.7+3 +LLD_JLL_VER := 18.1.7+5 diff --git a/deps/llvm-tools.version b/deps/llvm-tools.version index 8a1159fd69174..a25a9eb42512c 100644 --- a/deps/llvm-tools.version +++ b/deps/llvm-tools.version @@ -3,5 +3,5 @@ ## jll artifact # LLVM_tools (downloads LLVM_jll to get things like `lit` and `opt`) LLVM_TOOLS_JLL_NAME := LLVM -LLVM_TOOLS_JLL_VER := 18.1.7+3 -LLVM_TOOLS_ASSERT_JLL_VER := 18.1.7+3 +LLVM_TOOLS_JLL_VER := 18.1.7+4 +LLVM_TOOLS_ASSERT_JLL_VER := 18.1.7+4 diff --git a/deps/llvm.version b/deps/llvm.version index 27250f008cd8e..75f8120444ce1 100644 --- a/deps/llvm.version +++ b/deps/llvm.version @@ -2,14 +2,14 @@ ## jll artifact LLVM_JLL_NAME := libLLVM -LLVM_ASSERT_JLL_VER := 18.1.7+4 +LLVM_ASSERT_JLL_VER := 18.1.7+5 ## source build # Version number of LLVM LLVM_VER := 18.1.7 # Git branch name in `LLVM_GIT_URL` repository -LLVM_BRANCH=julia-18.1.7-3 +LLVM_BRANCH=julia-18.1.7-4 # Git ref in `LLVM_GIT_URL` repository -LLVM_SHA1=julia-18.1.7-3 +LLVM_SHA1=julia-18.1.7-4 ## Following options are used to automatically fetch patchset from Julia's fork. This is ## useful if you want to build an external LLVM while still applying Julia's patches. @@ -20,4 +20,4 @@ LLVM_JULIA_DIFF_GITHUB_REPO := https://github.com/llvm/llvm-project # Base GitHub ref for generating the diff. LLVM_BASE_REF := llvm:llvmorg-18.1.7 # Julia fork's GitHub ref for generating the diff. -LLVM_JULIA_REF := JuliaLang:julia-18.1.7-3 +LLVM_JULIA_REF := JuliaLang:julia-18.1.7-4 diff --git a/stdlib/LLD_jll/Project.toml b/stdlib/LLD_jll/Project.toml index 1aafd275d99b7..eb799f48d2309 100644 --- a/stdlib/LLD_jll/Project.toml +++ b/stdlib/LLD_jll/Project.toml @@ -1,6 +1,6 @@ name = "LLD_jll" uuid = "d55e3150-da41-5e91-b323-ecfd1eec6109" -version = "18.1.7+3" +version = "18.1.7+5" [deps] Zlib_jll = "83775a58-1f1d-513f-b197-d71354ab007a" diff --git a/stdlib/Manifest.toml b/stdlib/Manifest.toml index 0dcd58d217d0b..e0d3d3182b377 100644 --- a/stdlib/Manifest.toml +++ b/stdlib/Manifest.toml @@ -73,7 +73,7 @@ version = "1.12.0" [[deps.LLD_jll]] deps = ["Artifacts", "Libdl", "Zlib_jll", "libLLVM_jll"] uuid = "d55e3150-da41-5e91-b323-ecfd1eec6109" -version = "18.1.7+3" +version = "18.1.7+5" [[deps.LLVMLibUnwind_jll]] deps = ["Artifacts", "Libdl"] @@ -282,7 +282,7 @@ version = "2.2.5+2" [[deps.libLLVM_jll]] deps = ["Artifacts", "Libdl"] uuid = "8f36deef-c2a5-5394-99ed-8e07531fb29a" -version = "18.1.7+3" +version = "18.1.7+5" [[deps.libblastrampoline_jll]] deps = ["Artifacts", "Libdl"] diff --git a/stdlib/libLLVM_jll/Project.toml b/stdlib/libLLVM_jll/Project.toml index f6c343d878abb..32b1c5509b802 100644 --- a/stdlib/libLLVM_jll/Project.toml +++ b/stdlib/libLLVM_jll/Project.toml @@ -1,6 +1,6 @@ name = "libLLVM_jll" uuid = "8f36deef-c2a5-5394-99ed-8e07531fb29a" -version = "18.1.7+4" +version = "18.1.7+5" [deps] Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb" From 9d2db09966a4a27ff3d46e8d2525b533803f345b Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> Date: Wed, 18 Jun 2025 03:44:03 +0900 Subject: [PATCH 29/83] backport-1.12: move to the new versioning policy for Compiler stdlib (#58745) --- Compiler/Project.toml | 2 +- Compiler/README.md | 45 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 Compiler/README.md diff --git a/Compiler/Project.toml b/Compiler/Project.toml index 994634f5a8b78..f44b45a810708 100644 --- a/Compiler/Project.toml +++ b/Compiler/Project.toml @@ -1,6 +1,6 @@ name = "Compiler" uuid = "807dbc54-b67e-4c79-8afb-eafe4df6f2e1" -version = "0.0.3" +version = "0.1.0" [compat] julia = "1.10" diff --git a/Compiler/README.md b/Compiler/README.md new file mode 100644 index 0000000000000..5e58152519678 --- /dev/null +++ b/Compiler/README.md @@ -0,0 +1,45 @@ +# The `Compiler` module + +This directory maintains the implementation of the Julia compiler. + +Through a bootstrapping process, it is bundled into the Julia runtime as `Base.Compiler`. + +You can also use this `Compiler` module as the `Compiler` standard library by following the steps below. + +## How to use + +To utilize this `Compiler.jl` standard library, you need to declare it as a dependency in +your `Project.toml` as follows: +> Project.toml +```toml +[deps] +Compiler = "807dbc54-b67e-4c79-8afb-eafe4df6f2e1" + +[compat] +Compiler = "0.1" +``` + +With the setup above, [the special placeholder version (v0.1.0)](https://github.com/JuliaLang/BaseCompiler.jl) +will be installed by default.[^1] + +[^1]: Currently, only version v0.1.0 is registered in the [General](https://github.com/JuliaRegistries/General) registry. + +If needed, you can switch to a custom implementation of the `Compiler` module by running +```julia-repl +pkg> dev /path/to/Compiler.jl # to use a local implementation +``` +or +```julia-repl +pkg> add https://url/of/Compiler/branch # to use a remote implementation +``` +This feature is particularly useful for developing or experimenting with alternative compiler implementations. + +> [!note] +> The Compiler.jl standard library is available starting from Julia v1.10. +> However, switching to a custom compiler implementation is supported only from +> Julia v1.12 onwards. + +> [!warning] +> When using a custom, non-`Base` version of `Compiler` implementation, it may be necessary +> to run `InteractiveUtils.@activate Compiler` to ensure proper functionality of certain +> reflection utilities. From ed55ba4a5f907adfc2580c9514385c6ccacc3c3a Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> Date: Wed, 18 Jun 2025 03:45:02 +0900 Subject: [PATCH 30/83] bump Compiler.jl version to 0.1.1 (#58744) As the latest version of BaseCompiler.jl will be bumped to v0.1.1 after JuliaRegistries/General#132990. --- Compiler/LICENSE.md | 2 +- Compiler/Project.toml | 2 +- Compiler/README.md | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Compiler/LICENSE.md b/Compiler/LICENSE.md index 028a39923ef04..dbbcd7506fc1e 100644 --- a/Compiler/LICENSE.md +++ b/Compiler/LICENSE.md @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2009-2024: Jeff Bezanson, Stefan Karpinski, Viral B. Shah, and other contributors: https://github.com/JuliaLang/julia/contributors +Copyright (c) 2009-2025: Jeff Bezanson, Stefan Karpinski, Viral B. Shah, and other contributors: https://github.com/JuliaLang/julia/contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/Compiler/Project.toml b/Compiler/Project.toml index f44b45a810708..1a0cdf4abca39 100644 --- a/Compiler/Project.toml +++ b/Compiler/Project.toml @@ -1,6 +1,6 @@ name = "Compiler" uuid = "807dbc54-b67e-4c79-8afb-eafe4df6f2e1" -version = "0.1.0" +version = "0.1.1" [compat] julia = "1.10" diff --git a/Compiler/README.md b/Compiler/README.md index 5e58152519678..ae5aaa3f60792 100644 --- a/Compiler/README.md +++ b/Compiler/README.md @@ -19,10 +19,10 @@ Compiler = "807dbc54-b67e-4c79-8afb-eafe4df6f2e1" Compiler = "0.1" ``` -With the setup above, [the special placeholder version (v0.1.0)](https://github.com/JuliaLang/BaseCompiler.jl) +With the setup above, [the special placeholder version (v0.1)](https://github.com/JuliaLang/BaseCompiler.jl) will be installed by default.[^1] -[^1]: Currently, only version v0.1.0 is registered in the [General](https://github.com/JuliaRegistries/General) registry. +[^1]: Currently, only version v0.1 is registered in the [General](https://github.com/JuliaRegistries/General) registry. If needed, you can switch to a custom implementation of the `Compiler` module by running ```julia-repl From 8d890cc273d4b4edf491a762fd8a85a2f85e7de0 Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> Date: Wed, 18 Jun 2025 19:35:07 +0900 Subject: [PATCH 31/83] REPL: fix typo and potential `UndefVarError` (#58761) Detected by the new LS diagnostics:) --- stdlib/REPL/src/REPL.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/REPL/src/REPL.jl b/stdlib/REPL/src/REPL.jl index 9eaecf44c7633..f7485c75e95c5 100644 --- a/stdlib/REPL/src/REPL.jl +++ b/stdlib/REPL/src/REPL.jl @@ -1876,7 +1876,7 @@ function create_global_out!(mod) end return out end - return getglobal(mod, Out) + return getglobal(mod, :Out) end function capture_result(n::Ref{Int}, @nospecialize(x)) From e1676c11c30493f6088f6545dc8fe3350e07dac6 Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> Date: Wed, 18 Jun 2025 20:39:07 +0900 Subject: [PATCH 32/83] fix fallback code path in `take!(::IOBuffer)` method (#58762) JET told me that the `data` local variable was inparticular is undefined at this point. After reviewing this code, I think this code path is unreachable actually since `bytesavailable(io::IOBuffer)` returns `0` when `io` has been closed. So it's probably better to make it clear. --- base/iobuffer.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/iobuffer.jl b/base/iobuffer.jl index d121082f3585d..ca2757201aae8 100644 --- a/base/iobuffer.jl +++ b/base/iobuffer.jl @@ -771,7 +771,7 @@ function take!(io::IOBuffer) elseif io.writable data = wrap(Array, memoryref(io.data, io.ptr), nbytes) else - data = read!(io, data) + error("Unreachable IOBuffer state") end end if io.writable From 8ec81e2b57557087658689d45f7c8e22210522f1 Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> Date: Fri, 20 Jun 2025 14:39:59 +0900 Subject: [PATCH 33/83] inform compiler about local variable definedness (#58778) JET's new analysis pass now detects local variables that may be undefined, which has revealed such issues in several functions within Base (JuliaLang/julia#58762). This commit addresses local variables whose definedness the compiler cannot properly determine, primarily in functions reachable from JET's test suite. No functional changes are made. --- base/logging/logging.jl | 10 +++++++--- base/partr.jl | 8 +++----- base/ryu/shortest.jl | 1 + 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/base/logging/logging.jl b/base/logging/logging.jl index c4a3d21fed982..c44e74ffa627b 100644 --- a/base/logging/logging.jl +++ b/base/logging/logging.jl @@ -411,9 +411,13 @@ function logmsg_code(_module, file, line, level, message, exs...) end line = $(log_data._line) local msg, kwargs - $(logrecord) && $handle_message_nothrow( - logger, level, msg, _module, group, id, file, line; - kwargs...) + if $(logrecord) + @assert @isdefined(msg) "Assertion to tell the compiler about the definedness of this variable" + @assert @isdefined(kwargs) "Assertion to tell the compiler about the definedness of this variable" + $handle_message_nothrow( + logger, level, msg, _module, group, id, file, line; + kwargs...) + end end end end diff --git a/base/partr.jl b/base/partr.jl index 6053a584af5ba..d488330f0c87e 100644 --- a/base/partr.jl +++ b/base/partr.jl @@ -107,7 +107,6 @@ function multiq_sift_down(heap::taskheap, idx::Int32) end end - function multiq_size(tpid::Int8) nt = UInt32(Threads._nthreads_in_pool(tpid)) tp = tpid + 1 @@ -138,7 +137,6 @@ function multiq_size(tpid::Int8) return heap_p end - function multiq_insert(task::Task, priority::UInt16) tpid = ccall(:jl_get_task_threadpoolid, Int8, (Any,), task) @assert tpid > -1 @@ -171,10 +169,8 @@ function multiq_insert(task::Task, priority::UInt16) return true end - function multiq_deletemin() - local rn1, rn2 - local prio1, prio2 + local rn1::UInt32 tid = Threads.threadid() tp = ccall(:jl_threadpoolid, Int8, (Int16,), tid-1) + 1 @@ -208,6 +204,8 @@ function multiq_deletemin() end end + @assert @isdefined(rn1) "Assertion to tell the compiler about the definedness of this variable" + heap = tpheaps[rn1] task = heap.tasks[1] if ccall(:jl_set_task_tid, Cint, (Any, Cint), task, tid-1) == 0 diff --git a/base/ryu/shortest.jl b/base/ryu/shortest.jl index c1ec648bfacdd..3e2128e5730f3 100644 --- a/base/ryu/shortest.jl +++ b/base/ryu/shortest.jl @@ -196,6 +196,7 @@ integer. If a `maxsignif` argument is provided, then `b < maxsignif`. e10 = 0 if maxsignif !== nothing && b > maxsignif + roundup = false b_allzero = true # reduce to max significant digits while true From fa825877a2fa230bee7963acb3b1ba2ee264065a Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Sat, 21 Jun 2025 11:48:35 -0400 Subject: [PATCH 34/83] Update Pkg.version --- stdlib/Pkg.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/Pkg.version b/stdlib/Pkg.version index 0b835147d2885..875ccea09d055 100644 --- a/stdlib/Pkg.version +++ b/stdlib/Pkg.version @@ -1,4 +1,4 @@ -PKG_BRANCH = master +PKG_BRANCH = release-1.12 PKG_SHA1 = 7802601053e97179849ade041718a9c7f4009e97 PKG_GIT_URL := https://github.com/JuliaLang/Pkg.jl.git PKG_TAR_URL = https://api.github.com/repos/JuliaLang/Pkg.jl/tarball/$1 From 92f258eed4bcf1bba52031a15cbae8bf56b3ec38 Mon Sep 17 00:00:00 2001 From: DilumAluthgeBot <43731525+DilumAluthgeBot@users.noreply.github.com> Date: Sat, 21 Jun 2025 20:03:23 -0400 Subject: [PATCH 35/83] =?UTF-8?q?=F0=9F=A4=96=20[backports-release-1.12]?= =?UTF-8?q?=20Bump=20the=20Pkg=20stdlib=20from=20780260105=20to=20b5f97876?= =?UTF-8?q?0=20(#58789)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Pkg-7802601053e97179849ade041718a9c7f4009e97.tar.gz/md5 | 1 - .../Pkg-7802601053e97179849ade041718a9c7f4009e97.tar.gz/sha512 | 1 - .../Pkg-b5f97876073d0443d6dbbc080d7b28205f3d4ca1.tar.gz/md5 | 1 + .../Pkg-b5f97876073d0443d6dbbc080d7b28205f3d4ca1.tar.gz/sha512 | 1 + stdlib/Pkg.version | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) delete mode 100644 deps/checksums/Pkg-7802601053e97179849ade041718a9c7f4009e97.tar.gz/md5 delete mode 100644 deps/checksums/Pkg-7802601053e97179849ade041718a9c7f4009e97.tar.gz/sha512 create mode 100644 deps/checksums/Pkg-b5f97876073d0443d6dbbc080d7b28205f3d4ca1.tar.gz/md5 create mode 100644 deps/checksums/Pkg-b5f97876073d0443d6dbbc080d7b28205f3d4ca1.tar.gz/sha512 diff --git a/deps/checksums/Pkg-7802601053e97179849ade041718a9c7f4009e97.tar.gz/md5 b/deps/checksums/Pkg-7802601053e97179849ade041718a9c7f4009e97.tar.gz/md5 deleted file mode 100644 index 0b4c2231e76e3..0000000000000 --- a/deps/checksums/Pkg-7802601053e97179849ade041718a9c7f4009e97.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -12d113a3b16a74ea2025bcd372fde850 diff --git a/deps/checksums/Pkg-7802601053e97179849ade041718a9c7f4009e97.tar.gz/sha512 b/deps/checksums/Pkg-7802601053e97179849ade041718a9c7f4009e97.tar.gz/sha512 deleted file mode 100644 index 63c416108b72b..0000000000000 --- a/deps/checksums/Pkg-7802601053e97179849ade041718a9c7f4009e97.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -541aa2a5743a5e3834cef3ec6e4e4ff359f9b16b3f8c1df1e9a2327ed108d512f484c17ded8481467fbfe18dc5915b0f00037f20add7878baceb8a3bdb47625c diff --git a/deps/checksums/Pkg-b5f97876073d0443d6dbbc080d7b28205f3d4ca1.tar.gz/md5 b/deps/checksums/Pkg-b5f97876073d0443d6dbbc080d7b28205f3d4ca1.tar.gz/md5 new file mode 100644 index 0000000000000..2d029f736cd48 --- /dev/null +++ b/deps/checksums/Pkg-b5f97876073d0443d6dbbc080d7b28205f3d4ca1.tar.gz/md5 @@ -0,0 +1 @@ +d750336e7cb029d1f02e2b535f330b19 diff --git a/deps/checksums/Pkg-b5f97876073d0443d6dbbc080d7b28205f3d4ca1.tar.gz/sha512 b/deps/checksums/Pkg-b5f97876073d0443d6dbbc080d7b28205f3d4ca1.tar.gz/sha512 new file mode 100644 index 0000000000000..7705d546c8c41 --- /dev/null +++ b/deps/checksums/Pkg-b5f97876073d0443d6dbbc080d7b28205f3d4ca1.tar.gz/sha512 @@ -0,0 +1 @@ +5d94b5ff4aea20818d6fa4780236bf1b912127a57e0d9c48c9e3cdbb88484452452561bc68b72901e3b433bc6512d595af94f0d76425ab3cac0d3c00710710ad diff --git a/stdlib/Pkg.version b/stdlib/Pkg.version index 875ccea09d055..303fd9bbe4c28 100644 --- a/stdlib/Pkg.version +++ b/stdlib/Pkg.version @@ -1,4 +1,4 @@ PKG_BRANCH = release-1.12 -PKG_SHA1 = 7802601053e97179849ade041718a9c7f4009e97 +PKG_SHA1 = b5f97876073d0443d6dbbc080d7b28205f3d4ca1 PKG_GIT_URL := https://github.com/JuliaLang/Pkg.jl.git PKG_TAR_URL = https://api.github.com/repos/JuliaLang/Pkg.jl/tarball/$1 From 9a857ac97dafbb4d994fa25d632209a4746c6c10 Mon Sep 17 00:00:00 2001 From: Jakob Nybo Nissen Date: Thu, 12 Jun 2025 15:28:55 +0200 Subject: [PATCH 36/83] Add compat note for OncePer types (#58716) Closes #58703 (cherry picked from commit 66ec6ee4c79c2ad1e9dff7694a634c6fc3adbb4d) --- base/lock.jl | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/base/lock.jl b/base/lock.jl index 79e0ba264df15..2da4d47c3734b 100644 --- a/base/lock.jl +++ b/base/lock.jl @@ -674,6 +674,9 @@ calls in the same process will return exactly the same value. This is useful in code that will be precompiled, as it allows setting up caches or other state which won't get serialized. +!!! compat "Julia 1.12" + This type requires Julia 1.12 or later. + ## Example ```jldoctest @@ -784,6 +787,9 @@ if that behavior is correct within your library's threading-safety design. See also: [`OncePerTask`](@ref). +!!! compat "Julia 1.12" + This type requires Julia 1.12 or later. + ## Example ```jldoctest @@ -912,6 +918,9 @@ exactly once per Task. All future calls in the same Task will return exactly the See also: [`task_local_storage`](@ref). +!!! compat "Julia 1.12" + This type requires Julia 1.12 or later. + ## Example ```jldoctest From f650e9fcd1b4658009f037752deb30e7eac4235d Mon Sep 17 00:00:00 2001 From: Erik Schnetter Date: Fri, 13 Jun 2025 01:09:55 -0400 Subject: [PATCH 37/83] UnicodeData: Update to version 16 (#58710) (cherry picked from commit 866c89014ffde70fd81699497275a5fb21b717c5) --- deps/checksums/UnicodeData-13.0.0.txt/md5 | 1 - deps/checksums/UnicodeData-13.0.0.txt/sha512 | 1 - deps/checksums/UnicodeData-16.0.0.txt/md5 | 1 + deps/checksums/UnicodeData-16.0.0.txt/sha512 | 1 + doc/Makefile | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) delete mode 100644 deps/checksums/UnicodeData-13.0.0.txt/md5 delete mode 100644 deps/checksums/UnicodeData-13.0.0.txt/sha512 create mode 100644 deps/checksums/UnicodeData-16.0.0.txt/md5 create mode 100644 deps/checksums/UnicodeData-16.0.0.txt/sha512 diff --git a/deps/checksums/UnicodeData-13.0.0.txt/md5 b/deps/checksums/UnicodeData-13.0.0.txt/md5 deleted file mode 100644 index 2b3ffc179ce01..0000000000000 --- a/deps/checksums/UnicodeData-13.0.0.txt/md5 +++ /dev/null @@ -1 +0,0 @@ -85879f1976cc8eb739ee5585a93938e2 diff --git a/deps/checksums/UnicodeData-13.0.0.txt/sha512 b/deps/checksums/UnicodeData-13.0.0.txt/sha512 deleted file mode 100644 index a93ba01e7ddda..0000000000000 --- a/deps/checksums/UnicodeData-13.0.0.txt/sha512 +++ /dev/null @@ -1 +0,0 @@ -1a4a662e2ab33469976bf5f91aa6933ed9b73f6d4179a2daffb349e1869d7d6cfa885b164e82d15dcdad7458cd451c81add58d875eb0c70de854589dc97b2055 diff --git a/deps/checksums/UnicodeData-16.0.0.txt/md5 b/deps/checksums/UnicodeData-16.0.0.txt/md5 new file mode 100644 index 0000000000000..79ae5d27eff0e --- /dev/null +++ b/deps/checksums/UnicodeData-16.0.0.txt/md5 @@ -0,0 +1 @@ +f50a0495d2000b7d6dd979cb40e00ba2 diff --git a/deps/checksums/UnicodeData-16.0.0.txt/sha512 b/deps/checksums/UnicodeData-16.0.0.txt/sha512 new file mode 100644 index 0000000000000..05b998b3724ba --- /dev/null +++ b/deps/checksums/UnicodeData-16.0.0.txt/sha512 @@ -0,0 +1 @@ +963e5a1e7a480873c6e66d53e9288232b5029942477a694a0bfafa7e994c55189cb9c2f8d00255de84b82b72ff6066932e5531e3664fb422eeef9c69ea25d80e diff --git a/doc/Makefile b/doc/Makefile index 4469a40f74248..13bc0e2b61599 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -25,7 +25,7 @@ help: DOCUMENTER_OPTIONS := linkcheck=$(linkcheck) doctest=$(doctest) buildroot=$(call cygpath_w,$(BUILDROOT)) \ texplatform=$(texplatform) revise=$(revise) -UNICODE_DATA_VERSION=13.0.0 +UNICODE_DATA_VERSION=16.0.0 $(SRCCACHE)/UnicodeData-$(UNICODE_DATA_VERSION).txt: @mkdir -p "$(SRCCACHE)" $(JLDOWNLOAD) "$@" https://www.unicode.org/Public/$(UNICODE_DATA_VERSION)/ucd/UnicodeData.txt From 5d9466092d5abc589eca32a3dc0c485215b8a88a Mon Sep 17 00:00:00 2001 From: Jishnu Bhattacharya Date: Tue, 17 Jun 2025 15:07:28 +0530 Subject: [PATCH 38/83] Increment state conditionally in `CartesianIndices` iteration (#58742) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes https://github.com/JuliaLang/julia/issues/53430 ```julia julia> a = rand(100,100); b = similar(a); av = view(a, axes(a)...); bv = view(b, axes(b)...); bv2 = view(b, UnitRange.(axes(b))...); julia> @btime copyto!($bv2, $av); # slow, indices are UnitRanges 12.352 μs (0 allocations: 0 bytes) # master, v"1.13.0-DEV.745" 1.662 μs (0 allocations: 0 bytes) # this PR julia> @btime copyto!($bv, $av); # reference 1.733 μs (0 allocations: 0 bytes) ``` The performances become comparable after this PR. I've also renamed the second `I` to `Itail`, as the two variables represent different quantities. (cherry picked from commit 36a4616fc218479b09607b1c15e61a36f12d13ad) --- base/multidimensional.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/base/multidimensional.jl b/base/multidimensional.jl index 40fff7243cd55..ee0cf9690b469 100644 --- a/base/multidimensional.jl +++ b/base/multidimensional.jl @@ -446,12 +446,12 @@ module IteratorsMD end @inline function __inc(state::Tuple{Int,Int,Vararg{Int}}, indices::Tuple{OrdinalRangeInt,OrdinalRangeInt,Vararg{OrdinalRangeInt}}) rng = indices[1] - I = state[1] + step(rng) if state[1] != last(rng) + I = state[1] + step(rng) return true, (I, tail(state)...) end - valid, I = __inc(tail(state), tail(indices)) - return valid, (first(rng), I...) + valid, Itail = __inc(tail(state), tail(indices)) + return valid, (first(rng), Itail...) end # 0-d cartesian ranges are special-cased to iterate once and only once From 858eb0ffe65604142bdca549630e7c2a5c649523 Mon Sep 17 00:00:00 2001 From: Gabriel Baraldi Date: Tue, 17 Jun 2025 12:36:26 -0300 Subject: [PATCH 39/83] Work around LLVM JITLink stack overflow issue. (#58579) The JITLinker recurses for every symbol in the list so limit the size of the list This is kind of ugly. Also 1000 might be too large, we don't want to go too small because that wastes memory and 1000 was fine locally for the things I tested. Fixes https://github.com/JuliaLang/julia/issues/58229 (cherry picked from commit aa10603c188669d9f3b4be4fa744eeab32b975af) --- src/jitlayers.cpp | 13 +++++++++++-- test/cmdlineargs.jl | 3 +++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/jitlayers.cpp b/src/jitlayers.cpp index 2e2756dec35f1..3ea95ea42f596 100644 --- a/src/jitlayers.cpp +++ b/src/jitlayers.cpp @@ -666,8 +666,17 @@ static void jl_compile_codeinst_now(jl_code_instance_t *codeinst) if (!decls.specFunctionObject.empty()) NewDefs.push_back(decls.specFunctionObject); } - auto Addrs = jl_ExecutionEngine->findSymbols(NewDefs); - + // Split batches to avoid stack overflow in the JIT linker. + // FIXME: Patch ORCJITs InPlaceTaskDispatcher to not recurse on task dispatches but + // push the tasks to a queue to be drained later. This avoids the stackoverflow caused by recursion + // in the linker when compiling a large number of functions at once. + SmallVector Addrs; + for (size_t i = 0; i < NewDefs.size(); i += 1000) { + auto end = std::min(i + 1000, NewDefs.size()); + SmallVector batch(NewDefs.begin() + i, NewDefs.begin() + end); + auto AddrsBatch = jl_ExecutionEngine->findSymbols(batch); + Addrs.append(AddrsBatch); + } size_t nextaddr = 0; for (auto &this_code : linkready) { auto it = invokenames.find(this_code); diff --git a/test/cmdlineargs.jl b/test/cmdlineargs.jl index f5325c9eb67ce..6760b75c4fded 100644 --- a/test/cmdlineargs.jl +++ b/test/cmdlineargs.jl @@ -1281,3 +1281,6 @@ end end end end + +# https://github.com/JuliaLang/julia/issues/58229 Recursion in jitlinking with inline=no +@test success(`$(Base.julia_cmd()) --inline=no -e 'Base.compilecache(Base.identify_package("Pkg"))'`) From 5ae93429b8a083806c196e32762d46cbf2d0b53c Mon Sep 17 00:00:00 2001 From: Jakob Nybo Nissen Date: Wed, 18 Jun 2025 22:15:42 +0200 Subject: [PATCH 40/83] Define textwidth for overlong chars (#58602) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, this would error. There is no guarantee of how terminals render overlong encodings. Some terminals does not print them at all, and some print "�". Here, we set a textwidth of 1, conservatively. Refs #58593 (cherry picked from commit a812f03d866e3050216f6d18ccc291179f86e8bf) --- base/strings/unicode.jl | 16 +++++++--------- test/strings/util.jl | 2 ++ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/base/strings/unicode.jl b/base/strings/unicode.jl index 4214028d83653..7e0feed1c5bd5 100644 --- a/base/strings/unicode.jl +++ b/base/strings/unicode.jl @@ -6,7 +6,7 @@ module Unicode import Base: show, ==, hash, string, Symbol, isless, length, eltype, convert, isvalid, ismalformed, isoverlong, iterate, AnnotatedString, AnnotatedChar, annotated_chartransform, - @assume_effects, annotations + @assume_effects, annotations, is_overlong_enc # whether codepoints are valid Unicode scalar values, i.e. 0-0xd7ff, 0xe000-0x10ffff @@ -262,17 +262,15 @@ julia> textwidth('⛵') 2 ``` """ -function textwidth(c::AbstractChar) - ismalformed(c) && return 1 - i = codepoint(c) - i < 0x7f && return Int(i >= 0x20) # ASCII fast path - Int(ccall(:utf8proc_charwidth, Cint, (UInt32,), i)) -end +textwidth(c::AbstractChar) = textwidth(Char(c)::Char) function textwidth(c::Char) - b = bswap(reinterpret(UInt32, c)) # from isascii(c) + u = reinterpret(UInt32, c) + b = bswap(u) # from isascii(c) b < 0x7f && return Int(b >= 0x20) # ASCII fast path - ismalformed(c) && return 1 + # We can't know a priori how terminals will render invalid UTF8 chars, + # so we conservatively decide a width of 1. + (ismalformed(c) || is_overlong_enc(u)) && return 1 Int(ccall(:utf8proc_charwidth, Cint, (UInt32,), c)) end diff --git a/test/strings/util.jl b/test/strings/util.jl index bb87881bbaa1d..9ced27ee3f8d0 100644 --- a/test/strings/util.jl +++ b/test/strings/util.jl @@ -8,6 +8,8 @@ SubStr(s) = SubString("abc$(s)de", firstindex(s) + 3, lastindex(s) + 3) @test textwidth(c^3) == w*3 @test w == @invoke textwidth(c::AbstractChar) end + @test textwidth('\xc0\xa0') == 1 # overlong + @test textwidth('\xf0\x80\x80') == 1 # malformed for i in 0x00:0x7f # test all ASCII chars (which have fast path) w = Int(ccall(:utf8proc_charwidth, Cint, (UInt32,), i)) c = Char(i) From aba3834ece4b03855d5d074d9abbe184af09ad41 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Thu, 19 Jun 2025 15:17:27 -0400 Subject: [PATCH 41/83] fix showing types after removing using Core (#58773) PR #57357 changed the default using list, but only changed some of the places where the `show` code handled that. This led to duplicate (confusing) printing, since both Core. and Base. prefixes are dropped. Fix #58772 (cherry picked from commit 089810cd490d0f040d1ea5d748243c56307d6201) --- base/show.jl | 10 +++++----- test/show.jl | 1 + 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/base/show.jl b/base/show.jl index 7bc4dbed851eb..8fcec0102c19d 100644 --- a/base/show.jl +++ b/base/show.jl @@ -531,7 +531,7 @@ function active_module() return invokelatest(active_module, active_repl)::Module end -module UsesCoreAndBaseOnly +module UsesBaseOnly end function show_function(io::IO, f::Function, compact::Bool, fallback::Function) @@ -543,8 +543,8 @@ function show_function(io::IO, f::Function, compact::Bool, fallback::Function) elseif isdefined(fname, :module) && isdefinedglobal(fname.module, fname.singletonname) && isconst(fname.module, fname.singletonname) && getglobal(fname.module, fname.singletonname) === f # this used to call the removed internal function `is_exported_from_stdlib`, which effectively - # just checked for exports from Core and Base. - mod = get(io, :module, UsesCoreAndBaseOnly) + # just checked for exports from Base. + mod = get(io, :module, UsesBaseOnly) if !(isvisible(fname.singletonname, fname.module, mod) || fname.module === mod) print(io, fname.module, ".") end @@ -818,7 +818,7 @@ function make_typealiases(@nospecialize(x::Type)) Any === x && return aliases, Union{} x <: Tuple && return aliases, Union{} mods = modulesof!(Set{Module}(), x) - Core in mods && push!(mods, Base) + replace!(mods, Core=>Base) vars = Dict{Symbol,TypeVar}() xenv = UnionAll[] each = Any[] @@ -836,7 +836,7 @@ function make_typealiases(@nospecialize(x::Type)) ti === Union{} && continue # make sure this alias wasn't from an unrelated part of the Union mod2 = modulesof!(Set{Module}(), alias) - mod in mod2 || (mod === Base && Core in mods) || continue + mod in mod2 || (mod === Base && Core in mod2) || continue env = env::SimpleVector applied = alias if !isempty(env) diff --git a/test/show.jl b/test/show.jl index 864fdce8b9e5d..7c51768579042 100644 --- a/test/show.jl +++ b/test/show.jl @@ -2458,6 +2458,7 @@ end @test string(Union{M37012.SimpleU, Nothing, T} where T) == "Union{Nothing, $(curmod_prefix)M37012.SimpleU, T} where T" @test string(Union{AbstractVector{T}, T} where T) == "Union{AbstractVector{T}, T} where T" @test string(Union{AbstractVector, T} where T) == "Union{AbstractVector, T} where T" +@test string(Union{Array, Memory}) == "Union{Array, Memory}" @test sprint(show, :(./)) == ":((./))" @test sprint(show, :((.|).(.&, b))) == ":((.|).((.&), b))" From 9a825673bcc4593dad384a42bc996496a1383f80 Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Fri, 20 Jun 2025 12:39:54 -0400 Subject: [PATCH 42/83] Test: Hide REPL internals in backtraces (#58732) (cherry picked from commit 7b6065e9f25bca60f5ed21532a0163d760a7dbf8) --- stdlib/Test/src/Test.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/stdlib/Test/src/Test.jl b/stdlib/Test/src/Test.jl index 08c1df44e818a..20a1df8e773bd 100644 --- a/stdlib/Test/src/Test.jl +++ b/stdlib/Test/src/Test.jl @@ -230,7 +230,8 @@ struct Error <: Result end if test_type === :test_error || test_type === :nontest_error bt_str = try # try the latest world for this, since we might have eval'd new code for show - Base.invokelatest(sprint, Base.show_exception_stack, bt; context=stdout) + # Apply REPL backtrace scrubbing to hide REPL internals, similar to how REPL.jl handles it + Base.invokelatest(sprint, Base.show_exception_stack, Base.scrub_repl_backtrace(bt); context=stdout) catch ex "#=ERROR showing exception stack=# " * try From 0b32bbde243c8da6dcc0779691f04ad9a673f2dc Mon Sep 17 00:00:00 2001 From: Alexis Montoison <35051714+amontoison@users.noreply.github.com> Date: Sat, 21 Jun 2025 06:52:28 +0000 Subject: [PATCH 43/83] [libblastrampoline_jll] Upgrade to v5.13.1 (#58775) ### Check list Version numbers: - [x] `deps/libblastrampoline.version`: `LIBNAME_VER`, `LIBNAME_BRANCH`, `LIBNAME_SHA1` and `LIBNAME_JLL_VER` - [x] `stdlib/libblastrampoline_jll/Project.toml`: `version` Checksum: - [x] `deps/checksums/libblastrampoline` (cherry picked from commit 92bcc94af6c3818b66705c17676468de05061631) --- deps/blastrampoline.version | 6 +- deps/checksums/blastrampoline | 76 +++++++++++------------ stdlib/libblastrampoline_jll/Project.toml | 4 +- 3 files changed, 43 insertions(+), 43 deletions(-) diff --git a/deps/blastrampoline.version b/deps/blastrampoline.version index 1e4a75305a4dd..bb711cfcd67ec 100644 --- a/deps/blastrampoline.version +++ b/deps/blastrampoline.version @@ -4,6 +4,6 @@ BLASTRAMPOLINE_JLL_NAME := libblastrampoline ## source build -BLASTRAMPOLINE_VER := 5.12.0 -BLASTRAMPOLINE_BRANCH=v5.12.0 -BLASTRAMPOLINE_SHA1=b127bc8dd4758ffc064340fff2aef4ead552f386 +BLASTRAMPOLINE_VER := 5.13.1 +BLASTRAMPOLINE_BRANCH=v5.13.1 +BLASTRAMPOLINE_SHA1=f26278e83ddc9035ae7695da597f1a5b26a4c62b diff --git a/deps/checksums/blastrampoline b/deps/checksums/blastrampoline index 9e007f6055cf9..7870242560f34 100644 --- a/deps/checksums/blastrampoline +++ b/deps/checksums/blastrampoline @@ -1,38 +1,38 @@ -blastrampoline-b127bc8dd4758ffc064340fff2aef4ead552f386.tar.gz/md5/395f2035bcb52e886b55ac926a7bf183 -blastrampoline-b127bc8dd4758ffc064340fff2aef4ead552f386.tar.gz/sha512/9ae0fe2ca75dc0b2c784d5b7248caca29ed6d44258743ee2b32827032734757e9078dd6bcdf80a02b042deb5c7ca7b4e5be392be6700efde91427091fb53a03f -libblastrampoline.v5.12.0+0.aarch64-apple-darwin.tar.gz/md5/9a18b39bb575d0112834992043d302c0 -libblastrampoline.v5.12.0+0.aarch64-apple-darwin.tar.gz/sha512/4e406b155149414d3e4fd5db49ab56a87ed13577ebb399eaf8a251692c0b84e639c6e1a4eb20863e2638c31add0241ca916e57f91bb5a4aed07e2c56cc580870 -libblastrampoline.v5.12.0+0.aarch64-linux-gnu.tar.gz/md5/e100e93f0d6a104fc66c9f78a67150c5 -libblastrampoline.v5.12.0+0.aarch64-linux-gnu.tar.gz/sha512/f7e0c379e32d8163dbb4919b77e9637e1b16cf26618b9260222cf985bfab9ca3f36bebccd0e8360af68db925035c82127ba85d46b4a6578961dde6a049c7cf93 -libblastrampoline.v5.12.0+0.aarch64-linux-musl.tar.gz/md5/814a79e8cfe8744ca5a2a722f007fcaa -libblastrampoline.v5.12.0+0.aarch64-linux-musl.tar.gz/sha512/bc886b199500fc4245a95446d4c862fc636711e0875a9d5cf9aef661d819d00324adfd3e037d9c03e274be26034353d033fb041e7608ecef222e1d154f38337d -libblastrampoline.v5.12.0+0.aarch64-unknown-freebsd.tar.gz/md5/9b9a7fe0e45a73009bb9f8044f4a27a2 -libblastrampoline.v5.12.0+0.aarch64-unknown-freebsd.tar.gz/sha512/51d52afb13e326ef4750bdcad800aaf3db2c9e068b4c38bd148e312c63358b2228b81d23626d18b8983534a8a6f24df1b64b4e7121779d2535574ea907bd18ba -libblastrampoline.v5.12.0+0.armv6l-linux-gnueabihf.tar.gz/md5/1b6fd062d133b13e8efc63f08528fb51 -libblastrampoline.v5.12.0+0.armv6l-linux-gnueabihf.tar.gz/sha512/78d525f425ee27068b94b94f89ef44a51ffac9f642ffe66e177434804e59b4ac3ba875190aceee386a8d740f7903e979e5b91f0973138d0fc7753061c6f5f26d -libblastrampoline.v5.12.0+0.armv6l-linux-musleabihf.tar.gz/md5/506be2b7669aa171efcc541388cb5444 -libblastrampoline.v5.12.0+0.armv6l-linux-musleabihf.tar.gz/sha512/2975136376c3f61b8f227676c4e1368d1847d85ff469dddbc0a330635eac77c00072c7544ae4aa9981d16a4ab04d494be54fc951b434a56fbf14003c42626579 -libblastrampoline.v5.12.0+0.armv7l-linux-gnueabihf.tar.gz/md5/99403eae880f52aa97884143e2ca7215 -libblastrampoline.v5.12.0+0.armv7l-linux-gnueabihf.tar.gz/sha512/986dfcf5fe3ac731df3c71eb6b0bf3d7525511952d22cc9128ff35e6fcb330acf69e897aeb97920ebabd1ccccd1dd6ce9b6c16d0dbf661d39a103ce5b477462f -libblastrampoline.v5.12.0+0.armv7l-linux-musleabihf.tar.gz/md5/20adf8d2ef348f5362cb03e1a2780476 -libblastrampoline.v5.12.0+0.armv7l-linux-musleabihf.tar.gz/sha512/95068a3b5bcf17bd5f13373a2730a6508d3992f0aa83a91629527821cf038b9607327843cc44fb72730b63c01d3d70e2eb488eca8f48ed9444d7736f67745d02 -libblastrampoline.v5.12.0+0.i686-linux-gnu.tar.gz/md5/a56f833ad986fc3e9e64e5abdb16915f -libblastrampoline.v5.12.0+0.i686-linux-gnu.tar.gz/sha512/d478b4981dc17afb8aa8625fdbb23139f1c3edaa9aaa179e70d274984a056147b2e65e9f473b007733d094369f448823c33aa95fadd228016ecf9dfbf17f06bb -libblastrampoline.v5.12.0+0.i686-linux-musl.tar.gz/md5/8578119b3b3e84393e6324996e9506aa -libblastrampoline.v5.12.0+0.i686-linux-musl.tar.gz/sha512/b546de6687755ce43680f312008a23a8f9df422603098807f33e2ae969c9e9de0ca32a3319067d4f8fa1f782f21b6465638cd59e4c86fc6261fb4180f0ed116f -libblastrampoline.v5.12.0+0.i686-w64-mingw32.tar.gz/md5/b9e2800b8758d3fa0ac0597f738c399c -libblastrampoline.v5.12.0+0.i686-w64-mingw32.tar.gz/sha512/e0aa0ee2a750cfe702e0bd5861e352f97f433f67444dbc6e5814055fb32f571de318f640ac670c91bad233f8af85f0421daef71b7768a710de5b15febee28b27 -libblastrampoline.v5.12.0+0.powerpc64le-linux-gnu.tar.gz/md5/bab2048857c7c1ba4a6c3d540b9275c6 -libblastrampoline.v5.12.0+0.powerpc64le-linux-gnu.tar.gz/sha512/576026c970b19cc00480d7bb9439933c5bb432eec17def66b22f5c0dfd418bcf75bb10ccfc1b01fef48e8d504ebf953c5f6c63d504713315c43d9579ab5fa2e4 -libblastrampoline.v5.12.0+0.riscv64-linux-gnu.tar.gz/md5/f37e2849a948a8c8c8bfa6055e30909c -libblastrampoline.v5.12.0+0.riscv64-linux-gnu.tar.gz/sha512/89f30d52f1a1dcc0aa38b4b343534b7fadcff12d788f455172c043ea2511c03b2735fdacf8f794a6f62156cb5d82fb0e9e0edd04bb9c57a1ca3e680410456b17 -libblastrampoline.v5.12.0+0.x86_64-apple-darwin.tar.gz/md5/b07c42b602b91bf2229b1a5cfd8e37b3 -libblastrampoline.v5.12.0+0.x86_64-apple-darwin.tar.gz/sha512/ab064dff373826776f9b64a4a77e3418461d53d5119798a5e702967e4ac4f68c58cd8c3c0cc01bda3edeb613cf50b9d3171d9141c91ff9ef3a2c88a8e8f00a37 -libblastrampoline.v5.12.0+0.x86_64-linux-gnu.tar.gz/md5/c37b01242012e51e124711d5ad10cf97 -libblastrampoline.v5.12.0+0.x86_64-linux-gnu.tar.gz/sha512/3f9015bec4aaddc677cb3f3aebd432db8bad89b3f6e563634a37569afeb9fb0efa4f214166c984c2c1926831d5cd79fcd4d605d40675e0d1a7e494a76c066f02 -libblastrampoline.v5.12.0+0.x86_64-linux-musl.tar.gz/md5/c24e440a1757a45f087a2e1ac649fb45 -libblastrampoline.v5.12.0+0.x86_64-linux-musl.tar.gz/sha512/824b930d50df929fd22ead6dffad06593d2aad9fcb149f07f1c2f6d4b7b34911e89c2be5a1e9b8ad5ad8292ac29f9e5dbe6d7bb205d2b207432ade61ae5f8b68 -libblastrampoline.v5.12.0+0.x86_64-unknown-freebsd.tar.gz/md5/5721328a24473cefbb3e77ba85e46922 -libblastrampoline.v5.12.0+0.x86_64-unknown-freebsd.tar.gz/sha512/3537ea491828492f1cb68fa961dc5574b63a88b49abf19eb86f9d1a4544e1398fcd84d6338c6dcb9550ee3abcdcab0654f5cc2b85699c5ed5b3b31a1c35a199d -libblastrampoline.v5.12.0+0.x86_64-w64-mingw32.tar.gz/md5/450afb701cc2899c7c083bd3f3e580a0 -libblastrampoline.v5.12.0+0.x86_64-w64-mingw32.tar.gz/sha512/e4d1785a06b051a4f16edd7343021eed61ac45cf45d26b4e3ef1e54cfaadb44da2e74b7d854e31b05a733dbb3004f3e85644967316c4f41d1ad64400fed126f2 +blastrampoline-f26278e83ddc9035ae7695da597f1a5b26a4c62b.tar.gz/md5/855b7723a6e9eb8885876eb675d48329 +blastrampoline-f26278e83ddc9035ae7695da597f1a5b26a4c62b.tar.gz/sha512/29cbd060c8f5eb17ef486d0a10ee4b221eeceec3a2ab0f9f98f60880f3d19a2247d93ac0dc0d32ec568ef876acd30f6c0642aaf704757580c2e17884e425607f +libblastrampoline.v5.13.1+0.aarch64-apple-darwin.tar.gz/md5/d8dc0f092f86b379b2fb9da97382be70 +libblastrampoline.v5.13.1+0.aarch64-apple-darwin.tar.gz/sha512/d9fc0439565afaabe53f56f64c20aeddb846c991dafeafdef6c2369bd7a359c1a6b49cdf8d63eaae2730a336509854b5c306e630eb520445712efc4e41c0263e +libblastrampoline.v5.13.1+0.aarch64-linux-gnu.tar.gz/md5/c181e51a6ca4cde0da3d036d561e24dc +libblastrampoline.v5.13.1+0.aarch64-linux-gnu.tar.gz/sha512/fe4a86bb4c94ef86c2307adad528bb58d0508a33c194c64190fffe7902f5b915592567d9e0cc35414633c5ab9067def2fa20cf669a2f4309265744180a5ec51a +libblastrampoline.v5.13.1+0.aarch64-linux-musl.tar.gz/md5/6f9eb8d73a0e61f3a2b97dba7105086e +libblastrampoline.v5.13.1+0.aarch64-linux-musl.tar.gz/sha512/9c3db080155729a91b5dd47df91d3852539aefc331d4dc51167fccaf3b01e601b36911ec259c53e211fe192c108e839a1f14b837009fa4f7d88ed82d658f80ff +libblastrampoline.v5.13.1+0.aarch64-unknown-freebsd.tar.gz/md5/68f65db9da9938929d510eea3540335b +libblastrampoline.v5.13.1+0.aarch64-unknown-freebsd.tar.gz/sha512/2fc7b375a751f3bb201504e0417828602fe014a2c8626137779c09ca7264ac6d39d44db0d1d32e0dc506284f56b49e23791922b0cc1237021473fb505fbf06bd +libblastrampoline.v5.13.1+0.armv6l-linux-gnueabihf.tar.gz/md5/a377fa4e5751fbeb3c42f319cb6341de +libblastrampoline.v5.13.1+0.armv6l-linux-gnueabihf.tar.gz/sha512/9ddb1e2f4daab45d65b66dafc00df6ca7f788cb919cd6699c4aa0deca3e99a86d9ced10c3741610a6e480093d483e8a02c1d9165f91a7179632c1e2ae1abcfb7 +libblastrampoline.v5.13.1+0.armv6l-linux-musleabihf.tar.gz/md5/42c841baa05f80f17ea1b1d4f3405bef +libblastrampoline.v5.13.1+0.armv6l-linux-musleabihf.tar.gz/sha512/0c3ed42bd48f8f1ee9b1dc18faa7afa6e2fb27cffc59b9a420e29b5e6cdf8fb3bde36b82f3086075f8f7f329614aeb91ca5f173b1683e30e9530076f341ea2e0 +libblastrampoline.v5.13.1+0.armv7l-linux-gnueabihf.tar.gz/md5/61e515ec1223c99705175a26e6fbaf87 +libblastrampoline.v5.13.1+0.armv7l-linux-gnueabihf.tar.gz/sha512/92260dcc563ece74719f21921a7cb51266884ed01b50c97fa997b4a98737e900ec9eaa8012d2c4c67ab479c4080bd1cf2708612eaaaddbba28e4f9147f3708ea +libblastrampoline.v5.13.1+0.armv7l-linux-musleabihf.tar.gz/md5/d45816d705dd46572d85105567bc060e +libblastrampoline.v5.13.1+0.armv7l-linux-musleabihf.tar.gz/sha512/45cba07050b818cd85c67acdfc29515e1fe416eb4e0c219171f2c0c026f7412903c3a9367d48258259a16e89f36c1e8f9fa054e455759720f1c6c5e8e27be476 +libblastrampoline.v5.13.1+0.i686-linux-gnu.tar.gz/md5/c8d3fd5f314353133934396361857c92 +libblastrampoline.v5.13.1+0.i686-linux-gnu.tar.gz/sha512/a949b3c0655ad9d6f8d53fd8a3f0b4ab504046e49a373039defc94e832b7faf90c77520f3912c4d6db8b0829951d85b4fc2a4021b3d8bb2c399d1ad04ce77ab0 +libblastrampoline.v5.13.1+0.i686-linux-musl.tar.gz/md5/a7bbd2233366d180ce8aa61fd3568c11 +libblastrampoline.v5.13.1+0.i686-linux-musl.tar.gz/sha512/e78cbef5b3bcfa93a86e14eebf0d704a94ac7b1f5c7030706d1f4a960de888c42e3daddb65395c7102e08dfd444efbfb40273e58a5f1de199d44ad55fd3ae658 +libblastrampoline.v5.13.1+0.i686-w64-mingw32.tar.gz/md5/4ca5cf3f855d04d3e8bdbd15321944ad +libblastrampoline.v5.13.1+0.i686-w64-mingw32.tar.gz/sha512/33160caa000c6c44cedd594195e1f2efefb950459653ee12ad2be4cedf0b833874772512f1812948d753f075ee7b8fe5629e5f9bd753a3da7804c4a6e1b0e0a8 +libblastrampoline.v5.13.1+0.powerpc64le-linux-gnu.tar.gz/md5/8be947c20f7d35ec22247f9a11ccce43 +libblastrampoline.v5.13.1+0.powerpc64le-linux-gnu.tar.gz/sha512/56f4246f96d2f49b03f5e5f3b996660a48d50b3784f89df7cd1dc52bab6efea0c120a65015040041a51d18fc6f361f89486f77317d771fbf588a1ba7565d77a2 +libblastrampoline.v5.13.1+0.riscv64-linux-gnu.tar.gz/md5/85e1f70a3235097158b4884a58a58154 +libblastrampoline.v5.13.1+0.riscv64-linux-gnu.tar.gz/sha512/11f1f5c2a409dbdab11d6bc968610b5700e9b0cb95094e348fe43ddca5586eda47bda1c382fb1f4b5a15aa741a6fc2b31f58f9b08bfe46631b5471e864bc009b +libblastrampoline.v5.13.1+0.x86_64-apple-darwin.tar.gz/md5/c6756ca8b6778ce2a4a440f63355c32e +libblastrampoline.v5.13.1+0.x86_64-apple-darwin.tar.gz/sha512/895d9bba75a9a0861809dca48b3dae7b5ffc5d866a518729ffd52f70fa1742a41a4b8b4e03bb354cba12d9ad11a33f3f112fa69a30ab3f945a9dede0d59d92b3 +libblastrampoline.v5.13.1+0.x86_64-linux-gnu.tar.gz/md5/1326a406aa98b6045f7459d7fb237894 +libblastrampoline.v5.13.1+0.x86_64-linux-gnu.tar.gz/sha512/4965baa1de5532425ea57b8100e369cf44b55963340cd144c0359f845560f27a1bea1597e4c72ec541917f71aaff8a4863f47d01a095c2e761a68212bfb08d1e +libblastrampoline.v5.13.1+0.x86_64-linux-musl.tar.gz/md5/5103983b7fecc7b87f495cd3b6c4d7a5 +libblastrampoline.v5.13.1+0.x86_64-linux-musl.tar.gz/sha512/f3243d84a0a0a191abad9e3850c37be78892eb5905b63b47bfb3e5a4148e0dae672ee72d311c5c764ad0fffe57d39c10dfd2086466efd76b5030118941d36a00 +libblastrampoline.v5.13.1+0.x86_64-unknown-freebsd.tar.gz/md5/a001ecd07b5178ce724a4f78996dc43e +libblastrampoline.v5.13.1+0.x86_64-unknown-freebsd.tar.gz/sha512/508866d54a9a49df2ef7eaa5d807173016c6dfaec59c4c89d5b37cd3faa7384302d2d4d39aca1975d79a948414657b7ec048a3ebdf6bf5c938037aa89303013a +libblastrampoline.v5.13.1+0.x86_64-w64-mingw32.tar.gz/md5/14fc4ec99e72e5bb646f5e6e8410fe01 +libblastrampoline.v5.13.1+0.x86_64-w64-mingw32.tar.gz/sha512/b7d07218047917fe217736b3c97d2b0565f6c904cd9cf6de96e38c66552aeec13b3cde714775fce1eb5a230db0ec0f2822572de8f0e166cb042552a16beb2b79 diff --git a/stdlib/libblastrampoline_jll/Project.toml b/stdlib/libblastrampoline_jll/Project.toml index d1dde4c6074a7..ea4f645dc153c 100644 --- a/stdlib/libblastrampoline_jll/Project.toml +++ b/stdlib/libblastrampoline_jll/Project.toml @@ -1,13 +1,13 @@ name = "libblastrampoline_jll" uuid = "8e850b90-86db-534c-a0d3-1478176c7d93" -version = "5.12.0+0" +version = "5.13.1+0" [deps] Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb" Artifacts = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" [compat] -julia = "1.12" +julia = "1.13" [extras] Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" From da36d27b6330e17a6e0042e482b723e1f76ae7e6 Mon Sep 17 00:00:00 2001 From: Neven Sajko <4944410+nsajko@users.noreply.github.com> Date: Sun, 22 Jun 2025 19:41:02 +0200 Subject: [PATCH 44/83] prevent unnecessary repeated squaring calculation (#58720) (cherry picked from commit f61c640aaf218d4738a734ede86292c2a320dd9e) --- base/intfuncs.jl | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/base/intfuncs.jl b/base/intfuncs.jl index 552a51c33fb12..3f26d2597f9d9 100644 --- a/base/intfuncs.jl +++ b/base/intfuncs.jl @@ -335,11 +335,6 @@ function invmod(n::T) where {T<:BitInteger} end # ^ for any x supporting * -function to_power_type(x::Number) - T = promote_type(typeof(x), typeof(x*x)) - convert(T, x) -end -to_power_type(x) = oftype(x*x, x) @noinline throw_domerr_powbysq(::Any, p) = throw(DomainError(p, LazyString( "Cannot raise an integer x to a negative power ", p, ".", "\nConvert input to float."))) @@ -355,12 +350,23 @@ to_power_type(x) = oftype(x*x, x) "or write float(x)^", p, " or Rational.(x)^", p, "."))) # The * keyword supports `*=checked_mul` for `checked_pow` @assume_effects :terminates_locally function power_by_squaring(x_, p::Integer; mul=*) - x = to_power_type(x_) + x_squared_ = x_ * x_ + x_squared_type = typeof(x_squared_) + T = if x_ isa Number + promote_type(typeof(x_), x_squared_type) + else + x_squared_type + end + x = convert(T, x_) + square_is_useful = mul === * if p == 1 return copy(x) elseif p == 0 return one(x) elseif p == 2 + if square_is_useful # avoid performing the same multiplication a second time when possible + return convert(T, x_squared_) + end return mul(x, x) elseif p < 0 isone(x) && return copy(x) @@ -369,6 +375,11 @@ to_power_type(x) = oftype(x*x, x) end t = trailing_zeros(p) + 1 p >>= t + if square_is_useful # avoid performing the same multiplication a second time when possible + if (t -= 1) > 0 + x = convert(T, x_squared_) + end + end while (t -= 1) > 0 x = mul(x, x) end From ae388212adcf51109c609a4f209e2c6953b91b79 Mon Sep 17 00:00:00 2001 From: Cody Tapscott <84105208+topolarity@users.noreply.github.com> Date: Thu, 26 Jun 2025 07:35:02 -0400 Subject: [PATCH 45/83] Add `cfunction` support for `--trim` (#58812) --- Compiler/src/typeinfer.jl | 26 ++++++++++++++++++++------ Compiler/src/verifytrim.jl | 24 +++++++++++++++++++++--- Compiler/test/verifytrim.jl | 27 +++++++++++++++------------ src/codegen.cpp | 20 ++++++++++---------- test/trimming/basic_jll.jl | 15 +++++++++++++-- 5 files changed, 79 insertions(+), 33 deletions(-) diff --git a/Compiler/src/typeinfer.jl b/Compiler/src/typeinfer.jl index 03b19c9282a46..f998084f126fa 100644 --- a/Compiler/src/typeinfer.jl +++ b/Compiler/src/typeinfer.jl @@ -1361,16 +1361,30 @@ function collectinvokes!(workqueue::CompilationQueue, ci::CodeInfo, sptypes::Vec # No dynamic dispatch to resolve / enqueue continue end + elseif isexpr(stmt, :cfunction) && length(stmt.args) == 5 + (pointer_type, f, rt, at, call_type) = stmt.args + linfo = ci.parent - let workqueue = invokelatest_queue - # make a best-effort attempt to enqueue the relevant code for the finalizer - mi = compileable_specialization_for_call(workqueue.interp, atype) - mi === nothing && continue + linfo isa MethodInstance || continue + at isa SimpleVector || continue - push!(workqueue, mi) + ft = argextype(f, ci, sptypes) + argtypes = Any[ft] + for i = 1:length(at) + push!(argtypes, sp_type_rewrap(at[i], linfo, #= isreturn =# false)) end + atype = argtypes_to_type(argtypes) + else + # TODO: handle other StmtInfo like OpaqueClosure? + continue + end + let workqueue = invokelatest_queue + # make a best-effort attempt to enqueue the relevant code for the dynamic invokelatest call + mi = compileable_specialization_for_call(workqueue.interp, atype) + mi === nothing && continue + + push!(workqueue, mi) end - # TODO: handle other StmtInfo like @cfunction and OpaqueClosure? end end diff --git a/Compiler/src/verifytrim.jl b/Compiler/src/verifytrim.jl index 09a189b2ff223..eb775bfa290ce 100644 --- a/Compiler/src/verifytrim.jl +++ b/Compiler/src/verifytrim.jl @@ -14,7 +14,7 @@ using ..Compiler: argextype, empty!, error, get, get_ci_mi, get_world_counter, getindex, getproperty, hasintersect, haskey, in, isdispatchelem, isempty, isexpr, iterate, length, map!, max, pop!, popfirst!, push!, pushfirst!, reinterpret, reverse!, reverse, setindex!, - setproperty!, similar, singleton_type, sptypes_from_meth_instance, + setproperty!, similar, singleton_type, sptypes_from_meth_instance, sp_type_rewrap, unsafe_pointer_to_objref, widenconst, isconcretetype, # misc @nospecialize, @assert, C_NULL @@ -256,9 +256,27 @@ function verify_codeinstance!(interp::NativeInterpreter, codeinst::CodeInstance, warn = true # downgrade must-throw calls to be only a warning end elseif isexpr(stmt, :cfunction) + length(stmt.args) != 5 && continue # required by IR legality + (pointer_type, f, rt, at, call_type) = stmt.args + + at isa SimpleVector || continue # required by IR legality + ft = argextype(f, codeinfo, sptypes) + argtypes = Any[ft] + for i = 1:length(at) + push!(argtypes, sp_type_rewrap(at[i], get_ci_mi(codeinst), #= isreturn =# false)) + end + atype = argtypes_to_type(argtypes) + + mi = compileable_specialization_for_call(interp, atype) + if mi !== nothing + # n.b.: Codegen may choose unpredictably to emit this `@cfunction` as a dynamic invoke or a full + # dynamic call, but in either case it guarantees that the required adapter(s) are emitted. All + # that we are required to verify here is that the callee CodeInstance is covered. + ci = get(caches, mi, nothing) + ci isa CodeInstance && continue + end + error = "unresolved cfunction" - #TODO: parse the cfunction expression to check the target is defined - warn = true elseif isexpr(stmt, :foreigncall) foreigncall = stmt.args[1] if foreigncall isa QuoteNode diff --git a/Compiler/test/verifytrim.jl b/Compiler/test/verifytrim.jl index e7d57571b1db0..a84afd6933266 100644 --- a/Compiler/test/verifytrim.jl +++ b/Compiler/test/verifytrim.jl @@ -36,24 +36,27 @@ let infos = typeinf_ext_toplevel(Any[Core.svec(Nothing, Tuple{typeof(finalizer), \[1\] finalizer\(f::Any, o::Any\)""", repr) end +# test that basic `cfunction` generation is allowed, when the dispatch target can be resolved make_cfunction() = @cfunction(+, Float64, (Int64,Int64)) +let infos = typeinf_ext_toplevel(Any[Core.svec(Ptr{Cvoid}, Tuple{typeof(make_cfunction)})], [Base.get_world_counter()], TRIM_UNSAFE) + errors, parents = get_verify_typeinf_trim(infos) + @test isempty(errors) +end # use TRIM_UNSAFE to bypass verifier inside typeinf_ext_toplevel -let infos = typeinf_ext_toplevel(Any[Core.svec(Ptr{Cvoid}, Tuple{typeof(make_cfunction)})], [Base.get_world_counter()], TRIM_UNSAFE) +make_cfunction_bad(@nospecialize(f::Any)) = @cfunction($f, Float64, (Int64,Int64))::Base.CFunction +let infos = typeinf_ext_toplevel(Any[Core.svec(Base.CFunction, Tuple{typeof(make_cfunction_bad), Any})], [Base.get_world_counter()], TRIM_UNSAFE) errors, parents = get_verify_typeinf_trim(infos) - @test_broken isempty(errors) # missing cfunction + @test !isempty(errors) # missing cfunction - desc = only(errors) - @test desc.first - desc = desc.second + (is_warning, desc) = only(errors) + @test !is_warning @test desc isa CallMissing @test occursin("cfunction", desc.desc) repr = sprint(verify_print_error, desc, parents) - @test occursin( - r"""^unresolved cfunction from statement \$\(Expr\(:cfunction, Ptr{Nothing}, :\(\$\(QuoteNode\(\+\)\)\), Float64, :\(svec\(Int64, Int64\)::Core.SimpleVector\), :\(:ccall\)\)\)::Ptr{Nothing} + @test occursin(r"""^unresolved cfunction from statement \$\(Expr\(:cfunction, Base.CFunction, :\(f::Any\), Float64, :\(svec\(Int64, Int64\)::Core.SimpleVector\), :\(:ccall\)\)\)::Base.CFunction Stacktrace: - \[1\] make_cfunction\(\)""", repr) - + \[1\] make_cfunction_bad\(f::Any\)""", repr) resize!(infos, 1) @test infos[1] isa Core.SimpleVector && infos[1][1] isa Type && infos[1][2] isa Type errors, parents = get_verify_typeinf_trim(infos) @@ -61,11 +64,11 @@ let infos = typeinf_ext_toplevel(Any[Core.svec(Ptr{Cvoid}, Tuple{typeof(make_cfu @test !desc.first desc = desc.second @test desc isa CCallableMissing - @test desc.rt == Ptr{Cvoid} - @test desc.sig == Tuple{typeof(make_cfunction)} + @test desc.rt == Base.CFunction + @test desc.sig == Tuple{typeof(make_cfunction_bad), Any} @test occursin("unresolved ccallable", desc.desc) repr = sprint(verify_print_error, desc, parents) - @test repr == "unresolved ccallable for Tuple{$(typeof(make_cfunction))} => Ptr{Nothing}\n\n" + @test repr == "unresolved ccallable for Tuple{$(typeof(make_cfunction_bad)), Any} => Base.CFunction\n\n" end let infos = typeinf_ext_toplevel(Any[Core.svec(Base.SecretBuffer, Tuple{Type{Base.SecretBuffer}})], [Base.get_world_counter()], TRIM_UNSAFE) diff --git a/src/codegen.cpp b/src/codegen.cpp index aa0a56b28d1e8..36255a767ea14 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -6348,8 +6348,8 @@ static jl_cgval_t emit_expr(jl_codectx_t &ctx, jl_value_t *expr, ssize_t ssaidx_ } else if (head == jl_cfunction_sym) { assert(nargs == 5); - jl_cgval_t fexpr_rt = emit_expr(ctx, args[1]); - return emit_cfunction(ctx, args[0], fexpr_rt, args[2], (jl_svec_t*)args[3]); + jl_cgval_t fexpr_val = emit_expr(ctx, args[1]); + return emit_cfunction(ctx, args[0], fexpr_val, args[2], (jl_svec_t*)args[3]); } else if (head == jl_assign_sym) { assert(nargs == 2); @@ -7489,7 +7489,7 @@ static const char *derive_sigt_name(jl_value_t *jargty) // Get the LLVM Function* for the C-callable entry point for a certain function // and argument types. // here argt does not include the leading function type argument -static jl_cgval_t emit_cfunction(jl_codectx_t &ctx, jl_value_t *output_type, const jl_cgval_t &fexpr_rt, jl_value_t *declrt, jl_svec_t *argt) +static jl_cgval_t emit_cfunction(jl_codectx_t &ctx, jl_value_t *output_type, const jl_cgval_t &fexpr_val, jl_value_t *declrt, jl_svec_t *argt) { jl_unionall_t *unionall_env = (jl_is_method(ctx.linfo->def.method) && jl_is_unionall(ctx.linfo->def.method->sig)) ? (jl_unionall_t*)ctx.linfo->def.method->sig @@ -7547,8 +7547,8 @@ static jl_cgval_t emit_cfunction(jl_codectx_t &ctx, jl_value_t *output_type, con // compute+verify the dispatch signature, and see if it depends on the environment sparams bool approx = false; sigt = (jl_value_t*)jl_alloc_svec(nargt + 1); - jl_svecset(sigt, 0, fexpr_rt.typ); - if (!fexpr_rt.constant && (!jl_is_concrete_type(fexpr_rt.typ) || jl_is_kind(fexpr_rt.typ))) + jl_svecset(sigt, 0, fexpr_val.typ); + if (!fexpr_val.constant && (!jl_is_concrete_type(fexpr_val.typ) || jl_is_kind(fexpr_val.typ))) approx = true; for (size_t i = 0; i < nargt; i++) { jl_value_t *jargty = jl_svecref(argt, i); @@ -7577,7 +7577,7 @@ static jl_cgval_t emit_cfunction(jl_codectx_t &ctx, jl_value_t *output_type, con unionall_env = NULL; } - bool nest = (!fexpr_rt.constant || unionall_env); + bool nest = (!fexpr_val.constant || unionall_env); if (ctx.emission_context.TargetTriple.isAArch64() || ctx.emission_context.TargetTriple.isARM() || ctx.emission_context.TargetTriple.isPPC64()) { if (nest) { emit_error(ctx, "cfunction: closures are not supported on this platform"); @@ -7585,17 +7585,17 @@ static jl_cgval_t emit_cfunction(jl_codectx_t &ctx, jl_value_t *output_type, con return jl_cgval_t(); } } - const char *name = derive_sigt_name(fexpr_rt.typ); + const char *name = derive_sigt_name(fexpr_val.typ); Value *F = gen_cfun_wrapper( jl_Module, ctx.emission_context, - sig, fexpr_rt.constant, name, + sig, fexpr_val.constant, name, declrt, sigt, unionall_env, sparam_vals, &closure_types); bool outboxed; if (nest) { // F is actually an init_trampoline function that returns the real address // Now fill in the nest parameters - Value *fobj = boxed(ctx, fexpr_rt); + Value *fobj = boxed(ctx, fexpr_val); jl_svec_t *fill = jl_emptysvec; if (closure_types) { assert(ctx.spvals_ptr); @@ -7635,7 +7635,7 @@ static jl_cgval_t emit_cfunction(jl_codectx_t &ctx, jl_value_t *output_type, con jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA(ctx, tbaa); ai.decorateInst(ctx.builder.CreateStore(F, derived_strct)); ai.decorateInst(ctx.builder.CreateStore( - ctx.builder.CreatePtrToInt(literal_pointer_val(ctx, fexpr_rt.constant), ctx.types().T_size), + ctx.builder.CreatePtrToInt(literal_pointer_val(ctx, fexpr_val.constant), ctx.types().T_size), ctx.builder.CreateConstInBoundsGEP1_32(ctx.types().T_size, derived_strct, 1))); ai.decorateInst(ctx.builder.CreateStore(Constant::getNullValue(ctx.types().T_size), ctx.builder.CreateConstInBoundsGEP1_32(ctx.types().T_size, derived_strct, 2))); diff --git a/test/trimming/basic_jll.jl b/test/trimming/basic_jll.jl index fc0137dd4eab2..1e0d23fefcfd4 100644 --- a/test/trimming/basic_jll.jl +++ b/test/trimming/basic_jll.jl @@ -3,11 +3,22 @@ module MyApp using Libdl using Zstd_jll +function print_string(fptr::Ptr{Cvoid}) + println(Core.stdout, unsafe_string(ccall(fptr, Cstring, ()))) +end + Base.@ccallable function main()::Cint + # Test the basic "Hello, world!" println(Core.stdout, "Julia! Hello, world!") - fptr = dlsym(Zstd_jll.libzstd_handle, :ZSTD_versionString) - println(Core.stdout, unsafe_string(ccall(fptr, Cstring, ()))) + + # Make sure that JLL's are working as expected println(Core.stdout, unsafe_string(ccall((:ZSTD_versionString, libzstd), Cstring, ()))) + + # Add an indirection via `@cfunction` + cfunc = @cfunction(print_string, Cvoid, (Ptr{Cvoid},)) + fptr = dlsym(Zstd_jll.libzstd_handle, :ZSTD_versionString) + ccall(cfunc, Cvoid, (Ptr{Cvoid},), fptr) + return 0 end From de4204bb1fbf573faf0a3a80896c1d4101002ae9 Mon Sep 17 00:00:00 2001 From: Cody Tapscott <84105208+topolarity@users.noreply.github.com> Date: Fri, 27 Jun 2025 10:32:19 -0400 Subject: [PATCH 46/83] Add `trim_mode` parameter to JIT type-inference entrypoint (#58817) Resolves https://github.com/JuliaLang/julia/issues/58786. I think this is only a partial fix, since we can still end up loading code from pkgimages that has been poorly inferred due to running without these `InferenceParams`. However, many of the common scenarios (such as JLL's depending on each other) seem to be OK since we have a targeted heuristic that adds `__init__()` to a pkgimage only if the module has inference enabled. (cherry picked from commit 4ae3f5ebed5378909f6355fb03b00057052c6766) --- Compiler/src/bootstrap.jl | 4 ++-- Compiler/src/typeinfer.jl | 15 ++++++++------- src/aotcompile.cpp | 4 ++-- src/gf.c | 15 ++++++++------- src/julia_internal.h | 2 +- src/runtime_ccall.cpp | 2 +- src/toplevel.c | 2 +- test/trimming/basic_jll.jl | 12 +++++++++--- 8 files changed, 32 insertions(+), 24 deletions(-) diff --git a/Compiler/src/bootstrap.jl b/Compiler/src/bootstrap.jl index a847d1fb835c7..74943fc765f17 100644 --- a/Compiler/src/bootstrap.jl +++ b/Compiler/src/bootstrap.jl @@ -10,7 +10,7 @@ function activate_codegen!() Core.eval(Compiler, quote let typeinf_world_age = Base.tls_world_age() @eval Core.OptimizedGenerics.CompilerPlugins.typeinf(::Nothing, mi::MethodInstance, source_mode::UInt8) = - Base.invoke_in_world($(Expr(:$, :typeinf_world_age)), typeinf_ext_toplevel, mi, Base.tls_world_age(), source_mode) + Base.invoke_in_world($(Expr(:$, :typeinf_world_age)), typeinf_ext_toplevel, mi, Base.tls_world_age(), source_mode, Compiler.TRIM_NO) end end) end @@ -67,7 +67,7 @@ function bootstrap!() end mi = specialize_method(m.method, Tuple{params...}, m.sparams) #isa_compileable_sig(mi) || println(stderr, "WARNING: inferring `", mi, "` which isn't expected to be called.") - typeinf_ext_toplevel(mi, world, isa_compileable_sig(mi) ? SOURCE_MODE_ABI : SOURCE_MODE_NOT_REQUIRED) + typeinf_ext_toplevel(mi, world, isa_compileable_sig(mi) ? SOURCE_MODE_ABI : SOURCE_MODE_NOT_REQUIRED, TRIM_NO) end end end diff --git a/Compiler/src/typeinfer.jl b/Compiler/src/typeinfer.jl index f998084f126fa..8fdfaa2966b8f 100644 --- a/Compiler/src/typeinfer.jl +++ b/Compiler/src/typeinfer.jl @@ -1445,8 +1445,9 @@ function typeinf_ext_toplevel(interp::AbstractInterpreter, mi::MethodInstance, s end # This is a bridge for the C code calling `jl_typeinf_func()` on a single Method match -function typeinf_ext_toplevel(mi::MethodInstance, world::UInt, source_mode::UInt8) - interp = NativeInterpreter(world) +function typeinf_ext_toplevel(mi::MethodInstance, world::UInt, source_mode::UInt8, trim_mode::UInt8) + inf_params = InferenceParams(; force_enable_inference = trim_mode != TRIM_NO) + interp = NativeInterpreter(world; inf_params) return typeinf_ext_toplevel(interp, mi, source_mode) end @@ -1529,11 +1530,11 @@ end # This is a bridge for the C code calling `jl_typeinf_func()` on set of Method matches # The trim_mode can be any of: -const TRIM_NO = 0 -const TRIM_SAFE = 1 -const TRIM_UNSAFE = 2 -const TRIM_UNSAFE_WARN = 3 -function typeinf_ext_toplevel(methods::Vector{Any}, worlds::Vector{UInt}, trim_mode::Int) +const TRIM_NO = 0x0 +const TRIM_SAFE = 0x1 +const TRIM_UNSAFE = 0x2 +const TRIM_UNSAFE_WARN = 0x3 +function typeinf_ext_toplevel(methods::Vector{Any}, worlds::Vector{UInt}, trim_mode::UInt8) inf_params = InferenceParams(; force_enable_inference = trim_mode != TRIM_NO) # Create an "invokelatest" queue to enable eager compilation of speculative diff --git a/src/aotcompile.cpp b/src/aotcompile.cpp index 8c5d9e678a166..bace3e9b570d4 100644 --- a/src/aotcompile.cpp +++ b/src/aotcompile.cpp @@ -661,7 +661,7 @@ void *jl_create_native_impl(jl_array_t *methods, LLVMOrcThreadSafeModuleRef llvm fargs[2] = (jl_value_t*)worlds; jl_array_data(worlds, size_t)[0] = jl_typeinf_world; jl_array_data(worlds, size_t)[compiler_world] = world; // might overwrite previous - fargs[3] = jl_box_long(trim); + fargs[3] = jl_box_uint8(trim); size_t last_age = ct->world_age; ct->world_age = jl_typeinf_world; codeinfos = (jl_array_t*)jl_apply(fargs, 4); @@ -2387,7 +2387,7 @@ void jl_get_llvmf_defn_impl(jl_llvmf_dump_t *dump, jl_method_instance_t *mi, jl_ jl_method_instance_t *mi = jl_get_specialization1((jl_tupletype_t*)sigt, latestworld, 0); if (mi == nullptr) continue; - jl_code_instance_t *codeinst = jl_type_infer(mi, latestworld, SOURCE_MODE_NOT_REQUIRED); + jl_code_instance_t *codeinst = jl_type_infer(mi, latestworld, SOURCE_MODE_NOT_REQUIRED, jl_options.trim); if (codeinst == nullptr || compiled_functions.count(codeinst)) continue; orc::ThreadSafeModule decl_m = jl_create_ts_module("extern", ctx); diff --git a/src/gf.c b/src/gf.c index 496e5b050392b..dbe90dd9ab914 100644 --- a/src/gf.c +++ b/src/gf.c @@ -403,7 +403,7 @@ static jl_code_instance_t *jl_method_inferred_with_abi(jl_method_instance_t *mi // returns the inferred source, and may cache the result in mi // if successful, also updates the mi argument to describe the validity of this src // if inference doesn't occur (or can't finish), returns NULL instead -jl_code_instance_t *jl_type_infer(jl_method_instance_t *mi, size_t world, uint8_t source_mode) +jl_code_instance_t *jl_type_infer(jl_method_instance_t *mi, size_t world, uint8_t source_mode, uint8_t trim_mode) { if (jl_typeinf_func == NULL) { if (source_mode == SOURCE_MODE_ABI) @@ -427,11 +427,12 @@ jl_code_instance_t *jl_type_infer(jl_method_instance_t *mi, size_t world, uint8_ return NULL; JL_TIMING(INFERENCE, INFERENCE); jl_value_t **fargs; - JL_GC_PUSHARGS(fargs, 4); + JL_GC_PUSHARGS(fargs, 5); fargs[0] = (jl_value_t*)jl_typeinf_func; fargs[1] = (jl_value_t*)mi; fargs[2] = jl_box_ulong(world); fargs[3] = jl_box_uint8(source_mode); + fargs[4] = jl_box_uint8(trim_mode); int last_errno = errno; #ifdef _OS_WINDOWS_ DWORD last_error = GetLastError(); @@ -458,7 +459,7 @@ jl_code_instance_t *jl_type_infer(jl_method_instance_t *mi, size_t world, uint8_ // allocate another bit for the counter. ct->reentrant_timing += 0b10; JL_TRY { - ci = (jl_code_instance_t*)jl_apply(fargs, 4); + ci = (jl_code_instance_t*)jl_apply(fargs, 5); } JL_CATCH { jl_value_t *e = jl_current_exception(ct); @@ -3193,7 +3194,7 @@ jl_code_instance_t *jl_compile_method_internal(jl_method_instance_t *mi, size_t int should_skip_inference = !jl_is_method(mi->def.method) || jl_symbol_name(mi->def.method->name)[0] == '@'; if (!should_skip_inference) { - codeinst = jl_type_infer(mi, world, SOURCE_MODE_ABI); + codeinst = jl_type_infer(mi, world, SOURCE_MODE_ABI, jl_options.trim); } } @@ -3513,7 +3514,7 @@ static void _generate_from_hint(jl_method_instance_t *mi, size_t world) { jl_value_t *codeinst = jl_rettype_inferred_native(mi, world, world); if (codeinst == jl_nothing) { - (void)jl_type_infer(mi, world, SOURCE_MODE_NOT_REQUIRED); + (void)jl_type_infer(mi, world, SOURCE_MODE_NOT_REQUIRED, jl_options.trim); codeinst = jl_rettype_inferred_native(mi, world, world); } if (codeinst != jl_nothing) { @@ -3556,10 +3557,10 @@ JL_DLLEXPORT void jl_compile_method_instance(jl_method_instance_t *mi, jl_tuplet miflags = jl_atomic_load_relaxed(&mi2->flags) | JL_MI_FLAGS_MASK_PRECOMPILED; jl_atomic_store_relaxed(&mi2->flags, miflags); if (jl_rettype_inferred_native(mi2, world, world) == jl_nothing) - (void)jl_type_infer(mi2, world, SOURCE_MODE_NOT_REQUIRED); + (void)jl_type_infer(mi2, world, SOURCE_MODE_NOT_REQUIRED, jl_options.trim); if (jl_typeinf_func && jl_atomic_load_relaxed(&mi->def.method->primary_world) <= tworld) { if (jl_rettype_inferred_native(mi2, tworld, tworld) == jl_nothing) - (void)jl_type_infer(mi2, tworld, SOURCE_MODE_NOT_REQUIRED); + (void)jl_type_infer(mi2, tworld, SOURCE_MODE_NOT_REQUIRED, jl_options.trim); } } } diff --git a/src/julia_internal.h b/src/julia_internal.h index 629fd8c385691..affe497df8ff9 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -683,7 +683,7 @@ JL_DLLEXPORT void jl_engine_fulfill(jl_code_instance_t *ci, jl_code_info_t *src) void jl_engine_sweep(jl_ptls_t *gc_all_tls_states) JL_NOTSAFEPOINT; int jl_engine_hasreserved(jl_method_instance_t *m, jl_value_t *owner) JL_NOTSAFEPOINT; -JL_DLLEXPORT jl_code_instance_t *jl_type_infer(jl_method_instance_t *li JL_PROPAGATES_ROOT, size_t world, uint8_t source_mode); +JL_DLLEXPORT jl_code_instance_t *jl_type_infer(jl_method_instance_t *li JL_PROPAGATES_ROOT, size_t world, uint8_t source_mode, uint8_t trim_mode); JL_DLLEXPORT jl_code_info_t *jl_gdbcodetyped1(jl_method_instance_t *mi, size_t world); JL_DLLEXPORT jl_code_instance_t *jl_compile_method_internal(jl_method_instance_t *meth JL_PROPAGATES_ROOT, size_t world); JL_DLLEXPORT jl_code_instance_t *jl_get_method_inferred( diff --git a/src/runtime_ccall.cpp b/src/runtime_ccall.cpp index dd5ceb2c6ad90..f3f1632751c87 100644 --- a/src/runtime_ccall.cpp +++ b/src/runtime_ccall.cpp @@ -401,7 +401,7 @@ void *jl_get_abi_converter(jl_task_t *ct, _Atomic(void*) *fptr, _Atomic(size_t) } JL_UNLOCK(&cfun_lock); // next, try to figure out what the target should look like (outside of the lock since this is very slow) - codeinst = mi ? jl_type_infer(mi, world, SOURCE_MODE_ABI) : nullptr; + codeinst = mi ? jl_type_infer(mi, world, SOURCE_MODE_ABI, jl_options.trim) : nullptr; // relock for the remainder of the function JL_LOCK(&cfun_lock); } while (jl_atomic_load_acquire(&jl_world_counter) != world); // restart entirely, since jl_world_counter changed thus jl_get_specialization1 might have changed diff --git a/src/toplevel.c b/src/toplevel.c index 9e41fe5ac2e04..1941be934b810 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -1016,7 +1016,7 @@ JL_DLLEXPORT jl_value_t *jl_toplevel_eval_flex(jl_module_t *JL_NONNULL m, jl_val size_t world = jl_atomic_load_acquire(&jl_world_counter); ct->world_age = world; if (!has_defs && jl_get_module_infer(m) != 0) { - (void)jl_type_infer(mfunc, world, SOURCE_MODE_ABI); + (void)jl_type_infer(mfunc, world, SOURCE_MODE_ABI, jl_options.trim); } result = jl_invoke(/*func*/NULL, /*args*/NULL, /*nargs*/0, mfunc); ct->world_age = last_age; diff --git a/test/trimming/basic_jll.jl b/test/trimming/basic_jll.jl index 1e0d23fefcfd4..1cc1906d77bda 100644 --- a/test/trimming/basic_jll.jl +++ b/test/trimming/basic_jll.jl @@ -3,6 +3,10 @@ module MyApp using Libdl using Zstd_jll +# JLL usage at build-time should function as expected +Zstd_jll.__init__() +const build_ver = unsafe_string(ccall((:ZSTD_versionString, libzstd), Cstring, ())) + function print_string(fptr::Ptr{Cvoid}) println(Core.stdout, unsafe_string(ccall(fptr, Cstring, ()))) end @@ -11,10 +15,12 @@ Base.@ccallable function main()::Cint # Test the basic "Hello, world!" println(Core.stdout, "Julia! Hello, world!") - # Make sure that JLL's are working as expected - println(Core.stdout, unsafe_string(ccall((:ZSTD_versionString, libzstd), Cstring, ()))) + # JLL usage at run-time should function as expected + ver = unsafe_string(ccall((:ZSTD_versionString, libzstd), Cstring, ())) + println(Core.stdout, ver) + @assert ver == build_ver - # Add an indirection via `@cfunction` + # Add an indirection via `@cfunction` / 1-arg ccall cfunc = @cfunction(print_string, Cvoid, (Ptr{Cvoid},)) fptr = dlsym(Zstd_jll.libzstd_handle, :ZSTD_versionString) ccall(cfunc, Cvoid, (Ptr{Cvoid},), fptr) From 4c683794a10fb2d94781a8329b35b8b64c60ed6b Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Sun, 11 May 2025 00:28:10 +0200 Subject: [PATCH 47/83] Make trimming tests work in an out-of-tree build. (#58340) (cherry picked from commit 6a796e069340a98fd0f8288fcacd49d256c282d0) --- test/Makefile | 2 +- test/trimming/Makefile | 27 +++++++++++++++------------ test/trimming/trimming.jl | 7 +++++-- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/test/Makefile b/test/Makefile index 9b151cd213274..69b7ad1451d0f 100644 --- a/test/Makefile +++ b/test/Makefile @@ -24,7 +24,7 @@ EMBEDDING_ARGS := "JULIA=$(JULIA_EXECUTABLE)" "BIN=$(SRCDIR)/embedding" "CC=$(CC GCEXT_ARGS := "JULIA=$(JULIA_EXECUTABLE)" "BIN=$(SRCDIR)/gcext" "CC=$(CC)" -TRIMMING_ARGS := "JULIA=$(JULIA_EXECUTABLE)" "BIN=$(JULIAHOME)/usr/bin" "CC=$(CC)" +TRIMMING_ARGS := "JULIA=$(JULIA_EXECUTABLE)" "BIN=$(SRCDIR)/trimming" "CC=$(CC)" default: diff --git a/test/trimming/Makefile b/test/trimming/Makefile index 63114a2764570..e3c7536bbc92c 100644 --- a/test/trimming/Makefile +++ b/test/trimming/Makefile @@ -16,7 +16,6 @@ endif # location of test source SRCDIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) JULIAHOME := $(abspath $(SRCDIR)/../..) -BUILDSCRIPT := $(BIN)/../share/julia/juliac-buildscript.jl include $(JULIAHOME)/Make.inc # get the executable suffix, if any @@ -24,32 +23,36 @@ EXE := $(suffix $(abspath $(JULIA))) # get compiler and linker flags. (see: `contrib/julia-config.jl`) JULIA_CONFIG := $(JULIA) -e 'include(joinpath(Sys.BINDIR, Base.DATAROOTDIR, "julia", "julia-config.jl"))' -- +JULIA_LIBDIR := $(shell $(JULIA) -e 'println(joinpath(Sys.BINDIR, "..", "lib"))' --) CPPFLAGS_ADD := CFLAGS_ADD = $(shell $(JULIA_CONFIG) --cflags) LDFLAGS_ADD = -lm $(shell $(JULIA_CONFIG) --ldflags --ldlibs) -ljulia-internal +# get the JuliaC build script +JULIAC_BUILDSCRIPT := $(shell $(JULIA) -e 'print(joinpath(Sys.BINDIR, Base.DATAROOTDIR, "julia", "juliac-buildscript.jl"))') + #============================================================================= -release: hello$(EXE) basic_jll$(EXE) +release: $(BIN)/hello$(EXE) $(BIN)/basic_jll$(EXE) -hello-o.a: $(SRCDIR)/hello.jl $(BUILDSCRIPT) - $(JULIA) -t 1 -J $(BIN)/../lib/julia/sys.$(SHLIB_EXT) --startup-file=no --history-file=no --output-o $@ --output-incremental=no --strip-ir --strip-metadata --experimental --trim $(BUILDSCRIPT) $< --output-exe true +$(BIN)/hello-o.a: $(SRCDIR)/hello.jl $(JULIAC_BUILDSCRIPT) + $(JULIA) -t 1 -J $(JULIA_LIBDIR)/julia/sys.$(SHLIB_EXT) --startup-file=no --history-file=no --output-o $@ --output-incremental=no --strip-ir --strip-metadata --experimental --trim $(JULIAC_BUILDSCRIPT) $< --output-exe true -basic_jll-o.a: $(SRCDIR)/basic_jll.jl $(BUILDSCRIPT) - $(JULIA) -t 1 -J $(BIN)/../lib/julia/sys.$(SHLIB_EXT) --startup-file=no --history-file=no --project=$(SRCDIR) -e "using Pkg; Pkg.instantiate()" - $(JULIA) -t 1 -J $(BIN)/../lib/julia/sys.$(SHLIB_EXT) --startup-file=no --history-file=no --project=$(SRCDIR) --output-o $@ --output-incremental=no --strip-ir --strip-metadata --experimental --trim $(BUILDSCRIPT) $< --output-exe true +$(BIN)/basic_jll-o.a: $(SRCDIR)/basic_jll.jl $(JULIAC_BUILDSCRIPT) + $(JULIA) -t 1 -J $(JULIA_LIBDIR)/julia/sys.$(SHLIB_EXT) --startup-file=no --history-file=no --project=$(SRCDIR) -e "using Pkg; Pkg.instantiate()" + $(JULIA) -t 1 -J $(JULIA_LIBDIR)/julia/sys.$(SHLIB_EXT) --startup-file=no --history-file=no --project=$(SRCDIR) --output-o $@ --output-incremental=no --strip-ir --strip-metadata --experimental --trim $(JULIAC_BUILDSCRIPT) $< --output-exe true -hello$(EXE): hello-o.a +$(BIN)/hello$(EXE): $(BIN)/hello-o.a $(CC) -o $@ $(WHOLE_ARCHIVE) $< $(NO_WHOLE_ARCHIVE) $(CPPFLAGS_ADD) $(CPPFLAGS) $(CFLAGS_ADD) $(CFLAGS) $(LDFLAGS_ADD) $(LDFLAGS) -basic_jll$(EXE): basic_jll-o.a +$(BIN)/basic_jll$(EXE): $(BIN)/basic_jll-o.a $(CC) -o $@ $(WHOLE_ARCHIVE) $< $(NO_WHOLE_ARCHIVE) $(CPPFLAGS_ADD) $(CPPFLAGS) $(CFLAGS_ADD) $(CFLAGS) $(LDFLAGS_ADD) $(LDFLAGS) -check: hello$(EXE) basic_jll$(EXE) - $(JULIA) --depwarn=error $(SRCDIR)/../runtests.jl $(SRCDIR)/trimming +check: $(BIN)/hello$(EXE) $(BIN)/basic_jll$(EXE) + $(JULIA) --depwarn=error $(SRCDIR)/trimming.jl $< clean: - -rm -f hello$(EXE) basic_jll$(EXE) hello-o.a basic_jll-o.a + -rm -f $(BIN)/hello$(EXE) $(BIN)/basic_jll$(EXE) $(BIN)/hello-o.a $(BIN)/basic_jll-o.a .PHONY: release clean check diff --git a/test/trimming/trimming.jl b/test/trimming/trimming.jl index a752c69460ad4..e6e1eec7b8da4 100644 --- a/test/trimming/trimming.jl +++ b/test/trimming/trimming.jl @@ -1,12 +1,15 @@ using Test +@test length(ARGS) == 1 +bindir = dirname(ARGS[1]) + let exe_suffix = splitext(Base.julia_exename())[2] - hello_exe = joinpath(@__DIR__, "hello" * exe_suffix) + hello_exe = joinpath(bindir, "hello" * exe_suffix) @test readchomp(`$hello_exe`) == "Hello, world!" @test filesize(hello_exe) < 2000000 - basic_jll_exe = joinpath(@__DIR__, "basic_jll" * exe_suffix) + basic_jll_exe = joinpath(bindir, "basic_jll" * exe_suffix) lines = split(readchomp(`$basic_jll_exe`), "\n") @test lines[1] == "Julia! Hello, world!" @test lines[2] == lines[3] From 7ad297432fc91292b048238d4176d7f5dd44d3a2 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Thu, 22 May 2025 16:18:31 -0400 Subject: [PATCH 48/83] use `@main` for juliac executable entry point (#57588) Use at-main mechanism in juliac executables. Also add support for command line arguments. I changed `Core.ARGS` from a `Vector{Any}` to a `Vector{String}`. I don't know why we didn't do that years ago. Surely this is ok? (cherry picked from commit d9c8c42ad3fc54fa20f56886ad133a0c02729c7a) --- contrib/juliac-buildscript.jl | 42 ++++++++++++++++++++++++++--------- src/gf.c | 2 -- src/jlapi.c | 34 +++++++++++++++------------- src/julia.h | 2 +- test/trimming/basic_jll.jl | 6 +---- test/trimming/hello.jl | 7 ++---- test/trimming/trimming.jl | 4 ++-- 7 files changed, 56 insertions(+), 41 deletions(-) diff --git a/contrib/juliac-buildscript.jl b/contrib/juliac-buildscript.jl index 4bfbfd2272220..1697ed3fd1f03 100644 --- a/contrib/juliac-buildscript.jl +++ b/contrib/juliac-buildscript.jl @@ -1,9 +1,5 @@ # Script to run in the process that generates juliac's object file output -inputfile = ARGS[1] -output_type = ARGS[2] -add_ccallables = ARGS[3] == "true" - # Run the verifier in the current world (before modifications), so that error # messages and types print in their usual way. Core.Compiler._verify_trim_world_age[] = Base.get_world_counter() @@ -189,13 +185,37 @@ end import Base.Experimental.entrypoint -let mod = Base.include(Base.__toplevel__, inputfile) - if !isa(mod, Module) - mod = Main - end +# for use as C main if needed +function _main(argc::Cint, argv::Ptr{Ptr{Cchar}})::Cint + args = ccall(:jl_set_ARGS, Any, (Cint, Ptr{Ptr{Cchar}}), argc, argv)::Vector{String} + return Main.main(args) +end + +let mod = Base.include(Main, ARGS[1]) Core.@latestworld - if output_type == "--output-exe" && isdefined(mod, :main) && !add_ccallables - entrypoint(mod.main, ()) + if ARGS[2] == "--output-exe" + have_cmain = false + if isdefined(Main, :main) + for m in methods(Main.main) + if isdefined(m, :ccallable) + # TODO: possibly check signature and return type + have_cmain = true + break + end + end + end + if !have_cmain + if Base.should_use_main_entrypoint() + if hasmethod(Main.main, Tuple{Vector{String}}) + entrypoint(_main, (Cint, Ptr{Ptr{Cchar}})) + Base._ccallable("main", Cint, Tuple{typeof(_main), Cint, Ptr{Ptr{Cchar}}}) + else + error("`@main` must accept a `Vector{String}` argument.") + end + else + error("To generate an executable a `@main` function must be defined.") + end + end end #entrypoint(join, (Base.GenericIOBuffer{Memory{UInt8}}, Array{Base.SubString{String}, 1}, String)) #entrypoint(join, (Base.GenericIOBuffer{Memory{UInt8}}, Array{String, 1}, Char)) @@ -204,7 +224,7 @@ let mod = Base.include(Base.__toplevel__, inputfile) entrypoint(Base.wait_forever, ()) entrypoint(Base.trypoptask, (Base.StickyWorkqueue,)) entrypoint(Base.checktaskempty, ()) - if add_ccallables + if ARGS[3] == "true" ccall(:jl_add_ccallable_entrypoints, Cvoid, ()) end end diff --git a/src/gf.c b/src/gf.c index dbe90dd9ab914..1ca55a62ffc1a 100644 --- a/src/gf.c +++ b/src/gf.c @@ -4840,8 +4840,6 @@ JL_DLLEXPORT void jl_extern_c(jl_value_t *name, jl_value_t *declrt, jl_tupletype jl_error("@ccallable: function object must be a singleton"); // compute / validate return type - if (!jl_is_concrete_type(declrt) || jl_is_kind(declrt)) - jl_error("@ccallable: return type must be concrete and correspond to a C type"); if (!jl_type_mappable_to_c(declrt)) jl_error("@ccallable: return type doesn't correspond to a C type"); diff --git a/src/jlapi.c b/src/jlapi.c index 0290f12cb1de9..e127fd1367816 100644 --- a/src/jlapi.c +++ b/src/jlapi.c @@ -50,24 +50,28 @@ JL_DLLEXPORT int jl_is_initialized(void) * @param argc The number of command line arguments. * @param argv Array of command line arguments. */ -JL_DLLEXPORT void jl_set_ARGS(int argc, char **argv) +JL_DLLEXPORT jl_value_t *jl_set_ARGS(int argc, char **argv) { - if (jl_core_module != NULL) { - jl_array_t *args = (jl_array_t*)jl_get_global(jl_core_module, jl_symbol("ARGS")); - if (args == NULL) { - args = jl_alloc_vec_any(0); - JL_GC_PUSH1(&args); + jl_array_t *args = NULL; + jl_value_t *vecstr = NULL; + JL_GC_PUSH2(&args, &vecstr); + if (jl_core_module != NULL) + args = (jl_array_t*)jl_get_global(jl_core_module, jl_symbol("ARGS")); + if (args == NULL) { + vecstr = jl_apply_array_type((jl_value_t*)jl_string_type, 1); + args = jl_alloc_array_1d(vecstr, 0); + if (jl_core_module != NULL) jl_set_const(jl_core_module, jl_symbol("ARGS"), (jl_value_t*)args); - JL_GC_POP(); - } - assert(jl_array_nrows(args) == 0); - jl_array_grow_end(args, argc); - int i; - for (i = 0; i < argc; i++) { - jl_value_t *s = (jl_value_t*)jl_cstr_to_string(argv[i]); - jl_array_ptr_set(args, i, s); - } } + assert(jl_array_nrows(args) == 0); + jl_array_grow_end(args, argc); + int i; + for (i = 0; i < argc; i++) { + jl_value_t *s = (jl_value_t*)jl_cstr_to_string(argv[i]); + jl_array_ptr_set(args, i, s); + } + JL_GC_POP(); + return (jl_value_t*)args; } JL_DLLEXPORT void jl_init_with_image_handle(void *handle) { diff --git a/src/julia.h b/src/julia.h index 9d4d509e067f7..e4d177f620c45 100644 --- a/src/julia.h +++ b/src/julia.h @@ -2619,7 +2619,7 @@ uint64_t parse_heap_size_hint(const char *optarg, const char *option_name); // Set julia-level ARGS array according to the arguments provided in // argc/argv -JL_DLLEXPORT void jl_set_ARGS(int argc, char **argv); +JL_DLLEXPORT jl_value_t *jl_set_ARGS(int argc, char **argv); JL_DLLEXPORT int jl_generating_output(void) JL_NOTSAFEPOINT; diff --git a/test/trimming/basic_jll.jl b/test/trimming/basic_jll.jl index 1cc1906d77bda..b4b5ec2e92320 100644 --- a/test/trimming/basic_jll.jl +++ b/test/trimming/basic_jll.jl @@ -1,5 +1,3 @@ -module MyApp - using Libdl using Zstd_jll @@ -11,7 +9,7 @@ function print_string(fptr::Ptr{Cvoid}) println(Core.stdout, unsafe_string(ccall(fptr, Cstring, ()))) end -Base.@ccallable function main()::Cint +function @main(args::Vector{String})::Cint # Test the basic "Hello, world!" println(Core.stdout, "Julia! Hello, world!") @@ -27,5 +25,3 @@ Base.@ccallable function main()::Cint return 0 end - -end diff --git a/test/trimming/hello.jl b/test/trimming/hello.jl index fef25f9e8558f..579ef4e18de38 100644 --- a/test/trimming/hello.jl +++ b/test/trimming/hello.jl @@ -1,13 +1,10 @@ -module MyApp - world::String = "world!" const str = OncePerProcess{String}() do return "Hello, " * world end -Base.@ccallable function main()::Cint +function @main(args::Vector{String})::Cint println(Core.stdout, str()) + foreach(x->println(Core.stdout, x), args) return 0 end - -end diff --git a/test/trimming/trimming.jl b/test/trimming/trimming.jl index e6e1eec7b8da4..5d55ed62b03a8 100644 --- a/test/trimming/trimming.jl +++ b/test/trimming/trimming.jl @@ -6,8 +6,8 @@ bindir = dirname(ARGS[1]) let exe_suffix = splitext(Base.julia_exename())[2] hello_exe = joinpath(bindir, "hello" * exe_suffix) - @test readchomp(`$hello_exe`) == "Hello, world!" - @test filesize(hello_exe) < 2000000 + @test readchomp(`$hello_exe arg1 arg2`) == "Hello, world!\n$hello_exe\narg1\narg2" + @test filesize(hello_exe) < 2_000_000 basic_jll_exe = joinpath(bindir, "basic_jll" * exe_suffix) lines = split(readchomp(`$basic_jll_exe`), "\n") From 60980973c5520a74108c044ecd2ee9ce445e405a Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Wed, 25 Jun 2025 14:08:41 -0400 Subject: [PATCH 49/83] codegen: ensure safepoint functions can read the pgcstack (#58804) This needs to be readOnly over all memory, since GC could read anything (especially pgcstack), and which is not just argmem:read, but also the pointer accessed from argmem that is read from. Fix #58801 Note that this is thought not to be a problem for CleanupWriteBarriers, since while that does read the previously-inaccessibleMemOnly state, these functions are not marked nosync, so as long as the global state can be read, it also must be assumed that it might observe another thread has written to any global state. (cherry picked from commit c7a092a9c44956554d1609c0771481f85e2b5bb4) --- src/codegen.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index 36255a767ea14..2dfcdd39aa665 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -654,7 +654,7 @@ static AttributeList get_attrs_box_float(LLVMContext &C, unsigned nbytes) auto FnAttrs = AttrBuilder(C); FnAttrs.addAttribute(Attribute::WillReturn); FnAttrs.addAttribute(Attribute::NoUnwind); - FnAttrs.addMemoryAttr(MemoryEffects::inaccessibleMemOnly()); + FnAttrs.addMemoryAttr(MemoryEffects::inaccessibleMemOnly() | MemoryEffects::readOnly()); auto RetAttrs = AttrBuilder(C); RetAttrs.addAttribute(Attribute::NonNull); RetAttrs.addDereferenceableAttr(nbytes); @@ -670,7 +670,7 @@ static AttributeList get_attrs_box_sext(LLVMContext &C, unsigned nbytes) auto FnAttrs = AttrBuilder(C); FnAttrs.addAttribute(Attribute::WillReturn); FnAttrs.addAttribute(Attribute::NoUnwind); - FnAttrs.addMemoryAttr(MemoryEffects::inaccessibleMemOnly()); + FnAttrs.addMemoryAttr(MemoryEffects::inaccessibleMemOnly() | MemoryEffects::readOnly()); auto RetAttrs = AttrBuilder(C); RetAttrs.addAttribute(Attribute::NonNull); RetAttrs.addAttribute(Attribute::getWithDereferenceableBytes(C, nbytes)); @@ -687,7 +687,7 @@ static AttributeList get_attrs_box_zext(LLVMContext &C, unsigned nbytes) auto FnAttrs = AttrBuilder(C); FnAttrs.addAttribute(Attribute::WillReturn); FnAttrs.addAttribute(Attribute::NoUnwind); - FnAttrs.addMemoryAttr(MemoryEffects::inaccessibleMemOnly()); + FnAttrs.addMemoryAttr(MemoryEffects::inaccessibleMemOnly() | MemoryEffects::readOnly()); auto RetAttrs = AttrBuilder(C); RetAttrs.addAttribute(Attribute::NonNull); RetAttrs.addDereferenceableAttr(nbytes); @@ -1138,7 +1138,7 @@ static const auto jl_alloc_obj_func = new JuliaFunction{ auto FnAttrs = AttrBuilder(C); FnAttrs.addAllocSizeAttr(1, None); // returns %1 bytes FnAttrs.addAllocKindAttr(AllocFnKind::Alloc); - FnAttrs.addMemoryAttr(MemoryEffects::argMemOnly(ModRefInfo::Ref) | MemoryEffects::inaccessibleMemOnly(ModRefInfo::ModRef)); + FnAttrs.addMemoryAttr(MemoryEffects::argMemOnly(ModRefInfo::Ref) | MemoryEffects::inaccessibleMemOnly()); FnAttrs.addAttribute(Attribute::WillReturn); FnAttrs.addAttribute(Attribute::NoUnwind); auto RetAttrs = AttrBuilder(C); @@ -1162,7 +1162,7 @@ static const auto jl_alloc_genericmemory_unchecked_func = new JuliaFunction{ }, [](LLVMContext &C) { AttrBuilder FnAttrs(C); - FnAttrs.addMemoryAttr(MemoryEffects::inaccessibleMemOnly()); + FnAttrs.addMemoryAttr(MemoryEffects::inaccessibleMemOnly() | MemoryEffects::readOnly()); FnAttrs.addAttribute(Attribute::WillReturn); FnAttrs.addAttribute(Attribute::NoUnwind); return AttributeList::get(C, From 08f6ee95398399a967c3794caa3a670b5e301939 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Fri, 27 Jun 2025 11:58:03 -0400 Subject: [PATCH 50/83] codegen: gc wb for atomic FCA stores (#58792) Need to re-load the correct `r` since issetfield skips the intcast, resulting in no gc wb for the FCA. Fix #58760 (cherry picked from commit 309b1b158f59485772d5f5fe0a762f20185cf799) --- Compiler/test/codegen.jl | 6 ++++++ src/cgutils.cpp | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/Compiler/test/codegen.jl b/Compiler/test/codegen.jl index 7c985727d001f..be2df190764a0 100644 --- a/Compiler/test/codegen.jl +++ b/Compiler/test/codegen.jl @@ -1058,3 +1058,9 @@ let io = IOBuffer() str = String(take!(io)) @test !occursin("jtbaa_unionselbyte", str) end + +let io = IOBuffer() + code_llvm(io, (x, y) -> (@atomic x[1] = y; nothing), (AtomicMemory{Pair{Any,Any}}, Pair{Any,Any},), raw=true, optimize=false) + str = String(take!(io)) + @test occursin("julia.write_barrier", str) +end diff --git a/src/cgutils.cpp b/src/cgutils.cpp index a4618a32e1d7c..78b6571692163 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -2641,6 +2641,11 @@ static jl_cgval_t typed_store(jl_codectx_t &ctx, ctx.builder.CreateStore(r, intcast); r = ctx.builder.CreateLoad(intcast_eltyp, intcast); } + else if (!isboxed && intcast_eltyp) { + assert(issetfield); + // issetfield doesn't use intcast, so need to reload rhs with the correct type + r = emit_unbox(ctx, intcast_eltyp, rhs, jltype); + } if (!isboxed) emit_write_multibarrier(ctx, parent, r, rhs.typ); else From b6086529b8b46a3c7cb08e7ea4695be622431d8d Mon Sep 17 00:00:00 2001 From: K Pamnany Date: Tue, 17 Jun 2025 10:55:48 -0400 Subject: [PATCH 51/83] Revert "Scheduler: Use a "scheduler" task for thread sleep (#57544)" This reverts commit 640c4e1b5fd11c3b485c6982a90c06cd65cc9717. --- base/task.jl | 50 +++++++++------------------------ stdlib/Sockets/test/runtests.jl | 4 ++- test/channels.jl | 5 ++-- 3 files changed, 19 insertions(+), 40 deletions(-) diff --git a/base/task.jl b/base/task.jl index e33a7e4efddf6..951e980ee903c 100644 --- a/base/task.jl +++ b/base/task.jl @@ -1145,16 +1145,6 @@ function throwto(t::Task, @nospecialize exc) return try_yieldto(identity) end -@inline function wait_forever() - while true - wait() - end -end - -const get_sched_task = OncePerThread{Task}() do - Task(wait_forever) -end - function ensure_rescheduled(othertask::Task) ct = current_task() W = workqueue_for(Threads.threadid()) @@ -1191,39 +1181,25 @@ end checktaskempty = Partr.multiq_check_empty +@noinline function poptask(W::StickyWorkqueue) + task = trypoptask(W) + if !(task isa Task) + task = ccall(:jl_task_get_next, Ref{Task}, (Any, Any, Any), trypoptask, W, checktaskempty) + end + set_next_task(task) + nothing +end + function wait() ct = current_task() # [task] user_time -yield-or-done-> wait_time record_running_time!(ct) - # let GC run GC.safepoint() - # check for libuv events - process_events() - - # get the next task to run - result = nothing - have_result = false W = workqueue_for(Threads.threadid()) - task = trypoptask(W) - if !(task isa Task) - # No tasks to run; switch to the scheduler task to run the - # thread sleep logic. - sched_task = get_sched_task() - if ct !== sched_task - result = yieldto(sched_task) - have_result = true - else - task = ccall(:jl_task_get_next, Ref{Task}, (Any, Any, Any), - trypoptask, W, checktaskempty) - end - end - # We may have already switched tasks (via the scheduler task), so - # only switch if we haven't. - if !have_result - @assert task isa Task - set_next_task(task) - result = try_yieldto(ensure_rescheduled) - end + poptask(W) + result = try_yieldto(ensure_rescheduled) + process_events() + # return when we come out of the queue return result end diff --git a/stdlib/Sockets/test/runtests.jl b/stdlib/Sockets/test/runtests.jl index 5a822315ba2cd..26f95d4ce1819 100644 --- a/stdlib/Sockets/test/runtests.jl +++ b/stdlib/Sockets/test/runtests.jl @@ -547,12 +547,14 @@ end fetch(r) end - let addr = Sockets.InetAddr(ip"192.0.2.5", 4444) + let addr = Sockets.InetAddr(ip"127.0.0.1", 4444) + srv = listen(addr) s = Sockets.TCPSocket() Sockets.connect!(s, addr) r = @async close(s) @test_throws Base._UVError("connect", Base.UV_ECANCELED) Sockets.wait_connected(s) fetch(r) + close(srv) end end diff --git a/test/channels.jl b/test/channels.jl index 721eb478bd13a..f646b41cfa1a0 100644 --- a/test/channels.jl +++ b/test/channels.jl @@ -463,14 +463,15 @@ end cb = first(async.cond.waitq) @test isopen(async) ccall(:uv_async_send, Cvoid, (Ptr{Cvoid},), async) + ccall(:uv_async_send, Cvoid, (Ptr{Cvoid},), async) + @test isempty(Base.Workqueue) Base.process_events() # schedule event Sys.iswindows() && Base.process_events() # schedule event (windows?) + @test length(Base.Workqueue) == 1 ccall(:uv_async_send, Cvoid, (Ptr{Cvoid},), async) @test tc[] == 0 yield() # consume event @test tc[] == 1 - ccall(:uv_async_send, Cvoid, (Ptr{Cvoid},), async) - Base.process_events() Sys.iswindows() && Base.process_events() # schedule event (windows?) yield() # consume event @test tc[] == 2 From ddae588929f0b0d4a5dc0e6c112ffbca922d59c3 Mon Sep 17 00:00:00 2001 From: Cody Tapscott <84105208+topolarity@users.noreply.github.com> Date: Mon, 30 Jun 2025 08:09:32 -0400 Subject: [PATCH 52/83] libuv: Mark `(un)preserve_handle` as `@nospecialize` (#58844) These functions only worry about object identity, so there's no need for them to specialize them on their type. (cherry picked from commit 8caacdb69e3a9d649016d95bd032a8bd17ad4992) --- base/libuv.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/base/libuv.jl b/base/libuv.jl index 35b1a9097293e..8f066971a639d 100644 --- a/base/libuv.jl +++ b/base/libuv.jl @@ -39,7 +39,7 @@ macro handle_as(hand, typ) end end -associate_julia_struct(handle::Ptr{Cvoid}, @nospecialize(jlobj)) = +@nospecializeinfer associate_julia_struct(handle::Ptr{Cvoid}, @nospecialize(jlobj)) = ccall(:jl_uv_associate_julia_struct, Cvoid, (Ptr{Cvoid}, Any), handle, jlobj) disassociate_julia_struct(uv) = disassociate_julia_struct(uv.handle) disassociate_julia_struct(handle::Ptr{Cvoid}) = @@ -52,14 +52,14 @@ iolock_end() = ccall(:jl_iolock_end, Cvoid, ()) # and should thus not be garbage collected const uvhandles = IdDict() const preserve_handle_lock = Threads.SpinLock() -function preserve_handle(x) +@nospecializeinfer function preserve_handle(@nospecialize(x)) lock(preserve_handle_lock) v = get(uvhandles, x, 0)::Int uvhandles[x] = v + 1 unlock(preserve_handle_lock) nothing end -function unpreserve_handle(x) +@nospecializeinfer function unpreserve_handle(@nospecialize(x)) lock(preserve_handle_lock) v = get(uvhandles, x, 0)::Int if v == 0 From e3ef824e9d306ae91fc95e8cb25fe9f956ee2f98 Mon Sep 17 00:00:00 2001 From: Cody Tapscott Date: Mon, 30 Jun 2025 20:30:14 -0400 Subject: [PATCH 53/83] Fix broken `--trim` test due to `640c4e1` revert --- contrib/juliac-buildscript.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/juliac-buildscript.jl b/contrib/juliac-buildscript.jl index 1697ed3fd1f03..e71297ef8c847 100644 --- a/contrib/juliac-buildscript.jl +++ b/contrib/juliac-buildscript.jl @@ -221,7 +221,7 @@ let mod = Base.include(Main, ARGS[1]) #entrypoint(join, (Base.GenericIOBuffer{Memory{UInt8}}, Array{String, 1}, Char)) entrypoint(Base.task_done_hook, (Task,)) entrypoint(Base.wait, ()) - entrypoint(Base.wait_forever, ()) + entrypoint(Base.poptask, (Base.StickyWorkqueue,)) entrypoint(Base.trypoptask, (Base.StickyWorkqueue,)) entrypoint(Base.checktaskempty, ()) if ARGS[3] == "true" From e35e82bc306aa24f995f02521e0101c2d5ab1cb4 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 2 Jun 2025 14:45:27 -0400 Subject: [PATCH 54/83] fix `@invokelatest` performance regression (#58582) A bit of hacking to get back near to the same performance as before by using the GlobalRef to optimize the getglobal lookup for now and avoiding the extra Vararg function indirection which forced some extra boxing and lookups. julia> @btime foo(1.5) 22.892 ns (1 allocation: 16 bytes) # v1.11 141.543 ns (3 allocations: 48 bytes) # master 38.759 ns (2 allocations: 32 bytes) # PR The remaining difference is split about equally between the need now to box the world counter value for invoke_in_world and the extra cost of scanning the partition table for `Base.sin` to find the current entry. Fix #58334 (cherry picked from commit f12256bb545a4e7bc81bb1235b3ecf1115b7497d) --- base/reflection.jl | 11 ++++++----- src/builtins.c | 2 +- src/gf.c | 6 +++--- src/init.c | 4 ++-- src/interpreter.c | 12 ++++++------ src/jl_uv.c | 3 ++- src/jlapi.c | 2 +- src/jltypes.c | 1 + src/julia.h | 2 -- src/julia_internal.h | 5 ++++- src/module.c | 12 ++++++------ src/precompile.c | 4 ++-- src/rtutils.c | 5 +++-- src/scheduler.c | 2 +- src/staticdata_utils.c | 14 +++++++------- src/task.c | 2 +- src/threading.c | 2 +- src/toplevel.c | 43 ++++++++++++++++++++++-------------------- 18 files changed, 70 insertions(+), 62 deletions(-) diff --git a/base/reflection.jl b/base/reflection.jl index 406b14f48c3da..c3766447f87fe 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -1269,16 +1269,17 @@ macro invoke(ex) return esc(out) end -apply_gr(gr::GlobalRef, @nospecialize args...) = getglobal(gr.mod, gr.name)(args...) -apply_gr_kw(@nospecialize(kwargs::NamedTuple), gr::GlobalRef, @nospecialize args...) = Core.kwcall(kwargs, getglobal(gr.mod, gr.name), args...) +getglobalref(gr::GlobalRef, world::UInt) = ccall(:jl_eval_globalref, Any, (Any, UInt), gr, world) -function invokelatest_gr(gr::GlobalRef, @nospecialize args...; kwargs...) +function invokelatest_gr(gr::GlobalRef, args...; kwargs...) @inline kwargs = merge(NamedTuple(), kwargs) + world = get_world_counter() + f = getglobalref(gr, world) if isempty(kwargs) - return invokelatest(apply_gr, gr, args...) + return invoke_in_world(world, f, args...) end - return invokelatest(apply_gr_kw, kwargs, gr, args...) + return invoke_in_world(world, Core.kwcall, kwargs, f, args...) end """ diff --git a/src/builtins.c b/src/builtins.c index 641f54a5fde28..d68c7fc21ec40 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -1338,7 +1338,7 @@ JL_CALLABLE(jl_f_getglobal) jl_atomic_error("getglobal: module binding cannot be read non-atomically"); else if (order >= jl_memory_order_seq_cst) jl_fence(); - jl_value_t *v = jl_eval_global_var(mod, sym); // relaxed load + jl_value_t *v = jl_eval_global_var(mod, sym, jl_current_task->world_age); // relaxed load if (order >= jl_memory_order_acquire) jl_fence(); return v; diff --git a/src/gf.c b/src/gf.c index 1ca55a62ffc1a..9429faa9e6226 100644 --- a/src/gf.c +++ b/src/gf.c @@ -513,13 +513,13 @@ JL_DLLEXPORT jl_code_info_t *jl_gdbcodetyped1(jl_method_instance_t *mi, size_t w ct->world_age = jl_typeinf_world; jl_value_t **fargs; JL_GC_PUSHARGS(fargs, 4); - jl_module_t *CC = (jl_module_t*)jl_get_global_value(jl_core_module, jl_symbol("Compiler")); + jl_module_t *CC = (jl_module_t*)jl_get_global_value(jl_core_module, jl_symbol("Compiler"), ct->world_age); if (CC != NULL && jl_is_module(CC)) { JL_GC_PROMISE_ROOTED(CC); - fargs[0] = jl_get_global_value(CC, jl_symbol("NativeInterpreter"));; + fargs[0] = jl_get_global_value(CC, jl_symbol("NativeInterpreter"), ct->world_age); fargs[1] = jl_box_ulong(world); fargs[1] = jl_apply(fargs, 2); - fargs[0] = jl_get_global_value(CC, jl_symbol("typeinf_code")); + fargs[0] = jl_get_global_value(CC, jl_symbol("typeinf_code"), ct->world_age); fargs[2] = (jl_value_t*)mi; fargs[3] = jl_true; ci = (jl_code_info_t*)jl_apply(fargs, 4); diff --git a/src/init.c b/src/init.c index da95cbd006e73..e11b360b5d378 100644 --- a/src/init.c +++ b/src/init.c @@ -249,7 +249,7 @@ JL_DLLEXPORT void jl_atexit_hook(int exitcode) JL_NOTSAFEPOINT_ENTER if (jl_base_module) { size_t last_age = ct->world_age; ct->world_age = jl_get_world_counter(); - jl_value_t *f = jl_get_global_value(jl_base_module, jl_symbol("_atexit")); + jl_value_t *f = jl_get_global_value(jl_base_module, jl_symbol("_atexit"), ct->world_age); if (f != NULL) { jl_value_t **fargs; JL_GC_PUSHARGS(fargs, 2); @@ -357,7 +357,7 @@ JL_DLLEXPORT void jl_postoutput_hook(void) jl_task_t *ct = jl_get_current_task(); size_t last_age = ct->world_age; ct->world_age = jl_get_world_counter(); - jl_value_t *f = jl_get_global_value(jl_base_module, jl_symbol("_postoutput")); + jl_value_t *f = jl_get_global_value(jl_base_module, jl_symbol("_postoutput"), ct->world_age); if (f != NULL) { JL_TRY { JL_GC_PUSH1(&f); diff --git a/src/interpreter.c b/src/interpreter.c index 5df79e77a92c1..57c3e715ffed6 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -162,18 +162,18 @@ static jl_value_t *do_invoke(jl_value_t **args, size_t nargs, interpreter_state } // get the global (throwing if null) in the current world -jl_value_t *jl_eval_global_var(jl_module_t *m, jl_sym_t *e) +jl_value_t *jl_eval_global_var(jl_module_t *m, jl_sym_t *e, size_t world) { - jl_value_t *v = jl_get_global_value(m, e); + jl_value_t *v = jl_get_global_value(m, e, world); if (v == NULL) jl_undefined_var_error(e, (jl_value_t*)m); return v; } // get the global (throwing if null) in the current world, optimized -jl_value_t *jl_eval_globalref(jl_globalref_t *g) +jl_value_t *jl_eval_globalref(jl_globalref_t *g, size_t world) { - jl_value_t *v = jl_get_globalref_value(g); + jl_value_t *v = jl_get_globalref_value(g, world); if (v == NULL) jl_undefined_var_error(g->name, (jl_value_t*)g->mod); return v; @@ -218,10 +218,10 @@ static jl_value_t *eval_value(jl_value_t *e, interpreter_state *s) return jl_quotenode_value(e); } if (jl_is_globalref(e)) { - return jl_eval_globalref((jl_globalref_t*)e); + return jl_eval_globalref((jl_globalref_t*)e, jl_current_task->world_age); } if (jl_is_symbol(e)) { // bare symbols appear in toplevel exprs not wrapped in `thunk` - return jl_eval_global_var(s->module, (jl_sym_t*)e); + return jl_eval_global_var(s->module, (jl_sym_t*)e, jl_current_task->world_age); } if (jl_is_pinode(e)) { jl_value_t *val = eval_value(jl_fieldref_noalloc(e, 0), s); diff --git a/src/jl_uv.c b/src/jl_uv.c index 005d1ea727655..a21b05433b8c6 100644 --- a/src/jl_uv.c +++ b/src/jl_uv.c @@ -162,7 +162,8 @@ static void jl_uv_call_close_callback(jl_value_t *val) JL_GC_PUSHARGS(args, 2); // val is "rooted" in the finalizer list only right now args[0] = jl_eval_global_var( jl_base_relative_to(((jl_datatype_t*)jl_typeof(val))->name->module), - jl_symbol("_uv_hook_close")); // topmod(typeof(val))._uv_hook_close + jl_symbol("_uv_hook_close"), + jl_current_task->world_age); // topmod(typeof(val))._uv_hook_close args[1] = val; jl_apply(args, 2); // TODO: wrap in try-catch? JL_GC_POP(); diff --git a/src/jlapi.c b/src/jlapi.c index e127fd1367816..0d8ddd10d9ea1 100644 --- a/src/jlapi.c +++ b/src/jlapi.c @@ -955,7 +955,7 @@ static NOINLINE int true_main(int argc, char *argv[]) ct->world_age = jl_get_world_counter(); jl_function_t *start_client = jl_base_module ? - (jl_function_t*)jl_get_global_value(jl_base_module, jl_symbol("_start")) : NULL; + (jl_function_t*)jl_get_global_value(jl_base_module, jl_symbol("_start"), ct->world_age) : NULL; if (start_client) { int ret = 1; diff --git a/src/jltypes.c b/src/jltypes.c index 1c574a0fd5956..b8b8bf3e008e9 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -3286,6 +3286,7 @@ void jl_init_types(void) JL_GC_DISABLED jl_perm_symsvec(3, "mod", "name", "binding"), jl_svec(3, jl_module_type, jl_symbol_type, jl_binding_type), jl_emptysvec, 0, 0, 3); + jl_globalref_type->name->mayinlinealloc = 0; // not at all worthwhile, since the only constructor returns a boxed object jl_core_module = jl_new_module(jl_symbol("Core"), NULL); diff --git a/src/julia.h b/src/julia.h index e4d177f620c45..cf6bf6757a1f6 100644 --- a/src/julia.h +++ b/src/julia.h @@ -2117,9 +2117,7 @@ JL_DLLEXPORT jl_value_t *jl_get_existing_strong_gf(jl_binding_t *b JL_PROPAGATES JL_DLLEXPORT int jl_boundp(jl_module_t *m, jl_sym_t *var, int allow_import); JL_DLLEXPORT int jl_is_const(jl_module_t *m, jl_sym_t *var); JL_DLLEXPORT int jl_globalref_is_const(jl_globalref_t *gr); -JL_DLLEXPORT jl_value_t *jl_get_globalref_value(jl_globalref_t *gr); JL_DLLEXPORT jl_value_t *jl_get_global(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var); -JL_DLLEXPORT jl_value_t *jl_get_global_value(jl_module_t *m, jl_sym_t *var); JL_DLLEXPORT void jl_set_global(jl_module_t *m JL_ROOTING_ARGUMENT, jl_sym_t *var, jl_value_t *val JL_ROOTED_ARGUMENT); JL_DLLEXPORT void jl_set_const(jl_module_t *m JL_ROOTING_ARGUMENT, jl_sym_t *var, jl_value_t *val JL_ROOTED_ARGUMENT); void jl_set_initial_const(jl_module_t *m JL_ROOTING_ARGUMENT, jl_sym_t *var, jl_value_t *val JL_ROOTED_ARGUMENT, int exported); diff --git a/src/julia_internal.h b/src/julia_internal.h index affe497df8ff9..3fc5c9642fa29 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -901,7 +901,10 @@ STATIC_INLINE size_t module_usings_max(jl_module_t *m) JL_NOTSAFEPOINT { JL_DLLEXPORT jl_sym_t *jl_module_name(jl_module_t *m) JL_NOTSAFEPOINT; void jl_add_scanned_method(jl_module_t *m, jl_method_t *meth); -jl_value_t *jl_eval_global_var(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *e); +jl_value_t *jl_eval_global_var(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *e, size_t world); +JL_DLLEXPORT jl_value_t *jl_eval_globalref(jl_globalref_t *g, size_t world); +jl_value_t *jl_get_globalref_value(jl_globalref_t *gr, size_t world); +jl_value_t *jl_get_global_value(jl_module_t *m, jl_sym_t *var, size_t world); jl_value_t *jl_interpret_opaque_closure(jl_opaque_closure_t *clos, jl_value_t **args, size_t nargs); jl_value_t *jl_interpret_toplevel_thunk(jl_module_t *m, jl_code_info_t *src); jl_value_t *jl_interpret_toplevel_expr_in(jl_module_t *m, jl_value_t *e, diff --git a/src/module.c b/src/module.c index bcb245cce10e1..b53a5307b5c78 100644 --- a/src/module.c +++ b/src/module.c @@ -1539,20 +1539,20 @@ JL_DLLEXPORT jl_binding_t *jl_get_module_binding(jl_module_t *m, jl_sym_t *var, } -// get the value (or null) in the current world -JL_DLLEXPORT jl_value_t *jl_get_globalref_value(jl_globalref_t *gr) +// get the value (or null) in the world +jl_value_t *jl_get_globalref_value(jl_globalref_t *gr, size_t world) { jl_binding_t *b = gr->binding; if (!b) b = jl_get_module_binding(gr->mod, gr->name, 1); - return jl_get_binding_value_depwarn(b, jl_current_task->world_age); + return jl_get_binding_value_depwarn(b, world); } -// get the value (or null) in the current world -JL_DLLEXPORT jl_value_t *jl_get_global_value(jl_module_t *m, jl_sym_t *var) +// get the value (or null) in the world +jl_value_t *jl_get_global_value(jl_module_t *m, jl_sym_t *var, size_t world) { jl_binding_t *b = jl_get_module_binding(m, var, 1); - return jl_get_binding_value_depwarn(b, jl_current_task->world_age); + return jl_get_binding_value_depwarn(b, world); } // get the global (or null) in the latest world diff --git a/src/precompile.c b/src/precompile.c index a627d102f7dab..8d4e8495fc4bd 100644 --- a/src/precompile.c +++ b/src/precompile.c @@ -45,8 +45,8 @@ void write_srctext(ios_t *f, jl_array_t *udeps, int64_t srctextpos) { size_t last_age = ct->world_age; ct->world_age = jl_atomic_load_acquire(&jl_world_counter); JL_GC_PUSH4(&deptuple, &depots, &replace_depot_func, &normalize_depots_func); - replace_depot_func = jl_eval_global_var(jl_base_module, jl_symbol("replace_depot_path")); - normalize_depots_func = jl_eval_global_var(jl_base_module, jl_symbol("normalize_depots_for_relocation")); + replace_depot_func = jl_eval_global_var(jl_base_module, jl_symbol("replace_depot_path"), jl_current_task->world_age); + normalize_depots_func = jl_eval_global_var(jl_base_module, jl_symbol("normalize_depots_for_relocation"), jl_current_task->world_age); depots = jl_apply(&normalize_depots_func, 1); jl_datatype_t *deptuple_p[5] = {jl_module_type, jl_string_type, jl_uint64_type, jl_uint32_type, jl_float64_type}; jl_value_t *jl_deptuple_type = jl_apply_tuple_type_v((jl_value_t**)deptuple_p, 5); diff --git a/src/rtutils.c b/src/rtutils.c index d5ec8a78b39ce..e3672ab5d887e 100644 --- a/src/rtutils.c +++ b/src/rtutils.c @@ -1596,10 +1596,11 @@ void jl_log(int level, jl_value_t *module, jl_value_t *group, jl_value_t *id, jl_value_t *msg) { jl_value_t *logmsg_func = NULL; + jl_task_t *ct = jl_current_task; if (jl_base_module) { - jl_value_t *corelogging = jl_get_global_value(jl_base_module, jl_symbol("CoreLogging")); + jl_value_t *corelogging = jl_get_global_value(jl_base_module, jl_symbol("CoreLogging"), ct->world_age); if (corelogging && jl_is_module(corelogging)) { - logmsg_func = jl_get_global_value((jl_module_t*)corelogging, jl_symbol("logmsg_shim")); + logmsg_func = jl_get_global_value((jl_module_t*)corelogging, jl_symbol("logmsg_shim"), ct->world_age); } } if (!logmsg_func) { diff --git a/src/scheduler.c b/src/scheduler.c index 8e0202cc7a980..b13e4072c7d73 100644 --- a/src/scheduler.c +++ b/src/scheduler.c @@ -331,7 +331,7 @@ void jl_task_wait_empty(void) jl_wait_empty_begin(); size_t lastage = ct->world_age; ct->world_age = jl_atomic_load_acquire(&jl_world_counter); - jl_value_t *f = jl_get_global_value(jl_base_module, jl_symbol("wait")); + jl_value_t *f = jl_get_global_value(jl_base_module, jl_symbol("wait"), ct->world_age); wait_empty = ct; if (f) { JL_GC_PUSH1(&f); diff --git a/src/staticdata_utils.c b/src/staticdata_utils.c index 3f05de189c3ef..0b8cfc1cf4ebd 100644 --- a/src/staticdata_utils.c +++ b/src/staticdata_utils.c @@ -544,21 +544,21 @@ static int64_t write_dependency_list(ios_t *s, jl_array_t* worklist, jl_array_t jl_value_t *get_compiletime_prefs_func = NULL; JL_GC_PUSH8(&depots, &prefs_list, &unique_func, &replace_depot_func, &normalize_depots_func, &toplevel, &prefs_hash_func, &get_compiletime_prefs_func); - jl_array_t *udeps = (jl_array_t*)jl_get_global_value(jl_base_module, jl_symbol("_require_dependencies")); + jl_array_t *udeps = (jl_array_t*)jl_get_global_value(jl_base_module, jl_symbol("_require_dependencies"), ct->world_age); *udepsp = udeps; // unique(udeps) to eliminate duplicates while preserving order: // we preserve order so that the topmost included .jl file comes first if (udeps) { - unique_func = jl_eval_global_var(jl_base_module, jl_symbol("unique")); + unique_func = jl_eval_global_var(jl_base_module, jl_symbol("unique"), ct->world_age); jl_value_t *uniqargs[2] = {unique_func, (jl_value_t*)udeps}; udeps = (jl_array_t*)jl_apply(uniqargs, 2); *udepsp = udeps; JL_TYPECHK(write_dependency_list, array_any, (jl_value_t*)udeps); } - replace_depot_func = jl_get_global_value(jl_base_module, jl_symbol("replace_depot_path")); - normalize_depots_func = jl_eval_global_var(jl_base_module, jl_symbol("normalize_depots_for_relocation")); + replace_depot_func = jl_get_global_value(jl_base_module, jl_symbol("replace_depot_path"), ct->world_age); + normalize_depots_func = jl_eval_global_var(jl_base_module, jl_symbol("normalize_depots_for_relocation"), ct->world_age); depots = jl_apply(&normalize_depots_func, 1); @@ -616,9 +616,9 @@ static int64_t write_dependency_list(ios_t *s, jl_array_t* worklist, jl_array_t // Calculate Preferences hash for current package. if (jl_base_module) { // Toplevel module is the module we're currently compiling, use it to get our preferences hash - toplevel = jl_get_global_value(jl_base_module, jl_symbol("__toplevel__")); - prefs_hash_func = jl_eval_global_var(jl_base_module, jl_symbol("get_preferences_hash")); - get_compiletime_prefs_func = jl_eval_global_var(jl_base_module, jl_symbol("get_compiletime_preferences")); + toplevel = jl_get_global_value(jl_base_module, jl_symbol("__toplevel__"), ct->world_age); + prefs_hash_func = jl_eval_global_var(jl_base_module, jl_symbol("get_preferences_hash"), ct->world_age); + get_compiletime_prefs_func = jl_eval_global_var(jl_base_module, jl_symbol("get_compiletime_preferences"), ct->world_age); if (toplevel) { // call get_compiletime_prefs(__toplevel__) diff --git a/src/task.c b/src/task.c index c4976b5be0150..019a301b1f062 100644 --- a/src/task.c +++ b/src/task.c @@ -335,7 +335,7 @@ void JL_NORETURN jl_finish_task(jl_task_t *ct) // let the runtime know this task is dead and find a new task to run jl_function_t *done = jl_atomic_load_relaxed(&task_done_hook_func); if (done == NULL) { - done = (jl_function_t*)jl_get_global_value(jl_base_module, jl_symbol("task_done_hook")); + done = (jl_function_t*)jl_get_global_value(jl_base_module, jl_symbol("task_done_hook"), ct->world_age); if (done != NULL) jl_atomic_store_release(&task_done_hook_func, done); } diff --git a/src/threading.c b/src/threading.c index 889a1c651d9c9..0211c9798c8bb 100644 --- a/src/threading.c +++ b/src/threading.c @@ -408,7 +408,7 @@ static void jl_init_task_lock(jl_task_t *ct) ct->world_age = jl_get_world_counter(); jl_function_t *done = jl_atomic_load_relaxed(&init_task_lock_func); if (done == NULL) { - done = (jl_function_t*)jl_get_global_value(jl_base_module, jl_symbol("init_task_lock")); + done = (jl_function_t*)jl_get_global_value(jl_base_module, jl_symbol("init_task_lock"), ct->world_age); if (done != NULL) jl_atomic_store_release(&init_task_lock_func, done); } diff --git a/src/toplevel.c b/src/toplevel.c index 1941be934b810..6398a1bb241ba 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -62,7 +62,7 @@ void jl_module_run_initializer(jl_module_t *m) size_t last_age = ct->world_age; JL_TRY { ct->world_age = jl_atomic_load_acquire(&jl_world_counter); - jl_value_t *f = jl_get_global_value(m, jl_symbol("__init__")); + jl_value_t *f = jl_get_global_value(m, jl_symbol("__init__"), ct->world_age); if (f != NULL) { JL_GC_PUSH1(&f); jl_apply(&f, 1); @@ -104,10 +104,10 @@ jl_array_t *jl_get_loaded_modules(void) return NULL; } -static int jl_is__toplevel__mod(jl_module_t *mod) +static int jl_is__toplevel__mod(jl_module_t *mod, jl_task_t *ct) { return jl_base_module && - (jl_value_t*)mod == jl_get_global_value(jl_base_module, jl_symbol("__toplevel__")); + (jl_value_t*)mod == jl_get_global_value(jl_base_module, jl_symbol("__toplevel__"), ct->world_age); } // TODO: add locks around global state mutation operations @@ -129,7 +129,7 @@ static jl_value_t *jl_eval_module_expr(jl_module_t *parent_module, jl_expr_t *ex jl_type_error("module", (jl_value_t*)jl_symbol_type, (jl_value_t*)name); } - int is_parent__toplevel__ = jl_is__toplevel__mod(parent_module); + int is_parent__toplevel__ = jl_is__toplevel__mod(parent_module, ct); // If we have `Base`, don't also try to import `Core` - the `Base` exports are a superset. // While we allow multiple imports of the same binding from different modules, various error printing // performs reflection on which module a binding came from and we'd prefer users see "Base" here. @@ -245,19 +245,18 @@ static jl_value_t *jl_eval_module_expr(jl_module_t *parent_module, jl_expr_t *ex return (jl_value_t*)newm; } -static jl_value_t *jl_eval_dot_expr(jl_module_t *m, jl_value_t *x, jl_value_t *f, int fast, const char **toplevel_filename, int *toplevel_lineno) +static jl_value_t *jl_eval_dot_expr(jl_task_t *ct, jl_module_t *m, jl_value_t *x, jl_value_t *f, int fast, const char **toplevel_filename, int *toplevel_lineno) { - jl_task_t *ct = jl_current_task; jl_value_t **args; JL_GC_PUSHARGS(args, 3); args[1] = jl_toplevel_eval_flex(m, x, fast, 0, toplevel_filename, toplevel_lineno); args[2] = jl_toplevel_eval_flex(m, f, fast, 0, toplevel_filename, toplevel_lineno); if (jl_is_module(args[1])) { JL_TYPECHK(getglobal, symbol, args[2]); - args[0] = jl_eval_global_var((jl_module_t*)args[1], (jl_sym_t*)args[2]); + args[0] = jl_eval_global_var((jl_module_t*)args[1], (jl_sym_t*)args[2], ct->world_age); } else { - args[0] = jl_eval_global_var(jl_base_relative_to(m), jl_symbol("getproperty")); + args[0] = jl_eval_global_var(jl_base_relative_to(m), jl_symbol("getproperty"), ct->world_age); size_t last_age = ct->world_age; ct->world_age = jl_atomic_load_acquire(&jl_world_counter); args[0] = jl_apply(args, 3); @@ -560,7 +559,7 @@ static jl_module_t *eval_import_path(jl_task_t *ct, jl_module_t *where, jl_modul jl_errorf("invalid %s path: \".\" in identifier path", keyword); if (i == jl_array_nrows(args)-1) break; - m = (jl_module_t*)jl_eval_global_var(m, var); + m = (jl_module_t*)jl_eval_global_var(m, var, ct->world_age); JL_GC_PROMISE_ROOTED(m); if (!jl_is_module(m)) jl_errorf("invalid %s path: \"%s\" does not name a module", keyword, jl_symbol_name(var)); @@ -670,7 +669,7 @@ static jl_module_t *eval_import_from(jl_task_t *ct, jl_module_t *m JL_PROPAGATES jl_sym_t *name = NULL; jl_module_t *from = eval_import_path(ct, m, NULL, path->args, &name, keyword); if (name != NULL) { - from = (jl_module_t*)jl_eval_global_var(from, name); + from = (jl_module_t*)jl_eval_global_var(from, name, ct->world_age); if (!from || !jl_is_module(from)) jl_errorf("invalid %s path: \"%s\" does not name a module", keyword, jl_symbol_name(name)); } @@ -755,6 +754,16 @@ JL_DLLEXPORT void jl_eval_const_decl(jl_module_t *m, jl_value_t *arg, jl_value_t JL_DLLEXPORT jl_value_t *jl_toplevel_eval_flex(jl_module_t *JL_NONNULL m, jl_value_t *e, int fast, int expanded, const char **toplevel_filename, int *toplevel_lineno) { jl_task_t *ct = jl_current_task; + if (jl_is_globalref(e)) { + return jl_eval_globalref((jl_globalref_t*)e, ct->world_age); + } + if (jl_is_symbol(e)) { + char *n = jl_symbol_name((jl_sym_t*)e), *n0 = n; + while (*n == '_') ++n; + if (*n == 0 && n > n0) + jl_eval_errorf(m, *toplevel_filename, *toplevel_lineno, "all-underscore identifiers are write-only and their values cannot be used in expressions"); + return jl_eval_global_var(m, (jl_sym_t*)e, ct->world_age); + } if (!jl_is_expr(e)) { if (jl_is_linenode(e)) { *toplevel_lineno = jl_linenode_line(e); @@ -768,12 +777,6 @@ JL_DLLEXPORT jl_value_t *jl_toplevel_eval_flex(jl_module_t *JL_NONNULL m, jl_val jl_lineno = *toplevel_lineno; return jl_nothing; } - if (jl_is_symbol(e)) { - char *n = jl_symbol_name((jl_sym_t*)e), *n0 = n; - while (*n == '_') ++n; - if (*n == 0 && n > n0) - jl_eval_errorf(m, *toplevel_filename, *toplevel_lineno, "all-underscore identifiers are write-only and their values cannot be used in expressions"); - } return jl_interpret_toplevel_expr_in(m, e, NULL, NULL); } @@ -786,7 +789,7 @@ JL_DLLEXPORT jl_value_t *jl_toplevel_eval_flex(jl_module_t *JL_NONNULL m, jl_val jl_value_t *rhs = jl_exprarg(ex, 1); // only handle `a.b` syntax here, so qualified names can be eval'd in pure contexts if (jl_is_quotenode(rhs) && jl_is_symbol(jl_fieldref(rhs, 0))) { - return jl_eval_dot_expr(m, lhs, rhs, fast, toplevel_filename, toplevel_lineno); + return jl_eval_dot_expr(ct, m, lhs, rhs, fast, toplevel_filename, toplevel_lineno); } } @@ -832,7 +835,7 @@ JL_DLLEXPORT jl_value_t *jl_toplevel_eval_flex(jl_module_t *JL_NONNULL m, jl_val else { jl_module_t *u = import; if (name != NULL) - u = (jl_module_t*)jl_eval_global_var(import, name); + u = (jl_module_t*)jl_eval_global_var(import, name, ct->world_age); if (!jl_is_module(u)) jl_eval_errorf(m, *toplevel_filename, *toplevel_lineno, "invalid using path: \"%s\" does not name a module", @@ -986,7 +989,7 @@ JL_DLLEXPORT jl_value_t *jl_toplevel_eval_flex(jl_module_t *JL_NONNULL m, jl_val } else if (jl_is_symbol(ex)) { JL_GC_POP(); - return jl_eval_global_var(m, (jl_sym_t*)ex); + return jl_eval_global_var(m, (jl_sym_t*)ex, ct->world_age); } else if (head == NULL) { JL_GC_POP(); @@ -1063,7 +1066,7 @@ JL_DLLEXPORT void jl_check_top_level_effect(jl_module_t *m, char *fname) } } JL_UNLOCK(&jl_modules_mutex); - if (!open && !jl_is__toplevel__mod(m)) { + if (!open && !jl_is__toplevel__mod(m, jl_current_task)) { const char* name = jl_symbol_name(m->name); jl_errorf("Evaluation into the closed module `%s` breaks incremental compilation " "because the side effects will not be permanent. " From 7e16e14a194c01341db81a3ea31b77d3b7f119ed Mon Sep 17 00:00:00 2001 From: Gabriel Baraldi Date: Tue, 10 Jun 2025 16:49:55 -0300 Subject: [PATCH 55/83] Add 0 predecessor to entry basic block and handle it in inlining (#58683) (cherry picked from commit da004516e7b53a5cfd264170fcb3ea33f9ea0bc6) --- Compiler/src/ssair/inlining.jl | 19 +++++++++++-------- Compiler/src/ssair/ir.jl | 3 +++ Compiler/test/ssair.jl | 20 ++++++++++++++++++++ 3 files changed, 34 insertions(+), 8 deletions(-) diff --git a/Compiler/src/ssair/inlining.jl b/Compiler/src/ssair/inlining.jl index 120b891f09a9f..f5fd8c8882649 100644 --- a/Compiler/src/ssair/inlining.jl +++ b/Compiler/src/ssair/inlining.jl @@ -126,10 +126,11 @@ function cfg_inline_item!(ir::IRCode, idx::Int, todo::InliningTodo, state::CFGIn block = block_for_inst(ir, idx) inline_into_block!(state, block) - if !isempty(inlinee_cfg.blocks[1].preds) + if length(inlinee_cfg.blocks[1].preds) > 1 need_split_before = true + else + @assert inlinee_cfg.blocks[1].preds[1] == 0 end - last_block_idx = last(state.cfg.blocks[block].stmts) if false # TODO: ((idx+1) == last_block_idx && isa(ir[SSAValue(last_block_idx)], GotoNode)) need_split = false @@ -166,12 +167,18 @@ function cfg_inline_item!(ir::IRCode, idx::Int, todo::InliningTodo, state::CFGIn end new_block_range = (length(state.new_cfg_blocks)-length(inlinee_cfg.blocks)+1):length(state.new_cfg_blocks) - # Fixup the edges of the newely added blocks + # Fixup the edges of the newly added blocks for (old_block, new_block) in enumerate(bb_rename_range) if old_block != 1 || need_split_before p = state.new_cfg_blocks[new_block].preds let bb_rename_range = bb_rename_range map!(p, p) do old_pred_block + # the meaning of predecessor 0 depends on the block we encounter it: + # - in the first block, it represents the function entry and so needs to be re-mapped + if old_block == 1 && old_pred_block == 0 + return first(bb_rename_range) - 1 + end + # - elsewhere, it represents external control-flow from a caught exception which is un-affected by inlining return old_pred_block == 0 ? 0 : bb_rename_range[old_pred_block] end end @@ -186,10 +193,6 @@ function cfg_inline_item!(ir::IRCode, idx::Int, todo::InliningTodo, state::CFGIn end end - if need_split_before - push!(state.new_cfg_blocks[first(bb_rename_range)].preds, first(bb_rename_range)-1) - end - any_edges = false for (old_block, new_block) in enumerate(bb_rename_range) if (length(state.new_cfg_blocks[new_block].succs) == 0) @@ -399,7 +402,7 @@ function ir_inline_item!(compact::IncrementalCompact, idx::Int, argexprs::Vector else bb_offset, post_bb_id = popfirst!(todo_bbs) # This implements the need_split_before flag above - need_split_before = !isempty(item.ir.cfg.blocks[1].preds) + need_split_before = length(item.ir.cfg.blocks[1].preds) > 1 if need_split_before finish_current_bb!(compact, 0) end diff --git a/Compiler/src/ssair/ir.jl b/Compiler/src/ssair/ir.jl index e6c8f3a6d2c78..d7f0dbedcbec5 100644 --- a/Compiler/src/ssair/ir.jl +++ b/Compiler/src/ssair/ir.jl @@ -105,6 +105,9 @@ function compute_basic_blocks(stmts::Vector{Any}) end # Compute successors/predecessors for (num, b) in enumerate(blocks) + if b.stmts.start == 1 + push!(b.preds, 0) # the entry block has a virtual predecessor + end terminator = stmts[last(b.stmts)] if isa(terminator, ReturnNode) # return never has any successors diff --git a/Compiler/test/ssair.jl b/Compiler/test/ssair.jl index 3026202466599..80faac97d83a4 100644 --- a/Compiler/test/ssair.jl +++ b/Compiler/test/ssair.jl @@ -818,3 +818,23 @@ let cl = Int32[32, 1, 1, 1000, 240, 230] cl2 = ccall(:jl_uncompress_codelocs, Any, (Any, Int), str, 2) @test cl == cl2 end + +#57153 check that the CFG has a #0 block predecessor and that we don't fail to compile code that observes that +function _worker_task57153() + while true + r = let + try + if @noinline rand(Bool) + return nothing + end + q, m + finally + missing + end + end + r[1]::Bool + end +end +let ir = Base.code_ircode(_worker_task57153, (), optimize_until="CC: COMPACT_2")[1].first + @test findfirst(x->x==0, ir.cfg.blocks[1].preds) !== nothing +end From fc4066d0658ddf6c9e9e60b6ee90fc593365fae5 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Mon, 30 Jun 2025 17:33:10 -0400 Subject: [PATCH 56/83] move trim patches to separate files, only load if trimming (#58826) fixes part of #58458 (cherry picked from commit d7c70bcbab2cba3f7decb3ffa21cc4ef73ed87cb) --- Makefile | 2 +- contrib/juliac-buildscript.jl | 243 +--------------------------------- contrib/juliac-trim-base.jl | 161 ++++++++++++++++++++++ contrib/juliac-trim-stdlib.jl | 83 ++++++++++++ contrib/juliac.jl | 2 + 5 files changed, 253 insertions(+), 238 deletions(-) create mode 100644 contrib/juliac-trim-base.jl create mode 100644 contrib/juliac-trim-stdlib.jl diff --git a/Makefile b/Makefile index 3a529177b62de..9c9e99ea0ac91 100644 --- a/Makefile +++ b/Makefile @@ -89,7 +89,7 @@ julia-deps: | $(DIRS) $(build_datarootdir)/julia/base $(build_datarootdir)/julia julia-stdlib: | $(DIRS) julia-deps @$(MAKE) $(QUIET_MAKE) -C $(BUILDROOT)/stdlib -julia-base: julia-deps $(build_sysconfdir)/julia/startup.jl $(build_man1dir)/julia.1 $(build_datarootdir)/julia/julia-config.jl $(build_datarootdir)/julia/juliac.jl $(build_datarootdir)/julia/juliac-buildscript.jl +julia-base: julia-deps $(build_sysconfdir)/julia/startup.jl $(build_man1dir)/julia.1 $(build_datarootdir)/julia/julia-config.jl $(build_datarootdir)/julia/juliac.jl $(build_datarootdir)/julia/juliac-buildscript.jl $(build_datarootdir)/julia/juliac-trim-base.jl $(build_datarootdir)/julia/juliac-trim-stdlib.jl @$(MAKE) $(QUIET_MAKE) -C $(BUILDROOT)/base julia-libccalltest: julia-deps diff --git a/contrib/juliac-buildscript.jl b/contrib/juliac-buildscript.jl index e71297ef8c847..40b35c66a829f 100644 --- a/contrib/juliac-buildscript.jl +++ b/contrib/juliac-buildscript.jl @@ -1,3 +1,5 @@ +# This file is a part of Julia. License is MIT: https://julialang.org/license + # Script to run in the process that generates juliac's object file output # Run the verifier in the current world (before modifications), so that error @@ -21,164 +23,8 @@ if Base.get_bool_env("JULIA_USE_FLISP_PARSER", false) === false Base.JuliaSyntax.enable_in_core!() end -# Patch methods in Core and Base - -@eval Core begin - DomainError(@nospecialize(val), @nospecialize(msg::AbstractString)) = (@noinline; $(Expr(:new, :DomainError, :val, :msg))) -end - -(f::Base.RedirectStdStream)(io::Core.CoreSTDOUT) = Base._redirect_io_global(io, f.unix_fd) - -@eval Base begin - depwarn(msg, funcsym; force::Bool=false) = nothing - _assert_tostring(msg) = "" - reinit_stdio() = nothing - JuliaSyntax.enable_in_core!() = nothing - init_active_project() = ACTIVE_PROJECT[] = nothing - set_active_project(projfile::Union{AbstractString,Nothing}) = ACTIVE_PROJECT[] = projfile - disable_library_threading() = nothing - start_profile_listener() = nothing - invokelatest_trimmed(f, args...; kwargs...) = f(args...; kwargs...) - const invokelatest = invokelatest_trimmed - function sprint(f::F, args::Vararg{Any,N}; context=nothing, sizehint::Integer=0) where {F<:Function,N} - s = IOBuffer(sizehint=sizehint) - if context isa Tuple - f(IOContext(s, context...), args...) - elseif context !== nothing - f(IOContext(s, context), args...) - else - f(s, args...) - end - String(_unsafe_take!(s)) - end - function show_typeish(io::IO, @nospecialize(T)) - if T isa Type - show(io, T) - elseif T isa TypeVar - print(io, (T::TypeVar).name) - else - print(io, "?") - end - end - function show(io::IO, T::Type) - if T isa DataType - print(io, T.name.name) - if T !== T.name.wrapper && length(T.parameters) > 0 - print(io, "{") - first = true - for p in T.parameters - if !first - print(io, ", ") - end - first = false - if p isa Int - show(io, p) - elseif p isa Type - show(io, p) - elseif p isa Symbol - print(io, ":") - print(io, p) - elseif p isa TypeVar - print(io, p.name) - else - print(io, "?") - end - end - print(io, "}") - end - elseif T isa Union - print(io, "Union{") - show_typeish(io, T.a) - print(io, ", ") - show_typeish(io, T.b) - print(io, "}") - elseif T isa UnionAll - print(io, T.body::Type) - print(io, " where ") - print(io, T.var.name) - end - end - show_type_name(io::IO, tn::Core.TypeName) = print(io, tn.name) - - mapreduce(f::F, op::F2, A::AbstractArrayOrBroadcasted; dims=:, init=_InitialValue()) where {F, F2} = - _mapreduce_dim(f, op, init, A, dims) - mapreduce(f::F, op::F2, A::AbstractArrayOrBroadcasted...; kw...) where {F, F2} = - reduce(op, map(f, A...); kw...) - - _mapreduce_dim(f::F, op::F2, nt, A::AbstractArrayOrBroadcasted, ::Colon) where {F, F2} = - mapfoldl_impl(f, op, nt, A) - - _mapreduce_dim(f::F, op::F2, ::_InitialValue, A::AbstractArrayOrBroadcasted, ::Colon) where {F, F2} = - _mapreduce(f, op, IndexStyle(A), A) - - _mapreduce_dim(f::F, op::F2, nt, A::AbstractArrayOrBroadcasted, dims) where {F, F2} = - mapreducedim!(f, op, reducedim_initarray(A, dims, nt), A) - - _mapreduce_dim(f::F, op::F2, ::_InitialValue, A::AbstractArrayOrBroadcasted, dims) where {F,F2} = - mapreducedim!(f, op, reducedim_init(f, op, A, dims), A) - - mapreduce_empty_iter(f::F, op::F2, itr, ItrEltype) where {F, F2} = - reduce_empty_iter(MappingRF(f, op), itr, ItrEltype) - mapreduce_first(f::F, op::F2, x) where {F,F2} = reduce_first(op, f(x)) - - _mapreduce(f::F, op::F2, A::AbstractArrayOrBroadcasted) where {F,F2} = _mapreduce(f, op, IndexStyle(A), A) - mapreduce_empty(::typeof(identity), op::F, T) where {F} = reduce_empty(op, T) - mapreduce_empty(::typeof(abs), op::F, T) where {F} = abs(reduce_empty(op, T)) - mapreduce_empty(::typeof(abs2), op::F, T) where {F} = abs2(reduce_empty(op, T)) -end -@eval Base.Sys begin - __init_build() = nothing -end -@eval Base.GMP begin - function __init__() - try - ccall((:__gmp_set_memory_functions, libgmp), Cvoid, - (Ptr{Cvoid},Ptr{Cvoid},Ptr{Cvoid}), - cglobal(:jl_gc_counted_malloc), - cglobal(:jl_gc_counted_realloc_with_old_size), - cglobal(:jl_gc_counted_free_with_size)) - ZERO.alloc, ZERO.size, ZERO.d = 0, 0, C_NULL - ONE.alloc, ONE.size, ONE.d = 1, 1, pointer(_ONE) - catch ex - Base.showerror_nostdio(ex, "WARNING: Error during initialization of module GMP") - end - # This only works with a patched version of GMP, ignore otherwise - try - ccall((:__gmp_set_alloc_overflow_function, libgmp), Cvoid, - (Ptr{Cvoid},), - cglobal(:jl_throw_out_of_memory_error)) - ALLOC_OVERFLOW_FUNCTION[] = true - catch ex - # ErrorException("ccall: could not find function...") - if typeof(ex) != ErrorException - rethrow() - end - end - end -end -@eval Base.Sort begin - issorted(itr; - lt::T=isless, by::F=identity, rev::Union{Bool,Nothing}=nothing, order::Ordering=Forward) where {T,F} = - issorted(itr, ord(lt,by,rev,order)) -end -@eval Base.TOML begin - function try_return_datetime(p, year, month, day, h, m, s, ms) - return DateTime(year, month, day, h, m, s, ms) - end - function try_return_date(p, year, month, day) - return Date(year, month, day) - end - function parse_local_time(l::Parser) - h = @try parse_int(l, false) - h in 0:23 || return ParserError(ErrParsingDateTime) - _, m, s, ms = @try _parse_local_time(l, true) - # TODO: Could potentially parse greater accuracy for the - # fractional seconds here. - return try_return_time(l, h, m, s, ms) - end - function try_return_time(p, h, m, s, ms) - return Time(h, m, s, ms) - end +if Base.JLOptions().trim != 0 + include(joinpath(@__DIR__, "juliac-trim-base.jl")) end # Load user code @@ -229,85 +75,8 @@ let mod = Base.include(Main, ARGS[1]) end end -# Additional method patches depending on whether user code loads certain stdlibs -let - find_loaded_root_module(key::Base.PkgId) = Base.maybe_root_module(key) - - SparseArrays = find_loaded_root_module(Base.PkgId( - Base.UUID("2f01184e-e22b-5df5-ae63-d93ebab69eaf"), "SparseArrays")) - if SparseArrays !== nothing - @eval SparseArrays.CHOLMOD begin - function __init__() - ccall((:SuiteSparse_config_malloc_func_set, :libsuitesparseconfig), - Cvoid, (Ptr{Cvoid},), cglobal(:jl_malloc, Ptr{Cvoid})) - ccall((:SuiteSparse_config_calloc_func_set, :libsuitesparseconfig), - Cvoid, (Ptr{Cvoid},), cglobal(:jl_calloc, Ptr{Cvoid})) - ccall((:SuiteSparse_config_realloc_func_set, :libsuitesparseconfig), - Cvoid, (Ptr{Cvoid},), cglobal(:jl_realloc, Ptr{Cvoid})) - ccall((:SuiteSparse_config_free_func_set, :libsuitesparseconfig), - Cvoid, (Ptr{Cvoid},), cglobal(:jl_free, Ptr{Cvoid})) - end - end - end - - Artifacts = find_loaded_root_module(Base.PkgId( - Base.UUID("56f22d72-fd6d-98f1-02f0-08ddc0907c33"), "Artifacts")) - if Artifacts !== nothing - @eval Artifacts begin - function _artifact_str( - __module__, - artifacts_toml, - name, - path_tail, - artifact_dict, - hash, - platform, - _::Val{LazyArtifacts} - ) where LazyArtifacts - # If the artifact exists, we're in the happy path and we can immediately - # return the path to the artifact: - dirs = artifacts_dirs(bytes2hex(hash.bytes)) - for dir in dirs - if isdir(dir) - return jointail(dir, path_tail) - end - end - error("Artifact not found") - end - end - end - - Pkg = find_loaded_root_module(Base.PkgId( - Base.UUID("44cfe95a-1eb2-52ea-b672-e2afdf69b78f"), "Pkg")) - if Pkg !== nothing - @eval Pkg begin - __init__() = rand() #TODO, methods that do nothing don't get codegened - end - end - - StyledStrings = find_loaded_root_module(Base.PkgId( - Base.UUID("f489334b-da3d-4c2e-b8f0-e476e12c162b"), "StyledStrings")) - if StyledStrings !== nothing - @eval StyledStrings begin - __init__() = rand() - end - end - - Markdown = find_loaded_root_module(Base.PkgId( - Base.UUID("d6f4376e-aef5-505a-96c1-9c027394607a"), "Markdown")) - if Markdown !== nothing - @eval Markdown begin - __init__() = rand() - end - end - - JuliaSyntaxHighlighting = find_loaded_root_module(Base.PkgId( - Base.UUID("ac6e5ff7-fb65-4e79-a425-ec3bc9c03011"), "JuliaSyntaxHighlighting")) - if JuliaSyntaxHighlighting !== nothing - @eval JuliaSyntaxHighlighting begin - __init__() = rand() - end - end +if Base.JLOptions().trim != 0 + include(joinpath(@__DIR__, "juliac-trim-stdlib.jl")) end empty!(Core.ARGS) diff --git a/contrib/juliac-trim-base.jl b/contrib/juliac-trim-base.jl new file mode 100644 index 0000000000000..96fed77969c97 --- /dev/null +++ b/contrib/juliac-trim-base.jl @@ -0,0 +1,161 @@ +# This file is a part of Julia. License is MIT: https://julialang.org/license + +# Patches to Base needed for trimming + +@eval Core begin + DomainError(@nospecialize(val), @nospecialize(msg::AbstractString)) = (@noinline; $(Expr(:new, :DomainError, :val, :msg))) +end + +(f::Base.RedirectStdStream)(io::Core.CoreSTDOUT) = Base._redirect_io_global(io, f.unix_fd) + +@eval Base begin + depwarn(msg, funcsym; force::Bool=false) = nothing + _assert_tostring(msg) = "" + reinit_stdio() = nothing + JuliaSyntax.enable_in_core!() = nothing + init_active_project() = ACTIVE_PROJECT[] = nothing + set_active_project(projfile::Union{AbstractString,Nothing}) = ACTIVE_PROJECT[] = projfile + disable_library_threading() = nothing + start_profile_listener() = nothing + invokelatest_trimmed(f, args...; kwargs...) = f(args...; kwargs...) + const invokelatest = invokelatest_trimmed + function sprint(f::F, args::Vararg{Any,N}; context=nothing, sizehint::Integer=0) where {F<:Function,N} + s = IOBuffer(sizehint=sizehint) + if context isa Tuple + f(IOContext(s, context...), args...) + elseif context !== nothing + f(IOContext(s, context), args...) + else + f(s, args...) + end + String(_unsafe_take!(s)) + end + function show_typeish(io::IO, @nospecialize(T)) + if T isa Type + show(io, T) + elseif T isa TypeVar + print(io, (T::TypeVar).name) + else + print(io, "?") + end + end + function show(io::IO, T::Type) + if T isa DataType + print(io, T.name.name) + if T !== T.name.wrapper && length(T.parameters) > 0 + print(io, "{") + first = true + for p in T.parameters + if !first + print(io, ", ") + end + first = false + if p isa Int + show(io, p) + elseif p isa Type + show(io, p) + elseif p isa Symbol + print(io, ":") + print(io, p) + elseif p isa TypeVar + print(io, p.name) + else + print(io, "?") + end + end + print(io, "}") + end + elseif T isa Union + print(io, "Union{") + show_typeish(io, T.a) + print(io, ", ") + show_typeish(io, T.b) + print(io, "}") + elseif T isa UnionAll + print(io, T.body::Type) + print(io, " where ") + print(io, T.var.name) + end + end + show_type_name(io::IO, tn::Core.TypeName) = print(io, tn.name) + + mapreduce(f::F, op::F2, A::AbstractArrayOrBroadcasted; dims=:, init=_InitialValue()) where {F, F2} = + _mapreduce_dim(f, op, init, A, dims) + mapreduce(f::F, op::F2, A::AbstractArrayOrBroadcasted...; kw...) where {F, F2} = + reduce(op, map(f, A...); kw...) + + _mapreduce_dim(f::F, op::F2, nt, A::AbstractArrayOrBroadcasted, ::Colon) where {F, F2} = + mapfoldl_impl(f, op, nt, A) + + _mapreduce_dim(f::F, op::F2, ::_InitialValue, A::AbstractArrayOrBroadcasted, ::Colon) where {F, F2} = + _mapreduce(f, op, IndexStyle(A), A) + + _mapreduce_dim(f::F, op::F2, nt, A::AbstractArrayOrBroadcasted, dims) where {F, F2} = + mapreducedim!(f, op, reducedim_initarray(A, dims, nt), A) + + _mapreduce_dim(f::F, op::F2, ::_InitialValue, A::AbstractArrayOrBroadcasted, dims) where {F,F2} = + mapreducedim!(f, op, reducedim_init(f, op, A, dims), A) + + mapreduce_empty_iter(f::F, op::F2, itr, ItrEltype) where {F, F2} = + reduce_empty_iter(MappingRF(f, op), itr, ItrEltype) + mapreduce_first(f::F, op::F2, x) where {F,F2} = reduce_first(op, f(x)) + + _mapreduce(f::F, op::F2, A::AbstractArrayOrBroadcasted) where {F,F2} = _mapreduce(f, op, IndexStyle(A), A) + mapreduce_empty(::typeof(identity), op::F, T) where {F} = reduce_empty(op, T) + mapreduce_empty(::typeof(abs), op::F, T) where {F} = abs(reduce_empty(op, T)) + mapreduce_empty(::typeof(abs2), op::F, T) where {F} = abs2(reduce_empty(op, T)) +end +@eval Base.Sys begin + __init_build() = nothing +end +@eval Base.GMP begin + function __init__() + try + ccall((:__gmp_set_memory_functions, libgmp), Cvoid, + (Ptr{Cvoid},Ptr{Cvoid},Ptr{Cvoid}), + cglobal(:jl_gc_counted_malloc), + cglobal(:jl_gc_counted_realloc_with_old_size), + cglobal(:jl_gc_counted_free_with_size)) + ZERO.alloc, ZERO.size, ZERO.d = 0, 0, C_NULL + ONE.alloc, ONE.size, ONE.d = 1, 1, pointer(_ONE) + catch ex + Base.showerror_nostdio(ex, "WARNING: Error during initialization of module GMP") + end + # This only works with a patched version of GMP, ignore otherwise + try + ccall((:__gmp_set_alloc_overflow_function, libgmp), Cvoid, + (Ptr{Cvoid},), + cglobal(:jl_throw_out_of_memory_error)) + ALLOC_OVERFLOW_FUNCTION[] = true + catch ex + # ErrorException("ccall: could not find function...") + if typeof(ex) != ErrorException + rethrow() + end + end + end +end +@eval Base.Sort begin + issorted(itr; + lt::T=isless, by::F=identity, rev::Union{Bool,Nothing}=nothing, order::Ordering=Forward) where {T,F} = + issorted(itr, ord(lt,by,rev,order)) +end +@eval Base.TOML begin + function try_return_datetime(p, year, month, day, h, m, s, ms) + return DateTime(year, month, day, h, m, s, ms) + end + function try_return_date(p, year, month, day) + return Date(year, month, day) + end + function parse_local_time(l::Parser) + h = @try parse_int(l, false) + h in 0:23 || return ParserError(ErrParsingDateTime) + _, m, s, ms = @try _parse_local_time(l, true) + # TODO: Could potentially parse greater accuracy for the + # fractional seconds here. + return try_return_time(l, h, m, s, ms) + end + function try_return_time(p, h, m, s, ms) + return Time(h, m, s, ms) + end +end diff --git a/contrib/juliac-trim-stdlib.jl b/contrib/juliac-trim-stdlib.jl new file mode 100644 index 0000000000000..3e2501c2c3e50 --- /dev/null +++ b/contrib/juliac-trim-stdlib.jl @@ -0,0 +1,83 @@ +# This file is a part of Julia. License is MIT: https://julialang.org/license + +# Patches to stdlib needed for trimming + +let + find_loaded_root_module(key::Base.PkgId) = Base.maybe_root_module(key) + + SparseArrays = find_loaded_root_module(Base.PkgId( + Base.UUID("2f01184e-e22b-5df5-ae63-d93ebab69eaf"), "SparseArrays")) + if SparseArrays !== nothing + @eval SparseArrays.CHOLMOD begin + function __init__() + ccall((:SuiteSparse_config_malloc_func_set, :libsuitesparseconfig), + Cvoid, (Ptr{Cvoid},), cglobal(:jl_malloc, Ptr{Cvoid})) + ccall((:SuiteSparse_config_calloc_func_set, :libsuitesparseconfig), + Cvoid, (Ptr{Cvoid},), cglobal(:jl_calloc, Ptr{Cvoid})) + ccall((:SuiteSparse_config_realloc_func_set, :libsuitesparseconfig), + Cvoid, (Ptr{Cvoid},), cglobal(:jl_realloc, Ptr{Cvoid})) + ccall((:SuiteSparse_config_free_func_set, :libsuitesparseconfig), + Cvoid, (Ptr{Cvoid},), cglobal(:jl_free, Ptr{Cvoid})) + end + end + end + + Artifacts = find_loaded_root_module(Base.PkgId( + Base.UUID("56f22d72-fd6d-98f1-02f0-08ddc0907c33"), "Artifacts")) + if Artifacts !== nothing + @eval Artifacts begin + function _artifact_str( + __module__, + artifacts_toml, + name, + path_tail, + artifact_dict, + hash, + platform, + _::Val{LazyArtifacts} + ) where LazyArtifacts + # If the artifact exists, we're in the happy path and we can immediately + # return the path to the artifact: + dirs = artifacts_dirs(bytes2hex(hash.bytes)) + for dir in dirs + if isdir(dir) + return jointail(dir, path_tail) + end + end + error("Artifact not found") + end + end + end + + Pkg = find_loaded_root_module(Base.PkgId( + Base.UUID("44cfe95a-1eb2-52ea-b672-e2afdf69b78f"), "Pkg")) + if Pkg !== nothing + @eval Pkg begin + __init__() = rand() #TODO, methods that do nothing don't get codegened + end + end + + StyledStrings = find_loaded_root_module(Base.PkgId( + Base.UUID("f489334b-da3d-4c2e-b8f0-e476e12c162b"), "StyledStrings")) + if StyledStrings !== nothing + @eval StyledStrings begin + __init__() = rand() + end + end + + Markdown = find_loaded_root_module(Base.PkgId( + Base.UUID("d6f4376e-aef5-505a-96c1-9c027394607a"), "Markdown")) + if Markdown !== nothing + @eval Markdown begin + __init__() = rand() + end + end + + JuliaSyntaxHighlighting = find_loaded_root_module(Base.PkgId( + Base.UUID("ac6e5ff7-fb65-4e79-a425-ec3bc9c03011"), "JuliaSyntaxHighlighting")) + if JuliaSyntaxHighlighting !== nothing + @eval JuliaSyntaxHighlighting begin + __init__() = rand() + end + end +end diff --git a/contrib/juliac.jl b/contrib/juliac.jl index b110f1d233690..d637f1f1bf3a2 100644 --- a/contrib/juliac.jl +++ b/contrib/juliac.jl @@ -1,3 +1,5 @@ +# This file is a part of Julia. License is MIT: https://julialang.org/license + # Julia compiler wrapper script # NOTE: The interface and location of this script are considered unstable/experimental From 2e45e64626372c9641a9ff3170f374a4a5d2ab36 Mon Sep 17 00:00:00 2001 From: Cody Tapscott <84105208+topolarity@users.noreply.github.com> Date: Tue, 1 Jul 2025 10:24:38 -0400 Subject: [PATCH 57/83] juliac: Add rudimentary Windows support (#57481) This was essentially working as-is, except for our reliance on a C compiler. Not sure how we feel about having an `Artifacts.toml` floating around our `contrib` folder, but I'm not aware of an alternative other than moving `juliac.jl` to a subdirectory. (cherry picked from commit 34bb3e794a3a4e7638e3f88408da7e6507daad23) --- Makefile | 3 +- contrib/juliac/Artifacts.toml | 19 +++++++ contrib/{ => juliac}/juliac-buildscript.jl | 0 contrib/{ => juliac}/juliac-trim-base.jl | 0 contrib/{ => juliac}/juliac-trim-stdlib.jl | 0 contrib/{ => juliac}/juliac.jl | 64 ++++++++++++++++++++-- doc/src/devdocs/sysimg.md | 2 +- test/trimming/Makefile | 2 +- 8 files changed, 81 insertions(+), 9 deletions(-) create mode 100644 contrib/juliac/Artifacts.toml rename contrib/{ => juliac}/juliac-buildscript.jl (100%) rename contrib/{ => juliac}/juliac-trim-base.jl (100%) rename contrib/{ => juliac}/juliac-trim-stdlib.jl (100%) rename contrib/{ => juliac}/juliac.jl (66%) diff --git a/Makefile b/Makefile index 9c9e99ea0ac91..9a75c65673be8 100644 --- a/Makefile +++ b/Makefile @@ -89,7 +89,7 @@ julia-deps: | $(DIRS) $(build_datarootdir)/julia/base $(build_datarootdir)/julia julia-stdlib: | $(DIRS) julia-deps @$(MAKE) $(QUIET_MAKE) -C $(BUILDROOT)/stdlib -julia-base: julia-deps $(build_sysconfdir)/julia/startup.jl $(build_man1dir)/julia.1 $(build_datarootdir)/julia/julia-config.jl $(build_datarootdir)/julia/juliac.jl $(build_datarootdir)/julia/juliac-buildscript.jl $(build_datarootdir)/julia/juliac-trim-base.jl $(build_datarootdir)/julia/juliac-trim-stdlib.jl +julia-base: julia-deps $(build_sysconfdir)/julia/startup.jl $(build_man1dir)/julia.1 $(build_datarootdir)/julia/julia-config.jl $(build_datarootdir)/julia/juliac/juliac.jl $(build_datarootdir)/julia/juliac/juliac-buildscript.jl $(build_datarootdir)/julia/juliac/juliac-trim-base.jl $(build_datarootdir)/julia/juliac/juliac-trim-stdlib.jl @$(MAKE) $(QUIET_MAKE) -C $(BUILDROOT)/base julia-libccalltest: julia-deps @@ -190,6 +190,7 @@ $(build_sysconfdir)/julia/startup.jl: $(JULIAHOME)/etc/startup.jl | $(build_sysc @cp $< $@ $(build_datarootdir)/julia/%: $(JULIAHOME)/contrib/% | $(build_datarootdir)/julia + mkdir -p $(dir $@) $(INSTALL_M) $< $(dir $@) $(build_depsbindir)/stringreplace: $(JULIAHOME)/contrib/stringreplace.c | $(build_depsbindir) diff --git a/contrib/juliac/Artifacts.toml b/contrib/juliac/Artifacts.toml new file mode 100644 index 0000000000000..54771b41b21f7 --- /dev/null +++ b/contrib/juliac/Artifacts.toml @@ -0,0 +1,19 @@ +[[mingw-w64]] +arch = "x86_64" +git-tree-sha1 = "b17bda08a19173572926f43a48aad5ef3d845e7c" +os = "windows" +lazy = true + + [[mingw-w64.download]] + sha256 = "53645e06775a55733580426341395c67dda20a664af83bcda76a1d052b618b59" + url = "https://github.com/JuliaLang/PackageCompiler.jl/releases/download/v2.1.24/x86_64-14.2.0-release-posix-seh-msvcrt-rt_v12-rev0.tar.gz" + +[[mingw-w64]] +arch = "i686" +git-tree-sha1 = "76b9f278e7de1d7dfdfe3a786afbe9c1e29003ea" +os = "windows" +lazy = true + + [[mingw-w64.download]] + sha256 = "d049bd771e01b02f2ca9274435f0e6f9f4f295bf2af72a8059dd851c52144910" + url = "https://github.com/JuliaLang/PackageCompiler.jl/releases/download/v2.1.24/i686-14.2.0-release-posix-dwarf-msvcrt-rt_v12-rev0.tar.gz" diff --git a/contrib/juliac-buildscript.jl b/contrib/juliac/juliac-buildscript.jl similarity index 100% rename from contrib/juliac-buildscript.jl rename to contrib/juliac/juliac-buildscript.jl diff --git a/contrib/juliac-trim-base.jl b/contrib/juliac/juliac-trim-base.jl similarity index 100% rename from contrib/juliac-trim-base.jl rename to contrib/juliac/juliac-trim-base.jl diff --git a/contrib/juliac-trim-stdlib.jl b/contrib/juliac/juliac-trim-stdlib.jl similarity index 100% rename from contrib/juliac-trim-stdlib.jl rename to contrib/juliac/juliac-trim-stdlib.jl diff --git a/contrib/juliac.jl b/contrib/juliac/juliac.jl similarity index 66% rename from contrib/juliac.jl rename to contrib/juliac/juliac.jl index d637f1f1bf3a2..ed80d88444639 100644 --- a/contrib/juliac.jl +++ b/contrib/juliac/juliac.jl @@ -3,8 +3,10 @@ # Julia compiler wrapper script # NOTE: The interface and location of this script are considered unstable/experimental +using LazyArtifacts + module JuliaConfig - include(joinpath(@__DIR__, "julia-config.jl")) + include(joinpath(@__DIR__, "..", "julia-config.jl")) end julia_cmd = `$(Base.julia_cmd()) --startup-file=no --history-file=no` @@ -30,6 +32,57 @@ if help !== nothing exit(0) end +# Copied from PackageCompiler +# https://github.com/JuliaLang/PackageCompiler.jl/blob/1c35331d8ef81494f054bbc71214811253101993/src/PackageCompiler.jl#L147-L190 +function get_compiler_cmd(; cplusplus::Bool=false) + cc = get(ENV, "JULIA_CC", nothing) + path = nothing + @static if Sys.iswindows() + path = joinpath(LazyArtifacts.artifact"mingw-w64", + "extracted_files", + (Int==Int64 ? "mingw64" : "mingw32"), + "bin", + cplusplus ? "g++.exe" : "gcc.exe") + compiler_cmd = `$path` + end + if cc !== nothing + compiler_cmd = Cmd(Base.shell_split(cc)) + path = nothing + elseif !Sys.iswindows() + compilers_cpp = ("g++", "clang++") + compilers_c = ("gcc", "clang") + found_compiler = false + if cplusplus + for compiler in compilers_cpp + if Sys.which(compiler) !== nothing + compiler_cmd = `$compiler` + found_compiler = true + break + end + end + end + if !found_compiler + for compiler in compilers_c + if Sys.which(compiler) !== nothing + compiler_cmd = `$compiler` + found_compiler = true + if cplusplus && !WARNED_CPP_COMPILER[] + @warn "could not find a c++ compiler (g++ or clang++), falling back to $compiler, this might cause link errors" + WARNED_CPP_COMPILER[] = true + end + break + end + end + end + found_compiler || error("could not find a compiler, looked for ", + join(((cplusplus ? compilers_cpp : ())..., compilers_c...), ", ", " and ")) + end + if path !== nothing + compiler_cmd = addenv(compiler_cmd, "PATH" => string(ENV["PATH"], ";", dirname(path))) + end + return compiler_cmd +end + # arguments to forward to julia compilation process julia_args = [] enable_trim::Bool = false @@ -82,6 +135,7 @@ function get_rpath(; relative::Bool = false) end end +cc = get_compiler_cmd() absfile = abspath(file) cflags = JuliaConfig.cflags(; framework=false) cflags = Base.shell_split(cflags) @@ -93,7 +147,6 @@ tmpdir = mktempdir(cleanup=false) img_path = joinpath(tmpdir, "img.a") bc_path = joinpath(tmpdir, "img-bc.a") - function precompile_env() # Pre-compile the environment # (otherwise obscure error messages will occur) @@ -121,7 +174,6 @@ function compile_products(enable_trim::Bool) println(stderr, "\nFailed to compile $file") exit(1) end - end function link_products() @@ -137,11 +189,11 @@ function link_products() julia_libs = Base.shell_split(Base.isdebugbuild() ? "-ljulia-debug -ljulia-internal-debug" : "-ljulia -ljulia-internal") try if output_type == "--output-lib" - cmd2 = `cc $(allflags) $(rpath) -o $outname -shared -Wl,$(Base.Linking.WHOLE_ARCHIVE) $img_path -Wl,$(Base.Linking.NO_WHOLE_ARCHIVE) $(julia_libs)` + cmd2 = `$(cc) $(allflags) $(rpath) -o $outname -shared -Wl,$(Base.Linking.WHOLE_ARCHIVE) $img_path -Wl,$(Base.Linking.NO_WHOLE_ARCHIVE) $(julia_libs)` elseif output_type == "--output-sysimage" - cmd2 = `cc $(allflags) $(rpath) -o $outname -shared -Wl,$(Base.Linking.WHOLE_ARCHIVE) $img_path -Wl,$(Base.Linking.NO_WHOLE_ARCHIVE) $(julia_libs)` + cmd2 = `$(cc) $(allflags) $(rpath) -o $outname -shared -Wl,$(Base.Linking.WHOLE_ARCHIVE) $img_path -Wl,$(Base.Linking.NO_WHOLE_ARCHIVE) $(julia_libs)` else - cmd2 = `cc $(allflags) $(rpath) -o $outname -Wl,$(Base.Linking.WHOLE_ARCHIVE) $img_path -Wl,$(Base.Linking.NO_WHOLE_ARCHIVE) $(julia_libs)` + cmd2 = `$(cc) $(allflags) $(rpath) -o $outname -Wl,$(Base.Linking.WHOLE_ARCHIVE) $img_path -Wl,$(Base.Linking.NO_WHOLE_ARCHIVE) $(julia_libs)` end verbose && println("Running: $cmd2") run(cmd2) diff --git a/doc/src/devdocs/sysimg.md b/doc/src/devdocs/sysimg.md index 2cbba2744d4a1..e8202736e57e1 100644 --- a/doc/src/devdocs/sysimg.md +++ b/doc/src/devdocs/sysimg.md @@ -176,7 +176,7 @@ debug info, respectively, and so will make debugging more difficult. We have identified many small changes to Base that significantly increase the set of programs that can be reliably trimmed. Unfortunately some of those changes would be considered breaking, and so are only applied when trimming is requested (this is done by an external build script, -currently maintained inside the test suite as `contrib/juliac-buildscript.jl`). +currently maintained inside the test suite as `contrib/juliac/juliac-buildscript.jl`). Therefore in many cases trimming will require you to opt in to new variants of Base and some standard libraries. diff --git a/test/trimming/Makefile b/test/trimming/Makefile index e3c7536bbc92c..c3145765655e7 100644 --- a/test/trimming/Makefile +++ b/test/trimming/Makefile @@ -29,7 +29,7 @@ CFLAGS_ADD = $(shell $(JULIA_CONFIG) --cflags) LDFLAGS_ADD = -lm $(shell $(JULIA_CONFIG) --ldflags --ldlibs) -ljulia-internal # get the JuliaC build script -JULIAC_BUILDSCRIPT := $(shell $(JULIA) -e 'print(joinpath(Sys.BINDIR, Base.DATAROOTDIR, "julia", "juliac-buildscript.jl"))') +JULIAC_BUILDSCRIPT := $(shell $(JULIA) -e 'print(joinpath(Sys.BINDIR, Base.DATAROOTDIR, "julia", "juliac", "juliac-buildscript.jl"))') #============================================================================= From c37ee51475d90bad7ca7caaff15578564ee528b9 Mon Sep 17 00:00:00 2001 From: Cody Tapscott <84105208+topolarity@users.noreply.github.com> Date: Tue, 1 Jul 2025 14:10:00 -0400 Subject: [PATCH 58/83] debuginfo: Memoize object symbol lookup (#58851) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Supersedes https://github.com/JuliaLang/julia/pull/58355. Resolves https://github.com/JuliaLang/julia/issues/58326. On this PR: ```julia julia> @btime lgamma(2.0) ┌ Warning: `lgamma(x::Real)` is deprecated, use `(logabsgamma(x))[1]` instead. │ caller = var"##core#283"() at execution.jl:598 └ @ Core ~/.julia/packages/BenchmarkTools/1i1mY/src/execution.jl:598 47.730 μs (105 allocations: 13.24 KiB) ``` On `nightly`: ```julia julia> @btime lgamma(2.0) ┌ Warning: `lgamma(x::Real)` is deprecated, use `(logabsgamma(x))[1]` instead. │ caller = var"##core#283"() at execution.jl:598 └ @ Core ~/.julia/packages/BenchmarkTools/1i1mY/src/execution.jl:598 26.856 ms (89 allocations: 11.32 KiB) ``` --- src/debug-registry.h | 7 ++- src/debuginfo.cpp | 116 ++++++++++++++++++++++++------------------- 2 files changed, 71 insertions(+), 52 deletions(-) diff --git a/src/debug-registry.h b/src/debug-registry.h index 72189c60d3d40..00e3445200361 100644 --- a/src/debug-registry.h +++ b/src/debug-registry.h @@ -12,7 +12,8 @@ typedef struct { const llvm::object::ObjectFile *obj; llvm::DIContext *ctx; int64_t slide; -} objfileentry_t; + std::map> *symbolmap; +} jl_object_file_entry_t; // Central registry for resolving function addresses to `jl_code_instance_t`s and // originating `ObjectFile`s (for the DWARF debug info). @@ -121,7 +122,7 @@ class JITDebugInfoRegistry using rev_map = std::map>; typedef rev_map objectmap_t; - typedef rev_map objfilemap_t; + typedef rev_map objfilemap_t; objectmap_t objectmap{}; rev_map> cimap{}; @@ -152,4 +153,6 @@ class JITDebugInfoRegistry void add_image_info(image_info_t info) JL_NOTSAFEPOINT; bool get_image_info(uint64_t base, image_info_t *info) const JL_NOTSAFEPOINT; Locked::LockT get_objfile_map() JL_NOTSAFEPOINT; + + std::shared_mutex symbol_mutex; }; diff --git a/src/debuginfo.cpp b/src/debuginfo.cpp index 8625b82aedff8..4f6c399369c1b 100644 --- a/src/debuginfo.cpp +++ b/src/debuginfo.cpp @@ -706,7 +706,8 @@ static inline void ignoreError(T &err) JL_NOTSAFEPOINT #endif } -static void get_function_name_and_base(llvm::object::SectionRef Section, size_t pointer, int64_t slide, bool inimage, +static void get_function_name_and_base(llvm::object::SectionRef Section, std::map> *symbolmap, + size_t pointer, int64_t slide, bool inimage, void **saddr, char **name, bool untrusted_dladdr) JL_NOTSAFEPOINT { bool needs_saddr = saddr && (!*saddr || untrusted_dladdr); @@ -732,59 +733,73 @@ static void get_function_name_and_base(llvm::object::SectionRef Section, size_t #endif } if (Section.getObject() && (needs_saddr || needs_name)) { - size_t distance = (size_t)-1; - object::SymbolRef sym_found; - for (auto sym : Section.getObject()->symbols()) { - if (!Section.containsSymbol(sym)) - continue; - auto addr = sym.getAddress(); - if (!addr) - continue; - size_t symptr = addr.get(); - if (symptr > pointer + slide) - continue; - size_t new_dist = pointer + slide - symptr; - if (new_dist > distance) - continue; - distance = new_dist; - sym_found = sym; - } - if (distance != (size_t)-1) { - if (needs_saddr) { - uintptr_t addr = cantFail(sym_found.getAddress()); - *saddr = (void*)(addr - slide); - needs_saddr = false; + uintptr_t addr = 0; + StringRef nameref{}; + { + std::shared_lock read_lock(getJITDebugRegistry().symbol_mutex); + if (symbolmap->empty()) { + read_lock.unlock(); + { + // symbol map hasn't been generated yet, so fill it in now + std::unique_lock write_lock(getJITDebugRegistry().symbol_mutex); + if (symbolmap->empty()) { + for (auto sym : Section.getObject()->symbols()) { + if (!Section.containsSymbol(sym)) + continue; + + auto maybe_addr = sym.getAddress(); + if (!maybe_addr) + continue; + size_t addr = maybe_addr.get(); + + auto maybe_nameref = sym.getName(); + StringRef nameref{}; + if (maybe_nameref) + nameref = maybe_nameref.get(); + + symbolmap->emplace(addr, nameref); + } + } + } + read_lock.lock(); + } + auto fit = symbolmap->lower_bound(pointer + slide); + if (fit != symbolmap->end()) { + addr = fit->first; + nameref = fit->second; } - if (needs_name) { - if (auto name_or_err = sym_found.getName()) { - auto nameref = name_or_err.get(); - const char globalPrefix = // == DataLayout::getGlobalPrefix + } + std::string namerefstr = nameref.str(); + if (needs_saddr && addr != 0) { + *saddr = (void*)(addr - slide); + needs_saddr = false; + } + if (needs_name && !nameref.empty()) { + const char globalPrefix = // == DataLayout::getGlobalPrefix #if defined(_OS_WINDOWS_) && !defined(_CPU_X86_64_) - '_'; + '_'; #elif defined(_OS_DARWIN_) - '_'; + '_'; #else - '\0'; + '\0'; #endif - if (globalPrefix) { - if (nameref[0] == globalPrefix) - nameref = nameref.drop_front(); + if (globalPrefix) { + if (nameref[0] == globalPrefix) + nameref = nameref.drop_front(); #if defined(_OS_WINDOWS_) && !defined(_CPU_X86_64_) - else if (nameref[0] == '@') // X86_VectorCall - nameref = nameref.drop_front(); + else if (nameref[0] == '@') // X86_VectorCall + nameref = nameref.drop_front(); #endif - // else VectorCall, Assembly, Internal, etc. - } + // else VectorCall, Assembly, Internal, etc. + } #if defined(_OS_WINDOWS_) && !defined(_CPU_X86_64_) - nameref = nameref.split('@').first; + nameref = nameref.split('@').first; #endif - size_t len = nameref.size(); - *name = (char*)realloc_s(*name, len + 1); - memcpy(*name, nameref.data(), len); - (*name)[len] = 0; - needs_name = false; - } - } + size_t len = nameref.size(); + *name = (char*)realloc_s(*name, len + 1); + memcpy(*name, nameref.data(), len); + (*name)[len] = 0; + needs_name = false; } } #ifdef _OS_WINDOWS_ @@ -808,7 +823,7 @@ static void get_function_name_and_base(llvm::object::SectionRef Section, size_t #endif } -static objfileentry_t find_object_file(uint64_t fbase, StringRef fname) JL_NOTSAFEPOINT +static jl_object_file_entry_t find_object_file(uint64_t fbase, StringRef fname) JL_NOTSAFEPOINT { int isdarwin = 0, islinux = 0, iswindows = 0; #if defined(_OS_DARWIN_) @@ -821,7 +836,7 @@ static objfileentry_t find_object_file(uint64_t fbase, StringRef fname) JL_NOTSA (void)iswindows; // GOAL: Read debuginfo from file - objfileentry_t entry{nullptr, nullptr, 0}; + jl_object_file_entry_t entry{nullptr, nullptr, 0, nullptr}; auto success = getJITDebugRegistry().get_objfile_map()->emplace(fbase, entry); if (!success.second) // Return cached value @@ -995,7 +1010,8 @@ static objfileentry_t find_object_file(uint64_t fbase, StringRef fname) JL_NOTSA auto binary = errorobj->takeBinary(); binary.first.release(); binary.second.release(); - entry = {debugobj, context, slide}; + + entry = {debugobj, context, slide, new std::map>()}; // update cache (*getJITDebugRegistry().get_objfile_map())[fbase] = entry; } @@ -1125,7 +1141,7 @@ bool jl_dylib_DI_for_fptr(size_t pointer, object::SectionRef *Section, int64_t * jl_copy_str(filename, dlinfo.dli_fname); fname = dlinfo.dli_fname; #endif // ifdef _OS_WINDOWS_ - auto entry = find_object_file(fbase, fname); + jl_object_file_entry_t entry = find_object_file(fbase, fname); *slide = entry.slide; *context = entry.ctx; if (entry.obj) @@ -1133,7 +1149,7 @@ bool jl_dylib_DI_for_fptr(size_t pointer, object::SectionRef *Section, int64_t * // Assume we only need base address for sysimg for now if (!inimage || 0 == image_info.fptrs.nptrs) saddr = nullptr; - get_function_name_and_base(*Section, pointer, entry.slide, inimage, saddr, name, untrusted_dladdr); + get_function_name_and_base(*Section, entry.symbolmap, pointer, entry.slide, inimage, saddr, name, untrusted_dladdr); return true; } From 1e24c2e35de236de1840132c2de1d80032b93766 Mon Sep 17 00:00:00 2001 From: Cody Tapscott <84105208+topolarity@users.noreply.github.com> Date: Wed, 2 Jul 2025 08:50:30 -0400 Subject: [PATCH 59/83] trimming: Add `_uv_hook_close` support (#58871) Resolves https://github.com/JuliaLang/julia/issues/58862. Since this hook is called internally by the runtime, `--trim` was not aware of the callee edge required here. --- base/libuv.jl | 9 ++++++++- src/staticdata.c | 3 ++- test/trimming/basic_jll.jl | 2 ++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/base/libuv.jl b/base/libuv.jl index 8f066971a639d..5e9bdfaf1e75c 100644 --- a/base/libuv.jl +++ b/base/libuv.jl @@ -39,8 +39,15 @@ macro handle_as(hand, typ) end end -@nospecializeinfer associate_julia_struct(handle::Ptr{Cvoid}, @nospecialize(jlobj)) = +function _uv_hook_close end + +function associate_julia_struct(handle::Ptr{Cvoid}, jlobj::T) where T + # This `cfunction` is not used anywhere, but it triggers compilation of this + # MethodInstance for `--trim` so that it will be available when dispatched to + # by `jl_uv_call_close_callback()` + _ = @cfunction(Base._uv_hook_close, Cvoid, (Ref{T},)) ccall(:jl_uv_associate_julia_struct, Cvoid, (Ptr{Cvoid}, Any), handle, jlobj) +end disassociate_julia_struct(uv) = disassociate_julia_struct(uv.handle) disassociate_julia_struct(handle::Ptr{Cvoid}) = handle != C_NULL && ccall(:jl_uv_disassociate_julia_struct, Cvoid, (Ptr{Cvoid},), handle) diff --git a/src/staticdata.c b/src/staticdata.c index dc2e5605d71e4..83d87caa586fe 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -732,7 +732,8 @@ static void jl_queue_module_for_serialization(jl_serializer_state *s, jl_module_ !strcmp(jl_symbol_name(b->globalref->name), "__init__") || // ... or point to Base functions accessed by the runtime (m == jl_base_module && (!strcmp(jl_symbol_name(b->globalref->name), "wait") || - !strcmp(jl_symbol_name(b->globalref->name), "task_done_hook"))))) { + !strcmp(jl_symbol_name(b->globalref->name), "task_done_hook") || + !strcmp(jl_symbol_name(b->globalref->name), "_uv_hook_close"))))) { jl_queue_for_serialization(s, b); } } diff --git a/test/trimming/basic_jll.jl b/test/trimming/basic_jll.jl index b4b5ec2e92320..79b7699a25b31 100644 --- a/test/trimming/basic_jll.jl +++ b/test/trimming/basic_jll.jl @@ -18,6 +18,8 @@ function @main(args::Vector{String})::Cint println(Core.stdout, ver) @assert ver == build_ver + sleep(0.01) + # Add an indirection via `@cfunction` / 1-arg ccall cfunc = @cfunction(print_string, Cvoid, (Ptr{Cvoid},)) fptr = dlsym(Zstd_jll.libzstd_handle, :ZSTD_versionString) From 06febe3eb501f48c4af617a5e27422ad8c24401a Mon Sep 17 00:00:00 2001 From: Cody Tapscott <84105208+topolarity@users.noreply.github.com> Date: Wed, 2 Jul 2025 09:11:07 -0400 Subject: [PATCH 60/83] aotcompile: Fix early-exit if CI not found for `cfunction` (#58722) As written, this was accidentally skipping all the subsequent `cfuncs` that need adapters. --- src/aotcompile.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aotcompile.cpp b/src/aotcompile.cpp index bace3e9b570d4..4393a99c73380 100644 --- a/src/aotcompile.cpp +++ b/src/aotcompile.cpp @@ -620,7 +620,7 @@ static void generate_cfunc_thunks(jl_codegen_params_t ¶ms, jl_compiled_funct } } Function *f = codeinst ? aot_abi_converter(params, M, declrt, sigt, cfunc.nargs, cfunc.specsig, codeinst, defM, func, "", false) : unspec; - return assign_fptr(f); + assign_fptr(f); } } From 4bb1f8075d5cd28b10e3b058349388edaa7bc2a4 Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Fri, 4 Jul 2025 10:52:30 +0200 Subject: [PATCH 61/83] add back `to_power_type` to `deprecated.jl` since some packages call it (#58886) Co-authored-by: KristofferC (cherry picked from commit b6123e8ddc8ac3ebcd53b606055cdea70e42fd11) --- base/deprecated.jl | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/base/deprecated.jl b/base/deprecated.jl index 32bdd52a5288a..aba3aa89909b3 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -557,4 +557,11 @@ true """ isbindingresolved +# Some packages call this function +function to_power_type(x::Number) + T = promote_type(typeof(x), typeof(x*x)) + convert(T, x) +end +to_power_type(x) = oftype(x*x, x) + # END 1.12 deprecations From e931e8358745d9becee15eeeab746b26c951b440 Mon Sep 17 00:00:00 2001 From: KristofferC Date: Fri, 4 Jul 2025 13:38:19 +0200 Subject: [PATCH 62/83] bump Pkg to latest 1.12 --- .../Pkg-b5f97876073d0443d6dbbc080d7b28205f3d4ca1.tar.gz/md5 | 1 - .../Pkg-b5f97876073d0443d6dbbc080d7b28205f3d4ca1.tar.gz/sha512 | 1 - .../Pkg-e7a2dfecbfe43cf1c32f1ccd1e98a4dca52726ee.tar.gz/md5 | 1 + .../Pkg-e7a2dfecbfe43cf1c32f1ccd1e98a4dca52726ee.tar.gz/sha512 | 1 + stdlib/Pkg.version | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) delete mode 100644 deps/checksums/Pkg-b5f97876073d0443d6dbbc080d7b28205f3d4ca1.tar.gz/md5 delete mode 100644 deps/checksums/Pkg-b5f97876073d0443d6dbbc080d7b28205f3d4ca1.tar.gz/sha512 create mode 100644 deps/checksums/Pkg-e7a2dfecbfe43cf1c32f1ccd1e98a4dca52726ee.tar.gz/md5 create mode 100644 deps/checksums/Pkg-e7a2dfecbfe43cf1c32f1ccd1e98a4dca52726ee.tar.gz/sha512 diff --git a/deps/checksums/Pkg-b5f97876073d0443d6dbbc080d7b28205f3d4ca1.tar.gz/md5 b/deps/checksums/Pkg-b5f97876073d0443d6dbbc080d7b28205f3d4ca1.tar.gz/md5 deleted file mode 100644 index 2d029f736cd48..0000000000000 --- a/deps/checksums/Pkg-b5f97876073d0443d6dbbc080d7b28205f3d4ca1.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -d750336e7cb029d1f02e2b535f330b19 diff --git a/deps/checksums/Pkg-b5f97876073d0443d6dbbc080d7b28205f3d4ca1.tar.gz/sha512 b/deps/checksums/Pkg-b5f97876073d0443d6dbbc080d7b28205f3d4ca1.tar.gz/sha512 deleted file mode 100644 index 7705d546c8c41..0000000000000 --- a/deps/checksums/Pkg-b5f97876073d0443d6dbbc080d7b28205f3d4ca1.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -5d94b5ff4aea20818d6fa4780236bf1b912127a57e0d9c48c9e3cdbb88484452452561bc68b72901e3b433bc6512d595af94f0d76425ab3cac0d3c00710710ad diff --git a/deps/checksums/Pkg-e7a2dfecbfe43cf1c32f1ccd1e98a4dca52726ee.tar.gz/md5 b/deps/checksums/Pkg-e7a2dfecbfe43cf1c32f1ccd1e98a4dca52726ee.tar.gz/md5 new file mode 100644 index 0000000000000..afba373e163a4 --- /dev/null +++ b/deps/checksums/Pkg-e7a2dfecbfe43cf1c32f1ccd1e98a4dca52726ee.tar.gz/md5 @@ -0,0 +1 @@ +748d62ff0edc36821fbd739d5bc58bad diff --git a/deps/checksums/Pkg-e7a2dfecbfe43cf1c32f1ccd1e98a4dca52726ee.tar.gz/sha512 b/deps/checksums/Pkg-e7a2dfecbfe43cf1c32f1ccd1e98a4dca52726ee.tar.gz/sha512 new file mode 100644 index 0000000000000..17170e00be6ef --- /dev/null +++ b/deps/checksums/Pkg-e7a2dfecbfe43cf1c32f1ccd1e98a4dca52726ee.tar.gz/sha512 @@ -0,0 +1 @@ +c1dee8e8f0273897a8cdf29661f05dfb0e8025ddbf06b86d6b03bd5d499290c11694a6d089145c3698d100a49d0489337b770b23b54f49143498a28a74b87b6d diff --git a/stdlib/Pkg.version b/stdlib/Pkg.version index 303fd9bbe4c28..83277d857f05e 100644 --- a/stdlib/Pkg.version +++ b/stdlib/Pkg.version @@ -1,4 +1,4 @@ PKG_BRANCH = release-1.12 -PKG_SHA1 = b5f97876073d0443d6dbbc080d7b28205f3d4ca1 +PKG_SHA1 = e7a2dfecbfe43cf1c32f1ccd1e98a4dca52726ee PKG_GIT_URL := https://github.com/JuliaLang/Pkg.jl.git PKG_TAR_URL = https://api.github.com/repos/JuliaLang/Pkg.jl/tarball/$1 From 885f8e725eb2ba2ae680390b5929c5c8f0422151 Mon Sep 17 00:00:00 2001 From: Gabriel Baraldi Date: Tue, 3 Jun 2025 23:03:21 -0300 Subject: [PATCH 63/83] If the user explicitly asked for 1 thread don't add an interactive one. (#57454) Co-authored-by: Ian Butterworth (cherry picked from commit b04b1040203d4093163d285e25a71bb9bf5b9f0c) --- NEWS.md | 7 ++++--- doc/src/manual/multi-threading.md | 5 ++++- src/jloptions.c | 3 +++ src/threading.c | 2 ++ test/cmdlineargs.jl | 6 ++++++ 5 files changed, 19 insertions(+), 4 deletions(-) diff --git a/NEWS.md b/NEWS.md index 9dee73bda6898..94957fa86f5bb 100644 --- a/NEWS.md +++ b/NEWS.md @@ -36,9 +36,10 @@ Language changes * Julia now defaults to 1 "interactive" thread, in addition to the 1 default "worker" thread. i.e. `-t1,1`. This means in default configuration the main task and repl (when in interactive mode), which both run on thread 1, now run within the `interactive` threadpool. The libuv IO loop also runs on thread 1, - helping efficient utilization of the worker threadpool used by `Threads.@spawn`. Pass `0` to disable the - interactive thread i.e. `-t1,0` or `JULIA_NUM_THREADS=1,0`, or `-tauto,0` etc. The zero is explicitly - required to disable it, `-t2` will set the equivalent of `-t2,1` ([#57087]). + helping efficient utilization of the worker threadpool used by `Threads.@spawn`. Asking for specifically 1 thread + (`-t1`/`JULIA_NUM_THREADS=1`) or passing `0` will disable the interactive thread i.e. `-t1,0` or `JULIA_NUM_THREADS=1,0` + , or `-tauto,0` etc. Asking for more than 1 thread will enable the interactive thread so + `-t2` will set the equivalent of `-t2,1` ([#57087]). * When a method is replaced with an exactly equivalent one, the old method is not deleted. Instead, the new method takes priority and becomes more specific than the old method. Thus if the new method is deleted later, the old method will resume operating. This can be useful in mocking frameworks (as in SparseArrays, diff --git a/doc/src/manual/multi-threading.md b/doc/src/manual/multi-threading.md index ec470f867cc47..401169e9c2132 100644 --- a/doc/src/manual/multi-threading.md +++ b/doc/src/manual/multi-threading.md @@ -8,7 +8,7 @@ of Julia multi-threading features. By default, Julia starts up with 2 threads of execution; 1 worker thread and 1 interactive thread. This can be verified by using the command [`Threads.nthreads()`](@ref): -```jldoctest +```julia julia> Threads.nthreads(:default) 1 julia> Threads.nthreads(:interactive) @@ -37,6 +37,7 @@ each threadpool. !!! compat "Julia 1.12" Starting by default with 1 interactive thread, as well as the 1 worker thread, was made as such in Julia 1.12 + If the number of threads is set to 1 by either doing `-t1` or `JULIA_NUM_THREADS=1` an interactive thread will not be spawned. Lets start Julia with 4 threads: @@ -144,6 +145,8 @@ julia> nthreads(:interactive) julia> nthreads() 3 ``` +!!! note + Explicitly asking for 1 thread by doing `-t1` or `JULIA_NUM_THREADS=1` does not add an interactive thread. !!! note The zero-argument version of `nthreads` returns the number of threads diff --git a/src/jloptions.c b/src/jloptions.c index 79afe65ea9bf7..96cce1c8d29a3 100644 --- a/src/jloptions.c +++ b/src/jloptions.c @@ -662,6 +662,9 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp) if (nthreadsi == 0) jl_options.nthreadpools = 1; } + } else if (nthreads == 1) { // User asked for 1 thread so don't add an interactive one + jl_options.nthreadpools = 1; + nthreadsi = 0; } jl_options.nthreads = nthreads + nthreadsi; } diff --git a/src/threading.c b/src/threading.c index 0211c9798c8bb..655cf26c782b2 100644 --- a/src/threading.c +++ b/src/threading.c @@ -735,6 +735,8 @@ void jl_init_threading(void) if (errno != 0 || endptr == cp || nthreads <= 0) nthreads = 1; cp = endptr; + if (nthreads == 1) // User asked for 1 thread so lets assume they dont want an interactive thread + nthreadsi = 0; } if (*cp == ',') { cp++; diff --git a/test/cmdlineargs.jl b/test/cmdlineargs.jl index 6760b75c4fded..09cb4c1d6bf9a 100644 --- a/test/cmdlineargs.jl +++ b/test/cmdlineargs.jl @@ -351,6 +351,7 @@ let exename = `$(Base.julia_cmd()) --startup-file=no --color=no` # -t, --threads code = "print(Threads.threadpoolsize())" + code2 = "print(Threads.maxthreadid())" cpu_threads = ccall(:jl_effective_threads, Int32, ()) @test string(cpu_threads) == read(`$exename --threads auto -e $code`, String) == @@ -361,6 +362,11 @@ let exename = `$(Base.julia_cmd()) --startup-file=no --color=no` withenv("JULIA_NUM_THREADS" => nt) do @test read(`$exename --threads=2 -e $code`, String) == read(`$exename -t 2 -e $code`, String) == "2" + if nt === nothing + @test read(`$exename -e $code2`, String) == "2" #default + interactive + elseif nt == "1" + @test read(`$exename -e $code2`, String) == "1" #if user asks for 1 give 1 + end end end # We want to test oversubscription, but on manycore machines, this can From b310ecff5634beb44dec948617990ae02ed5ac0c Mon Sep 17 00:00:00 2001 From: KristofferC Date: Mon, 7 Jul 2025 13:00:53 +0200 Subject: [PATCH 64/83] fix module check for new Pkg module name --- stdlib/Artifacts/src/Artifacts.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stdlib/Artifacts/src/Artifacts.jl b/stdlib/Artifacts/src/Artifacts.jl index e21db58b9445e..f240f6defa0d0 100644 --- a/stdlib/Artifacts/src/Artifacts.jl +++ b/stdlib/Artifacts/src/Artifacts.jl @@ -562,7 +562,7 @@ function _artifact_str(__module__, artifacts_toml, name, path_tail, artifact_dic meta = artifact_meta(name, artifact_dict, artifacts_toml; platform) if meta !== nothing && get(meta, "lazy", false) if LazyArtifacts isa Module && isdefined(LazyArtifacts, :ensure_artifact_installed) - if nameof(LazyArtifacts) in (:Pkg, :Artifacts) + if nameof(LazyArtifacts) in (:Pkg, :Artifacts, :PkgArtifacts) Base.depwarn("using Pkg instead of using LazyArtifacts is deprecated", :var"@artifact_str", force=true) end return jointail(LazyArtifacts.ensure_artifact_installed(string(name), meta, artifacts_toml; platform), path_tail) @@ -697,7 +697,7 @@ macro artifact_str(name, platform=nothing) # Check if the user has provided `LazyArtifacts`, and thus supports lazy artifacts # If not, check to see if `Pkg` or `Pkg.Artifacts` has been imported. LazyArtifacts = nothing - for module_name in (:LazyArtifacts, :Pkg, :Artifacts) + for module_name in (:LazyArtifacts, :Pkg, :Artifacts, :PkgArtifacts) if isdefined(__module__, module_name) LazyArtifacts = GlobalRef(__module__, module_name) break From 38306650b979ff47350b3eb0f74673c258d44a82 Mon Sep 17 00:00:00 2001 From: Matt Bauman Date: Wed, 7 May 2025 15:01:56 -0400 Subject: [PATCH 65/83] Remove bugged and typically slower `minimum`/`maximum` method (#58267) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This method intends to be a SIMD-able optimization for reductions with `min` and `max`, but it fails to achieve those goals on nearly every architecture. For example, on my Mac M1 the generic implementation is more than **6x** faster than this method. Fixes #45932, fixes #36412, fixes #36081. --------- Co-authored-by: Mosè Giordano <765740+giordano@users.noreply.github.com> (cherry picked from commit 99ba3c798534c365b2eb815ed0624fd7eacbb21e) --- base/reduce.jl | 57 -------------------------------------------------- test/reduce.jl | 20 +++++++++++++++++- 2 files changed, 19 insertions(+), 58 deletions(-) diff --git a/base/reduce.jl b/base/reduce.jl index 60bff3acb52ed..2a6a268f2e6c1 100644 --- a/base/reduce.jl +++ b/base/reduce.jl @@ -609,63 +609,6 @@ julia> prod(1:5; init = 1.0) prod(a; kw...) = mapreduce(identity, mul_prod, a; kw...) ## maximum, minimum, & extrema -_fast(::typeof(min),x,y) = min(x,y) -_fast(::typeof(max),x,y) = max(x,y) -function _fast(::typeof(max), x::AbstractFloat, y::AbstractFloat) - ifelse(isnan(x), - x, - ifelse(x > y, x, y)) -end - -function _fast(::typeof(min),x::AbstractFloat, y::AbstractFloat) - ifelse(isnan(x), - x, - ifelse(x < y, x, y)) -end - -isbadzero(::typeof(max), x::AbstractFloat) = (x == zero(x)) & signbit(x) -isbadzero(::typeof(min), x::AbstractFloat) = (x == zero(x)) & !signbit(x) -isbadzero(op, x) = false -isgoodzero(::typeof(max), x) = isbadzero(min, x) -isgoodzero(::typeof(min), x) = isbadzero(max, x) - -function mapreduce_impl(f, op::Union{typeof(max), typeof(min)}, - A::AbstractArrayOrBroadcasted, first::Int, last::Int) - a1 = @inbounds A[first] - v1 = mapreduce_first(f, op, a1) - v2 = v3 = v4 = v1 - chunk_len = 256 - start = first + 1 - simdstop = start + chunk_len - 4 - while simdstop <= last - 3 - for i in start:4:simdstop - v1 = _fast(op, v1, f(@inbounds(A[i+0]))) - v2 = _fast(op, v2, f(@inbounds(A[i+1]))) - v3 = _fast(op, v3, f(@inbounds(A[i+2]))) - v4 = _fast(op, v4, f(@inbounds(A[i+3]))) - end - checkbounds(A, simdstop+3) - start += chunk_len - simdstop += chunk_len - end - v = op(op(v1,v2),op(v3,v4)) - for i in start:last - @inbounds ai = A[i] - v = op(v, f(ai)) - end - - # enforce correct order of 0.0 and -0.0 - # e.g. maximum([0.0, -0.0]) === 0.0 - # should hold - if isbadzero(op, v) - for i in first:last - x = @inbounds A[i] - isgoodzero(op,x) && return x - end - end - return v -end - """ maximum(f, itr; [init]) diff --git a/test/reduce.jl b/test/reduce.jl index f5140c8a34bd9..2f30fcb905808 100644 --- a/test/reduce.jl +++ b/test/reduce.jl @@ -299,19 +299,37 @@ end arr = zeros(N) @test minimum(arr) === 0.0 @test maximum(arr) === 0.0 + @test minimum(abs, arr) === 0.0 + @test maximum(abs, arr) === 0.0 + @test minimum(-, arr) === -0.0 + @test maximum(-, arr) === -0.0 arr[i] = -0.0 @test minimum(arr) === -0.0 @test maximum(arr) === 0.0 + @test minimum(abs, arr) === 0.0 + @test maximum(abs, arr) === 0.0 + @test minimum(-, arr) === -0.0 + @test maximum(-, arr) === 0.0 arr = -zeros(N) @test minimum(arr) === -0.0 @test maximum(arr) === -0.0 + @test minimum(abs, arr) === 0.0 + @test maximum(abs, arr) === 0.0 + @test minimum(-, arr) === 0.0 + @test maximum(-, arr) === 0.0 arr[i] = 0.0 @test minimum(arr) === -0.0 - @test maximum(arr) === 0.0 + @test maximum(arr) === 0.0 + @test minimum(abs, arr) === 0.0 + @test maximum(abs, arr) === 0.0 + @test minimum(-, arr) === -0.0 + @test maximum(-, arr) === 0.0 end end + + @test minimum(abs, fill(-0.0, 16)) === mapreduce(abs, (x,y)->min(x,y), fill(-0.0, 16)) === 0.0 end @testset "maximum works on generic order #30320" begin From 3ca6ec57476241f3896f0bde83e6d6e74715aaf8 Mon Sep 17 00:00:00 2001 From: Simeon David Schaub Date: Tue, 1 Jul 2025 16:58:39 +0200 Subject: [PATCH 66/83] fix null comparisons for non-standard address spaces (#58837) Co-authored-by: Jameson Nash (cherry picked from commit 3ed13ea7ab3d73f408b12a70ad29565c97bf5562) --- src/cgutils.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/cgutils.cpp b/src/cgutils.cpp index 78b6571692163..945e125c71be2 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -1601,10 +1601,17 @@ static void undef_var_error_ifnot(jl_codectx_t &ctx, Value *ok, jl_sym_t *name, ctx.builder.SetInsertPoint(ifok); } +// ctx.builder.CreateIsNotNull(v) lowers incorrectly in non-standard +// address spaces where null is not zero +// TODO: adapt to https://github.com/llvm/llvm-project/pull/131557 once merged static Value *null_pointer_cmp(jl_codectx_t &ctx, Value *v) { ++EmittedNullchecks; - return ctx.builder.CreateIsNotNull(v); + Type *T = v->getType(); + return ctx.builder.CreateICmpNE( + v, + ctx.builder.CreateAddrSpaceCast( + Constant::getNullValue(ctx.builder.getPtrTy(0)), T)); } From 8180b74036e5761ec33edd5358d5d4b5888f5a5c Mon Sep 17 00:00:00 2001 From: Gabriel Baraldi Date: Tue, 1 Jul 2025 19:24:58 -0300 Subject: [PATCH 67/83] Re-add old function name for backward compatibility in init (#58860) While julia has no C-API backwards compatibility guarantees this is simple enough to add. Fixes #58859 (cherry picked from commit 92aacab2ed35671fa0762fc1a65df8b254fbd302) --- src/jl_exported_funcs.inc | 1 + src/jlapi.c | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/src/jl_exported_funcs.inc b/src/jl_exported_funcs.inc index 60a5256af2b58..e5631ae24849a 100644 --- a/src/jl_exported_funcs.inc +++ b/src/jl_exported_funcs.inc @@ -243,6 +243,7 @@ XX(jl_init_) \ XX(jl_init_options) \ XX(jl_init_restored_module) \ + XX(jl_init_with_image) \ XX(jl_init_with_image_file) \ XX(jl_init_with_image_handle) \ XX(jl_install_sigint_handler) \ diff --git a/src/jlapi.c b/src/jlapi.c index 0d8ddd10d9ea1..6559adc94c1b9 100644 --- a/src/jlapi.c +++ b/src/jlapi.c @@ -120,6 +120,13 @@ JL_DLLEXPORT void jl_init_with_image_file(const char *julia_bindir, jl_exception_clear(); } +// Deprecated function, kept for backward compatibility +JL_DLLEXPORT void jl_init_with_image(const char *julia_bindir, + const char *image_path) +{ + jl_init_with_image_file(julia_bindir, image_path); +} + /** * @brief Initialize the Julia runtime. * From ba3d2d8b98a4c52b92146f9cfc09a45533ede4c5 Mon Sep 17 00:00:00 2001 From: Alex Arslan Date: Wed, 2 Jul 2025 10:46:19 -0700 Subject: [PATCH 68/83] Add a `similar` method for `Type{<:CodeUnits}` (#57826) Currently, `similar(::CodeUnits)` works as expected by going through the generic `AbstractArray` method. However, the fallback method hit by `similar(::Type{<:CodeUnits}, dims)` does not work, as it assumes the existence of a constructor that accepts an `UndefInitializer`. This can be made to work by defining a corresponding `similar` method that returns an `Array`. One could make a case that this is a bugfix since it was arguably a bug that this method didn't work given that `CodeUnits` is an `AbstractArray` subtype and the other `similar` methods work. If anybody buys that argument, it could be nice to backport this; it came up in some internal code that uses Arrow.jl and JSON3.jl together. (cherry picked from commit 8e524c73804a9615dd68011b2c5741947d19bbb6) --- base/strings/basic.jl | 2 ++ test/strings/basic.jl | 1 + 2 files changed, 3 insertions(+) diff --git a/base/strings/basic.jl b/base/strings/basic.jl index c40deb0656ced..50b0d419b9101 100644 --- a/base/strings/basic.jl +++ b/base/strings/basic.jl @@ -810,6 +810,8 @@ write(io::IO, s::CodeUnits) = write(io, s.s) cconvert(::Type{Ptr{T}}, s::CodeUnits{T}) where {T} = cconvert(Ptr{T}, s.s) cconvert(::Type{Ptr{Int8}}, s::CodeUnits{UInt8}) = cconvert(Ptr{Int8}, s.s) +similar(::Type{<:CodeUnits{T}}, dims::Dims) where {T} = similar(Array{T}, dims) + """ codeunits(s::AbstractString) diff --git a/test/strings/basic.jl b/test/strings/basic.jl index c3e0bcc501070..f36f45e9a2ce3 100644 --- a/test/strings/basic.jl +++ b/test/strings/basic.jl @@ -1078,6 +1078,7 @@ let s = "∀x∃y", u = codeunits(s) @test_throws Base.CanonicalIndexError (u[1] = 0x00) @test collect(u) == b"∀x∃y" @test Base.elsize(u) == Base.elsize(typeof(u)) == 1 + @test similar(typeof(u), 3) isa Vector{UInt8} end @testset "issue #24388" begin From ff0e3234ca80eb564233f74853f6f73392ae9bde Mon Sep 17 00:00:00 2001 From: Sam Schweigel <33556084+xal-0@users.noreply.github.com> Date: Wed, 2 Jul 2025 16:02:30 -0700 Subject: [PATCH 69/83] Fix data race in jl_new_module__ (#58880) Use an atomic fetch and add to fix a data race in `Module()` identified by tsan: ``` ./usr/bin/julia -t4,0 --gcthreads=1 -e 'Threads.@threads for i=1:100 Module() end' ================== WARNING: ThreadSanitizer: data race (pid=5575) Write of size 4 at 0xffff9bf9bd28 by thread T9: #0 jl_new_module__ /home/user/c/julia/src/module.c:487:22 (libjulia-internal.so.1.13+0x897d4) #1 jl_new_module_ /home/user/c/julia/src/module.c:527:22 (libjulia-internal.so.1.13+0x897d4) #2 jl_f_new_module /home/user/c/julia/src/module.c:649:22 (libjulia-internal.so.1.13+0x8a968) #3 (0xffff76a21164) #4 (0xffff76a1f074) #5 (0xffff76a1f0c4) #6 _jl_invoke /home/user/c/julia/src/gf.c (libjulia-internal.so.1.13+0x5ea04) #7 ijl_apply_generic /home/user/c/julia/src/gf.c:3892:12 (libjulia-internal.so.1.13+0x5ea04) #8 jl_apply /home/user/c/julia/src/julia.h:2343:12 (libjulia-internal.so.1.13+0x9e4c4) #9 start_task /home/user/c/julia/src/task.c:1249:19 (libjulia-internal.so.1.13+0x9e4c4) Previous write of size 4 at 0xffff9bf9bd28 by thread T10: #0 jl_new_module__ /home/user/c/julia/src/module.c:487:22 (libjulia-internal.so.1.13+0x897d4) #1 jl_new_module_ /home/user/c/julia/src/module.c:527:22 (libjulia-internal.so.1.13+0x897d4) #2 jl_f_new_module /home/user/c/julia/src/module.c:649:22 (libjulia-internal.so.1.13+0x8a968) #3 (0xffff76a21164) #4 (0xffff76a1f074) #5 (0xffff76a1f0c4) #6 _jl_invoke /home/user/c/julia/src/gf.c (libjulia-internal.so.1.13+0x5ea04) #7 ijl_apply_generic /home/user/c/julia/src/gf.c:3892:12 (libjulia-internal.so.1.13+0x5ea04) #8 jl_apply /home/user/c/julia/src/julia.h:2343:12 (libjulia-internal.so.1.13+0x9e4c4) #9 start_task /home/user/c/julia/src/task.c:1249:19 (libjulia-internal.so.1.13+0x9e4c4) Location is global 'jl_new_module__.mcounter' of size 4 at 0xffff9bf9bd28 (libjulia-internal.so.1.13+0x3dbd28) ``` (cherry picked from commit 903955503f99ea5235ffef6a638e43593fb4a950) --- src/module.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/module.c b/src/module.c index b53a5307b5c78..c28e1a834ce46 100644 --- a/src/module.c +++ b/src/module.c @@ -482,9 +482,10 @@ static jl_module_t *jl_new_module__(jl_sym_t *name, jl_module_t *parent) m->parent = parent ? parent : m; m->istopmod = 0; m->uuid = uuid_zero; - static unsigned int mcounter; // simple counter backup, in case hrtime is not incrementing + static _Atomic(unsigned int) mcounter; // simple counter backup, in case hrtime is not incrementing + unsigned int count = jl_atomic_fetch_add_relaxed(&mcounter, 1); // TODO: this is used for ir decompression and is liable to hash collisions so use more of the bits - m->build_id.lo = bitmix(jl_hrtime() + (++mcounter), jl_rand()); + m->build_id.lo = bitmix(jl_hrtime() + count, jl_rand()); if (!m->build_id.lo) m->build_id.lo++; // build id 0 is invalid m->build_id.hi = ~(uint64_t)0; From 97f21e3ef4e5722fc13d62ea4037cb061e8a7f4b Mon Sep 17 00:00:00 2001 From: Andy Dienes <51664769+adienes@users.noreply.github.com> Date: Wed, 2 Jul 2025 23:06:00 -0400 Subject: [PATCH 70/83] fix trailing indices stackoverflow in reinterpreted array (#58293) would fix https://github.com/JuliaLang/julia/issues/57170, fix https://github.com/JuliaLang/julia/issues/54623 @nanosoldier `runbenchmarks("array", vs=":master")` (cherry picked from commit e853a4f8bac99c6458cf3e09d95d9bea67b687e7) --- base/reinterpretarray.jl | 8 ++++---- test/reinterpretarray.jl | 23 +++++++++++++++++++++++ 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/base/reinterpretarray.jl b/base/reinterpretarray.jl index 4feb14539f9dc..b88c7b06621d9 100644 --- a/base/reinterpretarray.jl +++ b/base/reinterpretarray.jl @@ -313,13 +313,13 @@ end _maybe_reshape(::IndexSCartesian2, A::ReshapedReinterpretArray, I...) = A # fallbacks -function _getindex(::IndexSCartesian2, A::AbstractArray{T,N}, I::Vararg{Int, N}) where {T,N} +function _getindex(::IndexSCartesian2, A::AbstractArray, I::Vararg{Int, N}) where {N} @_propagate_inbounds_meta - getindex(A, I...) + _getindex(IndexCartesian(), A, I...) end -function _setindex!(::IndexSCartesian2, A::AbstractArray{T,N}, v, I::Vararg{Int, N}) where {T,N} +function _setindex!(::IndexSCartesian2, A::AbstractArray, v, I::Vararg{Int, N}) where {N} @_propagate_inbounds_meta - setindex!(A, v, I...) + _setindex!(IndexCartesian(), A, v, I...) end # fallbacks for array types that use "pass-through" indexing (e.g., `IndexStyle(A) = IndexStyle(parent(A))`) # but which don't handle SCartesianIndex2 diff --git a/test/reinterpretarray.jl b/test/reinterpretarray.jl index e6381329e4ec6..1d6748a89fb19 100644 --- a/test/reinterpretarray.jl +++ b/test/reinterpretarray.jl @@ -320,6 +320,23 @@ test_many_wrappers(fill(1.0, 5, 3), (identity, wrapper)) do a_ @test r[goodinds...] == -5 end end + +let a = rand(ComplexF32, 5) + r = reinterpret(reshape, Float32, a) + ref = Array(r) + + @test r[1, :, 1] == ref[1, :] + @test r[1, :, 1, 1, 1] == ref[1, :] + @test r[1, :, UInt8(1)] == ref[1, :] + + r[2, :, 1] .= 0f0 + ref[2, :] .= 0f0 + @test r[2, :, 1] == ref[2, :] + + @test r[4] == ref[4] + @test_throws BoundsError r[1, :, 2] +end + let ar = [(1,2), (3,4)] arr = reinterpret(reshape, Int, ar) @test @inferred(IndexStyle(arr)) == Base.IndexSCartesian2{2}() @@ -607,3 +624,9 @@ let R = reinterpret(reshape, Float32, ComplexF32[1.0f0+2.0f0*im, 4.0f0+3.0f0*im] @test !isassigned(R, 5) @test Array(R)::Matrix{Float32} == [1.0f0 4.0f0; 2.0f0 3.0f0] end + +@testset "issue #54623" begin + x = 0xabcdef01234567 + @test reinterpret(reshape, UInt8, fill(x)) == [0x67, 0x45, 0x23, 0x01, 0xef, 0xcd, 0xab, 0x00] + @test reinterpret(reshape, UInt8, [x]) == [0x67; 0x45; 0x23; 0x01; 0xef; 0xcd; 0xab; 0x00;;] +end From 9517f8121261d660bde2a2bcedf43c853fe0344a Mon Sep 17 00:00:00 2001 From: Erik Schnetter Date: Thu, 3 Jul 2025 04:07:16 -0400 Subject: [PATCH 71/83] OpenSSL: Update to 3.5.1 (#58876) Update the stdlib OpenSSL to 3.5.1. This is a candidate for backporting to Julia 1.12 if there is another beta release. (cherry picked from commit 41570e9800c872fc7ad8cf1c74fbbed4236e88c4) --- deps/checksums/openssl | 76 ++++++++++++++--------------- deps/openssl.version | 2 +- stdlib/OpenSSL_jll/Project.toml | 2 +- stdlib/OpenSSL_jll/test/runtests.jl | 2 +- 4 files changed, 41 insertions(+), 41 deletions(-) diff --git a/deps/checksums/openssl b/deps/checksums/openssl index 3b41bfa69231d..cca21ccd8c5a5 100644 --- a/deps/checksums/openssl +++ b/deps/checksums/openssl @@ -1,38 +1,38 @@ -OpenSSL.v3.5.0+0.aarch64-apple-darwin.tar.gz/md5/b8dc9909528f769bd9ac56cf2681f387 -OpenSSL.v3.5.0+0.aarch64-apple-darwin.tar.gz/sha512/0d9ea24d8f856c31c8b88afa1de317d13aff1f1f60b309e06e77eea91d195526ec91ed2d077f0dbb75370c17b8875c24d3066e6872bbef04312616e99d0aff3d -OpenSSL.v3.5.0+0.aarch64-linux-gnu.tar.gz/md5/7cf5baeacf4d882b547c229758a9fa9b -OpenSSL.v3.5.0+0.aarch64-linux-gnu.tar.gz/sha512/726ceee82379e667a65abe27c482d3b57e611c630d82b1314f6d385f0f2e8256835ef707c2e015f9204d563d7ee469bed2dee88d245af81dcde2af3b8331b19c -OpenSSL.v3.5.0+0.aarch64-linux-musl.tar.gz/md5/4601e56eaed365548203752a19f4f8e8 -OpenSSL.v3.5.0+0.aarch64-linux-musl.tar.gz/sha512/da349081850d47b9393665c4365787c26f61471362475c2acd3c8205063d09a785f7b6c836ba6793e880440115b19e85821b4d1938e57dafea0cabb45048a70b -OpenSSL.v3.5.0+0.aarch64-unknown-freebsd.tar.gz/md5/6a9e78436727e67af2f537170e18445e -OpenSSL.v3.5.0+0.aarch64-unknown-freebsd.tar.gz/sha512/4dc2f7a39f17255871773d10ed1b74de5c908af0f7a4bd3f94fd71bc12480fd4cdee0bd859a154328218935f004eee20359dacc353e366c47ed890229a579fc4 -OpenSSL.v3.5.0+0.armv6l-linux-gnueabihf.tar.gz/md5/5c751092c27910a48cab31f87700fe19 -OpenSSL.v3.5.0+0.armv6l-linux-gnueabihf.tar.gz/sha512/b44e2356f719549dd831745963b8c74346be173d176ca15ab2ee6f4a1ec7e105086d89115cb76831a3251eb67bf7c5ff5cba3a03fd4614a3501af235a8e03beb -OpenSSL.v3.5.0+0.armv6l-linux-musleabihf.tar.gz/md5/fc05f9645ff000b21e46951f16833fb0 -OpenSSL.v3.5.0+0.armv6l-linux-musleabihf.tar.gz/sha512/8c960294fe542ab9d9ae7dc283c0c30621f348ff8011a9a47f38c1460234b3b128011426c3e5d0cb6c9b02fbee261b7b264d0b0c55bdf3be2a2cd5bdd210d71d -OpenSSL.v3.5.0+0.armv7l-linux-gnueabihf.tar.gz/md5/8928d47a0f549d15240eb934caddf599 -OpenSSL.v3.5.0+0.armv7l-linux-gnueabihf.tar.gz/sha512/4b5dbfb3a4ea4ebe6510cbe63da2de0bb3762a0fc98946acbb059e9a92791ac65a3519577250dcb571fa07f29be182f165a5d4fa05fc96b60270441adab30e74 -OpenSSL.v3.5.0+0.armv7l-linux-musleabihf.tar.gz/md5/1e4c11043d05bea0fcdbf92525152c51 -OpenSSL.v3.5.0+0.armv7l-linux-musleabihf.tar.gz/sha512/e9514cd0c3a8c3659ff87d505490ca3011a65800222b21e4f932bc2a80fb38bb11de1d13925c3a6313f6bea1c2baf35b38b3db18193ac11ec42eb434edee3418 -OpenSSL.v3.5.0+0.i686-linux-gnu.tar.gz/md5/ee699f302edd1f7677baa565ae631c74 -OpenSSL.v3.5.0+0.i686-linux-gnu.tar.gz/sha512/16dd396b192b4ca23d1fad54d130a92ef43a36259482cd3b276001d084711ef8674dcd167c9f832f5989d6197889af69d2ae6bcef3e6b9f538066bf347c89584 -OpenSSL.v3.5.0+0.i686-linux-musl.tar.gz/md5/e6ffea118acb68d39ccb13df51e15125 -OpenSSL.v3.5.0+0.i686-linux-musl.tar.gz/sha512/44335dcaf144d388bd47dd80db08862f4cff1d5a90861f34001127df74d0d16babedbe0ffd02ab398bddd17ecda605f433a940b3cc5159947cb54810a564b0df -OpenSSL.v3.5.0+0.i686-w64-mingw32.tar.gz/md5/8ef4284ac47a6b45f8c5b01d203ae668 -OpenSSL.v3.5.0+0.i686-w64-mingw32.tar.gz/sha512/d7ea8c94d54a139631f2710cb2c47c0387b694e60dc7afddbca3c6705e17d25ec8958a84b4424edd1ea27d6d1c78457fbacd92f7634345f4ccc1a81cf242c28f -OpenSSL.v3.5.0+0.powerpc64le-linux-gnu.tar.gz/md5/21674471f2a3352ede9aef3454381edd -OpenSSL.v3.5.0+0.powerpc64le-linux-gnu.tar.gz/sha512/5615d438db7c3e97dc422b260b3152cd89a2412b7b9b5d7cea36b0ce471fbd3f1a2e8a9d77f399e257f5c38b8b5dfc256acfbdbe2645ba47b89c177dadd066e9 -OpenSSL.v3.5.0+0.riscv64-linux-gnu.tar.gz/md5/7761384fd5991eb56286f24c9a0fbdba -OpenSSL.v3.5.0+0.riscv64-linux-gnu.tar.gz/sha512/e63d5f7ddc368f4cdb03c299361faef7274930c622404907c3560eb04e6110f851b9a201b402bb6e52fdafe64988f909c209f659f84ba77957eb45a933c8baf1 -OpenSSL.v3.5.0+0.x86_64-apple-darwin.tar.gz/md5/a970728a9aa6f25d56db7e43e7b0cae2 -OpenSSL.v3.5.0+0.x86_64-apple-darwin.tar.gz/sha512/8ab5b2dd90914e193d1f7689c8560228d03cb6ee79fd43a48ae9339b61274fea0557a2bf3a7ae4ce4d4b51630aede55d6d6e860f263e1ffc0bfd6141367a9514 -OpenSSL.v3.5.0+0.x86_64-linux-gnu.tar.gz/md5/4530c0e1791b0eaec99b68f2967a3c2f -OpenSSL.v3.5.0+0.x86_64-linux-gnu.tar.gz/sha512/ba952738be38f52ebc23f48c52c12c1bec9c8b81416264612da21ca21f23604c8e59bf49f73d4b80256ea17b6b662179620deadb8660be98d8ad5ed57e346394 -OpenSSL.v3.5.0+0.x86_64-linux-musl.tar.gz/md5/eb49cefbb938d80198dbab90e1ad9108 -OpenSSL.v3.5.0+0.x86_64-linux-musl.tar.gz/sha512/f038e9bd950e4472cdd82b0c39aebbfd60e75cdf24fd8408d39e4db0793813c9d30471d1ca8d112b0bb4049f18f8fb36b4c3069dfce61032dc73cb6568852b77 -OpenSSL.v3.5.0+0.x86_64-unknown-freebsd.tar.gz/md5/25023844dae8c7d326620b1f9e730a07 -OpenSSL.v3.5.0+0.x86_64-unknown-freebsd.tar.gz/sha512/e38f1f7c452903a09b3f0127e377d5e46e538903f9a58076e53dfc53883b2423463d3fdcf13dc961516965b6dbc2d289bfbfa1027f8c3110a61bdee060bccf73 -OpenSSL.v3.5.0+0.x86_64-w64-mingw32.tar.gz/md5/a73f5220598dfc5e71e1eee6b26f7a27 -OpenSSL.v3.5.0+0.x86_64-w64-mingw32.tar.gz/sha512/c028527230b6e9e675b7e22a21997e5d032e1099dd1f3437c6e764b7967fd0196d4cb46d66b36f2f6ddeb8200f445aa8d6a7a61f7be61288ee5e0e510b5800f8 -openssl-3.5.0.tar.gz/md5/51da7d2bdf7f4f508cb024f562eb9b03 -openssl-3.5.0.tar.gz/sha512/39cc80e2843a2ee30f3f5de25cd9d0f759ad8de71b0b39f5a679afaaa74f4eb58d285ae50e29e4a27b139b49343ac91d1f05478f96fb0c6b150f16d7b634676f +OpenSSL.v3.5.1+0.aarch64-apple-darwin.tar.gz/md5/b19522093c25c50685002ad48933a835 +OpenSSL.v3.5.1+0.aarch64-apple-darwin.tar.gz/sha512/afa6363f8396deac5131f5efbe92d5b60f4d6982d279d63b5847e80ac4717d89e32edcc9bc7a5fbaab95e03908a6e3e9b386a3931effb0a7163b947b38ed2cd5 +OpenSSL.v3.5.1+0.aarch64-linux-gnu.tar.gz/md5/60af2cb22b7d5f4fddd94bd196f86ad2 +OpenSSL.v3.5.1+0.aarch64-linux-gnu.tar.gz/sha512/3d384f5da4be3af848b47f48f2438dbda8cdb228b8569d01bd4fbd6feea9f494ecafd3cab6e7b0bbed596746aa2614826971133a2b6dea02836c0904ce870760 +OpenSSL.v3.5.1+0.aarch64-linux-musl.tar.gz/md5/5f96641ec5256a547e03cd6028892a50 +OpenSSL.v3.5.1+0.aarch64-linux-musl.tar.gz/sha512/668c08f2a08f9d65b2e5c1ca4db8f74932995d0fa97c4737a2d9cedb3548482f85fddd478fad37325e2d48f76259fd8f7e003d31fc2a9ecfdb88c4748f90e1d6 +OpenSSL.v3.5.1+0.aarch64-unknown-freebsd.tar.gz/md5/377bd17ae448f4394b3100b290602f35 +OpenSSL.v3.5.1+0.aarch64-unknown-freebsd.tar.gz/sha512/f989a15062b47f059086d4dc8fd53af00717ca622ef8c475a11f6e62a29d8ec4a80159d93a683e8729da66c4bda4c46b7647754dc996ed2ff5635cbbdaf702aa +OpenSSL.v3.5.1+0.armv6l-linux-gnueabihf.tar.gz/md5/83bcc0b545bea092a0a5de9e64cbcbf1 +OpenSSL.v3.5.1+0.armv6l-linux-gnueabihf.tar.gz/sha512/c589119945ff6c1341bc229a2e61096c630288f7d483ea9538202915f8ee1a9e26cd53efc479f1e92a83a75aa6c7453ceba446832678ffed340a4bec13fefbfc +OpenSSL.v3.5.1+0.armv6l-linux-musleabihf.tar.gz/md5/3b2e34e506960259dbb40a36fed26ffe +OpenSSL.v3.5.1+0.armv6l-linux-musleabihf.tar.gz/sha512/735f22fe1202818f64f369471292bb8fdf8cf1f3395d01e70ddf8f65efc5430aec54a63fe950e52625f2c8a5dbd59ed0175f088144af8d99c7db1967ed0e5aeb +OpenSSL.v3.5.1+0.armv7l-linux-gnueabihf.tar.gz/md5/aedb37bde1b3fad428987745dc1dd095 +OpenSSL.v3.5.1+0.armv7l-linux-gnueabihf.tar.gz/sha512/1919823df3c0de01c59a5f9cf42b912a1d56fe7de903c4e7cbcd54603760783a99fe34cd1c108e954d5fe41502c1791b803d67742d70abae64d316c3656b7280 +OpenSSL.v3.5.1+0.armv7l-linux-musleabihf.tar.gz/md5/573a752ca28fd62644208a4c0b32eaa4 +OpenSSL.v3.5.1+0.armv7l-linux-musleabihf.tar.gz/sha512/3385b170973a9e50919981e66e591077479ae7561368941f018aca6f42c86b3d01aa1d9896d4d5f6deb69760fa42f535f6aaa076b75a15f207328ba6f0a32660 +OpenSSL.v3.5.1+0.i686-linux-gnu.tar.gz/md5/fcdb2ab108900c412abf154a6cbd46e7 +OpenSSL.v3.5.1+0.i686-linux-gnu.tar.gz/sha512/b558e6c23809f702a7388dba7031a9df577e1a2eb1ca86b7cf0dcd9809973dff1c9b56d4a09c315b17dcc9860e7f89604513a2d022117d9145f2bc81befa094b +OpenSSL.v3.5.1+0.i686-linux-musl.tar.gz/md5/0192e44a52d9518d712db58019ace62c +OpenSSL.v3.5.1+0.i686-linux-musl.tar.gz/sha512/fe9740850e6eb32eb539d16303b39d9ad1d3e8cc2e5a742304013890a0e1e8af93e131a5393c3c817b5723680425947d6954455dd715cc83589fd097c517b5c2 +OpenSSL.v3.5.1+0.i686-w64-mingw32.tar.gz/md5/51b5546301f8c474bcc9c97b625df2c1 +OpenSSL.v3.5.1+0.i686-w64-mingw32.tar.gz/sha512/47874ce005e6944f3a4d482f3edf44bcaa3724338230d68fff22c484c0620fe857a11bdc515ef9154522a2884f64bacadfd1fddb1430a45c7722a6a4799107f6 +OpenSSL.v3.5.1+0.powerpc64le-linux-gnu.tar.gz/md5/1aeaa0660006b4b8c13cd1cb45b2acfc +OpenSSL.v3.5.1+0.powerpc64le-linux-gnu.tar.gz/sha512/dff025feb0d1ae96a7c33f1beff5e6f76d5a85833314470f59d75bf791e90363145ae79f3ed82c5c40e36416b75fa9deb5807911c8133fe11f31b4705737f0bc +OpenSSL.v3.5.1+0.riscv64-linux-gnu.tar.gz/md5/160065eb12650c504fd40a25e4bae2ba +OpenSSL.v3.5.1+0.riscv64-linux-gnu.tar.gz/sha512/68951cf98c4eb778d372e239d14497405e6161461a623135a5254c3fd65bc3a12fe3df1ecce88909cb05dc29104b5b18caafea115799c5abf2505afe75be3207 +OpenSSL.v3.5.1+0.x86_64-apple-darwin.tar.gz/md5/7e5903d1d051de70a93a9b801ce274db +OpenSSL.v3.5.1+0.x86_64-apple-darwin.tar.gz/sha512/729b33cc208b8646394bcf0029a276ad41cf2e9d44737dbc1e15dca794cc55a52e2b782b0c72ef57b5580b84a93b25133788424f1b16ef2b784d409bca598150 +OpenSSL.v3.5.1+0.x86_64-linux-gnu.tar.gz/md5/9cee745524f41dc21af2f460ac2f1293 +OpenSSL.v3.5.1+0.x86_64-linux-gnu.tar.gz/sha512/6949c7f19b7919073542af903019ec0d8fd5172450141a3f69f0c325f0c5cc19618f1959b96380719538c5a1a5a388165a0db8e6eab041d0a5874a627820212b +OpenSSL.v3.5.1+0.x86_64-linux-musl.tar.gz/md5/e55565c84e5cff597ea490e02c559d1a +OpenSSL.v3.5.1+0.x86_64-linux-musl.tar.gz/sha512/c27930401c72b6be94ba7717f7b3be0025b09138e146f3d2a761e805308ee51f4ca871459941448e102f64b0e3c1aa479f39ee77f3234321890fa7105418ed44 +OpenSSL.v3.5.1+0.x86_64-unknown-freebsd.tar.gz/md5/276d97e2d573977727ca8d2113335fac +OpenSSL.v3.5.1+0.x86_64-unknown-freebsd.tar.gz/sha512/71f72a82c590542928660f004f38f84ea335b303e7da53578d712994fff9e84a3b69fc836c08d03dd8310d17c9edc63e5f6975e6d26e67124124763633ab1b59 +OpenSSL.v3.5.1+0.x86_64-w64-mingw32.tar.gz/md5/cebdbbf8a8a301e332d75c46dcdb1af0 +OpenSSL.v3.5.1+0.x86_64-w64-mingw32.tar.gz/sha512/0e141d7317ac8f5c43d1ecc9d161b00345f99145af785d7554f750b5787ea69969f785e7a1305059137271d26450835c25dd126bf9e5aef2cdf7dcbbdebb6911 +openssl-3.5.1.tar.gz/md5/562a4e8d14ee5272f677a754b9c1ca5c +openssl-3.5.1.tar.gz/sha512/0fa152ae59ab5ea066319de039dfb1d24cbb247172d7512feb5dd920db3740f219d76b0195ea562f84fe5eae36c23772302eddfbb3509df13761452b4dafb9d3 diff --git a/deps/openssl.version b/deps/openssl.version index 49c463aad1565..2313ae5ffe116 100644 --- a/deps/openssl.version +++ b/deps/openssl.version @@ -3,4 +3,4 @@ OPENSSL_JLL_NAME := OpenSSL ## source build -OPENSSL_VER := 3.5.0 +OPENSSL_VER := 3.5.1 diff --git a/stdlib/OpenSSL_jll/Project.toml b/stdlib/OpenSSL_jll/Project.toml index 28ecf86381213..d11c3b25a6922 100644 --- a/stdlib/OpenSSL_jll/Project.toml +++ b/stdlib/OpenSSL_jll/Project.toml @@ -1,6 +1,6 @@ name = "OpenSSL_jll" uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95" -version = "3.5.0+0" +version = "3.5.1+0" [deps] Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb" diff --git a/stdlib/OpenSSL_jll/test/runtests.jl b/stdlib/OpenSSL_jll/test/runtests.jl index e5ae938b68311..9ef99d57134e0 100644 --- a/stdlib/OpenSSL_jll/test/runtests.jl +++ b/stdlib/OpenSSL_jll/test/runtests.jl @@ -6,5 +6,5 @@ using Test, Libdl, OpenSSL_jll major = ccall((:OPENSSL_version_major, libcrypto), Cuint, ()) minor = ccall((:OPENSSL_version_minor, libcrypto), Cuint, ()) patch = ccall((:OPENSSL_version_patch, libcrypto), Cuint, ()) - @test VersionNumber(major, minor, patch) == v"3.5.0" + @test VersionNumber(major, minor, patch) == v"3.5.1" end From be73573f7e6865dea2c16dd162435c71f9c561a4 Mon Sep 17 00:00:00 2001 From: Nicholas Bauer Date: Thu, 3 Jul 2025 15:54:27 -0400 Subject: [PATCH 72/83] Add offset in `hvncat` dimension calculation to fix issue with 0-length elements in first dimension (#58881) (cherry picked from commit ed1fd390b59b7554c37bfe8f89b8c1f2ca654ead) --- base/abstractarray.jl | 13 ++++++++++++- test/abstractarray.jl | 6 ++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/base/abstractarray.jl b/base/abstractarray.jl index 2632592ede7c1..ac49209273adf 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -2553,16 +2553,23 @@ function _typed_hvncat_dims(::Type{T}, dims::NTuple{N, Int}, row_first::Bool, as end # discover number of rows or columns + # d1 dimension is increased by 1 to appropriately handle 0-length arrays for i ∈ 1:dims[d1] outdims[d1] += cat_size(as[i], d1) end + # adjustment to handle 0-length arrays + first_dim_zero = outdims[d1] == 0 + if first_dim_zero + outdims[d1] = dims[d1] + end + currentdims = zeros(Int, N) blockcount = 0 elementcount = 0 for i ∈ eachindex(as) elementcount += cat_length(as[i]) - currentdims[d1] += cat_size(as[i], d1) + currentdims[d1] += first_dim_zero ? 1 : cat_size(as[i], d1) if currentdims[d1] == outdims[d1] currentdims[d1] = 0 for d ∈ (d2, 3:N...) @@ -2590,6 +2597,10 @@ function _typed_hvncat_dims(::Type{T}, dims::NTuple{N, Int}, row_first::Bool, as throw(DimensionMismatch("argument $i has too many elements along axis $d1")) end end + # restore 0-length adjustment + if first_dim_zero + outdims[d1] = 0 + end outlen = prod(outdims) elementcount == outlen || diff --git a/test/abstractarray.jl b/test/abstractarray.jl index 446102bc625d1..fae2cc2d982e5 100644 --- a/test/abstractarray.jl +++ b/test/abstractarray.jl @@ -831,6 +831,9 @@ function test_cat(::Type{TestAbstractArray}) r = rand(Float32, 56, 56, 64, 1); f(r) = cat(r, r, dims=(3,)) @inferred f(r); + + #58866 - ensure proper dimension calculation for 0-dimension elements + @test [zeros(1, 0) zeros(1,0); zeros(0,0) zeros(0, 0)] == Matrix{Float64}(undef, 1, 0) end function test_ind2sub(::Type{TestAbstractArray}) @@ -1743,6 +1746,9 @@ using Base: typed_hvncat @test ["A";;"B";;"C";;"D"] == ["A" "B" "C" "D"] @test ["A";"B";;"C";"D"] == ["A" "C"; "B" "D"] @test [["A";"B"];;"C";"D"] == ["A" "C"; "B" "D"] + + #58866 - ensure proper dimension calculation for 0-dimension elements + @test [zeros(1, 0) zeros(1,0);;; zeros(0,0) zeros(0, 0)] == Array{Float64, 3}(undef, 1, 0, 0) end @testset "stack" begin From f60e44b1e10797c732efc53ab68b7c1d3807cc1d Mon Sep 17 00:00:00 2001 From: Fons van der Plas Date: Fri, 4 Jul 2025 14:09:57 +0200 Subject: [PATCH 73/83] Pkg: Allow configuring can_fancyprint(io::IO) using IOContext (#58887) (cherry picked from commit c0cc1e1022b780a3b7de6ad33593ef12484e46e2) --- base/precompilation.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/precompilation.jl b/base/precompilation.jl index c24026aa2a8ef..c51297ee2a791 100644 --- a/base/precompilation.jl +++ b/base/precompilation.jl @@ -355,7 +355,7 @@ Base.show(io::IO, err::PkgPrecompileError) = print(io, "PkgPrecompileError: ", e import Base: StaleCacheKey -can_fancyprint(io::IO) = io isa Base.TTY && (get(ENV, "CI", nothing) != "true") +can_fancyprint(io::IO) = @something(get(io, :force_fancyprint, nothing), (io isa Base.TTY && (get(ENV, "CI", nothing) != "true"))) function printpkgstyle(io, header, msg; color=:green) printstyled(io, header; color, bold=true) From 304847e35afaebfeb1c03b85b3b016606097824b Mon Sep 17 00:00:00 2001 From: Jishnu Bhattacharya Date: Mon, 16 Jun 2025 23:33:13 +0530 Subject: [PATCH 74/83] Define `in` for `CartesianIndex` ranges (#58616) Currently, this hits a fallback method that assumes that division is defined for the elements of the range. After this, the following works: ```julia julia> r = StepRangeLen(CartesianIndex(1), CartesianIndex(1), 3); julia> r[1] in r true julia> CartesianIndex(0) in r false ``` (cherry picked from commit 24b3273c190243fa95e24bec8884ece6284cad91) --- base/multidimensional.jl | 18 ++++++++++++++ test/cartesian.jl | 54 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/base/multidimensional.jl b/base/multidimensional.jl index ee0cf9690b469..73e4f69dd528f 100644 --- a/base/multidimensional.jl +++ b/base/multidimensional.jl @@ -183,6 +183,24 @@ module IteratorsMD step(r), ", ", length(r), ")") end + Base.in(x::CartesianIndex, r::AbstractRange{<:CartesianIndex}) = false + function Base.in(x::CartesianIndex{N}, r::AbstractRange{CartesianIndex{N}}) where {N} + isempty(r) && return false + f, st, l = first(r), step(r), last(r) + # The n-th element of the range is a CartesianIndex + # whose elements are the n-th along each dimension + # Find the first dimension along which the index is changing, + # so that n may be uniquely determined + for i in 1:N + iszero(st[i]) && continue + n = findfirst(==(x[i]), f[i]:st[i]:l[i]) + isnothing(n) && return false + return r[n] == x + end + # if the step is zero, the elements are identical, so compare with the first + return x == f + end + # Iteration const OrdinalRangeInt = OrdinalRange{Int, Int} """ diff --git a/test/cartesian.jl b/test/cartesian.jl index 7064b54ebbb8d..6097d4ca3770a 100644 --- a/test/cartesian.jl +++ b/test/cartesian.jl @@ -573,3 +573,57 @@ end end @test t3 == (1, 2, 0) end + +@testset "CartesianIndex show" begin + c = CartesianIndex() + @test sprint(show, c) == "CartesianIndex()" + c = CartesianIndex(3) + @test sprint(show, c) == "CartesianIndex(3)" + c = CartesianIndex(3, 3) + @test sprint(show, c) == "CartesianIndex(3, 3)" +end + +@testset "CartesianIndex indexing with begin/end" begin + I = CartesianIndex(3,4) + @test I[begin] == I[1] + @test I[end] == I[2] +end + +@testset "in for a CartesianIndex StepRangeLen" begin + @testset for l in [0, 1, 4], r in Any[ + StepRangeLen(CartesianIndex(), CartesianIndex(), l), + StepRangeLen(CartesianIndex(1), CartesianIndex(0), l), + StepRangeLen(CartesianIndex(1), CartesianIndex(1), l), + StepRangeLen(CartesianIndex(1), CartesianIndex(4), l), + StepRangeLen(CartesianIndex(1), CartesianIndex(-4), l), + StepRangeLen(CartesianIndex(-1, 2), CartesianIndex(0, 0), l), + StepRangeLen(CartesianIndex(-1, 2), CartesianIndex(0, 4), l), + StepRangeLen(CartesianIndex(-1, 2), CartesianIndex(0, -4), l), + StepRangeLen(CartesianIndex(-1, 2), CartesianIndex(4, 0), l), + StepRangeLen(CartesianIndex(-1, 2), CartesianIndex(-4, 0), l), + StepRangeLen(CartesianIndex(-1, 2), CartesianIndex(4, 2), l), + StepRangeLen(CartesianIndex(-1, 2), CartesianIndex(-4, 2), l), + StepRangeLen(CartesianIndex(-1, 2), CartesianIndex(4, -2), l), + StepRangeLen(CartesianIndex(-1, 2), CartesianIndex(-4, -2), l), + StepRangeLen(CartesianIndex(-1, 2, 0), CartesianIndex(0, 0, 0), l), + StepRangeLen(CartesianIndex(-1, 2, 0), CartesianIndex(0, 0, -2), l), + ] + + if length(r) == 0 + @test !(first(r) in r) + @test !(last(r) in r) + end + for x in r + @test x in r + if step(r) != oneunit(x) + @test !((x + oneunit(x)) in r) + end + end + @test !(CartesianIndex(ntuple(x->0, ndims(r))) in r) + @test !(CartesianIndex(ntuple(x->typemax(Int), ndims(r))) in r) + @test !(CartesianIndex(ntuple(x->typemin(Int), ndims(r))) in r) + if ndims(r) > 1 + @test !(CartesianIndex(ntuple(x->0, ndims(r)-1)...) in r) + end + end +end From 1ef9ca375ec584542720d140d75c6c292c19101d Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Sat, 10 May 2025 09:30:55 -0500 Subject: [PATCH 75/83] bpart: failed "edge" invalidation (#58336) This adds a test for an invalidation failure when `consts` are redefined. The failure occurs only in "edge" mode, i.e., due to the separation of precompilation from the user's running session. (cherry picked from commit c13ea2b4f0f9733dfb6521c64ed1c62ec311b351) --- test/precompile.jl | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/test/precompile.jl b/test/precompile.jl index b98288af6e555..2555086214c77 100644 --- a/test/precompile.jl +++ b/test/precompile.jl @@ -956,6 +956,17 @@ precompile_test_harness("code caching") do dir use_stale(c) = stale(c[1]) + not_stale("hello") build_stale(x) = use_stale(Any[x]) + # bindings + struct InvalidatedBinding + x::Int + end + struct Wrapper + ib::InvalidatedBinding + end + makewib(x) = Wrapper(InvalidatedBinding(x)) + const gib = makewib(1) + fib() = gib.ib.x + # force precompilation build_stale(37) stale('c') @@ -985,6 +996,7 @@ precompile_test_harness("code caching") do dir Base.Experimental.@force_compile useA2() end + precompile($StaleA.fib, ()) ## Reporting tests call_nbits(x::Integer) = $StaleA.nbits(x) @@ -1014,6 +1026,15 @@ precompile_test_harness("code caching") do dir @eval using $StaleA MA = invokelatest(getfield, @__MODULE__, StaleA) Base.eval(MA, :(nbits(::UInt8) = 8)) + Base.eval(MA, quote + struct InvalidatedBinding + x::Float64 + end + struct Wrapper + ib::InvalidatedBinding + end + const gib = makewib(2.0) + end) @eval using $StaleC invalidations = Base.StaticData.debug_method_invalidation(true) @eval using $StaleB @@ -1044,6 +1065,11 @@ precompile_test_harness("code caching") do dir m = only(methods(MC.call_buildstale)) mi = m.specializations::Core.MethodInstance @test hasvalid(mi, world) # was compiled with the new method + m = only(methods(MA.fib)) + mi = m.specializations::Core.MethodInstance + @test isdefined(mi, :cache) # it was precompiled by StaleB + @test_broken !hasvalid(mi, world) # invalidated by redefining `gib` before loading StaleB + @test_broken MA.fib() === 2.0 # Reporting test (ensure SnoopCompile works) @test all(i -> isassigned(invalidations, i), eachindex(invalidations)) From a121e3b13e558ddf99f28cf7ae43e0d7a485357a Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Fri, 30 May 2025 05:53:36 -0500 Subject: [PATCH 76/83] Add binding invalidations to log (#58226) Currently we log the invalidated backedges of a binding invalidation, but the actual trigger of the invalidation is not logged. This is needed to allow SnoopCompile to attribute a cause to those invalidations. (cherry picked from commit 75946ce31ccc4c32979e6a0fec5daabe20f8a58a) --- base/invalidation.jl | 23 ++++++++++++++++++----- src/gf.c | 13 +++++++++++++ test/precompile.jl | 26 ++++++++++++++++++++++++++ test/worlds.jl | 28 ++++++++++++++++++++++++++++ 4 files changed, 85 insertions(+), 5 deletions(-) diff --git a/base/invalidation.jl b/base/invalidation.jl index 2fb308d58ed91..ea8803d22e476 100644 --- a/base/invalidation.jl +++ b/base/invalidation.jl @@ -67,20 +67,25 @@ function invalidate_method_for_globalref!(gr::GlobalRef, method::Method, invalid binding = convert(Core.Binding, gr) if isdefined(method, :source) src = _uncompressed_ir(method) - old_stmts = src.code invalidate_all = should_invalidate_code_for_globalref(gr, src) end + invalidated_any = false for mi in specializations(method) isdefined(mi, :cache) || continue ci = mi.cache + invalidated = false while true if ci.max_world > new_max_world && (invalidate_all || scan_edge_list(ci, binding)) ccall(:jl_invalidate_code_instance, Cvoid, (Any, UInt), ci, new_max_world) + invalidated = true end isdefined(ci, :next) || break ci = ci.next end + invalidated && ccall(:jl_maybe_log_binding_invalidation, Cvoid, (Any,), mi) + invalidated_any |= invalidated end + return invalidated_any end export_affecting_partition_flags(bpart::Core.BindingPartition) = @@ -104,18 +109,21 @@ function invalidate_code_for_globalref!(b::Core.Binding, invalidated_bpart::Core need_to_invalidate_export = export_affecting_partition_flags(invalidated_bpart) !== export_affecting_partition_flags(new_bpart) + invalidated_any = false + queued_bindings = Tuple{Core.Binding, Core.BindingPartition, Core.BindingPartition}[] # defer handling these to keep the logging coherent if need_to_invalidate_code if (b.flags & BINDING_FLAG_ANY_IMPLICIT_EDGES) != 0 nmethods = ccall(:jl_module_scanned_methods_length, Csize_t, (Any,), gr.mod) for i = 1:nmethods method = ccall(:jl_module_scanned_methods_getindex, Any, (Any, Csize_t), gr.mod, i)::Method - invalidate_method_for_globalref!(gr, method, invalidated_bpart, new_max_world) + invalidated_any |= invalidate_method_for_globalref!(gr, method, invalidated_bpart, new_max_world) end end if isdefined(b, :backedges) for edge in b.backedges if isa(edge, CodeInstance) ccall(:jl_invalidate_code_instance, Cvoid, (Any, UInt), edge, new_max_world) + invalidated_any = true elseif isa(edge, Core.Binding) isdefined(edge, :partitions) || continue latest_bpart = edge.partitions @@ -124,9 +132,9 @@ function invalidate_code_for_globalref!(b::Core.Binding, invalidated_bpart::Core if is_some_binding_imported(binding_kind(latest_bpart)) partition_restriction(latest_bpart) === b || continue end - invalidate_code_for_globalref!(edge, latest_bpart, latest_bpart, new_max_world) + push!(queued_bindings, (edge, latest_bpart, latest_bpart)) else - invalidate_method_for_globalref!(gr, edge::Method, invalidated_bpart, new_max_world) + invalidated_any |= invalidate_method_for_globalref!(gr, edge::Method, invalidated_bpart, new_max_world) end end end @@ -148,11 +156,16 @@ function invalidate_code_for_globalref!(b::Core.Binding, invalidated_bpart::Core ccall(:jl_maybe_reresolve_implicit, Any, (Any, Csize_t), user_binding, new_max_world) : latest_bpart if need_to_invalidate_code || new_bpart !== latest_bpart - invalidate_code_for_globalref!(convert(Core.Binding, user_binding), latest_bpart, new_bpart, new_max_world) + push!(queued_bindings, (convert(Core.Binding, user_binding), latest_bpart, new_bpart)) end end end end + invalidated_any && ccall(:jl_maybe_log_binding_invalidation, Cvoid, (Any,), invalidated_bpart) + for (edge, invalidated_bpart, new_bpart) in queued_bindings + invalidated_any |= invalidate_code_for_globalref!(edge, invalidated_bpart, new_bpart, new_max_world) + end + return invalidated_any end invalidate_code_for_globalref!(gr::GlobalRef, invalidated_bpart::Core.BindingPartition, new_bpart::Core.BindingPartition, new_max_world::UInt) = invalidate_code_for_globalref!(convert(Core.Binding, gr), invalidated_bpart, new_bpart, new_max_world) diff --git a/src/gf.c b/src/gf.c index 9429faa9e6226..f4b96b3716859 100644 --- a/src/gf.c +++ b/src/gf.c @@ -1954,6 +1954,19 @@ JL_DLLEXPORT void jl_invalidate_code_instance(jl_code_instance_t *replaced, size invalidate_code_instance(replaced, max_world, 1); } +JL_DLLEXPORT void jl_maybe_log_binding_invalidation(jl_value_t *replaced) +{ + if (_jl_debug_method_invalidation) { + if (replaced) { + jl_array_ptr_1d_push(_jl_debug_method_invalidation, replaced); + } + jl_value_t *loctag = jl_cstr_to_string("jl_maybe_log_binding_invalidation"); + JL_GC_PUSH1(&loctag); + jl_array_ptr_1d_push(_jl_debug_method_invalidation, loctag); + JL_GC_POP(); + } +} + static void _invalidate_backedges(jl_method_instance_t *replaced_mi, jl_code_instance_t *replaced_ci, size_t max_world, int depth) { uint8_t recursion_flags = 0; jl_array_t *backedges = jl_mi_get_backedges_mutate(replaced_mi, &recursion_flags); diff --git a/test/precompile.jl b/test/precompile.jl index 2555086214c77..e95df0d50ae60 100644 --- a/test/precompile.jl +++ b/test/precompile.jl @@ -967,6 +967,12 @@ precompile_test_harness("code caching") do dir const gib = makewib(1) fib() = gib.ib.x + struct LogBindingInvalidation + x::Int + end + const glbi = LogBindingInvalidation(1) + flbi() = @__MODULE__().glbi.x + # force precompilation build_stale(37) stale('c') @@ -991,10 +997,13 @@ precompile_test_harness("code caching") do dir useA() = $StaleA.stale("hello") useA2() = useA() + useflbi() = $StaleA.flbi() + # force precompilation begin Base.Experimental.@force_compile useA2() + useflbi() end precompile($StaleA.fib, ()) @@ -1035,6 +1044,13 @@ precompile_test_harness("code caching") do dir end const gib = makewib(2.0) end) + # TODO: test a "method_globalref" invalidation also + Base.eval(MA, quote + struct LogBindingInvalidation # binding invalidations can't be done during precompilation + x::Float64 + end + const glbi = LogBindingInvalidation(2.0) + end) @eval using $StaleC invalidations = Base.StaticData.debug_method_invalidation(true) @eval using $StaleB @@ -1096,6 +1112,16 @@ precompile_test_harness("code caching") do dir @test !hasvalid(mi, world) @test any(x -> x isa Core.CodeInstance && x.def === mi, invalidations) + idxb = findfirst(x -> x isa Core.Binding, invalidations) + @test invalidations[idxb+1] == "insert_backedges_callee" + idxv = findnext(==("verify_methods"), invalidations, idxb) + if invalidations[idxv-1].def.def.name === :getproperty + idxv = findnext(==("verify_methods"), invalidations, idxv+1) + end + @test invalidations[idxv-1].def.def.name === :flbi + idxv = findnext(==("verify_methods"), invalidations, idxv+1) + @test invalidations[idxv-1].def.def.name === :useflbi + m = only(methods(MB.map_nbits)) @test !hasvalid(m.specializations::Core.MethodInstance, world+1) # insert_backedges invalidations also trigger their backedges end diff --git a/test/worlds.jl b/test/worlds.jl index e99ab7189e25a..e6fd407b9d30f 100644 --- a/test/worlds.jl +++ b/test/worlds.jl @@ -436,6 +436,34 @@ idxi = findfirst(==(m58080i), logmeths) @test logmeths[end-1] == m58080s @test logmeths[end] == "jl_method_table_insert" +# logging binding invalidations +struct LogBindingInvalidation + x::Int +end +makelbi(x) = LogBindingInvalidation(x) +const glbi = makelbi(1) +oLBI, oglbi = LogBindingInvalidation, glbi +flbi() = @__MODULE__().glbi.x +flbi() +milbi1 = only(Base.specializations(only(methods(makelbi)))) +milbi2 = only(Base.specializations(only(methods(flbi)))) +logmeths = ccall(:jl_debug_method_invalidation, Any, (Cint,), 1) +struct LogBindingInvalidation + x::Float64 +end +const glbi = makelbi(2.0) +@test flbi() === 2.0 +ccall(:jl_debug_method_invalidation, Any, (Cint,), 0) +@test milbi1.cache.def ∈ logmeths +@test milbi2.cache.next.def ∈ logmeths +i = findfirst(x -> isa(x, Core.BindingPartition), logmeths) +T = logmeths[i].restriction +@test T === oLBI +@test logmeths[i+1] == "jl_maybe_log_binding_invalidation" +T = logmeths[end-1].restriction +@test T === oglbi +@test logmeths[end] == "jl_maybe_log_binding_invalidation" + # issue #50091 -- missing invoke edge affecting nospecialized dispatch module ExceptionUnwrapping @nospecialize From fa74542bc31aaeb55e198be398993ed3db36b88a Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Sat, 28 Jun 2025 18:46:31 -0400 Subject: [PATCH 77/83] bpart: Properly track methods with invalidated source after require_world (#58830) There are three categories of methods we need to worry about during staticdata validation: 1. New methods added to existing generic functions 2. New methods added to new generic functions 3. Existing methods that now have new CodeInstances In each of these cases, we need to check whether any of the implicit binding edges from the method's source was invalidated. Currently, we handle this for 1 and 2 by explicitly scanning the method on load. However, we were not tracking it for case 3. Fix that by using an extra bit in did_scan_method that gets set when we see an existing method getting invalidated, so we know that we need to drop the corresponding CodeInstances during load. Fixes #58346 (cherry picked from commit 77b90b9e621d025a11780ae94c8e0afcaa7c2aee) --- base/invalidation.jl | 16 +++++++++------- base/runtime_internals.jl | 2 ++ base/staticdata.jl | 32 +++++++++++++++++--------------- src/jltypes.c | 2 +- src/julia.h | 1 + test/core.jl | 2 +- test/precompile.jl | 5 ++--- 7 files changed, 33 insertions(+), 27 deletions(-) diff --git a/base/invalidation.jl b/base/invalidation.jl index ea8803d22e476..b14a1f65930c8 100644 --- a/base/invalidation.jl +++ b/base/invalidation.jl @@ -69,6 +69,9 @@ function invalidate_method_for_globalref!(gr::GlobalRef, method::Method, invalid src = _uncompressed_ir(method) invalidate_all = should_invalidate_code_for_globalref(gr, src) end + if invalidate_all && !Base.generating_output() + @atomic method.did_scan_source |= 0x4 + end invalidated_any = false for mi in specializations(method) isdefined(mi, :cache) || continue @@ -182,7 +185,7 @@ function binding_was_invalidated(b::Core.Binding) b.partitions.min_world > unsafe_load(cglobal(:jl_require_world, UInt)) end -function scan_new_method!(methods_with_invalidated_source::IdSet{Method}, method::Method, image_backedges_only::Bool) +function scan_new_method!(method::Method, image_backedges_only::Bool) isdefined(method, :source) || return if image_backedges_only && !has_image_globalref(method) return @@ -195,21 +198,20 @@ function scan_new_method!(methods_with_invalidated_source::IdSet{Method}, method # TODO: We could turn this into an addition if condition. For now, use it as a reasonably cheap # additional consistency chekc @assert !image_backedges_only - push!(methods_with_invalidated_source, method) + @atomic method.did_scan_source |= 0x4 end maybe_add_binding_backedge!(b, method) end + @atomic method.did_scan_source |= 0x1 end -function scan_new_methods(extext_methods::Vector{Any}, internal_methods::Vector{Any}, image_backedges_only::Bool) - methods_with_invalidated_source = IdSet{Method}() +function scan_new_methods!(extext_methods::Vector{Any}, internal_methods::Vector{Any}, image_backedges_only::Bool) for method in internal_methods if isa(method, Method) - scan_new_method!(methods_with_invalidated_source, method, image_backedges_only) + scan_new_method!(method, image_backedges_only) end end for tme::Core.TypeMapEntry in extext_methods - scan_new_method!(methods_with_invalidated_source, tme.func::Method, image_backedges_only) + scan_new_method!(tme.func::Method, image_backedges_only) end - return methods_with_invalidated_source end diff --git a/base/runtime_internals.jl b/base/runtime_internals.jl index bef04fd84e6ff..f48b4734a7b8b 100644 --- a/base/runtime_internals.jl +++ b/base/runtime_internals.jl @@ -1266,6 +1266,8 @@ Returns the world the [current_task()](@ref) is executing within. """ tls_world_age() = ccall(:jl_get_tls_world_age, UInt, ()) +get_require_world() = unsafe_load(cglobal(:jl_require_world, UInt)) + """ propertynames(x, private=false) diff --git a/base/staticdata.jl b/base/staticdata.jl index c9983c72064de..3c9e008302904 100644 --- a/base/staticdata.jl +++ b/base/staticdata.jl @@ -26,20 +26,20 @@ function insert_backedges(edges::Vector{Any}, ext_ci_list::Union{Nothing,Vector{ # determine which CodeInstance objects are still valid in our image # to enable any applicable new codes backedges_only = unsafe_load(cglobal(:jl_first_image_replacement_world, UInt)) == typemax(UInt) - methods_with_invalidated_source = Base.scan_new_methods(extext_methods, internal_methods, backedges_only) + Base.scan_new_methods!(extext_methods, internal_methods, backedges_only) stack = CodeInstance[] visiting = IdDict{CodeInstance,Int}() - _insert_backedges(edges, stack, visiting, methods_with_invalidated_source) + _insert_backedges(edges, stack, visiting) if ext_ci_list !== nothing - _insert_backedges(ext_ci_list, stack, visiting, methods_with_invalidated_source, #=external=#true) + _insert_backedges(ext_ci_list, stack, visiting, #=external=#true) end end -function _insert_backedges(edges::Vector{Any}, stack::Vector{CodeInstance}, visiting::IdDict{CodeInstance,Int}, mwis::IdSet{Method}, external::Bool=false) +function _insert_backedges(edges::Vector{Any}, stack::Vector{CodeInstance}, visiting::IdDict{CodeInstance,Int}, external::Bool=false) for i = 1:length(edges) codeinst = edges[i]::CodeInstance validation_world = get_world_counter() - verify_method_graph(codeinst, stack, visiting, mwis, validation_world) + verify_method_graph(codeinst, stack, visiting, validation_world) # After validation, under the world_counter_lock, set max_world to typemax(UInt) for all dependencies # (recursively). From that point onward the ordinary backedge mechanism is responsible for maintaining # validity. @@ -63,16 +63,14 @@ function _insert_backedges(edges::Vector{Any}, stack::Vector{CodeInstance}, visi end end -function verify_method_graph(codeinst::CodeInstance, stack::Vector{CodeInstance}, visiting::IdDict{CodeInstance,Int}, mwis::IdSet{Method}, validation_world::UInt) +function verify_method_graph(codeinst::CodeInstance, stack::Vector{CodeInstance}, visiting::IdDict{CodeInstance,Int}, validation_world::UInt) @assert isempty(stack); @assert isempty(visiting); - child_cycle, minworld, maxworld = verify_method(codeinst, stack, visiting, mwis, validation_world) + child_cycle, minworld, maxworld = verify_method(codeinst, stack, visiting, validation_world) @assert child_cycle == 0 @assert isempty(stack); @assert isempty(visiting); nothing end -get_require_world() = unsafe_load(cglobal(:jl_require_world, UInt)) - function gen_staged_sig(def::Method, mi::MethodInstance) isdefined(def, :generator) || return nothing isdispatchtuple(mi.specTypes) || return nothing @@ -122,7 +120,7 @@ end # - Visit the entire call graph, starting from edges[idx] to determine if that method is valid # - Implements Tarjan's SCC (strongly connected components) algorithm, simplified to remove the count variable # and slightly modified with an early termination option once the computation reaches its minimum -function verify_method(codeinst::CodeInstance, stack::Vector{CodeInstance}, visiting::IdDict{CodeInstance,Int}, mwis::IdSet{Method}, validation_world::UInt) +function verify_method(codeinst::CodeInstance, stack::Vector{CodeInstance}, visiting::IdDict{CodeInstance,Int}, validation_world::UInt) world = codeinst.min_world let max_valid2 = codeinst.max_world if max_valid2 ≠ WORLD_AGE_REVALIDATION_SENTINEL @@ -136,13 +134,13 @@ function verify_method(codeinst::CodeInstance, stack::Vector{CodeInstance}, visi end # Implicitly referenced bindings in the current module do not get explicit edges. - # If they were invalidated, they'll be in `mwis`. If they weren't, they imply a minworld + # If they were invalidated, they'll have the flag set in did_scan_source. If they weren't, they imply a minworld # of `get_require_world`. In principle, this is only required for methods that do reference # an implicit globalref. However, we already don't perform this validation for methods that # don't have any (implicit or explicit) edges at all. The remaining corner case (some explicit, # but no implicit edges) is rare and there would be little benefit to lower the minworld for it # in any case, so we just always use `get_require_world` here. - local minworld::UInt, maxworld::UInt = get_require_world(), validation_world + local minworld::UInt, maxworld::UInt = Base.get_require_world(), validation_world if haskey(visiting, codeinst) return visiting[codeinst], minworld, maxworld end @@ -152,7 +150,11 @@ function verify_method(codeinst::CodeInstance, stack::Vector{CodeInstance}, visi # TODO JL_TIMING(VERIFY_IMAGE, VERIFY_Methods) callees = codeinst.edges # Check for invalidation of the implicit edges from GlobalRef in the Method source - if def in mwis + if (def.did_scan_source & 0x1) == 0x0 + backedges_only = unsafe_load(cglobal(:jl_first_image_replacement_world, UInt)) == typemax(UInt) + Base.scan_new_method!(def, backedges_only) + end + if (def.did_scan_source & 0x4) != 0x0 maxworld = 0 invalidations = _jl_debug_method_invalidation[] if invalidations !== nothing @@ -162,7 +164,7 @@ function verify_method(codeinst::CodeInstance, stack::Vector{CodeInstance}, visi # verify current edges if isempty(callees) # quick return: no edges to verify (though we probably shouldn't have gotten here from WORLD_AGE_REVALIDATION_SENTINEL) - elseif maxworld == get_require_world() + elseif maxworld == Base.get_require_world() # if no new worlds were allocated since serializing the base module, then no new validation is worth doing right now either else j = 1 @@ -240,7 +242,7 @@ function verify_method(codeinst::CodeInstance, stack::Vector{CodeInstance}, visi end callee = edge local min_valid2::UInt, max_valid2::UInt - child_cycle, min_valid2, max_valid2 = verify_method(callee, stack, visiting, mwis, validation_world) + child_cycle, min_valid2, max_valid2 = verify_method(callee, stack, visiting, validation_world) if minworld < min_valid2 minworld = min_valid2 end diff --git a/src/jltypes.c b/src/jltypes.c index b8b8bf3e008e9..90bd862df808a 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -3607,7 +3607,7 @@ void jl_init_types(void) JL_GC_DISABLED 0, 1, 10); //const static uint32_t method_constfields[1] = { 0b0 }; // (1<<0)|(1<<1)|(1<<2)|(1<<3)|(1<<6)|(1<<9)|(1<<10)|(1<<17)|(1<<21)|(1<<22)|(1<<23)|(1<<24)|(1<<25)|(1<<26)|(1<<27)|(1<<28)|(1<<29)|(1<<30); //jl_method_type->name->constfields = method_constfields; - const static uint32_t method_atomicfields[1] = { 0x00000030 }; // (1<<4)|(1<<5) + const static uint32_t method_atomicfields[1] = { 0x10000030 }; // (1<<4)|(1<<5)||(1<<28) jl_method_type->name->atomicfields = method_atomicfields; jl_method_instance_type = diff --git a/src/julia.h b/src/julia.h index cf6bf6757a1f6..c9a14e202cc9f 100644 --- a/src/julia.h +++ b/src/julia.h @@ -377,6 +377,7 @@ typedef struct _jl_method_t { uint8_t nospecializeinfer; // bit flags, 0x01 = scanned // 0x02 = added to module scanned list (either from scanning or inference edge) + // 0x04 = Source was invalidated since jl_require_world _Atomic(uint8_t) did_scan_source; // uint8 settings diff --git a/test/core.jl b/test/core.jl index d1b454db08009..027e79b8b7c03 100644 --- a/test/core.jl +++ b/test/core.jl @@ -36,7 +36,7 @@ end for (T, c) in ( (Core.CodeInfo, []), (Core.CodeInstance, [:next, :min_world, :max_world, :inferred, :edges, :debuginfo, :ipo_purity_bits, :invoke, :specptr, :specsigflags, :precompile, :time_compile]), - (Core.Method, [:primary_world, :dispatch_status]), + (Core.Method, [:primary_world, :did_scan_source, :dispatch_status]), (Core.MethodInstance, [:cache, :flags]), (Core.MethodTable, [:defs]), (Core.MethodCache, [:leafcache, :cache, :var""]), diff --git a/test/precompile.jl b/test/precompile.jl index e95df0d50ae60..4cf2b2ae473e3 100644 --- a/test/precompile.jl +++ b/test/precompile.jl @@ -1083,9 +1083,8 @@ precompile_test_harness("code caching") do dir @test hasvalid(mi, world) # was compiled with the new method m = only(methods(MA.fib)) mi = m.specializations::Core.MethodInstance - @test isdefined(mi, :cache) # it was precompiled by StaleB - @test_broken !hasvalid(mi, world) # invalidated by redefining `gib` before loading StaleB - @test_broken MA.fib() === 2.0 + @test !hasvalid(mi, world) # invalidated by redefining `gib` before loading StaleB + @test MA.fib() === 2.0 # Reporting test (ensure SnoopCompile works) @test all(i -> isassigned(invalidations, i), eachindex(invalidations)) From a28d9b436c4d73d0e44c17f2bb76935a9e771c24 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 30 Jun 2025 15:00:38 -0400 Subject: [PATCH 78/83] 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 b459d8885cabeb4c16089933b76c0d4c1605236f) --- base/essentials.jl | 2 +- base/staticdata.jl | 19 ++++- doc/src/devdocs/locks.md | 4 + src/gf.c | 163 +++++++++++++++++++++++++++++++-------- src/jltypes.c | 14 ++-- src/julia.h | 3 +- src/method.c | 1 + src/staticdata.c | 46 +---------- test/core.jl | 2 +- 9 files changed, 165 insertions(+), 89 deletions(-) diff --git a/base/essentials.jl b/base/essentials.jl index 5068acf24cbc1..bf48f24f5234c 100644 --- a/base/essentials.jl +++ b/base/essentials.jl @@ -684,7 +684,7 @@ Neither `convert` nor `cconvert` should take a Julia object and turn it into a ` """ function cconvert end -cconvert(T::Type, x) = x isa T ? x : convert(T, x) # do the conversion eagerly in most cases +cconvert(::Type{T}, x) where {T} = x isa T ? x : convert(T, x) # do the conversion eagerly in most cases cconvert(::Type{Union{}}, x...) = convert(Union{}, x...) cconvert(::Type{<:Ptr}, x) = x # but defer the conversion to Ptr to unsafe_convert unsafe_convert(::Type{T}, x::T) where {T} = x # unsafe_convert (like convert) defaults to assuming the convert occurred diff --git a/base/staticdata.jl b/base/staticdata.jl index 3c9e008302904..c4053889febc6 100644 --- a/base/staticdata.jl +++ b/base/staticdata.jl @@ -290,6 +290,7 @@ end function verify_call(@nospecialize(sig), expecteds::Core.SimpleVector, i::Int, n::Int, world::UInt) # verify that these edges intersect with the same methods as before + mi = nothing if n == 1 # first, fast-path a check if the expected method simply dominates its sig anyways # 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 meth = t else if t isa CodeInstance - t = get_ci_mi(t) + mi = get_ci_mi(t)::MethodInstance else - t = t::MethodInstance + mi = t::MethodInstance + end + meth = mi.def::Method + if !iszero(mi.dispatch_status & METHOD_SIG_LATEST_ONLY) + minworld = meth.primary_world + @assert minworld ≤ world + maxworld = typemax(UInt) + result = Any[] # result is unused + return minworld, maxworld, result end - meth = t.def::Method end if !iszero(meth.dispatch_status & METHOD_SIG_LATEST_ONLY) minworld = meth.primary_world @@ -336,7 +344,7 @@ function verify_call(@nospecialize(sig), expecteds::Core.SimpleVector, i::Int, n meth = t else if t isa CodeInstance - t = get_ci_mi(t) + t = get_ci_mi(t)::MethodInstance else t = t::MethodInstance end @@ -363,6 +371,9 @@ function verify_call(@nospecialize(sig), expecteds::Core.SimpleVector, i::Int, n resize!(result, ins) end end + if maxworld[] == typemax(UInt) && mi isa MethodInstance + ccall(:jl_promote_mi_to_current, Cvoid, (Any, UInt, UInt), mi, minworld[], world) + end return minworld[], maxworld[], result end diff --git a/doc/src/devdocs/locks.md b/doc/src/devdocs/locks.md index 8d6672842c3c8..c89499a4162a9 100644 --- a/doc/src/devdocs/locks.md +++ b/doc/src/devdocs/locks.md @@ -85,6 +85,10 @@ may result in pernicious and hard-to-find deadlocks. BE VERY CAREFUL! > > * Libdl.LazyLibrary lock +The following is a level 7 lock, which can only be acquired when not holding any other locks: + +> * world_counter_lock + The following is the root lock, meaning no other lock shall be held when trying to acquire it: diff --git a/src/gf.c b/src/gf.c index f4b96b3716859..603f2beef7a0a 100644 --- a/src/gf.c +++ b/src/gf.c @@ -308,7 +308,7 @@ jl_method_t *jl_mk_builtin_func(jl_datatype_t *dt, jl_sym_t *sname, jl_fptr_args m->isva = 1; m->nargs = 2; jl_atomic_store_relaxed(&m->primary_world, 1); - jl_atomic_store_relaxed(&m->dispatch_status, METHOD_SIG_LATEST_ONLY | METHOD_SIG_LATEST_ONLY); + jl_atomic_store_relaxed(&m->dispatch_status, METHOD_SIG_LATEST_ONLY | METHOD_SIG_LATEST_WHICH); m->sig = (jl_value_t*)jl_anytuple_type; m->slot_syms = jl_an_empty_string; m->nospecialize = 0; @@ -1506,22 +1506,26 @@ jl_method_instance_t *cache_method( size_t world, size_t min_valid, size_t max_valid, jl_svec_t *sparams) { - // caller must hold the parent->writelock + // caller must hold the parent->writelock, which this releases // short-circuit (now that we hold the lock) if this entry is already present int8_t offs = mc ? jl_cachearg_offset() : 1; { // scope block if (mc) { jl_genericmemory_t *leafcache = jl_atomic_load_relaxed(&mc->leafcache); jl_typemap_entry_t *entry = lookup_leafcache(leafcache, (jl_value_t*)tt, world); - if (entry) + if (entry) { + if (mc) JL_UNLOCK(&mc->writelock); return entry->func.linfo; + } } struct jl_typemap_assoc search = {(jl_value_t*)tt, world, NULL}; jl_typemap_t *cacheentry = jl_atomic_load_relaxed(cache); assert(cacheentry != NULL); jl_typemap_entry_t *entry = jl_typemap_assoc_by_type(cacheentry, &search, offs, /*subtype*/1); - if (entry && entry->func.value) + if (entry && entry->func.value) { + if (mc) JL_UNLOCK(&mc->writelock); return entry->func.linfo; + } } jl_method_instance_t *newmeth = NULL; @@ -1534,6 +1538,7 @@ jl_method_instance_t *cache_method( JL_GC_PUSH1(&newentry); jl_typemap_insert(cache, parent, newentry, offs); JL_GC_POP(); + if (mc) JL_UNLOCK(&mc->writelock); return newmeth; } } @@ -1578,8 +1583,11 @@ jl_method_instance_t *cache_method( if (newmeth->cache_with_orig) cache_with_orig = 1; + // Capture world counter at start to detect races + size_t current_world = mc ? jl_atomic_load_acquire(&jl_world_counter) : ~(size_t)0; + jl_tupletype_t *cachett = tt; - jl_svec_t* guardsigs = jl_emptysvec; + jl_svec_t *guardsigs = jl_emptysvec; if (!cache_with_orig && mt) { // now examine what will happen if we chose to use this sig in the cache size_t min_valid2 = 1; @@ -1649,6 +1657,10 @@ jl_method_instance_t *cache_method( } } + int unconstrained_max = max_valid == ~(size_t)0; + if (max_valid > current_world) + max_valid = current_world; + // now scan `cachett` and ensure that `Type{T}` in the cache will be matched exactly by `typeof(T)` // and also reduce the complexity of rejecting this entry in the cache // by replacing non-simple types with jl_any_type to build a new `type` @@ -1727,12 +1739,91 @@ jl_method_instance_t *cache_method( } } } + if (mc) { + JL_UNLOCK(&mc->writelock); + + // Only set METHOD_SIG_LATEST_ONLY on method instance if method does NOT have the bit, no guards required, and min_valid == primary_world + int should_set_dispatch_status = !(jl_atomic_load_relaxed(&definition->dispatch_status) & METHOD_SIG_LATEST_ONLY) && + (!cache_with_orig && jl_svec_len(guardsigs) == 0) && + min_valid == jl_atomic_load_relaxed(&definition->primary_world) && + !(jl_atomic_load_relaxed(&newmeth->dispatch_status) & METHOD_SIG_LATEST_ONLY); + + // Combined trylock for both dispatch_status setting and max_world restoration + if ((should_set_dispatch_status || unconstrained_max) && + jl_atomic_load_relaxed(&jl_world_counter) == current_world) { + JL_LOCK(&world_counter_lock); + if (jl_atomic_load_relaxed(&jl_world_counter) == current_world) { + if (should_set_dispatch_status) { + jl_atomic_store_relaxed(&newmeth->dispatch_status, METHOD_SIG_LATEST_ONLY); + } + if (unconstrained_max) { + jl_atomic_store_relaxed(&newentry->max_world, ~(size_t)0); + } + } + JL_UNLOCK(&world_counter_lock); + } + } JL_GC_POP(); return newmeth; } -static jl_method_match_t *_gf_invoke_lookup(jl_value_t *types JL_PROPAGATES_ROOT, jl_methtable_t *mt, size_t world, size_t *min_valid, size_t *max_valid); +static void _jl_promote_ci_to_current(jl_code_instance_t *ci, size_t validated_world) JL_NOTSAFEPOINT +{ + if (jl_atomic_load_relaxed(&ci->max_world) != validated_world) + return; + jl_atomic_store_relaxed(&ci->max_world, ~(size_t)0); + jl_svec_t *edges = jl_atomic_load_relaxed(&ci->edges); + for (size_t i = 0; i < jl_svec_len(edges); i++) { + jl_value_t *edge = jl_svecref(edges, i); + if (!jl_is_code_instance(edge)) + continue; + _jl_promote_ci_to_current((jl_code_instance_t *)edge, validated_world); + } +} + +JL_DLLEXPORT void jl_promote_cis_to_current(jl_code_instance_t **cis, size_t n, size_t validated_world) +{ + size_t current_world = jl_atomic_load_relaxed(&jl_world_counter); + // No need to acquire the lock if we've been invalidated anyway + if (current_world > validated_world) + return; + JL_LOCK(&world_counter_lock); + current_world = jl_atomic_load_relaxed(&jl_world_counter); + if (current_world == validated_world) { + for (size_t i = 0; i < n; i++) { + _jl_promote_ci_to_current(cis[i], validated_world); + } + } + JL_UNLOCK(&world_counter_lock); +} + +JL_DLLEXPORT void jl_promote_ci_to_current(jl_code_instance_t *ci, size_t validated_world) +{ + jl_promote_cis_to_current(&ci, 1, validated_world); +} + +JL_DLLEXPORT void jl_promote_mi_to_current(jl_method_instance_t *mi, size_t min_world, size_t validated_world) +{ + size_t current_world = jl_atomic_load_relaxed(&jl_world_counter); + // No need to acquire the lock if we've been invalidated anyway + if (current_world > validated_world) + return; + // Only set METHOD_SIG_LATEST_ONLY on method instance if method does NOT have the bit and min_valid == primary_world + jl_method_t *definition = mi->def.method; + if ((jl_atomic_load_relaxed(&definition->dispatch_status) & METHOD_SIG_LATEST_ONLY) || + min_world != jl_atomic_load_relaxed(&definition->primary_world) || + (jl_atomic_load_relaxed(&mi->dispatch_status) & METHOD_SIG_LATEST_ONLY)) + return; + JL_LOCK(&world_counter_lock); + current_world = jl_atomic_load_relaxed(&jl_world_counter); + if (current_world == validated_world) { + jl_atomic_store_relaxed(&mi->dispatch_status, METHOD_SIG_LATEST_ONLY); + } + JL_UNLOCK(&world_counter_lock); +} + +static jl_method_match_t *_gf_invoke_lookup(jl_value_t *types JL_PROPAGATES_ROOT, jl_methtable_t *mt, size_t world, int cache, size_t *min_valid, size_t *max_valid); JL_DLLEXPORT jl_typemap_entry_t *jl_mt_find_cache_entry(jl_methcache_t *mc JL_PROPAGATES_ROOT, jl_datatype_t *tt JL_MAYBE_UNROOTED JL_ROOTS_TEMPORARILY, size_t world) { // exported only for debugging purposes, not for casual use @@ -1766,11 +1857,13 @@ static jl_method_instance_t *jl_mt_assoc_by_type(jl_methcache_t *mc JL_PROPAGATE if (!mi) { size_t min_valid = 0; size_t max_valid = ~(size_t)0; - matc = _gf_invoke_lookup((jl_value_t*)tt, jl_method_table, world, &min_valid, &max_valid); + matc = _gf_invoke_lookup((jl_value_t*)tt, jl_method_table, world, 0, &min_valid, &max_valid); if (matc) { jl_method_t *m = matc->method; jl_svec_t *env = matc->sparams; mi = cache_method(jl_method_table, mc, &mc->cache, (jl_value_t*)mc, tt, m, world, min_valid, max_valid, env); + JL_GC_POP(); + return mi; } } JL_UNLOCK(&mc->writelock); @@ -2127,6 +2220,7 @@ static int _invalidate_dispatch_backedges(jl_method_instance_t *mi, jl_value_t * // invalidate cached methods that overlap this definition static void invalidate_backedges(jl_method_instance_t *replaced_mi, size_t max_world, const char *why) { + // Reset dispatch_status when method instance is replaced JL_LOCK(&replaced_mi->def.method->writelock); _invalidate_backedges(replaced_mi, NULL, max_world, 1); JL_UNLOCK(&replaced_mi->def.method->writelock); @@ -2137,6 +2231,7 @@ static void invalidate_backedges(jl_method_instance_t *replaced_mi, size_t max_w jl_array_ptr_1d_push(_jl_debug_method_invalidation, loctag); JL_GC_POP(); } + jl_atomic_store_relaxed(&replaced_mi->dispatch_status, 0); } // add a backedge from callee to caller @@ -2634,6 +2729,8 @@ void jl_method_table_activate(jl_typemap_entry_t *newentry) // call invalidate_backedges(mi, max_world, "jl_method_table_insert"); // but ignore invoke-type edges int invalidatedmi = _invalidate_dispatch_backedges(mi, type, m, d, n, replaced_dispatch, ambig, max_world, morespec); + if (replaced_dispatch) + jl_atomic_store_relaxed(&mi->dispatch_status, 0); jl_array_ptr_1d_push(oldmi, (jl_value_t*)mi); if (_jl_debug_method_invalidation && invalidatedmi) { jl_array_ptr_1d_push(_jl_debug_method_invalidation, (jl_value_t*)mi); @@ -3415,7 +3512,6 @@ JL_DLLEXPORT jl_method_instance_t *jl_method_match_to_mi(jl_method_match_t *matc assert(mc); JL_LOCK(&mc->writelock); mi = cache_method(jl_method_get_table(m), mc, &mc->cache, (jl_value_t*)mc, ti, m, world, min_valid, max_valid, env); - JL_UNLOCK(&mc->writelock); } else { jl_value_t *tt = jl_normalize_to_compilable_sig(ti, env, m, 1); @@ -3909,7 +4005,7 @@ JL_DLLEXPORT jl_value_t *jl_apply_generic(jl_value_t *F, jl_value_t **args, uint return _jl_invoke(F, args, nargs, mfunc, world); } -static jl_method_match_t *_gf_invoke_lookup(jl_value_t *types JL_PROPAGATES_ROOT, jl_methtable_t *mt, size_t world, size_t *min_valid, size_t *max_valid) +static jl_method_match_t *_gf_invoke_lookup(jl_value_t *types JL_PROPAGATES_ROOT, jl_methtable_t *mt, size_t world, int cache_result, size_t *min_valid, size_t *max_valid) { jl_value_t *unw = jl_unwrap_unionall((jl_value_t*)types); if (!jl_is_tuple_type(unw)) @@ -3917,7 +4013,7 @@ static jl_method_match_t *_gf_invoke_lookup(jl_value_t *types JL_PROPAGATES_ROOT if (jl_tparam0(unw) == jl_bottom_type) return NULL; jl_methcache_t *mc = ((jl_methtable_t*)mt)->cache; - jl_value_t *matches = ml_matches((jl_methtable_t*)mt, mc, (jl_tupletype_t*)types, 1, 0, 0, world, 1, min_valid, max_valid, NULL); + jl_value_t *matches = ml_matches((jl_methtable_t*)mt, mc, (jl_tupletype_t*)types, 1, 0, 0, world, cache_result, min_valid, max_valid, NULL); if (matches == jl_nothing || jl_array_nrows(matches) != 1) return NULL; jl_method_match_t *matc = (jl_method_match_t*)jl_array_ptr_ref(matches, 0); @@ -3931,7 +4027,7 @@ JL_DLLEXPORT jl_value_t *jl_gf_invoke_lookup(jl_value_t *types, jl_value_t *mt, size_t max_valid = ~(size_t)0; if (mt == jl_nothing) mt = (jl_value_t*)jl_method_table; - jl_method_match_t *matc = _gf_invoke_lookup(types, (jl_methtable_t*)mt, world, &min_valid, &max_valid); + jl_method_match_t *matc = _gf_invoke_lookup(types, (jl_methtable_t*)mt, world, 1, &min_valid, &max_valid); if (matc == NULL) return jl_nothing; return (jl_value_t*)matc->method; @@ -3942,7 +4038,7 @@ JL_DLLEXPORT jl_value_t *jl_gf_invoke_lookup_worlds(jl_value_t *types, jl_value_ { if (mt == jl_nothing) mt = (jl_value_t*)jl_method_table; - jl_method_match_t *matc = _gf_invoke_lookup(types, (jl_methtable_t*)mt, world, min_world, max_world); + jl_method_match_t *matc = _gf_invoke_lookup(types, (jl_methtable_t*)mt, world, 1, min_world, max_world); if (matc == NULL) return jl_nothing; return (jl_value_t*)matc; @@ -4004,7 +4100,6 @@ jl_value_t *jl_gf_invoke_by_method(jl_method_t *method, jl_value_t *gf, jl_value int sub = jl_subtype_matching((jl_value_t*)tt, (jl_value_t*)method->sig, &tpenv); assert(sub); (void)sub; } - mfunc = cache_method(NULL, NULL, &method->invokes, (jl_value_t*)method, tt, method, 1, 1, ~(size_t)0, tpenv); } JL_UNLOCK(&method->writelock); @@ -4503,26 +4598,29 @@ static jl_value_t *ml_matches(jl_methtable_t *mt, jl_methcache_t *mc, if (entry && (((jl_datatype_t*)unw)->isdispatchtuple || entry->guardsigs == jl_emptysvec)) { jl_method_instance_t *mi = entry->func.linfo; jl_method_t *meth = mi->def.method; - if (!jl_is_unionall(meth->sig) && ((jl_datatype_t*)unw)->isdispatchtuple) { - env.match.env = jl_emptysvec; - env.match.ti = unw; - } - else { - // this just calls jl_subtype_env (since we know that `type <: meth->sig` by transitivity) - env.match.ti = jl_type_intersection_env((jl_value_t*)type, (jl_value_t*)meth->sig, &env.match.env); - } - env.matc = make_method_match((jl_tupletype_t*)env.match.ti, - env.match.env, meth, FULLY_COVERS); - env.t = (jl_value_t*)jl_alloc_vec_any(1); - jl_array_ptr_set(env.t, 0, env.matc); size_t min_world = jl_atomic_load_relaxed(&entry->min_world); - size_t max_world = jl_atomic_load_relaxed(&entry->max_world); - if (*min_valid < min_world) - *min_valid = min_world; - if (*max_valid > max_world) - *max_valid = max_world; - JL_GC_POP(); - return env.t; + // only return this if it appears min_would is fully computed, otherwise do the full lookup to compute min_world exactly + if (min_world == jl_atomic_load_relaxed(&meth->primary_world)) { + size_t max_world = jl_atomic_load_relaxed(&entry->max_world); + if (!jl_is_unionall(meth->sig) && ((jl_datatype_t*)unw)->isdispatchtuple) { + env.match.env = jl_emptysvec; + env.match.ti = unw; + } + else { + // this just calls jl_subtype_env (since we know that `type <: meth->sig` by transitivity) + env.match.ti = jl_type_intersection_env((jl_value_t*)type, (jl_value_t*)meth->sig, &env.match.env); + } + env.matc = make_method_match((jl_tupletype_t*)env.match.ti, + env.match.env, meth, FULLY_COVERS); + env.t = (jl_value_t*)jl_alloc_vec_any(1); + jl_array_ptr_set(env.t, 0, env.matc); + if (*min_valid < min_world) + *min_valid = min_world; + if (*max_valid > max_world) + *max_valid = max_world; + JL_GC_POP(); + return env.t; + } } } } @@ -4787,7 +4885,6 @@ static jl_value_t *ml_matches(jl_methtable_t *mt, jl_methcache_t *mc, jl_svec_t *tpenv = env.matc->sparams; JL_LOCK(&mc->writelock); cache_method(mt, mc, &mc->cache, (jl_value_t*)mc, (jl_tupletype_t*)unw, meth, world, env.match.min_valid, env.match.max_valid, tpenv); - JL_UNLOCK(&mc->writelock); } } *min_valid = env.match.min_valid; diff --git a/src/jltypes.c b/src/jltypes.c index 90bd862df808a..d30adbd4b72fa 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -3575,7 +3575,7 @@ void jl_init_types(void) JL_GC_DISABLED jl_module_type, jl_symbol_type, jl_int32_type, - jl_int32_type, + jl_uint8_type, jl_ulong_type, jl_type_type, jl_any_type, // union(jl_simplevector_type, jl_method_instance_type), @@ -3613,27 +3613,29 @@ void jl_init_types(void) JL_GC_DISABLED jl_method_instance_type = jl_new_datatype(jl_symbol("MethodInstance"), core, jl_any_type, jl_emptysvec, - jl_perm_symsvec(7, + jl_perm_symsvec(8, "def", "specTypes", "sparam_vals", "backedges", "cache", "cache_with_orig", - "flags"), - jl_svec(7, + "flags", + "dispatch_status"), + jl_svec(8, jl_new_struct(jl_uniontype_type, jl_method_type, jl_module_type), jl_any_type, jl_simplevector_type, jl_array_any_type, jl_any_type/*jl_code_instance_type*/, jl_bool_type, - jl_bool_type), + jl_bool_type, + jl_uint8_type), jl_emptysvec, 0, 1, 3); // These fields should be constant, but Serialization wants to mutate them in initialization //const static uint32_t method_instance_constfields[1] = { 0b0000111 }; // fields 1, 2, 3 - const static uint32_t method_instance_atomicfields[1] = { 0b1010000 }; // fields 5, 7 + const static uint32_t method_instance_atomicfields[1] = { 0b11010000 }; // fields 5, 7, 8 //Fields 4 and 5 must be protected by method->write_lock, and thus all operations on jl_method_instance_t are threadsafe. //jl_method_instance_type->name->constfields = method_instance_constfields; jl_method_instance_type->name->atomicfields = method_instance_atomicfields; diff --git a/src/julia.h b/src/julia.h index c9a14e202cc9f..2d8eecbf358f2 100644 --- a/src/julia.h +++ b/src/julia.h @@ -332,7 +332,7 @@ typedef struct _jl_method_t { struct _jl_module_t *module; jl_sym_t *file; int32_t line; - _Atomic(int32_t) dispatch_status; // bits defined in staticdata.jl + _Atomic(uint8_t) dispatch_status; // bits defined in staticdata.jl _Atomic(size_t) primary_world; // method's type signature. redundant with TypeMapEntry->specTypes @@ -417,6 +417,7 @@ struct _jl_method_instance_t { // bit 2: The ->backedges field is currently being walked higher up the stack - entries may be deleted, but not moved // bit 3: The ->backedges field was modified and should be compacted when clearing bit 2 _Atomic(uint8_t) flags; + _Atomic(uint8_t) dispatch_status; // bits defined in staticdata.jl }; #define JL_MI_FLAGS_MASK_PRECOMPILED 0x01 #define JL_MI_FLAGS_MASK_DISPATCHED 0x02 diff --git a/src/method.c b/src/method.c index eba485ff9eb69..a04035086df90 100644 --- a/src/method.c +++ b/src/method.c @@ -609,6 +609,7 @@ JL_DLLEXPORT jl_method_instance_t *jl_new_method_instance_uninit(void) jl_atomic_store_relaxed(&mi->cache, NULL); mi->cache_with_orig = 0; jl_atomic_store_relaxed(&mi->flags, 0); + jl_atomic_store_relaxed(&mi->dispatch_status, 0); return mi; } diff --git a/src/staticdata.c b/src/staticdata.c index 83d87caa586fe..5b7f7026de96d 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -1846,6 +1846,9 @@ static void jl_write_values(jl_serializer_state *s) JL_GC_DISABLED assert(f == s->s); jl_method_instance_t *newmi = (jl_method_instance_t*)&f->buf[reloc_offset]; jl_atomic_store_relaxed(&newmi->flags, 0); + if (s->incremental) { + jl_atomic_store_relaxed(&newmi->dispatch_status, 0); + } } else if (jl_is_code_instance(v)) { assert(f == s->s); @@ -4544,49 +4547,6 @@ JL_DLLEXPORT jl_value_t *jl_restore_package_image_from_file(const char *fname, j return mod; } -JL_DLLEXPORT void _jl_promote_ci_to_current(jl_code_instance_t *ci, size_t validated_world) JL_NOTSAFEPOINT -{ - if (jl_atomic_load_relaxed(&ci->max_world) != validated_world) - return; - jl_atomic_store_relaxed(&ci->max_world, ~(size_t)0); - jl_svec_t *edges = jl_atomic_load_relaxed(&ci->edges); - for (size_t i = 0; i < jl_svec_len(edges); i++) { - jl_value_t *edge = jl_svecref(edges, i); - if (!jl_is_code_instance(edge)) - continue; - _jl_promote_ci_to_current((jl_code_instance_t *)edge, validated_world); - } -} - -JL_DLLEXPORT void jl_promote_ci_to_current(jl_code_instance_t *ci, size_t validated_world) -{ - size_t current_world = jl_atomic_load_relaxed(&jl_world_counter); - // No need to acquire the lock if we've been invalidated anyway - if (current_world > validated_world) - return; - JL_LOCK(&world_counter_lock); - current_world = jl_atomic_load_relaxed(&jl_world_counter); - if (current_world == validated_world) { - _jl_promote_ci_to_current(ci, validated_world); - } - JL_UNLOCK(&world_counter_lock); -} - -JL_DLLEXPORT void jl_promote_cis_to_current(jl_code_instance_t **cis, size_t n, size_t validated_world) -{ - size_t current_world = jl_atomic_load_relaxed(&jl_world_counter); - // No need to acquire the lock if we've been invalidated anyway - if (current_world > validated_world) - return; - JL_LOCK(&world_counter_lock); - current_world = jl_atomic_load_relaxed(&jl_world_counter); - if (current_world == validated_world) { - for (size_t i = 0; i < n; i++) { - _jl_promote_ci_to_current(cis[i], validated_world); - } - } - JL_UNLOCK(&world_counter_lock); -} #ifdef __cplusplus } diff --git a/test/core.jl b/test/core.jl index 027e79b8b7c03..63ee04ddc0c41 100644 --- a/test/core.jl +++ b/test/core.jl @@ -37,7 +37,7 @@ for (T, c) in ( (Core.CodeInfo, []), (Core.CodeInstance, [:next, :min_world, :max_world, :inferred, :edges, :debuginfo, :ipo_purity_bits, :invoke, :specptr, :specsigflags, :precompile, :time_compile]), (Core.Method, [:primary_world, :did_scan_source, :dispatch_status]), - (Core.MethodInstance, [:cache, :flags]), + (Core.MethodInstance, [:cache, :flags, :dispatch_status]), (Core.MethodTable, [:defs]), (Core.MethodCache, [:leafcache, :cache, :var""]), (Core.TypeMapEntry, [:next, :min_world, :max_world]), From 9a7388c8ee2207bb49d757ef70c4108fd9130f44 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 7 Jul 2025 12:20:09 -0400 Subject: [PATCH 79/83] correctly encode and validate fully_covers as edges (#58861) This is a bugfix and code cleanup, since it wasn't properly encoding and checking for newly "missing"-type backedges `fully_covering` during verification. Co-authored-by: Claude (cherry picked from commit 6efd218a99284871fd252b2b1146cde0cc82ff98) --- Compiler/src/stmtinfo.jl | 12 +++--- base/staticdata.jl | 32 ++++++++++------ src/gf.c | 81 +++++++++++++++++++--------------------- src/julia_internal.h | 2 + src/staticdata.c | 7 +++- 5 files changed, 74 insertions(+), 60 deletions(-) diff --git a/Compiler/src/stmtinfo.jl b/Compiler/src/stmtinfo.jl index 2a2e2509b0fc2..1c6d47ec53b57 100644 --- a/Compiler/src/stmtinfo.jl +++ b/Compiler/src/stmtinfo.jl @@ -60,7 +60,7 @@ function _add_edges_impl(edges::Vector{Any}, info::MethodMatchInfo, mi_edge::Boo end end nmatches = length(info.results) - if nmatches == length(info.edges) == 1 + if nmatches == length(info.edges) == 1 && fully_covering(info) # try the optimized format for the representation, if possible and applicable # if this doesn't succeed, the backedge will be less precise, # but the forward edge will maintain the precision @@ -78,13 +78,15 @@ function _add_edges_impl(edges::Vector{Any}, info::MethodMatchInfo, mi_edge::Boo end end # add check for whether this lookup already existed in the edges list + # encode nmatches as negative if fully_covers is false + encoded_nmatches = fully_covering(info) ? nmatches : -nmatches for i in 1:length(edges) - if edges[i] === nmatches && edges[i+1] == info.atype + if edges[i] === encoded_nmatches && edges[i+1] == info.atype # TODO: must also verify the CodeInstance match too return nothing end end - push!(edges, nmatches, info.atype) + push!(edges, encoded_nmatches, info.atype) for i = 1:nmatches edge = info.edges[i] m = info.results[i] @@ -101,7 +103,7 @@ function add_one_edge!(edges::Vector{Any}, edge::MethodInstance) i = 1 while i <= length(edges) edgeᵢ = edges[i] - edgeᵢ isa Int && (i += 2 + edgeᵢ; continue) + edgeᵢ isa Int && (i += 2 + abs(edgeᵢ); continue) edgeᵢ isa CodeInstance && (edgeᵢ = get_ci_mi(edgeᵢ)) edgeᵢ isa MethodInstance || (i += 1; continue) if edgeᵢ === edge && !(i > 1 && edges[i-1] isa Type) @@ -116,7 +118,7 @@ function add_one_edge!(edges::Vector{Any}, edge::CodeInstance) i = 1 while i <= length(edges) edgeᵢ_orig = edgeᵢ = edges[i] - edgeᵢ isa Int && (i += 2 + edgeᵢ; continue) + edgeᵢ isa Int && (i += 2 + abs(edgeᵢ); continue) edgeᵢ isa CodeInstance && (edgeᵢ = get_ci_mi(edgeᵢ)) edgeᵢ isa MethodInstance || (i += 1; continue) if edgeᵢ === edge.def && !(i > 1 && edges[i-1] isa Type) diff --git a/base/staticdata.jl b/base/staticdata.jl index c4053889febc6..9f7ef67743906 100644 --- a/base/staticdata.jl +++ b/base/staticdata.jl @@ -177,12 +177,15 @@ function verify_method(codeinst::CodeInstance, stack::Vector{CodeInstance}, visi end if edge isa MethodInstance sig = edge.specTypes - min_valid2, max_valid2, matches = verify_call(sig, callees, j, 1, world) + min_valid2, max_valid2, matches = verify_call(sig, callees, j, 1, world, true) j += 1 elseif edge isa Int sig = callees[j+1] - min_valid2, max_valid2, matches = verify_call(sig, callees, j+2, edge, world) - j += 2 + edge + # Handle negative counts (fully_covers=false) + nmatches = abs(edge) + fully_covers = edge > 0 + min_valid2, max_valid2, matches = verify_call(sig, callees, j+2, nmatches, world, fully_covers) + j += 2 + nmatches edge = sig elseif edge isa Core.Binding j += 1 @@ -288,7 +291,7 @@ function verify_method(codeinst::CodeInstance, stack::Vector{CodeInstance}, visi return 0, minworld, maxworld end -function verify_call(@nospecialize(sig), expecteds::Core.SimpleVector, i::Int, n::Int, world::UInt) +function verify_call(@nospecialize(sig), expecteds::Core.SimpleVector, i::Int, n::Int, world::UInt, fully_covers::Bool) # verify that these edges intersect with the same methods as before mi = nothing if n == 1 @@ -304,7 +307,9 @@ function verify_call(@nospecialize(sig), expecteds::Core.SimpleVector, i::Int, n mi = t::MethodInstance end meth = mi.def::Method - if !iszero(mi.dispatch_status & METHOD_SIG_LATEST_ONLY) + # Fast path is legal when fully_covers=true OR when METHOD_SIG_LATEST_HAS_NOTMORESPECIFIC is unset + if (fully_covers || iszero(meth.dispatch_status & METHOD_SIG_LATEST_HAS_NOTMORESPECIFIC)) && + !iszero(mi.dispatch_status & METHOD_SIG_LATEST_ONLY) minworld = meth.primary_world @assert minworld ≤ world maxworld = typemax(UInt) @@ -312,12 +317,15 @@ function verify_call(@nospecialize(sig), expecteds::Core.SimpleVector, i::Int, n return minworld, maxworld, result end end - if !iszero(meth.dispatch_status & METHOD_SIG_LATEST_ONLY) - minworld = meth.primary_world - @assert minworld ≤ world - maxworld = typemax(UInt) - result = Any[] # result is unused - return minworld, maxworld, result + # Fast path is legal when fully_covers=true OR when METHOD_SIG_LATEST_HAS_NOTMORESPECIFIC is unset + if fully_covers || iszero(meth.dispatch_status & METHOD_SIG_LATEST_HAS_NOTMORESPECIFIC) + if !iszero(meth.dispatch_status & METHOD_SIG_LATEST_ONLY) + minworld = meth.primary_world + @assert minworld ≤ world + maxworld = typemax(UInt) + result = Any[] # result is unused + return minworld, maxworld, result + end end end end @@ -382,6 +390,8 @@ end const METHOD_SIG_LATEST_WHICH = 0x1 # true indicates this method would be returned as the only result from `methods` when calling `method.sig` in the current latest world const METHOD_SIG_LATEST_ONLY = 0x2 +# true indicates there exists some other method that is not more specific than this one in the current latest world (which might be more fully covering) +const METHOD_SIG_LATEST_HAS_NOTMORESPECIFIC = 0x8 function verify_invokesig(@nospecialize(invokesig), expected::Method, world::UInt) @assert invokesig isa Type diff --git a/src/gf.c b/src/gf.c index 603f2beef7a0a..b0c7a65ea8f99 100644 --- a/src/gf.c +++ b/src/gf.c @@ -2140,12 +2140,6 @@ static int jl_type_intersection2(jl_value_t *t1, jl_value_t *t2, jl_value_t **is } -enum morespec_options { - morespec_unknown, - morespec_isnot, - morespec_is -}; - // check if `type` is replacing `m` with an ambiguity here, given other methods in `d` that already match it static int is_replacing(char ambig, jl_value_t *type, jl_method_t *m, jl_method_t *const *d, size_t n, jl_value_t *isect, jl_value_t *isect2, char *morespec) { @@ -2155,9 +2149,7 @@ static int is_replacing(char ambig, jl_value_t *type, jl_method_t *m, jl_method_ // see if m2 also fully covered this intersection if (m == m2 || !(jl_subtype(isect, m2->sig) || (isect2 && jl_subtype(isect2, m2->sig)))) continue; - if (morespec[k] == (char)morespec_unknown) - morespec[k] = (char)(jl_type_morespecific(m2->sig, type) ? morespec_is : morespec_isnot); - if (morespec[k] == (char)morespec_is) + if (morespec[k]) // not actually shadowing this--m2 will still be better return 0; // if type is not more specific than m (thus now dominating it) @@ -2165,7 +2157,7 @@ static int is_replacing(char ambig, jl_value_t *type, jl_method_t *m, jl_method_ // since m2 was also a previous match over isect, // see if m was previously dominant over all m2 // or if this was already ambiguous before - if (ambig == morespec_is && !jl_type_morespecific(m->sig, m2->sig)) { + if (ambig && !jl_type_morespecific(m->sig, m2->sig)) { // m and m2 were previously ambiguous over the full intersection of mi with type, and will still be ambiguous with addition of type return 0; } @@ -2659,17 +2651,27 @@ void jl_method_table_activate(jl_typemap_entry_t *newentry) oldvalue = get_intersect_matches(jl_atomic_load_relaxed(&mt->defs), newentry, &replaced, max_world); int invalidated = 0; - int only = !(jl_atomic_load_relaxed(&method->dispatch_status) & METHOD_SIG_PRECOMPILE_MANY); // will compute if this will be currently the only result that would returned from `ml_matches` given `sig` + int dispatch_bits = METHOD_SIG_LATEST_WHICH; // Always set LATEST_WHICH + // Check precompiled dispatch status bits + int precompiled_status = jl_atomic_load_relaxed(&method->dispatch_status); + if (!(precompiled_status & METHOD_SIG_PRECOMPILE_MANY)) + dispatch_bits |= METHOD_SIG_LATEST_ONLY; // Tentatively set, will be cleared if not applicable + if (precompiled_status & METHOD_SIG_PRECOMPILE_HAS_NOTMORESPECIFIC) + dispatch_bits |= METHOD_SIG_LATEST_HAS_NOTMORESPECIFIC; if (replaced) { oldvalue = (jl_value_t*)replaced; jl_method_t *m = replaced->func.method; invalidated = 1; method_overwrite(newentry, m); - // this is an optimized version of below, given we know the type-intersection is exact + // This is an optimized version of below, given we know the type-intersection is exact jl_method_table_invalidate(m, max_world); int m_dispatch = jl_atomic_load_relaxed(&m->dispatch_status); - jl_atomic_store_relaxed(&m->dispatch_status, 0); - only = m_dispatch & METHOD_SIG_LATEST_ONLY; + // Clear METHOD_SIG_LATEST_ONLY and METHOD_SIG_LATEST_WHICH bits, only keeping NOTMORESPECIFIC + jl_atomic_store_relaxed(&m->dispatch_status, m_dispatch & METHOD_SIG_LATEST_HAS_NOTMORESPECIFIC); + // Edge case: don't set dispatch_bits |= METHOD_SIG_LATEST_HAS_NOTMORESPECIFIC unconditionally since `m` is not an visible method for invalidations + dispatch_bits |= (m_dispatch & METHOD_SIG_LATEST_HAS_NOTMORESPECIFIC); + if (!(m_dispatch & METHOD_SIG_LATEST_ONLY)) + dispatch_bits &= ~METHOD_SIG_LATEST_ONLY; } else { jl_method_t *const *d; @@ -2685,13 +2687,28 @@ void jl_method_table_activate(jl_typemap_entry_t *newentry) oldmi = jl_alloc_vec_any(0); char *morespec = (char*)alloca(n); - memset(morespec, morespec_unknown, n); + // Compute all morespec values upfront + for (j = 0; j < n; j++) + morespec[j] = (char)jl_type_morespecific(d[j]->sig, type); for (j = 0; j < n; j++) { jl_method_t *m = d[j]; - if (morespec[j] == (char)morespec_is) { - only = 0; - continue; + // Compute ambig state: is there an ambiguity between new method and old m? + char ambig = !morespec[j] && !jl_type_morespecific(type, m->sig); + // Compute updates to the dispatch state bits + int m_dispatch = jl_atomic_load_relaxed(&m->dispatch_status); + if (morespec[j] || ambig) { + // !morespecific(new, old) + dispatch_bits &= ~METHOD_SIG_LATEST_ONLY; + m_dispatch |= METHOD_SIG_LATEST_HAS_NOTMORESPECIFIC; + } + if (!morespec[j]) { + // !morespecific(old, new) + dispatch_bits |= METHOD_SIG_LATEST_HAS_NOTMORESPECIFIC; + m_dispatch &= ~METHOD_SIG_LATEST_ONLY; } + jl_atomic_store_relaxed(&m->dispatch_status, m_dispatch); + if (morespec[j]) + continue; loctag = jl_atomic_load_relaxed(&m->specializations); // use loctag for a gcroot _Atomic(jl_method_instance_t*) *data; size_t l; @@ -2703,27 +2720,19 @@ void jl_method_table_activate(jl_typemap_entry_t *newentry) data = (_Atomic(jl_method_instance_t*)*) &loctag; l = 1; } - enum morespec_options ambig = morespec_unknown; for (size_t i = 0; i < l; i++) { jl_method_instance_t *mi = jl_atomic_load_relaxed(&data[i]); if ((jl_value_t*)mi == jl_nothing) continue; isect3 = jl_type_intersection(m->sig, (jl_value_t*)mi->specTypes); if (jl_type_intersection2(type, isect3, &isect, &isect2)) { + // Replacing a method--see if this really was the selected method previously + // over the intersection (not ambiguous) and the new method will be selected now (morespec_is). // TODO: this only checks pair-wise for ambiguities, but the ambiguities could arise from the interaction of multiple methods // and thus might miss a case where we introduce an ambiguity between two existing methods // We could instead work to sort this into 3 groups `morespecific .. ambiguous .. lesspecific`, with `type` in ambiguous, // such that everything in `morespecific` dominates everything in `ambiguous`, and everything in `ambiguous` dominates everything in `lessspecific` // And then compute where each isect falls, and whether it changed group--necessitating invalidation--or not. - if (morespec[j] == (char)morespec_unknown) - morespec[j] = (char)(jl_type_morespecific(m->sig, type) ? morespec_is : morespec_isnot); - if (morespec[j] == (char)morespec_is) - // not actually shadowing--the existing method is still better - break; - if (ambig == morespec_unknown) - ambig = jl_type_morespecific(type, m->sig) ? morespec_isnot : morespec_is; - // replacing a method--see if this really was the selected method previously - // over the intersection (not ambiguous) and the new method will be selected now (morespec_is) int replaced_dispatch = is_replacing(ambig, type, m, d, n, isect, isect2, morespec); // found that this specialization dispatch got replaced by m // call invalidate_backedges(mi, max_world, "jl_method_table_insert"); @@ -2740,20 +2749,6 @@ void jl_method_table_activate(jl_typemap_entry_t *newentry) invalidated |= invalidatedmi; } } - // now compute and store updates to METHOD_SIG_LATEST_ONLY - int m_dispatch = jl_atomic_load_relaxed(&m->dispatch_status); - if (m_dispatch & METHOD_SIG_LATEST_ONLY) { - if (morespec[j] == (char)morespec_unknown) - morespec[j] = (char)(jl_type_morespecific(m->sig, type) ? morespec_is : morespec_isnot); - if (morespec[j] == (char)morespec_isnot) - jl_atomic_store_relaxed(&m->dispatch_status, ~METHOD_SIG_LATEST_ONLY & m_dispatch); - } - if (only) { - if (morespec[j] == (char)morespec_is || ambig == morespec_is || - (ambig == morespec_unknown && !jl_type_morespecific(type, m->sig))) { - only = 0; - } - } } } @@ -2802,7 +2797,7 @@ void jl_method_table_activate(jl_typemap_entry_t *newentry) jl_array_ptr_1d_push(_jl_debug_method_invalidation, loctag); } jl_atomic_store_relaxed(&newentry->max_world, ~(size_t)0); - jl_atomic_store_relaxed(&method->dispatch_status, METHOD_SIG_LATEST_WHICH | (only ? METHOD_SIG_LATEST_ONLY : 0)); // TODO: this should be sequenced fully after the world counter store + jl_atomic_store_relaxed(&method->dispatch_status, dispatch_bits); // TODO: this should be sequenced fully after the world counter store JL_GC_POP(); } diff --git a/src/julia_internal.h b/src/julia_internal.h index 3fc5c9642fa29..42f77c6a59f72 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -677,6 +677,8 @@ typedef union { #define METHOD_SIG_LATEST_WHICH 0b0001 #define METHOD_SIG_LATEST_ONLY 0b0010 #define METHOD_SIG_PRECOMPILE_MANY 0b0100 +#define METHOD_SIG_LATEST_HAS_NOTMORESPECIFIC 0b1000 // indicates there exists some other method that is not more specific than this one +#define METHOD_SIG_PRECOMPILE_HAS_NOTMORESPECIFIC 0b10000 // precompiled version of METHOD_SIG_LATEST_HAS_NOTMORESPECIFIC JL_DLLEXPORT jl_code_instance_t *jl_engine_reserve(jl_method_instance_t *m, jl_value_t *owner); JL_DLLEXPORT void jl_engine_fulfill(jl_code_instance_t *ci, jl_code_info_t *src); diff --git a/src/staticdata.c b/src/staticdata.c index 5b7f7026de96d..65b6146e0805a 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -1834,7 +1834,12 @@ static void jl_write_values(jl_serializer_state *s) JL_GC_DISABLED if (jl_atomic_load_relaxed(&newm->primary_world) > 1) { jl_atomic_store_relaxed(&newm->primary_world, ~(size_t)0); // min-world int dispatch_status = jl_atomic_load_relaxed(&newm->dispatch_status); - jl_atomic_store_relaxed(&newm->dispatch_status, dispatch_status & METHOD_SIG_LATEST_ONLY ? 0 : METHOD_SIG_PRECOMPILE_MANY); + int new_dispatch_status = 0; + if (!(dispatch_status & METHOD_SIG_LATEST_ONLY)) + new_dispatch_status |= METHOD_SIG_PRECOMPILE_MANY; + if (dispatch_status & METHOD_SIG_LATEST_HAS_NOTMORESPECIFIC) + new_dispatch_status |= METHOD_SIG_PRECOMPILE_HAS_NOTMORESPECIFIC; + jl_atomic_store_relaxed(&newm->dispatch_status, new_dispatch_status); arraylist_push(&s->fixup_objs, (void*)reloc_offset); } } From c4e298cb975fcb211aa66172b7d22cd4eac584d1 Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Tue, 8 Jul 2025 09:05:22 +0200 Subject: [PATCH 80/83] Binding invalidation data race fixes (#58924) (cherry picked from commit c3282ceaacb3a41dad6da853b7677e404e603c9a) --- base/invalidation.jl | 34 +++++++++++++++++----------------- src/module.c | 24 ++++++++++++++++++++++++ src/staticdata.c | 4 ++++ 3 files changed, 45 insertions(+), 17 deletions(-) diff --git a/base/invalidation.jl b/base/invalidation.jl index b14a1f65930c8..b55b09e29961d 100644 --- a/base/invalidation.jl +++ b/base/invalidation.jl @@ -122,23 +122,23 @@ function invalidate_code_for_globalref!(b::Core.Binding, invalidated_bpart::Core invalidated_any |= invalidate_method_for_globalref!(gr, method, invalidated_bpart, new_max_world) end end - if isdefined(b, :backedges) - for edge in b.backedges - if isa(edge, CodeInstance) - ccall(:jl_invalidate_code_instance, Cvoid, (Any, UInt), edge, new_max_world) - invalidated_any = true - elseif isa(edge, Core.Binding) - isdefined(edge, :partitions) || continue - latest_bpart = edge.partitions - latest_bpart.max_world == typemax(UInt) || continue - is_some_imported(binding_kind(latest_bpart)) || continue - if is_some_binding_imported(binding_kind(latest_bpart)) - partition_restriction(latest_bpart) === b || continue - end - push!(queued_bindings, (edge, latest_bpart, latest_bpart)) - else - invalidated_any |= invalidate_method_for_globalref!(gr, edge::Method, invalidated_bpart, new_max_world) + nbackedges = ccall(:jl_binding_backedges_length, Csize_t, (Any,), b) + for i = 1:nbackedges + edge = ccall(:jl_binding_backedges_getindex, Any, (Any, Csize_t), b, i) + if isa(edge, CodeInstance) + ccall(:jl_invalidate_code_instance, Cvoid, (Any, UInt), edge, new_max_world) + invalidated_any = true + elseif isa(edge, Core.Binding) + isdefined(edge, :partitions) || continue + latest_bpart = edge.partitions + latest_bpart.max_world == typemax(UInt) || continue + is_some_imported(binding_kind(latest_bpart)) || continue + if is_some_binding_imported(binding_kind(latest_bpart)) + partition_restriction(latest_bpart) === b || continue end + push!(queued_bindings, (edge, latest_bpart, latest_bpart)) + else + invalidated_any |= invalidate_method_for_globalref!(gr, edge::Method, invalidated_bpart, new_max_world) end end end @@ -149,7 +149,7 @@ function invalidate_code_for_globalref!(b::Core.Binding, invalidated_bpart::Core usings_backedges = ccall(:jl_get_module_usings_backedges, Any, (Any,), gr.mod) if usings_backedges !== nothing for user::Module in usings_backedges::Vector{Any} - user_binding = ccall(:jl_get_module_binding_or_nothing, Any, (Any, Any), user, gr.name) + user_binding = ccall(:jl_get_module_binding_or_nothing, Any, (Any, Any), user, gr.name)::Union{Core.Binding, Nothing} user_binding === nothing && continue isdefined(user_binding, :partitions) || continue latest_bpart = user_binding.partitions diff --git a/src/module.c b/src/module.c index c28e1a834ce46..a792861ca55a9 100644 --- a/src/module.c +++ b/src/module.c @@ -470,6 +470,25 @@ JL_DLLEXPORT jl_value_t *jl_get_binding_leaf_partitions_value_if_const(jl_bindin return NULL; } +JL_DLLEXPORT size_t jl_binding_backedges_length(jl_binding_t *b) +{ + JL_LOCK(&b->globalref->mod->lock); + size_t len = 0; + if (b->backedges) + len = jl_array_len(b->backedges); + JL_UNLOCK(&b->globalref->mod->lock); + return len; +} + +JL_DLLEXPORT jl_value_t *jl_binding_backedges_getindex(jl_binding_t *b, size_t i) +{ + JL_LOCK(&b->globalref->mod->lock); + assert(b->backedges); + jl_value_t *ret = jl_array_ptr_ref(b->backedges, i-1); + JL_UNLOCK(&b->globalref->mod->lock); + return ret; +} + static jl_module_t *jl_new_module__(jl_sym_t *name, jl_module_t *parent) { jl_task_t *ct = jl_current_task; @@ -527,7 +546,9 @@ jl_module_t *jl_new_module_(jl_sym_t *name, jl_module_t *parent, uint8_t default { jl_module_t *m = jl_new_module__(name, parent); JL_GC_PUSH1(&m); + JL_LOCK(&world_counter_lock); jl_add_default_names(m, default_using_core, self_name); + JL_UNLOCK(&world_counter_lock); JL_GC_POP(); return m; } @@ -1617,6 +1638,7 @@ void jl_invalidate_binding_refs(jl_globalref_t *ref, jl_binding_partition_t *inv JL_DLLEXPORT void jl_add_binding_backedge(jl_binding_t *b, jl_value_t *edge) { + JL_LOCK(&b->globalref->mod->lock); if (!b->backedges) { b->backedges = jl_alloc_vec_any(0); jl_gc_wb(b, b->backedges); @@ -1624,9 +1646,11 @@ JL_DLLEXPORT void jl_add_binding_backedge(jl_binding_t *b, jl_value_t *edge) jl_array_ptr_ref(b->backedges, jl_array_len(b->backedges)-1) == edge) { // Optimization: Deduplicate repeated insertion of the same edge (e.g. during // definition of a method that contains many references to the same global) + JL_UNLOCK(&b->globalref->mod->lock); return; } jl_array_ptr_1d_push(b->backedges, edge); + JL_UNLOCK(&b->globalref->mod->lock); } // Called for all GlobalRefs found in lowered code. Adds backedges for cross-module diff --git a/src/staticdata.c b/src/staticdata.c index 65b6146e0805a..88304c1eb6f7f 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -3745,6 +3745,7 @@ static int jl_validate_binding_partition(jl_binding_t *b, jl_binding_partition_t // We need to go through and re-validate any bindings in the same image that // may have imported us. if (b->backedges) { + JL_LOCK(&b->globalref->mod->lock); for (size_t i = 0; i < jl_array_len(b->backedges); i++) { jl_value_t *edge = jl_array_ptr_ref(b->backedges, i); if (!jl_is_binding(edge)) @@ -3752,8 +3753,11 @@ static int jl_validate_binding_partition(jl_binding_t *b, jl_binding_partition_t jl_binding_t *bedge = (jl_binding_t*)edge; if (!jl_atomic_load_relaxed(&bedge->partitions)) continue; + JL_UNLOCK(&b->globalref->mod->lock); jl_validate_binding_partition(bedge, jl_atomic_load_relaxed(&bedge->partitions), mod_idx, 0, 0); + JL_LOCK(&b->globalref->mod->lock); } + JL_UNLOCK(&b->globalref->mod->lock); } if (bpart->kind & PARTITION_FLAG_EXPORTED) { jl_module_t *mod = b->globalref->mod; From 7c1ef006dddb9ed4b933b6075d7013895a8e6148 Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Tue, 8 Jul 2025 13:23:32 +0200 Subject: [PATCH 81/83] Revert "Define `in` for `CartesianIndex` ranges (#58616)" This reverts commit 304847e35afaebfeb1c03b85b3b016606097824b. --- base/multidimensional.jl | 18 -------------- test/cartesian.jl | 54 ---------------------------------------- 2 files changed, 72 deletions(-) diff --git a/base/multidimensional.jl b/base/multidimensional.jl index 73e4f69dd528f..ee0cf9690b469 100644 --- a/base/multidimensional.jl +++ b/base/multidimensional.jl @@ -183,24 +183,6 @@ module IteratorsMD step(r), ", ", length(r), ")") end - Base.in(x::CartesianIndex, r::AbstractRange{<:CartesianIndex}) = false - function Base.in(x::CartesianIndex{N}, r::AbstractRange{CartesianIndex{N}}) where {N} - isempty(r) && return false - f, st, l = first(r), step(r), last(r) - # The n-th element of the range is a CartesianIndex - # whose elements are the n-th along each dimension - # Find the first dimension along which the index is changing, - # so that n may be uniquely determined - for i in 1:N - iszero(st[i]) && continue - n = findfirst(==(x[i]), f[i]:st[i]:l[i]) - isnothing(n) && return false - return r[n] == x - end - # if the step is zero, the elements are identical, so compare with the first - return x == f - end - # Iteration const OrdinalRangeInt = OrdinalRange{Int, Int} """ diff --git a/test/cartesian.jl b/test/cartesian.jl index 6097d4ca3770a..7064b54ebbb8d 100644 --- a/test/cartesian.jl +++ b/test/cartesian.jl @@ -573,57 +573,3 @@ end end @test t3 == (1, 2, 0) end - -@testset "CartesianIndex show" begin - c = CartesianIndex() - @test sprint(show, c) == "CartesianIndex()" - c = CartesianIndex(3) - @test sprint(show, c) == "CartesianIndex(3)" - c = CartesianIndex(3, 3) - @test sprint(show, c) == "CartesianIndex(3, 3)" -end - -@testset "CartesianIndex indexing with begin/end" begin - I = CartesianIndex(3,4) - @test I[begin] == I[1] - @test I[end] == I[2] -end - -@testset "in for a CartesianIndex StepRangeLen" begin - @testset for l in [0, 1, 4], r in Any[ - StepRangeLen(CartesianIndex(), CartesianIndex(), l), - StepRangeLen(CartesianIndex(1), CartesianIndex(0), l), - StepRangeLen(CartesianIndex(1), CartesianIndex(1), l), - StepRangeLen(CartesianIndex(1), CartesianIndex(4), l), - StepRangeLen(CartesianIndex(1), CartesianIndex(-4), l), - StepRangeLen(CartesianIndex(-1, 2), CartesianIndex(0, 0), l), - StepRangeLen(CartesianIndex(-1, 2), CartesianIndex(0, 4), l), - StepRangeLen(CartesianIndex(-1, 2), CartesianIndex(0, -4), l), - StepRangeLen(CartesianIndex(-1, 2), CartesianIndex(4, 0), l), - StepRangeLen(CartesianIndex(-1, 2), CartesianIndex(-4, 0), l), - StepRangeLen(CartesianIndex(-1, 2), CartesianIndex(4, 2), l), - StepRangeLen(CartesianIndex(-1, 2), CartesianIndex(-4, 2), l), - StepRangeLen(CartesianIndex(-1, 2), CartesianIndex(4, -2), l), - StepRangeLen(CartesianIndex(-1, 2), CartesianIndex(-4, -2), l), - StepRangeLen(CartesianIndex(-1, 2, 0), CartesianIndex(0, 0, 0), l), - StepRangeLen(CartesianIndex(-1, 2, 0), CartesianIndex(0, 0, -2), l), - ] - - if length(r) == 0 - @test !(first(r) in r) - @test !(last(r) in r) - end - for x in r - @test x in r - if step(r) != oneunit(x) - @test !((x + oneunit(x)) in r) - end - end - @test !(CartesianIndex(ntuple(x->0, ndims(r))) in r) - @test !(CartesianIndex(ntuple(x->typemax(Int), ndims(r))) in r) - @test !(CartesianIndex(ntuple(x->typemin(Int), ndims(r))) in r) - if ndims(r) > 1 - @test !(CartesianIndex(ntuple(x->0, ndims(r)-1)...) in r) - end - end -end From aa56078b6564c6bf0b784c202048a3f8c977c62d Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Thu, 5 Jun 2025 09:23:26 -0400 Subject: [PATCH 82/83] test: replcompletions: Replace timedwait by proper condvar (#58643) Replace fragile timing-based synchronization with proper condition variable signaling to ensure PATH cache updates complete before testing completions. This eliminates test flakiness on systems where the cache update takes longer than 5s. The test failure was seen in CI: https://buildkite.com/julialang/julia-master/builds/48273 (cherry picked from commit a4ab11016c0d19cd56b1662afae906afaf8f7a3d) --- stdlib/REPL/src/REPLCompletions.jl | 12 +++++--- stdlib/REPL/test/replcompletions.jl | 47 +++++++++++++++++++++++------ 2 files changed, 44 insertions(+), 15 deletions(-) diff --git a/stdlib/REPL/src/REPLCompletions.jl b/stdlib/REPL/src/REPLCompletions.jl index 4244111f0aa36..e30a59b8c00d5 100644 --- a/stdlib/REPL/src/REPLCompletions.jl +++ b/stdlib/REPL/src/REPLCompletions.jl @@ -330,7 +330,8 @@ end const PATH_cache_lock = Base.ReentrantLock() const PATH_cache = Set{String}() -PATH_cache_task::Union{Task,Nothing} = nothing # used for sync in tests +PATH_cache_task::Union{Task,Nothing} = nothing +PATH_cache_condition::Union{Threads.Condition, Nothing} = nothing # used for sync in tests next_cache_update::Float64 = 0.0 function maybe_spawn_cache_PATH() global PATH_cache_task, next_cache_update @@ -339,7 +340,11 @@ function maybe_spawn_cache_PATH() time() < next_cache_update && return PATH_cache_task = Threads.@spawn begin REPLCompletions.cache_PATH() - @lock PATH_cache_lock PATH_cache_task = nothing # release memory when done + @lock PATH_cache_lock begin + next_cache_update = time() + 10 # earliest next update can run is 10s after + PATH_cache_task = nothing # release memory when done + PATH_cache_condition !== nothing && notify(PATH_cache_condition) + end end Base.errormonitor(PATH_cache_task) end @@ -350,8 +355,6 @@ function cache_PATH() path = get(ENV, "PATH", nothing) path isa String || return - global next_cache_update - # Calling empty! on PATH_cache would be annoying for async typing hints as completions would temporarily disappear. # So keep track of what's added this time and at the end remove any that didn't appear this time from the global cache. this_PATH_cache = Set{String}() @@ -414,7 +417,6 @@ function cache_PATH() @lock PATH_cache_lock begin intersect!(PATH_cache, this_PATH_cache) # remove entries from PATH_cache that weren't found this time - next_cache_update = time() + 10 # earliest next update can run is 10s after end @debug "caching PATH files took $t seconds" length(pathdirs) length(PATH_cache) diff --git a/stdlib/REPL/test/replcompletions.jl b/stdlib/REPL/test/replcompletions.jl index 5f2990e970d97..43bea08e285f1 100644 --- a/stdlib/REPL/test/replcompletions.jl +++ b/stdlib/REPL/test/replcompletions.jl @@ -1073,6 +1073,39 @@ let c, r, res @test res === false end +# A pair of utility function for the REPL completions test to test PATH_cache +# dependent completions, which ordinarily happen asynchronously. +# Only to be used from the test suite +function test_only_arm_cache_refresh() + @lock REPL.REPLCompletions.PATH_cache_lock begin + @assert REPL.REPLCompletions.PATH_cache_condition === nothing + + # Arm a condition we can wait on + REPL.REPLCompletions.PATH_cache_condition = Threads.Condition(REPL.REPLCompletions.PATH_cache_lock) + + # Check if the previous update is still running - if so, wait for it to finish + while REPL.REPLCompletions.PATH_cache_task !== nothing + @assert !istaskdone(REPL.REPLCompletions.PATH_cache_task) + wait(REPL.REPLCompletions.PATH_cache_condition) + end + + # force the next cache update to happen immediately + REPL.REPLCompletions.next_cache_update = 0 + end + return REPL.REPLCompletions.PATH_cache_condition +end + +function test_only_wait_cache_path_done() + @lock REPL.REPLCompletions.PATH_cache_lock begin + @assert REPL.REPLCompletions.PATH_cache_condition !== nothing + + while REPL.REPLCompletions.next_cache_update == 0. + wait(REPL.REPLCompletions.PATH_cache_condition) + end + REPL.REPLCompletions.PATH_cache_condition = nothing + end +end + if Sys.isunix() let s, c, r #Assume that we can rely on the existence and accessibility of /tmp @@ -1204,12 +1237,9 @@ let s, c, r # Files reachable by PATH are cached async when PATH is seen to have been changed by `complete_path` # so changes are unlikely to appear in the first complete. For testing purposes we can wait for # caching to finish - @lock REPL.REPLCompletions.PATH_cache_lock begin - # force the next cache update to happen immediately - REPL.REPLCompletions.next_cache_update = 0 - end + test_only_arm_cache_refresh() c,r = test_scomplete(s) - timedwait(()->REPL.REPLCompletions.next_cache_update != 0, 5) # wait for caching to complete + test_only_wait_cache_path_done() c,r = test_scomplete(s) @test "tmp-executable" in c @test r == 1:9 @@ -1238,12 +1268,9 @@ let s, c, r withenv("PATH" => string(tempdir(), ":", dir)) do s = string("repl-completio") - @lock REPL.REPLCompletions.PATH_cache_lock begin - # force the next cache update to happen immediately - REPL.REPLCompletions.next_cache_update = 0 - end + test_only_arm_cache_refresh() c,r = test_scomplete(s) - timedwait(()->REPL.REPLCompletions.next_cache_update != 0, 5) # wait for caching to complete + test_only_wait_cache_path_done() c,r = test_scomplete(s) @test ["repl-completion"] == c @test s[r] == "repl-completio" From c1f27d2cd0a2753bc36a69080f3894c32a3cdbad Mon Sep 17 00:00:00 2001 From: DilumAluthgeBot <43731525+DilumAluthgeBot@users.noreply.github.com> Date: Tue, 8 Jul 2025 18:49:12 -0400 Subject: [PATCH 83/83] =?UTF-8?q?=F0=9F=A4=96=20[backports-release-1.12]?= =?UTF-8?q?=20Bump=20the=20Distributed=20stdlib=20from=2051e5297=20to=2036?= =?UTF-8?q?79026=20(#58910)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stdlib: Distributed URL: https://github.com/JuliaLang/Distributed.jl Stdlib branch: master Julia branch: backports-release-1.12 Old commit: 51e5297 New commit: 3679026 Julia version: 1.12.0-beta4 Distributed version: 1.11.0(Does not match) Bump invoked by: @DilumAluthge Powered by: [BumpStdlibs.jl](https://github.com/JuliaLang/BumpStdlibs.jl) Diff: https://github.com/JuliaLang/Distributed.jl/compare/51e52978481835413d15b589919aba80dd85f890...3679026d7b510befdedfa8c6497e3cb032f9cea1 ``` $ git log --oneline 51e5297..3679026 3679026 Merge pull request #137 from JuliaLang/dpa/dont-use-link-local 875cd5a Rewrite the code to be a bit more explicit 2a6ee53 Non-link-local IP4 > non-link-local IP6 > link-local IP4 > link-local IP6 c0e9eb4 Factor functionality out into separate `choose_bind_addr()` function 86cbb8a Add explanation 0b7288c Worker: Bind to the first non-link-local IPv4 address ff8689a Merge pull request #131 from JuliaLang/spawnat-docs ba3c843 Document that `@spawnat :any` doesn't do load-balancing ``` Co-authored-by: DilumAluthge <5619885+DilumAluthge@users.noreply.github.com> --- .../md5 | 1 + .../sha512 | 1 + .../md5 | 1 - .../sha512 | 1 - stdlib/Distributed.version | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 deps/checksums/Distributed-3679026d7b510befdedfa8c6497e3cb032f9cea1.tar.gz/md5 create mode 100644 deps/checksums/Distributed-3679026d7b510befdedfa8c6497e3cb032f9cea1.tar.gz/sha512 delete mode 100644 deps/checksums/Distributed-51e52978481835413d15b589919aba80dd85f890.tar.gz/md5 delete mode 100644 deps/checksums/Distributed-51e52978481835413d15b589919aba80dd85f890.tar.gz/sha512 diff --git a/deps/checksums/Distributed-3679026d7b510befdedfa8c6497e3cb032f9cea1.tar.gz/md5 b/deps/checksums/Distributed-3679026d7b510befdedfa8c6497e3cb032f9cea1.tar.gz/md5 new file mode 100644 index 0000000000000..ca3d9730181f4 --- /dev/null +++ b/deps/checksums/Distributed-3679026d7b510befdedfa8c6497e3cb032f9cea1.tar.gz/md5 @@ -0,0 +1 @@ +fdf2e62fcaed6aa5ad69bca405329675 diff --git a/deps/checksums/Distributed-3679026d7b510befdedfa8c6497e3cb032f9cea1.tar.gz/sha512 b/deps/checksums/Distributed-3679026d7b510befdedfa8c6497e3cb032f9cea1.tar.gz/sha512 new file mode 100644 index 0000000000000..186dfb34221b6 --- /dev/null +++ b/deps/checksums/Distributed-3679026d7b510befdedfa8c6497e3cb032f9cea1.tar.gz/sha512 @@ -0,0 +1 @@ +2361fc4ccad83139cf728f14fa38466f075fbf93dddfac533af8f5c0c35d6b86511881b7b97a95ee59f858ba9a33428d3514ac3bd605b745b002a673acfc3190 diff --git a/deps/checksums/Distributed-51e52978481835413d15b589919aba80dd85f890.tar.gz/md5 b/deps/checksums/Distributed-51e52978481835413d15b589919aba80dd85f890.tar.gz/md5 deleted file mode 100644 index cdf885890db7c..0000000000000 --- a/deps/checksums/Distributed-51e52978481835413d15b589919aba80dd85f890.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -bf358a22ed4aa0d57b8672ef81fb2b44 diff --git a/deps/checksums/Distributed-51e52978481835413d15b589919aba80dd85f890.tar.gz/sha512 b/deps/checksums/Distributed-51e52978481835413d15b589919aba80dd85f890.tar.gz/sha512 deleted file mode 100644 index 171fd2fdbf512..0000000000000 --- a/deps/checksums/Distributed-51e52978481835413d15b589919aba80dd85f890.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -399ab073d8c8cd1404e2e89ce2753486c782aa18646d56d8508c0a929c6a312e8bac2c791eddc01966f99cec1af34e56bbdccd8d75196b26f0b1bbb1fa8bd9ac diff --git a/stdlib/Distributed.version b/stdlib/Distributed.version index be52c0d684b50..99b5238a55491 100644 --- a/stdlib/Distributed.version +++ b/stdlib/Distributed.version @@ -1,4 +1,4 @@ DISTRIBUTED_BRANCH = master -DISTRIBUTED_SHA1 = 51e52978481835413d15b589919aba80dd85f890 +DISTRIBUTED_SHA1 = 3679026d7b510befdedfa8c6497e3cb032f9cea1 DISTRIBUTED_GIT_URL := https://github.com/JuliaLang/Distributed.jl DISTRIBUTED_TAR_URL = https://api.github.com/repos/JuliaLang/Distributed.jl/tarball/$1