From a4844f4a14407110dbc386e53abb0a2618bc3d6e Mon Sep 17 00:00:00 2001 From: Gabriel Baraldi Date: Tue, 6 May 2025 06:08:40 -0300 Subject: [PATCH 01/46] Fix removal of globals with addrspaces in removeAddrspaces (#58322) (cherry picked from commit 088bb9002e95631738c8ec5ba58b7b8a7b33019d) --- src/llvm-remove-addrspaces.cpp | 4 ++-- test/llvmpasses/remove-addrspaces.ll | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/llvm-remove-addrspaces.cpp b/src/llvm-remove-addrspaces.cpp index bb492f467e74c..78ff70b12409b 100644 --- a/src/llvm-remove-addrspaces.cpp +++ b/src/llvm-remove-addrspaces.cpp @@ -256,7 +256,7 @@ bool removeAddrspaces(Module &M, AddrspaceRemapFunction ASRemapper) Name, (GlobalVariable *)nullptr, GV->getThreadLocalMode(), - GV->getType()->getAddressSpace()); + cast(TypeRemapper.remapType(GV->getType()))->getAddressSpace()); NGV->copyAttributesFrom(GV); VMap[GV] = NGV; } @@ -276,7 +276,7 @@ bool removeAddrspaces(Module &M, AddrspaceRemapFunction ASRemapper) auto *NGA = GlobalAlias::create( TypeRemapper.remapType(GA->getValueType()), - GA->getType()->getPointerAddressSpace(), + cast(TypeRemapper.remapType(GA->getType()))->getAddressSpace(), GA->getLinkage(), Name, &M); diff --git a/test/llvmpasses/remove-addrspaces.ll b/test/llvmpasses/remove-addrspaces.ll index fbd84de85a4a3..99acd92b0e03b 100644 --- a/test/llvmpasses/remove-addrspaces.ll +++ b/test/llvmpasses/remove-addrspaces.ll @@ -2,6 +2,9 @@ ; RUN: opt --load-pass-plugin=libjulia-codegen%shlibext -passes='RemoveJuliaAddrspaces' -S %s | FileCheck %s --check-prefixes=CHECK,OPAQUE +; COM: check that the addrspace of the global itself is removed +; OPAQUE: @ejl_enz_runtime_exc = external global {} +@ejl_enz_runtime_exc = external addrspace(10) global {} ; COM: check that package image fptrs work @pjlsys_BoundsError_32 = internal global {} addrspace(10)* ({}***, {} addrspace(10)*, [1 x i64] addrspace(11)*)* null @@ -111,6 +114,13 @@ define void @byval_type([1 x {} addrspace(10)*] addrspace(11)* byval([1 x {} add } +define private fastcc void @diffejulia__mapreduce_97() { +L6: +; OPAQUE: store atomic ptr @ejl_enz_runtime_exc, ptr null unordered + store atomic {} addrspace(10)* @ejl_enz_runtime_exc, {} addrspace(10)* addrspace(10)* null unordered, align 8 + unreachable +} + ; COM: check that function attributes are preserved on declarations too declare void @convergent_function() #0 attributes #0 = { convergent } From e4d859d8d9d305cee699aa68dc22919f246ccdac Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Tue, 6 May 2025 15:44:11 -0400 Subject: [PATCH 02/46] replace incorrect Method.deleted_world with more useful Method.dispatch_status enum (#58291) The original purpose of this field was to manage quickly detecting if a method was replaced, but that stopped being correct after #53415. It was a fairly heavy-weight description of that single bit of information. This bit of information allows quickly bypassing some method lookups from pkgimages, since it can quickly detect that the result is trivially correct (such as single-argument functions). Also fixes #58215 (cherry picked from commit 5eb515587f45b80b9650daf1f7fe11f2bbb87e34) --- Compiler/src/typeinfer.jl | 2 +- base/errorshow.jl | 2 - base/staticdata.jl | 43 ++++++++++++++++----- src/gf.c | 78 ++++++++++++++++++++++++++------------- src/jltypes.c | 4 +- src/julia.h | 2 +- src/julia_internal.h | 4 ++ src/method.c | 4 +- src/opaque_closure.c | 1 - src/precompile_utils.c | 13 ++++--- src/staticdata.c | 15 +++----- src/staticdata_utils.c | 2 - src/typemap.c | 6 +-- test/core.jl | 2 +- test/worlds.jl | 2 + 15 files changed, 113 insertions(+), 67 deletions(-) diff --git a/Compiler/src/typeinfer.jl b/Compiler/src/typeinfer.jl index 8acec133d7912..debae93089c02 100644 --- a/Compiler/src/typeinfer.jl +++ b/Compiler/src/typeinfer.jl @@ -1422,7 +1422,7 @@ function compile!(codeinfos::Vector{Any}, workqueue::CompilationQueue; # if this method is generally visible to the current compilation world, # and this is either the primary world, or not applicable in the primary world # then we want to compile and emit this - if item.def.primary_world <= world <= item.def.deleted_world + if item.def.primary_world <= world ci = typeinf_ext(interp, item, SOURCE_MODE_GET_SOURCE) ci isa CodeInstance && push!(workqueue, ci) end diff --git a/base/errorshow.jl b/base/errorshow.jl index 809ba29d96501..de315914c8b5c 100644 --- a/base/errorshow.jl +++ b/base/errorshow.jl @@ -588,8 +588,6 @@ function show_method_candidates(io::IO, ex::MethodError, kwargs=[]) end if ex.world < reinterpret(UInt, method.primary_world) print(iob, " (method too new to be called from this world context.)") - elseif ex.world > reinterpret(UInt, method.deleted_world) - print(iob, " (method deleted before this world age.)") end println(iob) diff --git a/base/staticdata.jl b/base/staticdata.jl index cb0888e9d56bb..0b65d97750194 100644 --- a/base/staticdata.jl +++ b/base/staticdata.jl @@ -288,6 +288,30 @@ 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 + 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 + let t = expecteds[i], meth, minworld, maxworld, result + if t isa Method + meth = t + else + if t isa CodeInstance + t = get_ci_mi(t) + else + t = t::MethodInstance + end + meth = t.def::Method + 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 + end + end + end + # next, compare the current result of ml_matches to the old result lim = _jl_debug_method_invalidation[] !== nothing ? Int(typemax(Int32)) : n minworld = Ref{UInt}(1) maxworld = Ref{UInt}(typemax(UInt)) @@ -340,24 +364,25 @@ function verify_call(@nospecialize(sig), expecteds::Core.SimpleVector, i::Int, n return minworld[], maxworld[], result end +# fast-path dispatch_status bit definitions (false indicates unknown) +# true indicates this method would be returned as the result from `which` when invoking `method.sig` in the current latest world +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 + function verify_invokesig(@nospecialize(invokesig), expected::Method, world::UInt) @assert invokesig isa Type local minworld::UInt, maxworld::UInt matched = nothing - if invokesig === expected.sig - # the invoke match is `expected` for `expected->sig`, unless `expected` is invalid - # TODO: this is broken since PR #53415 + if invokesig === expected.sig && !iszero(expected.dispatch_status & METHOD_SIG_LATEST_WHICH) + # the invoke match is `expected` for `expected->sig`, unless `expected` is replaced minworld = expected.primary_world - maxworld = expected.deleted_world @assert minworld ≤ world - if maxworld < world - maxworld = 0 - end - else - minworld = 1 maxworld = typemax(UInt) + else mt = get_methodtable(expected) if mt === nothing + minworld = 1 maxworld = 0 else matched, valid_worlds = Compiler._findsup(invokesig, mt, world) diff --git a/src/gf.c b/src/gf.c index f70fc08c8ec47..5e4d0395b6d62 100644 --- a/src/gf.c +++ b/src/gf.c @@ -304,7 +304,7 @@ jl_datatype_t *jl_mk_builtin_func(jl_datatype_t *dt, const char *name, jl_fptr_a m->isva = 1; m->nargs = 2; jl_atomic_store_relaxed(&m->primary_world, 1); - jl_atomic_store_relaxed(&m->deleted_world, ~(size_t)0); + jl_atomic_store_relaxed(&m->dispatch_status, METHOD_SIG_LATEST_ONLY | METHOD_SIG_LATEST_ONLY); m->sig = (jl_value_t*)jl_anytuple_type; m->slot_syms = jl_an_empty_string; m->nospecialize = 0; @@ -315,7 +315,7 @@ jl_datatype_t *jl_mk_builtin_func(jl_datatype_t *dt, const char *name, jl_fptr_a JL_GC_PUSH2(&m, &newentry); newentry = jl_typemap_alloc(jl_anytuple_type, NULL, jl_emptysvec, - (jl_value_t*)m, jl_atomic_load_relaxed(&m->primary_world), jl_atomic_load_relaxed(&m->deleted_world)); + (jl_value_t*)m, 1, ~(size_t)0); jl_typemap_insert(&mt->defs, (jl_value_t*)mt, newentry, jl_cachearg_offset(mt)); jl_method_instance_t *mi = jl_get_specialized(m, (jl_value_t*)jl_anytuple_type, jl_emptysvec); @@ -1917,7 +1917,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 == morespec_is && !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; } @@ -2251,17 +2251,22 @@ JL_DLLEXPORT void jl_method_table_disable(jl_methtable_t *mt, jl_method_t *metho 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."); - JL_LOCK(&mt->writelock); - // 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); - assert(jl_atomic_load_relaxed(&method->deleted_world) == ~(size_t)0); - jl_atomic_store_relaxed(&method->deleted_world, world); - jl_atomic_store_relaxed(&methodentry->max_world, world); - jl_method_table_invalidate(mt, method, world); - jl_atomic_store_release(&jl_world_counter, world + 1); - JL_UNLOCK(&mt->writelock); + 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 + 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_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) @@ -2301,9 +2306,9 @@ jl_typemap_entry_t *jl_method_table_add(jl_methtable_t *mt, jl_method_t *method, 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->deleted_world) == 1); // max-world - newentry = jl_typemap_alloc((jl_tupletype_t*)method->sig, simpletype, jl_emptysvec, (jl_value_t*)method, - jl_atomic_load_relaxed(&method->primary_world), jl_atomic_load_relaxed(&method->deleted_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); + 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); @@ -2324,7 +2329,8 @@ void jl_method_table_activate(jl_methtable_t *mt, jl_typemap_entry_t *newentry) 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->deleted_world) == ~(size_t)0); // max-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); assert(jl_atomic_load_relaxed(&newentry->min_world) == ~(size_t)0); assert(jl_atomic_load_relaxed(&newentry->max_world) == 1); jl_atomic_store_relaxed(&newentry->min_world, world); @@ -2339,12 +2345,17 @@ void jl_method_table_activate(jl_methtable_t *mt, jl_typemap_entry_t *newentry) // then check what entries we replaced oldvalue = get_intersect_matches(jl_atomic_load_relaxed(&mt->defs), newentry, &replaced, jl_cachearg_offset(mt), 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) { oldvalue = (jl_value_t*)replaced; + jl_method_t *m = replaced->func.method; invalidated = 1; - method_overwrite(newentry, replaced->func.method); + method_overwrite(newentry, m); // this is an optimized version of below, given we know the type-intersection is exact - jl_method_table_invalidate(mt, replaced->func.method, max_world); + jl_method_table_invalidate(mt, 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; } else { jl_method_t *const *d; @@ -2416,8 +2427,10 @@ void jl_method_table_activate(jl_methtable_t *mt, jl_typemap_entry_t *newentry) memset(morespec, morespec_unknown, n); for (j = 0; j < n; j++) { jl_method_t *m = d[j]; - if (morespec[j] == (char)morespec_is) + if (morespec[j] == (char)morespec_is) { + only = 0; continue; + } loctag = jl_atomic_load_relaxed(&m->specializations); // use loctag for a gcroot _Atomic(jl_method_instance_t*) *data; size_t l; @@ -2447,7 +2460,7 @@ void jl_method_table_activate(jl_methtable_t *mt, jl_typemap_entry_t *newentry) // not actually shadowing--the existing method is still better break; if (ambig == morespec_unknown) - ambig = jl_type_morespecific(type, m->sig) ? morespec_is : morespec_isnot; + 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); @@ -2464,6 +2477,20 @@ void jl_method_table_activate(jl_methtable_t *mt, 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; + } + } } if (jl_array_nrows(oldmi)) { // search mt->cache and leafcache and drop anything that might overlap with the new method @@ -2494,7 +2521,8 @@ void jl_method_table_activate(jl_methtable_t *mt, jl_typemap_entry_t *newentry) loctag = jl_cstr_to_string("jl_method_table_insert"); jl_array_ptr_1d_push(_jl_debug_method_invalidation, loctag); } - jl_atomic_store_relaxed(&newentry->max_world, jl_atomic_load_relaxed(&method->deleted_world)); + 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(); } @@ -2508,7 +2536,6 @@ 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_atomic_store_relaxed(&method->deleted_world, ~(size_t)0); jl_method_table_activate(mt, newentry); jl_atomic_store_release(&jl_world_counter, world); JL_UNLOCK(&world_counter_lock); @@ -3906,6 +3933,8 @@ static int ml_matches_visitor(jl_typemap_entry_t *ml, struct typemap_intersectio closure->match.min_valid = max_world + 1; return 1; } + if (closure->match.max_valid > max_world) + closure->match.max_valid = max_world; jl_method_t *meth = ml->func.method; if (closure->lim >= 0 && jl_is_dispatch_tupletype(meth->sig)) { int replaced = 0; @@ -4578,12 +4607,9 @@ static jl_value_t *ml_matches(jl_methtable_t *mt, jl_method_t *m = matc->method; // method applicability is the same as typemapentry applicability size_t min_world = jl_atomic_load_relaxed(&m->primary_world); - size_t max_world = jl_atomic_load_relaxed(&m->deleted_world); // intersect the env valid range with method lookup's inclusive valid range if (env.match.min_valid < min_world) env.match.min_valid = min_world; - if (env.match.max_valid > max_world) - env.match.max_valid = max_world; } if (mt && cache_result && ((jl_datatype_t*)unw)->isdispatchtuple) { // cache_result parameter keeps this from being recursive if (len == 1 && !has_ambiguity) { diff --git a/src/jltypes.c b/src/jltypes.c index 0a14832b8ae6b..52e707b618211 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -3545,8 +3545,8 @@ void jl_init_types(void) JL_GC_DISABLED "module", "file", "line", + "dispatch_status", // atomic "primary_world", // atomic - "deleted_world", // atomic "sig", "specializations", // !const "speckeyset", // !const @@ -3578,7 +3578,7 @@ void jl_init_types(void) JL_GC_DISABLED jl_module_type, jl_symbol_type, jl_int32_type, - jl_ulong_type, + jl_int32_type, jl_ulong_type, jl_type_type, jl_any_type, // union(jl_simplevector_type, jl_method_instance_type), diff --git a/src/julia.h b/src/julia.h index a3fcc516997df..e4ad2448c4356 100644 --- a/src/julia.h +++ b/src/julia.h @@ -331,8 +331,8 @@ 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(size_t) primary_world; - _Atomic(size_t) deleted_world; // method's type signature. redundant with TypeMapEntry->specTypes jl_value_t *sig; diff --git a/src/julia_internal.h b/src/julia_internal.h index 46d6404edc86f..bf37716c1e3ae 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -674,6 +674,10 @@ typedef union { #define SOURCE_MODE_NOT_REQUIRED 0x0 #define SOURCE_MODE_ABI 0x1 +#define METHOD_SIG_LATEST_WHICH 0b0001 +#define METHOD_SIG_LATEST_ONLY 0b0010 +#define METHOD_SIG_PRECOMPILE_MANY 0b0100 + 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); void jl_engine_sweep(jl_ptls_t *gc_all_tls_states) JL_NOTSAFEPOINT; diff --git a/src/method.c b/src/method.c index b3ed63e810f77..1f195a5eef979 100644 --- a/src/method.c +++ b/src/method.c @@ -728,7 +728,7 @@ JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *mi, size_t JL_TRY { ct->ptls->in_pure_callback = 1; ct->world_age = jl_atomic_load_relaxed(&def->primary_world); - if (ct->world_age > jl_atomic_load_acquire(&jl_world_counter) || jl_atomic_load_relaxed(&def->deleted_world) < ct->world_age) + if (ct->world_age > jl_atomic_load_acquire(&jl_world_counter)) jl_error("The generator method cannot run until it is added to a method table."); // invoke code generator @@ -1007,7 +1007,7 @@ JL_DLLEXPORT jl_method_t *jl_new_method_uninit(jl_module_t *module) m->isva = 0; m->nargs = 0; jl_atomic_store_relaxed(&m->primary_world, ~(size_t)0); - jl_atomic_store_relaxed(&m->deleted_world, 1); + jl_atomic_store_relaxed(&m->dispatch_status, 0); m->is_for_opaque_closure = 0; m->nospecializeinfer = 0; jl_atomic_store_relaxed(&m->did_scan_source, 0); diff --git a/src/opaque_closure.c b/src/opaque_closure.c index a10b5c617753c..2e39d5965b45a 100644 --- a/src/opaque_closure.c +++ b/src/opaque_closure.c @@ -159,7 +159,6 @@ JL_DLLEXPORT jl_opaque_closure_t *jl_new_opaque_closure_from_code_info(jl_tuplet size_t world = jl_current_task->world_age; // these are only legal in the current world since they are not in any tables jl_atomic_store_release(&meth->primary_world, world); - jl_atomic_store_release(&meth->deleted_world, world); if (isinferred) { jl_value_t *argslotty = jl_array_ptr_ref(ci->slottypes, 0); diff --git a/src/precompile_utils.c b/src/precompile_utils.c index 84619b714b624..295f91ad31e67 100644 --- a/src/precompile_utils.c +++ b/src/precompile_utils.c @@ -416,20 +416,21 @@ static void jl_rebuild_methtables(arraylist_t* MIs, htable_t* mtables) ptrhash_put(mtables, old_mt, jl_new_method_table(name, m->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); + 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 = jl_atomic_load_relaxed(&m->deleted_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->deleted_world, 1); + 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->deleted_world, max_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); + jl_atomic_store_relaxed(&newentry->max_world, max_world); // short-circuit jl_method_table_insert } } - } diff --git a/src/staticdata.c b/src/staticdata.c index 4704b6527ec30..eac3bba62f01a 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -1833,16 +1833,11 @@ static void jl_write_values(jl_serializer_state *s) JL_GC_DISABLED jl_method_t *m = (jl_method_t*)v; jl_method_t *newm = (jl_method_t*)&f->buf[reloc_offset]; if (s->incremental) { - if (jl_atomic_load_relaxed(&newm->deleted_world) == ~(size_t)0) { - if (jl_atomic_load_relaxed(&newm->primary_world) > 1) { - jl_atomic_store_relaxed(&newm->primary_world, ~(size_t)0); // min-world - jl_atomic_store_relaxed(&newm->deleted_world, 1); // max_world - arraylist_push(&s->fixup_objs, (void*)reloc_offset); - } - } - else { - jl_atomic_store_relaxed(&newm->primary_world, 1); - jl_atomic_store_relaxed(&newm->deleted_world, 0); + 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); + arraylist_push(&s->fixup_objs, (void*)reloc_offset); } } else { diff --git a/src/staticdata_utils.c b/src/staticdata_utils.c index c3f6a7e98a550..65f7dc59d9397 100644 --- a/src/staticdata_utils.c +++ b/src/staticdata_utils.c @@ -706,9 +706,7 @@ static void jl_activate_methods(jl_array_t *external, jl_array_t *internal, size else if (jl_is_method(obj)) { jl_method_t *m = (jl_method_t*)obj; assert(jl_atomic_load_relaxed(&m->primary_world) == ~(size_t)0); - assert(jl_atomic_load_relaxed(&m->deleted_world) == WORLD_AGE_REVALIDATION_SENTINEL); jl_atomic_store_release(&m->primary_world, world); - jl_atomic_store_release(&m->deleted_world, ~(size_t)0); } else if (jl_is_code_instance(obj)) { jl_code_instance_t *ci = (jl_code_instance_t*)obj; diff --git a/src/typemap.c b/src/typemap.c index 6ee8f9c599f3a..8c0e585601944 100644 --- a/src/typemap.c +++ b/src/typemap.c @@ -569,10 +569,8 @@ int has_covariant_var(jl_datatype_t *ttypes, jl_tvar_t *tv) void typemap_slurp_search(jl_typemap_entry_t *ml, struct typemap_intersection_env *closure) { - // n.b. we could consider mt->max_args here too, so this optimization - // usually works even if the user forgets the `slurp...` argument, but - // there is discussion that parameter may be going away? (and it is - // already not accurately up-to-date for all tables currently anyways) + // TODO: we should consider nparams(closure->type) here too, so this optimization + // usually works even if the user forgets the `slurp...` argument if (closure->search_slurp && ml->va) { jl_value_t *sig = jl_unwrap_unionall((jl_value_t*)ml->sig); size_t nargs = jl_nparams(sig); diff --git a/test/core.jl b/test/core.jl index 5c2950c83b2d3..c6ca43bd0079b 100644 --- a/test/core.jl +++ b/test/core.jl @@ -35,7 +35,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, :deleted_world]), + (Core.Method, [:primary_world, :dispatch_status]), (Core.MethodInstance, [:cache, :flags]), (Core.MethodTable, [:defs, :leafcache, :cache, :max_args]), (Core.TypeMapEntry, [:next, :min_world, :max_world]), diff --git a/test/worlds.jl b/test/worlds.jl index dd98170721b1a..0ac54c3192b24 100644 --- a/test/worlds.jl +++ b/test/worlds.jl @@ -502,6 +502,8 @@ Base.delete_method(fshadow_m2) @test Base.morespecific(fshadow_m3, fshadow_m1) @test !Base.morespecific(fshadow_m2, fshadow_m3) +@test_throws "Method of fshadow already disabled" Base.delete_method(fshadow_m2) + # Generated functions without edges must have min_world = 1. # N.B.: If changing this, move this test to precompile and make sure # that the specialization survives revalidation. From a8270829beb2d038312698d7fe6b6dd57bc8ad3f Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Wed, 7 May 2025 16:52:23 -0400 Subject: [PATCH 03/46] extend Method.dispatch_status optimization to ml_matches_visitor also (#58335) This extends the use of the optimization in #58291 to also apply to some uses of ml_matches also. (cherry picked from commit d1ec7d57000604c9335531197798f2267d511021) --- src/gf.c | 55 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/src/gf.c b/src/gf.c index 5e4d0395b6d62..f1deffc954b41 100644 --- a/src/gf.c +++ b/src/gf.c @@ -1691,7 +1691,6 @@ static int get_intersect_visitor(jl_typemap_entry_t *oldentry, struct typemap_in assert(jl_atomic_load_relaxed(&oldentry->min_world) <= jl_atomic_load_relaxed(&closure->newentry->min_world) && "old method cannot be newer than new method"); assert(jl_atomic_load_relaxed(&oldentry->max_world) != jl_atomic_load_relaxed(&closure->newentry->min_world) && "method cannot be added at the same time as method deleted"); // don't need to consider other similar methods if this oldentry will always fully intersect with them and dominates all of them - typemap_slurp_search(oldentry, &closure->match); jl_method_t *oldmethod = oldentry->func.method; if (closure->match.issubty // e.g. jl_subtype(closure->newentry.sig, oldentry->sig) && jl_subtype(oldmethod->sig, (jl_value_t*)closure->newentry->sig)) { // e.g. jl_type_equal(closure->newentry->sig, oldentry->sig) @@ -1700,7 +1699,18 @@ static int get_intersect_visitor(jl_typemap_entry_t *oldentry, struct typemap_in } if (closure->shadowed == NULL) closure->shadowed = (jl_value_t*)jl_alloc_vec_any(0); + if (closure->match.issubty) { // this should be rarely true (in fact, get_intersect_visitor should be rarely true), but might as well skip the rest of the scan fast anyways since we can + int only = jl_atomic_load_relaxed(&oldmethod->dispatch_status) & METHOD_SIG_LATEST_ONLY; + if (only) { + size_t len = jl_array_nrows(closure->shadowed); + if (len > 0) + jl_array_del_end((jl_array_t*)closure->shadowed, len); + jl_array_ptr_1d_push((jl_array_t*)closure->shadowed, (jl_value_t*)oldmethod); + return 0; + } + } jl_array_ptr_1d_push((jl_array_t*)closure->shadowed, (jl_value_t*)oldmethod); + typemap_slurp_search(oldentry, &closure->match); return 1; } @@ -3936,30 +3946,26 @@ static int ml_matches_visitor(jl_typemap_entry_t *ml, struct typemap_intersectio if (closure->match.max_valid > max_world) closure->match.max_valid = max_world; jl_method_t *meth = ml->func.method; - if (closure->lim >= 0 && jl_is_dispatch_tupletype(meth->sig)) { - int replaced = 0; - // check if this is replaced, in which case we need to avoid double-counting it against the limit - // (although it will figure out later which one to keep and return) - size_t len = jl_array_nrows(closure->t); - for (int i = 0; i < len; i++) { - if (jl_types_equal(((jl_method_match_t*)jl_array_ptr_ref(closure->t, i))->method->sig, meth->sig)) { - replaced = 1; - break; - } - } - if (!replaced) { - if (closure->lim == 0) - return 0; - closure->lim--; + int only = jl_atomic_load_relaxed(&meth->dispatch_status) & METHOD_SIG_LATEST_ONLY; + if (closure->lim >= 0 && only) { + if (closure->lim == 0) { + closure->t = jl_an_empty_vec_any; + return 0; } + closure->lim--; } - // don't need to consider other similar methods if this ml will always fully intersect with them and dominates all of them - if (!closure->include_ambiguous || closure->lim != -1) - typemap_slurp_search(ml, &closure->match); closure->matc = make_method_match((jl_tupletype_t*)closure->match.ti, closure->match.env, meth, closure->match.issubty ? FULLY_COVERS : NOT_FULLY_COVERS); size_t len = jl_array_nrows(closure->t); + if (closure->match.issubty && only) { + if (len == 0) + closure->t = (jl_value_t*)jl_alloc_vec_any(1); + else if (len > 1) + jl_array_del_end((jl_array_t*)closure->t, len - 1); + jl_array_ptr_set(closure->t, 0, (jl_value_t*)closure->matc); + return 0; + } if (len == 0) { closure->t = (jl_value_t*)jl_alloc_vec_any(1); jl_array_ptr_set(closure->t, 0, (jl_value_t*)closure->matc); @@ -3967,6 +3973,9 @@ static int ml_matches_visitor(jl_typemap_entry_t *ml, struct typemap_intersectio else { jl_array_ptr_1d_push((jl_array_t*)closure->t, (jl_value_t*)closure->matc); } + // don't need to consider other similar methods if this ml will always fully intersect with them and dominates all of them + if (!closure->include_ambiguous || closure->lim != -1) + typemap_slurp_search(ml, &closure->match); return 1; } @@ -4347,9 +4356,9 @@ static jl_value_t *ml_matches(jl_methtable_t *mt, return env.t; } } - if (!ml_mtable_visitor(mt, &env.match)) { + if (!ml_mtable_visitor(mt, &env.match) && env.t == jl_an_empty_vec_any) { JL_GC_POP(); - // if we return early, set only the min/max valid collected from matching + // 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; @@ -4357,9 +4366,9 @@ static jl_value_t *ml_matches(jl_methtable_t *mt, } else { // else: scan everything - if (!jl_foreach_reachable_mtable(ml_mtable_visitor, &env.match)) { + if (!jl_foreach_reachable_mtable(ml_mtable_visitor, &env.match) && env.t == jl_an_empty_vec_any) { JL_GC_POP(); - // if we return early, set only the min/max valid collected from matching + // 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; From 996ce67b1805025dc66c38731b54a7b4d205f762 Mon Sep 17 00:00:00 2001 From: GHTaarn <62629455+GHTaarn@users.noreply.github.com> Date: Thu, 8 May 2025 02:28:37 +0200 Subject: [PATCH 04/46] Base.get_extension & Dates.format made public (#58108) `Base.get_extension` and `Dates.format` both appear in the manual and should therefore be `public` symbols according to [51335](https://github.com/JuliaLang/julia/issues/51335#issuecomment-1743091402). They appear in the manual [here](https://docs.julialang.org/en/v1/base/base/#Base.get_extension) and [here](https://docs.julialang.org/en/v1/stdlib/Dates/#Dates.format-Tuple%7BTimeType,%20AbstractString%7D). Please also consider back porting this to version 1.12 (cherry picked from commit 963eaa744c211e5a5500c860f6fc745a3cf6c098) --- base/public.jl | 1 + stdlib/Dates/src/Dates.jl | 2 ++ 2 files changed, 3 insertions(+) diff --git a/base/public.jl b/base/public.jl index 8d2a65f9a150c..4960a08e1ad0b 100644 --- a/base/public.jl +++ b/base/public.jl @@ -52,6 +52,7 @@ public active_project, # Reflection and introspection + get_extension, isambiguous, isexpr, isidentifier, diff --git a/stdlib/Dates/src/Dates.jl b/stdlib/Dates/src/Dates.jl index a4600a5f82043..0e6d0d0ef6986 100644 --- a/stdlib/Dates/src/Dates.jl +++ b/stdlib/Dates/src/Dates.jl @@ -81,4 +81,6 @@ export Period, DatePeriod, TimePeriod, # io.jl ISODateTimeFormat, ISODateFormat, ISOTimeFormat, DateFormat, RFC1123Format, @dateformat_str +public format + end # module From e83cb43804c319b9a5c5e450c45c23772c94a0ff Mon Sep 17 00:00:00 2001 From: Gabriel Baraldi Date: Thu, 8 May 2025 15:27:52 -0300 Subject: [PATCH 05/46] Fix late gc lowering pass for vector intrinsics (#55864) Fixes #55844 (cherry picked from commit 9986d97b879f77941f32f39be6fe785c2acd9c95) --- src/llvm-late-gc-lowering.cpp | 50 +++++++++++++++++++++++++++++--- test/llvmpasses/image-codegen.jl | 2 +- test/llvmpasses/late-lower-gc.ll | 15 ++++++++++ 3 files changed, 62 insertions(+), 5 deletions(-) diff --git a/src/llvm-late-gc-lowering.cpp b/src/llvm-late-gc-lowering.cpp index aef5524c2c4c3..46214666c5d36 100644 --- a/src/llvm-late-gc-lowering.cpp +++ b/src/llvm-late-gc-lowering.cpp @@ -1,6 +1,8 @@ // This file is a part of Julia. License is MIT: https://julialang.org/license #include "llvm-gc-interface-passes.h" +#include "llvm/IR/Intrinsics.h" +#include "llvm/Support/Casting.h" #define DEBUG_TYPE "late_lower_gcroot" @@ -171,12 +173,12 @@ static std::pair FindBaseValue(const State &S, Value *V, bool UseCac (void)LI; break; } - else if (auto II = dyn_cast(CurrentV)) { - // Some intrinsics behave like LoadInst followed by a SelectInst - // This should never happen in a derived addrspace (since those cannot be stored to memory) - // so we don't need to lift these operations, but we do need to check if it's loaded and continue walking the base pointer + else if (auto *II = dyn_cast(CurrentV)) { if (II->getIntrinsicID() == Intrinsic::masked_load || II->getIntrinsicID() == Intrinsic::masked_gather) { + // Some intrinsics behave like LoadInst followed by a SelectInst + // This should never happen in a derived addrspace (since those cannot be stored to memory) + // so we don't need to lift these operations, but we do need to check if it's loaded and continue walking the base pointer if (auto VTy = dyn_cast(II->getType())) { if (hasLoadedTy(VTy->getElementType())) { Value *Mask = II->getOperand(2); @@ -205,6 +207,24 @@ static std::pair FindBaseValue(const State &S, Value *V, bool UseCac // In general a load terminates a walk break; } + else if (II->getIntrinsicID() == Intrinsic::vector_extract) { + if (auto VTy = dyn_cast(II->getType())) { + if (hasLoadedTy(VTy->getElementType())) { + Value *Idx = II->getOperand(1); + if (!isa(Idx)) { + assert(isa(Idx) && "unimplemented"); + (void)Idx; + } + CurrentV = II->getOperand(0); + fld_idx = -1; + continue; + } + } + break; + } else { + // Unknown Intrinsic + break; + } } else if (auto CI = dyn_cast(CurrentV)) { auto callee = CI->getCalledFunction(); @@ -212,9 +232,11 @@ static std::pair FindBaseValue(const State &S, Value *V, bool UseCac CurrentV = CI->getArgOperand(0); continue; } + // Unknown Call break; } else { + // Unknown Instruction break; } } @@ -518,6 +540,22 @@ SmallVector LateLowerGCFrame::NumberAllBase(State &S, Value *CurrentV) { Numbers = NumberAll(S, IEI->getOperand(0)); int ElNumber = Number(S, IEI->getOperand(1)); Numbers[idx] = ElNumber; + // C++17 + // } else if (auto *II = dyn_cast(CurrentV); II && II->getIntrinsicID() == Intrinsic::vector_insert) { + } else if (isa(CurrentV) && cast(CurrentV)->getIntrinsicID() == Intrinsic::vector_insert) { + auto *II = dyn_cast(CurrentV); + // Vector insert is a bit like a shuffle so use the same approach + SmallVector Numbers1 = NumberAll(S, II->getOperand(0)); + SmallVector Numbers2 = NumberAll(S, II->getOperand(1)); + unsigned first_idx = cast(II->getOperand(2))->getZExtValue(); + for (unsigned i = 0; i < Numbers1.size(); ++i) { + if (i < first_idx) + Numbers.push_back(Numbers1[i]); + else if (i - first_idx < Numbers2.size()) + Numbers.push_back(Numbers2[i - first_idx]); + else + Numbers.push_back(Numbers1[i]); + } } else if (auto *IVI = dyn_cast(CurrentV)) { Numbers = NumberAll(S, IVI->getAggregateOperand()); auto Tracked = TrackCompositeType(IVI->getType()); @@ -1150,6 +1188,10 @@ State LateLowerGCFrame::LocalScan(Function &F) { } } } + if (II->getIntrinsicID() == Intrinsic::vector_extract || II->getIntrinsicID() == Intrinsic::vector_insert) { + // These are not real defs + continue; + } } auto callee = CI->getCalledFunction(); if (callee && callee == typeof_func) { diff --git a/test/llvmpasses/image-codegen.jl b/test/llvmpasses/image-codegen.jl index 2e52245b7d3b9..b174680629eb4 100644 --- a/test/llvmpasses/image-codegen.jl +++ b/test/llvmpasses/image-codegen.jl @@ -2,7 +2,7 @@ # RUN: export JULIA_LLVM_ARGS="--print-before=loop-vectorize --print-module-scope" # RUN: rm -rf %t # RUN: mkdir %t -# RUN: julia --image-codegen --startup-file=no %s 2> %t/output.txt +# RUN: julia --image-codegen -t1,0 --startup-file=no %s 2> %t/output.txt # RUN: FileCheck %s < %t/output.txt # COM: checks that global variables compiled in imaging codegen diff --git a/test/llvmpasses/late-lower-gc.ll b/test/llvmpasses/late-lower-gc.ll index 81a1df61d3bd9..bdb10e97093b2 100644 --- a/test/llvmpasses/late-lower-gc.ll +++ b/test/llvmpasses/late-lower-gc.ll @@ -164,6 +164,21 @@ define {} addrspace(10)* @gclift_switch({} addrspace(13)* addrspace(10)* %input, ret {} addrspace(10)* %ret } +; Shouldn't hang +define void @vector_insert(<4 x {} addrspace(10)* > %0, <2 x {} addrspace(10)* > %1) { +top: + %pgcstack = call {}*** @julia.get_pgcstack() + %2 = call <4 x {} addrspace(10)*> @llvm.vector.insert.v4p10.v2p10(<4 x {} addrspace(10)*> %0, <2 x {} addrspace(10)*> %1, i64 2) + ret void +} + +define void @vector_extract(<4 x {} addrspace(10)* > %0, <2 x {} addrspace(10)* > %1) { +top: + %pgcstack = call {}*** @julia.get_pgcstack() + %2 = call <2 x {} addrspace(10)*> @llvm.vector.extract.v2p10.v4p10(<4 x {} addrspace(10)* > %0, i64 2) + ret void +} + define void @decayar([2 x {} addrspace(10)* addrspace(11)*] %ar) { %v2 = call {}*** @julia.get_pgcstack() %e0 = extractvalue [2 x {} addrspace(10)* addrspace(11)*] %ar, 0 From 69fef33a0ee7e8a702cdaba1c09e8280e383d1b0 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Fri, 9 May 2025 15:05:33 -0400 Subject: [PATCH 06/46] codegen: remove readonly from abstract type calling convention (#58356) Refs: #58070 (cherry picked from commit f07565fc65f3a0339d0fedbb2fbc2801d6cc853c) --- Compiler/test/codegen.jl | 4 ++++ src/cgutils.cpp | 2 +- src/codegen.cpp | 39 ++++++++++++++++++++++----------------- src/julia.h | 2 +- 4 files changed, 28 insertions(+), 19 deletions(-) diff --git a/Compiler/test/codegen.jl b/Compiler/test/codegen.jl index fd8bbae70a346..8f5a47c5efa62 100644 --- a/Compiler/test/codegen.jl +++ b/Compiler/test/codegen.jl @@ -1032,3 +1032,7 @@ end const x57872 = "Hello" f57872() = (Core.isdefinedglobal(@__MODULE__, Base.compilerbarrier(:const, :x57872)), x57872) # Extra globalref here to force world age bounds @test f57872() == (true, "Hello") + +@noinline f_mutateany(@nospecialize x) = x[] = 1 +g_mutateany() = (y = Ref(0); f_mutateany(y); y[]) +@test g_mutateany() === 1 diff --git a/src/cgutils.cpp b/src/cgutils.cpp index 9e70b2f3e6679..f3425d058841a 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -1479,6 +1479,7 @@ static Value *emit_sizeof(jl_codectx_t &ctx, const jl_cgval_t &p) return dyn_size; } } +*/ static Value *emit_datatype_mutabl(jl_codectx_t &ctx, Value *dt) { @@ -1493,7 +1494,6 @@ static Value *emit_datatype_mutabl(jl_codectx_t &ctx, Value *dt) mutabl = ctx.builder.CreateLShr(mutabl, 1); return ctx.builder.CreateTrunc(mutabl, getInt1Ty(ctx.builder.getContext())); } -*/ static Value *emit_datatype_isprimitivetype(jl_codectx_t &ctx, Value *typ) { diff --git a/src/codegen.cpp b/src/codegen.cpp index 24d30e0ba8eb3..ec1685d9ad7c8 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1657,7 +1657,7 @@ static MDNode *best_tbaa(jl_tbaacache_t &tbaa_cache, jl_value_t *jt) { // note that this includes jl_isbits, although codegen should work regardless static bool jl_is_concrete_immutable(jl_value_t* t) { - return jl_is_immutable_datatype(t) && ((jl_datatype_t*)t)->isconcretetype; + return jl_may_be_immutable_datatype(t) && ((jl_datatype_t*)t)->isconcretetype; } static bool jl_is_pointerfree(jl_value_t* t) @@ -7355,8 +7355,8 @@ static Function *gen_cfun_wrapper( inputarg = mark_julia_type(ctx, val, false, jargty); } } - else if (static_at || (!jl_is_typevar(jargty) && !jl_is_immutable_datatype(jargty))) { - // must be a jl_value_t* (because it's mutable or contains gc roots) + else if (static_at || (!jl_is_typevar(jargty) && (!jl_is_datatype(jargty) || jl_is_abstracttype(jargty) || jl_is_mutable_datatype(jargty)))) { + // must be a jl_value_t* (because it is mutable or abstract) inputarg = mark_julia_type(ctx, maybe_decay_untracked(ctx, val), true, jargty_proper); } else { @@ -7370,31 +7370,36 @@ static Function *gen_cfun_wrapper( emit_ptrgep(ctx, nestPtr, jl_array_nrows(*closure_types) * ctx.types().sizeof_ptr), Align(sizeof(void*))); BasicBlock *boxedBB = BasicBlock::Create(ctx.builder.getContext(), "isboxed", cw); - BasicBlock *loadBB = BasicBlock::Create(ctx.builder.getContext(), "need-load", cw); + BasicBlock *notanyBB = BasicBlock::Create(ctx.builder.getContext(), "not-any", cw); BasicBlock *unboxedBB = BasicBlock::Create(ctx.builder.getContext(), "maybe-unboxed", cw); BasicBlock *isanyBB = BasicBlock::Create(ctx.builder.getContext(), "any", cw); BasicBlock *afterBB = BasicBlock::Create(ctx.builder.getContext(), "after", cw); - Value *isrtboxed = ctx.builder.CreateIsNull(val); // XXX: this is the wrong condition and should be inspecting runtime_dt instead - ctx.builder.CreateCondBr(isrtboxed, boxedBB, loadBB); - ctx.builder.SetInsertPoint(boxedBB); - Value *p1 = val; - p1 = track_pjlvalue(ctx, p1); - ctx.builder.CreateBr(afterBB); - ctx.builder.SetInsertPoint(loadBB); Value *isrtany = ctx.builder.CreateICmpEQ( - literal_pointer_val(ctx, (jl_value_t*)jl_any_type), val); - ctx.builder.CreateCondBr(isrtany, isanyBB, unboxedBB); + track_pjlvalue(ctx,literal_pointer_val(ctx, (jl_value_t*)jl_any_type)), runtime_dt); + ctx.builder.CreateCondBr(isrtany, isanyBB, notanyBB); ctx.builder.SetInsertPoint(isanyBB); - Value *p2 = ctx.builder.CreateAlignedLoad(ctx.types().T_prjlvalue, val, Align(sizeof(void*))); + Value *p1 = ctx.builder.CreateAlignedLoad(ctx.types().T_prjlvalue, val, Align(sizeof(void*))); + ctx.builder.CreateBr(afterBB); + isanyBB = ctx.builder.GetInsertBlock(); // could have changed + ctx.builder.SetInsertPoint(notanyBB); + jl_cgval_t runtime_dt_val = mark_julia_type(ctx, runtime_dt, true, jl_any_type); + Value *isrtboxed = // (!jl_is_datatype(runtime_dt) || !jl_is_concrete_datatype(runtime_dt) || jl_is_mutable_datatype(runtime_dt)) + emit_guarded_test(ctx, emit_exactly_isa(ctx, runtime_dt_val, jl_datatype_type), true, [&] { + return ctx.builder.CreateOr(ctx.builder.CreateNot(emit_isconcrete(ctx, runtime_dt)), emit_datatype_mutabl(ctx, runtime_dt)); + }); + ctx.builder.CreateCondBr(isrtboxed, boxedBB, unboxedBB); + ctx.builder.SetInsertPoint(boxedBB); + Value *p2 = track_pjlvalue(ctx, val); ctx.builder.CreateBr(afterBB); + boxedBB = ctx.builder.GetInsertBlock(); // could have changed ctx.builder.SetInsertPoint(unboxedBB); Value *p3 = emit_new_bits(ctx, runtime_dt, val); unboxedBB = ctx.builder.GetInsertBlock(); // could have changed ctx.builder.CreateBr(afterBB); ctx.builder.SetInsertPoint(afterBB); PHINode *p = ctx.builder.CreatePHI(ctx.types().T_prjlvalue, 3); - p->addIncoming(p1, boxedBB); - p->addIncoming(p2, isanyBB); + p->addIncoming(p1, isanyBB); + p->addIncoming(p2, boxedBB); p->addIncoming(p3, unboxedBB); inputarg = mark_julia_type(ctx, p, true, jargty_proper); } @@ -7939,7 +7944,7 @@ static jl_returninfo_t get_specsig_function(jl_codegen_params_t ¶ms, Module param.addAttribute(Attribute::ReadOnly); ty = PointerType::get(M->getContext(), AddressSpace::Derived); } - else if (isboxed && jl_is_immutable_datatype(jt)) { + else if (isboxed && jl_may_be_immutable_datatype(jt) && !jl_is_abstracttype(jt)) { param.addAttribute(Attribute::ReadOnly); } else if (jl_is_primitivetype(jt) && ty->isIntegerTy()) { diff --git a/src/julia.h b/src/julia.h index e4ad2448c4356..13348fa9b153d 100644 --- a/src/julia.h +++ b/src/julia.h @@ -1631,7 +1631,7 @@ static inline int jl_field_isconst(jl_datatype_t *st, int i) JL_NOTSAFEPOINT #define jl_is_mutable(t) (((jl_datatype_t*)t)->name->mutabl) #define jl_is_mutable_datatype(t) (jl_is_datatype(t) && (((jl_datatype_t*)t)->name->mutabl)) #define jl_is_immutable(t) (!((jl_datatype_t*)t)->name->mutabl) -#define jl_is_immutable_datatype(t) (jl_is_datatype(t) && (!((jl_datatype_t*)t)->name->mutabl)) +#define jl_may_be_immutable_datatype(t) (jl_is_datatype(t) && (!((jl_datatype_t*)t)->name->mutabl)) #define jl_is_uniontype(v) jl_typetagis(v,jl_uniontype_tag<<4) #define jl_is_typevar(v) jl_typetagis(v,jl_tvar_tag<<4) #define jl_is_unionall(v) jl_typetagis(v,jl_unionall_tag<<4) From 6728717a671f2b5d54e8062cdfd872a456408cb6 Mon Sep 17 00:00:00 2001 From: Gabriel Baraldi Date: Sat, 10 May 2025 16:57:45 -0300 Subject: [PATCH 07/46] Add set to temporary roots to avoid O(N) check (#57961) (cherry picked from commit d53422ceff19ad1381992292c520142564651b69) --- src/aotcompile.cpp | 1 + src/codegen.cpp | 7 +++---- src/jitlayers.cpp | 1 + src/jitlayers.h | 2 ++ 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/aotcompile.cpp b/src/aotcompile.cpp index e3c52e4796788..8c5d9e678a166 100644 --- a/src/aotcompile.cpp +++ b/src/aotcompile.cpp @@ -812,6 +812,7 @@ void *jl_emit_native_impl(jl_array_t *codeinfos, LLVMOrcThreadSafeModuleRef llvm generate_cfunc_thunks(params, compiled_functions); aot_optimize_roots(params, method_roots, compiled_functions); params.temporary_roots = nullptr; + params.temporary_roots_set.clear(); JL_GC_POP(); // process the globals array, before jl_merge_module destroys them diff --git a/src/codegen.cpp b/src/codegen.cpp index ec1685d9ad7c8..ee40596a82701 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3212,11 +3212,10 @@ static void jl_temporary_root(jl_codegen_params_t &ctx, jl_value_t *val) { if (!jl_is_globally_rooted(val)) { jl_array_t *roots = ctx.temporary_roots; - for (size_t i = 0; i < jl_array_dim0(roots); i++) { - if (jl_array_ptr_ref(roots, i) == val) - return; - } + if (ctx.temporary_roots_set.find(val) != ctx.temporary_roots_set.end()) + return; jl_array_ptr_1d_push(roots, val); + ctx.temporary_roots_set.insert(val); } } static void jl_temporary_root(jl_codectx_t &ctx, jl_value_t *val) diff --git a/src/jitlayers.cpp b/src/jitlayers.cpp index 4537d069e4a44..2e2756dec35f1 100644 --- a/src/jitlayers.cpp +++ b/src/jitlayers.cpp @@ -765,6 +765,7 @@ void jl_emit_codeinst_to_jit_impl( } jl_optimize_roots(params, jl_get_ci_mi(codeinst), *result_m.getModuleUnlocked()); // contains safepoints params.temporary_roots = nullptr; + params.temporary_roots_set.clear(); JL_GC_POP(); { // drop lock before acquiring engine_lock auto release = std::move(params.tsctx_lock); diff --git a/src/jitlayers.h b/src/jitlayers.h index b411febd792b8..88b03fe3ceaa9 100644 --- a/src/jitlayers.h +++ b/src/jitlayers.h @@ -1,5 +1,6 @@ // This file is a part of Julia. License is MIT: https://julialang.org/license +#include "llvm/ADT/SmallSet.h" #include #include #include @@ -240,6 +241,7 @@ struct jl_codegen_params_t { SmallVector cfuncs; std::map global_targets; jl_array_t *temporary_roots = nullptr; + SmallSet temporary_roots_set; std::map, GlobalVariable*> external_fns; std::map ditypes; std::map llvmtypes; From aa0e223d2f7467a6352738aec7a03004120f7252 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Sat, 10 May 2025 18:27:55 -0400 Subject: [PATCH 08/46] fix called-argument analysis for calls with splat (#58070) (cherry picked from commit bbb058295a6ed57dd33b6e35be18dbdfb7447ac4) --- src/julia-syntax.scm | 5 +++++ test/syntax.jl | 2 ++ 2 files changed, 7 insertions(+) diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 3c003b04e4ce4..16120c3696b99 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -3461,6 +3461,11 @@ (let ((vi (get tab (cadr e) #f))) (if vi (vinfo:set-called! vi #t)) + ;; calls f(x...) go through `_apply_iterate` + (if (and (length> e 3) (equal? (cadr e) '(core _apply_iterate))) + (let ((vi2 (get tab (cadddr e) #f))) + (if vi2 + (vinfo:set-called! vi2 #t)))) ;; calls to functions with keyword args have head of `kwcall` first (if (and (length> e 3) (equal? (cadr e) '(core kwcall))) (let ((vi2 (get tab (cadddr e) #f))) diff --git a/test/syntax.jl b/test/syntax.jl index b53a3b4357dc4..08472fce7a803 100644 --- a/test/syntax.jl +++ b/test/syntax.jl @@ -3514,6 +3514,8 @@ end # issue #45162 f45162(f) = f(x=1) @test first(methods(f45162)).called != 0 +f45162_2(f) = f([]...) +@test first(methods(f45162_2)).called != 0 # issue #45024 @test_parseerror "const x" "expected assignment after \"const\"" From e26756d4885cfc0c205d88f699732ce9efc64cfe Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Tue, 13 May 2025 12:42:05 +0200 Subject: [PATCH 09/46] Use a nonzero initial size with llvm::SmallSet. (cherry picked from commit f1a87b6301c127b2808a4eeacce0ada306c8c83a) --- src/jitlayers.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jitlayers.h b/src/jitlayers.h index 88b03fe3ceaa9..070bf576ffd35 100644 --- a/src/jitlayers.h +++ b/src/jitlayers.h @@ -241,7 +241,7 @@ struct jl_codegen_params_t { SmallVector cfuncs; std::map global_targets; jl_array_t *temporary_roots = nullptr; - SmallSet temporary_roots_set; + SmallSet temporary_roots_set; std::map, GlobalVariable*> external_fns; std::map ditypes; std::map llvmtypes; From dbdfa11fc76ebab3fc8e2f297a1e2c522e808a5f Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Wed, 14 May 2025 12:11:46 +0200 Subject: [PATCH 10/46] Bump LLVM 18 to include ORC patch. (#58398) Bumps `libLLVM` to include https://github.com/llvm/llvm-project/pull/139259, a simple patch to fix the mangling of a C symbol. --- deps/checksums/llvm | 228 ++++++++++++++++---------------- deps/llvm.version | 8 +- stdlib/libLLVM_jll/Project.toml | 4 +- 3 files changed, 120 insertions(+), 120 deletions(-) diff --git a/deps/checksums/llvm b/deps/checksums/llvm index fbbb34480d893..ac8c678bdf653 100644 --- a/deps/checksums/llvm +++ b/deps/checksums/llvm @@ -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+3.aarch64-apple-darwin-llvm_version+18.asserts.tar.gz/md5/f7ce9539d0802dd4b5e5e673d36d1a99 -libLLVM.v18.1.7+3.aarch64-apple-darwin-llvm_version+18.asserts.tar.gz/sha512/7a54be16ccc327731c802380d29f2c9ee5e635cd6af0b7eb6b69e9d3b0b4fecb74147359af182def3b016ec4445891bdb91eb0d541b783e451e8263968c25161 -libLLVM.v18.1.7+3.aarch64-apple-darwin-llvm_version+18.tar.gz/md5/cd946ab46745ce71ad7438cf0f30cfd0 -libLLVM.v18.1.7+3.aarch64-apple-darwin-llvm_version+18.tar.gz/sha512/15f8bcdf6f66e654d5d6e950392ced62586e2bf7c2b0845db78282669c5440c2140432950c7726fcc8910c7113685cc29ac880de565f85b77536d63dbab0a8b5 -libLLVM.v18.1.7+3.aarch64-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/md5/766a2de98d275877bb676ff1f23e972f -libLLVM.v18.1.7+3.aarch64-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/sha512/3b353ea038fafefc13ccb4a81c7242d569c206362605be374fb312cb495f385796d052c3a7e08c7fe6ecaa3018e2a7e3dfa43d71a8c3a94987f7dc7aa378fd22 -libLLVM.v18.1.7+3.aarch64-linux-gnu-cxx03-llvm_version+18.tar.gz/md5/0684a6b210b799a8a0f45a286f3dfcc5 -libLLVM.v18.1.7+3.aarch64-linux-gnu-cxx03-llvm_version+18.tar.gz/sha512/4221e2d74117bd7e89aba2945030c1507e51999b236814fd23036565364c328392e87032daf1b9fe274ed89fcf9a6dcd203f0f1c8602c2a08d3fcfa189a5fefe -libLLVM.v18.1.7+3.aarch64-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/md5/6b460256e923637e5107d67859eb60ba -libLLVM.v18.1.7+3.aarch64-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/sha512/7d3f2736afe4022842529b1355cf9914b7a1c7b1e261f814a4523ad30a0cf0189056d5117a06720bbb7a844a435bb632ddbda2daadbf7e01c0120452cd13e6a3 -libLLVM.v18.1.7+3.aarch64-linux-gnu-cxx11-llvm_version+18.tar.gz/md5/c2b13a6a296adbb4be91dd3bb5be0877 -libLLVM.v18.1.7+3.aarch64-linux-gnu-cxx11-llvm_version+18.tar.gz/sha512/9086937e718125afd535b0066ee08a3523161a94fa7ef3c9a3e86bfe760f251b6ea7b035888e61a0e7f192ed25c9bd0f4dc153df86e08569e7067a7a30ba48c5 -libLLVM.v18.1.7+3.aarch64-linux-musl-cxx03-llvm_version+18.asserts.tar.gz/md5/758d33fe0b2b3d0371708614365450e8 -libLLVM.v18.1.7+3.aarch64-linux-musl-cxx03-llvm_version+18.asserts.tar.gz/sha512/79a662f72ba1b89b373d1d143ee880a12cb128211e79182e7befe8b3e50298b594de2ce489ca8bcdeadb17fceee811622f8bfcbc3e232cefdaf9927177469eec -libLLVM.v18.1.7+3.aarch64-linux-musl-cxx03-llvm_version+18.tar.gz/md5/2dcbb811be8985bfed3c8b37733c0d40 -libLLVM.v18.1.7+3.aarch64-linux-musl-cxx03-llvm_version+18.tar.gz/sha512/17f6fbd96ed5029f360c101cedad127881e14b42498d66f717448d99ca1909057ae79169d934e08157edcc7467db4b3941bdda26a2e9f42645963eec51f27e29 -libLLVM.v18.1.7+3.aarch64-linux-musl-cxx11-llvm_version+18.asserts.tar.gz/md5/bd3b904b5f9464aaaf87c41b899c8ca5 -libLLVM.v18.1.7+3.aarch64-linux-musl-cxx11-llvm_version+18.asserts.tar.gz/sha512/fa99e8025419a18f548f658ea589771c2803480c3cb3a25cfb75e26ed0993b7b37bba204d7cba1475319a71159813b2b58a3b3327ba24d264cf80ef24263628d -libLLVM.v18.1.7+3.aarch64-linux-musl-cxx11-llvm_version+18.tar.gz/md5/b4f9038d5c3c13207111ee1a9a918cba -libLLVM.v18.1.7+3.aarch64-linux-musl-cxx11-llvm_version+18.tar.gz/sha512/e8b97bee30f597cc06d31175e12f0c2035aef0054e8abdb431f31b1e9d440d561bd9bc6637a403441aa7f3e1d2a46c600734e17e3b7ed0ae899c92df91758780 -libLLVM.v18.1.7+3.aarch64-unknown-freebsd-llvm_version+18.asserts.tar.gz/md5/1f59987d027a3bc930fca6bef917f739 -libLLVM.v18.1.7+3.aarch64-unknown-freebsd-llvm_version+18.asserts.tar.gz/sha512/7bd0532e11abf1c4979e59d513257d53ea940f15c08d2fa30dc16e59e11d1899dcd2abe4a35dd3c7719aa49aacfa1b0e49049df3548336e5ec64355319129b30 -libLLVM.v18.1.7+3.aarch64-unknown-freebsd-llvm_version+18.tar.gz/md5/e4ff6f08094846700acc4e55d5b79e93 -libLLVM.v18.1.7+3.aarch64-unknown-freebsd-llvm_version+18.tar.gz/sha512/8a575e9640e5ff9b75ef4e970f203139e51afbcbf1b82c774fbe4a0176c22c51029533c188fb89068c1714eb3c8b1b232804f276a68c0c40aa0a6611ae72d1ce -libLLVM.v18.1.7+3.armv6l-linux-gnueabihf-cxx03-llvm_version+18.asserts.tar.gz/md5/06d8e634b4a6914efc18b7962df52021 -libLLVM.v18.1.7+3.armv6l-linux-gnueabihf-cxx03-llvm_version+18.asserts.tar.gz/sha512/cf6aeed1eaf652e5830e34dd2ba88abc33668953281146106bbfdbc92f5f225645f00ff5b4a0eb902baf904362ab4eb32192fa50ee5b2672e8b031fe2550f9a8 -libLLVM.v18.1.7+3.armv6l-linux-gnueabihf-cxx03-llvm_version+18.tar.gz/md5/53e83804b63e6ae4d0f1c97abcbbd1c8 -libLLVM.v18.1.7+3.armv6l-linux-gnueabihf-cxx03-llvm_version+18.tar.gz/sha512/45b3ee9b105ef2ef106fa8ac7b8e902cd1d6bf3c9bfb57edeca9e14f1654714d23fb086b369a9fd3cbb828c04fee4cfe80d2b2a2bfaa852d3ac65c0d213d8c62 -libLLVM.v18.1.7+3.armv6l-linux-gnueabihf-cxx11-llvm_version+18.asserts.tar.gz/md5/91b6cf00564053d385e30b34e5b8778e -libLLVM.v18.1.7+3.armv6l-linux-gnueabihf-cxx11-llvm_version+18.asserts.tar.gz/sha512/9111f3f02b49bf78340c9b0c5c1325a1ca09b62c83aefece1121573dcc21dce095060351f18997971e5cfbaab346cb12c75cdc0fbe8fa92aca2e8a68b5f5f577 -libLLVM.v18.1.7+3.armv6l-linux-gnueabihf-cxx11-llvm_version+18.tar.gz/md5/f6c91b71dfd73c7301a4e3de48e072de -libLLVM.v18.1.7+3.armv6l-linux-gnueabihf-cxx11-llvm_version+18.tar.gz/sha512/581d7e1e4d85aeaf082fa31555074471705e391de0771bf66665807afb5192c79c481ca30e73a25f4e2d48d4d325f0198e39bcbfaed2c9bc7477ee917667f5ce -libLLVM.v18.1.7+3.armv6l-linux-musleabihf-cxx03-llvm_version+18.asserts.tar.gz/md5/ce41ee46959e5e3a17b6c99293afedb7 -libLLVM.v18.1.7+3.armv6l-linux-musleabihf-cxx03-llvm_version+18.asserts.tar.gz/sha512/73d8c5af750ea9deef822aec58d8697243ca154bc4435ac0b0ab8c90fc97750e91fa55f8de7b8283eb1ab19951cda3e3c4c60834bcf13730163e593126a8eb57 -libLLVM.v18.1.7+3.armv6l-linux-musleabihf-cxx03-llvm_version+18.tar.gz/md5/67ed5b654852dad400aef17fb542703f -libLLVM.v18.1.7+3.armv6l-linux-musleabihf-cxx03-llvm_version+18.tar.gz/sha512/07f70c57e27eea37f520f6f0a954b54d2506530d5eb5a74e5a8526ba8ef55a948073c49037544b602d03d0aa482704292eac943f0a83421386ccbfbf22ee8510 -libLLVM.v18.1.7+3.armv6l-linux-musleabihf-cxx11-llvm_version+18.asserts.tar.gz/md5/5b8bd88d49ce21e5b63af6f77782eed4 -libLLVM.v18.1.7+3.armv6l-linux-musleabihf-cxx11-llvm_version+18.asserts.tar.gz/sha512/cef1c561ae388b2baa08e39dc195989cb795d8a2747f5f11e0dc9d9e107b9e99dbba465335376beff2e1b326512f6afc962775e0b246f3edcfadf509235cabd8 -libLLVM.v18.1.7+3.armv6l-linux-musleabihf-cxx11-llvm_version+18.tar.gz/md5/5fbf26d20b2ce3f61edc9a9ca2eb5284 -libLLVM.v18.1.7+3.armv6l-linux-musleabihf-cxx11-llvm_version+18.tar.gz/sha512/2c564c95d648458b9a0f0c963246cf5564c625107682f680390b6db5fde0e2b15a964fd3fd23734b5b2bb135db1fc698812d61b3f275710593f4defaee4a9c23 -libLLVM.v18.1.7+3.armv7l-linux-gnueabihf-cxx03-llvm_version+18.asserts.tar.gz/md5/c81bc29a75acf4f806f3eb13bf890604 -libLLVM.v18.1.7+3.armv7l-linux-gnueabihf-cxx03-llvm_version+18.asserts.tar.gz/sha512/c8c922a0a4fefd549f1c2ba396a3cab9cf7738aa82e7ccf7ca29c090260e2d73ec45d6f2b07173d584f6074b10fa04052114deef6ecb6f53ea87f1924074137a -libLLVM.v18.1.7+3.armv7l-linux-gnueabihf-cxx03-llvm_version+18.tar.gz/md5/1fcb40ba1a427105b4e7d13a6c11dc78 -libLLVM.v18.1.7+3.armv7l-linux-gnueabihf-cxx03-llvm_version+18.tar.gz/sha512/392c9ee85ba7ab6697bb8979c7f443d1d25f7ac9178e96a886401cfc68d75a43ce98bf3038a7ba70a9a990f65e604d38e043472cec3badb25fbd1b38cfbb7162 -libLLVM.v18.1.7+3.armv7l-linux-gnueabihf-cxx11-llvm_version+18.asserts.tar.gz/md5/427a19eaf69725d11bb33f48de9cb205 -libLLVM.v18.1.7+3.armv7l-linux-gnueabihf-cxx11-llvm_version+18.asserts.tar.gz/sha512/542e209b10c13d8dca867247a7414f84adb832f40051fcbdf0dcb09bc9664a77248e1b0ea1687805847dd9f5a05b86475dd76aba427c9a1bc83f8502444c60bd -libLLVM.v18.1.7+3.armv7l-linux-gnueabihf-cxx11-llvm_version+18.tar.gz/md5/ab34bfa2950014936edd13a7b5db8170 -libLLVM.v18.1.7+3.armv7l-linux-gnueabihf-cxx11-llvm_version+18.tar.gz/sha512/6376b25d0278e5c97581480fb4d54371b09a08be88f4cc39d2c7b3875f1189cef60c1be6bea5e12b0cf306cef8b394bc7d00f8b0fd95d749bd1b4eb318af7e15 -libLLVM.v18.1.7+3.armv7l-linux-musleabihf-cxx03-llvm_version+18.asserts.tar.gz/md5/cb6300fe87fd7cb9840f3bc44af26878 -libLLVM.v18.1.7+3.armv7l-linux-musleabihf-cxx03-llvm_version+18.asserts.tar.gz/sha512/a7984cd90fef55559142fc05d91b0da1f37f77f25214e93ff7641b7c3958f08dc7c082611915dbfda4bbbaa392656ac8604d4f75369777dacfb78baee2f99b16 -libLLVM.v18.1.7+3.armv7l-linux-musleabihf-cxx03-llvm_version+18.tar.gz/md5/b8a4e8ef43340e9cbdf5e4479c6a5a56 -libLLVM.v18.1.7+3.armv7l-linux-musleabihf-cxx03-llvm_version+18.tar.gz/sha512/fc249f2b666c8a8129e05ea08c773cbeb7af6d37791f271461eedd99adcfc5082e8609ed096d8a46edd1e73505352712a41e0ddc247a371f78227aab01fbe0f3 -libLLVM.v18.1.7+3.armv7l-linux-musleabihf-cxx11-llvm_version+18.asserts.tar.gz/md5/5864689df3298be4b1b4df1ae0412d3a -libLLVM.v18.1.7+3.armv7l-linux-musleabihf-cxx11-llvm_version+18.asserts.tar.gz/sha512/8f32f73e366c3a6993fa8d6b8cd1a9391611b0644cd4a77a4f7a235c037fdb75308d99b5a23ada6e4a73ed5fbd8f929a981d6bf317d79d52396220c221619303 -libLLVM.v18.1.7+3.armv7l-linux-musleabihf-cxx11-llvm_version+18.tar.gz/md5/6bf798476c4e94716cc47a95580104ad -libLLVM.v18.1.7+3.armv7l-linux-musleabihf-cxx11-llvm_version+18.tar.gz/sha512/9dbd27a000dd3c3dda9047d366a667c4b179cc61582525adb0f8227e8055413ce46efcbc1530305400239656e2f1016fb8833fb7f4734714078e035d388f3531 -libLLVM.v18.1.7+3.i686-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/md5/66e2889f86ae6bc1977419e6d9be729e -libLLVM.v18.1.7+3.i686-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/sha512/d0cac798c4979b4d818d36596b173e523cba3f41ff7ab1e2111f6a75c3e819e563e207a547328f005c5a93c7f8f88c17bf43c1139b5c2690df4f1d719f82920a -libLLVM.v18.1.7+3.i686-linux-gnu-cxx03-llvm_version+18.tar.gz/md5/0534b72d6d33c8573f79dce8a2a5a6e6 -libLLVM.v18.1.7+3.i686-linux-gnu-cxx03-llvm_version+18.tar.gz/sha512/6beaf1b45eec8b46fbf92f692f53e6df40bf48e50589aeb5ef99240a5a3ec9089ffb350dda6df24530937d613bf6d2cc4da76e92921ea00def9d2d38ac5bbeba -libLLVM.v18.1.7+3.i686-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/md5/2cf9a1ca20472179ce4a9eb3a949457b -libLLVM.v18.1.7+3.i686-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/sha512/cebae06ccee12a14d20d3056ce0519b1e774e3c9d9200a783262fcc40aee6d7aabfb08714bf53b88e03d8b09a96d3cda248a70c16188f8c707b291642998262a -libLLVM.v18.1.7+3.i686-linux-gnu-cxx11-llvm_version+18.tar.gz/md5/4712f6a46e0ff407ece958a7701511b9 -libLLVM.v18.1.7+3.i686-linux-gnu-cxx11-llvm_version+18.tar.gz/sha512/9a0a2dfa2076b93027f766277a6890cf94d67c131697f74945e92cf13ae64e84c09d3dd744498986fb22ad5e5465300aa9c8ae6632fcf919a0932515edfcc1e6 -libLLVM.v18.1.7+3.i686-w64-mingw32-cxx03-llvm_version+18.asserts.tar.gz/md5/274c51cc4dc133d7470ef82987b78df6 -libLLVM.v18.1.7+3.i686-w64-mingw32-cxx03-llvm_version+18.asserts.tar.gz/sha512/24944b1fec24bd21f2f773480c7783975b2cce5ef9909f285c959d954669b98ae18a174126440c03de28d1fa9b055f4bd092104dcb29d8c0c07400dd8e4cb493 -libLLVM.v18.1.7+3.i686-w64-mingw32-cxx03-llvm_version+18.tar.gz/md5/8b36d976399e4b603a1c4f8bce1510fc -libLLVM.v18.1.7+3.i686-w64-mingw32-cxx03-llvm_version+18.tar.gz/sha512/4f5a1169cd566898357c98f86786bf86f6f1d9282327f8026c7d04359fa7148f4026ef2de765debfb45d4013368cbf420e78802289ceea253a9ed2f58e89db8a -libLLVM.v18.1.7+3.i686-w64-mingw32-cxx11-llvm_version+18.asserts.tar.gz/md5/121a0c243591d8295fd3063821569e01 -libLLVM.v18.1.7+3.i686-w64-mingw32-cxx11-llvm_version+18.asserts.tar.gz/sha512/e55fbf36802e7d8547e1aa0f60c650b29cc3dbeaff67e6b6a095e0647d6a8c6f55bc7cf72daaeb6f3d2e87e831b3cb275d8c3b4beea2413de8a1cfbac4771ec0 -libLLVM.v18.1.7+3.i686-w64-mingw32-cxx11-llvm_version+18.tar.gz/md5/7af4fdf2475dcf896750e046edc9fd2c -libLLVM.v18.1.7+3.i686-w64-mingw32-cxx11-llvm_version+18.tar.gz/sha512/e8294e855565109e70d0596402dd8b7886174034242cbc6deb55f481a306c85ed9840732b3cb346c2ed5ce10a3d42647f2d1a97d2e998805089533880a326197 -libLLVM.v18.1.7+3.powerpc64le-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/md5/bbf060d61b294b86f7e3dde381b00b8a -libLLVM.v18.1.7+3.powerpc64le-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/sha512/632372d41f6e400a10fae27c6cd06a5a344cfb5902cad7928cb4133f14f36f0a3373e69e73ce9baf52f518340593c3a5a16173ef59a1878e6300e9975aeaa157 -libLLVM.v18.1.7+3.powerpc64le-linux-gnu-cxx03-llvm_version+18.tar.gz/md5/3d730b713e01cdb5a7a5a46028afd41b -libLLVM.v18.1.7+3.powerpc64le-linux-gnu-cxx03-llvm_version+18.tar.gz/sha512/052ab4fa7ac3b2c430601753ab078cdc9fd6db7f65ee0b76bb05473f4c5b99ec8919ad9d347425f1928cf619548e992c86ba97f9994218f50bca617e43d2f0d9 -libLLVM.v18.1.7+3.powerpc64le-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/md5/bf9dcb92ba8c031ae62ed4434fd5447f -libLLVM.v18.1.7+3.powerpc64le-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/sha512/e53be14dd02a2cef8eccafb9301d29c51d652c635703529c1444947002993f6639083eb8bef13af21c9796717ce4b3129dcdcbe2751a1173d39e321db8f6e3c7 -libLLVM.v18.1.7+3.powerpc64le-linux-gnu-cxx11-llvm_version+18.tar.gz/md5/b5cab0fc7c6643c6dd161f1e553ef1a0 -libLLVM.v18.1.7+3.powerpc64le-linux-gnu-cxx11-llvm_version+18.tar.gz/sha512/4032634449e2669479761c4323096b152f8df4948e3a97eea10f0b400fbf2a00d1edda59b74a714b62c4e204b113d8ecda78d828c3344ebe8bd750d14b3c4c7d -libLLVM.v18.1.7+3.x86_64-apple-darwin-llvm_version+18.asserts.tar.gz/md5/9f31ae627df95fb4818d8bb96e17c941 -libLLVM.v18.1.7+3.x86_64-apple-darwin-llvm_version+18.asserts.tar.gz/sha512/da67146a80ba3615e5e46455144c5f4a25919e391aadd3d63c9c645b639d68f8883a61e947b767f4583f666e653721c53d5d4098c8af2abd81691f941fdde686 -libLLVM.v18.1.7+3.x86_64-apple-darwin-llvm_version+18.tar.gz/md5/55fc5ae75087cb1ff1f08a1ef65f8b94 -libLLVM.v18.1.7+3.x86_64-apple-darwin-llvm_version+18.tar.gz/sha512/a000c0e349722f6b0196cc9a10aff8040dbe6a679bd79787c96c1de76968df636ab79dc24a31e4da960502858514fd74c3586c37411381d7ca68c5474576f7e0 -libLLVM.v18.1.7+3.x86_64-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/md5/69564913bae176a167d24d3291ef7af7 -libLLVM.v18.1.7+3.x86_64-linux-gnu-cxx03-llvm_version+18.asserts.tar.gz/sha512/b8eeb86b66d767218e59671bdd597623238eea72319913c2ac5e116faec3f4c13739a24f3b95338ed857ec29e714dc0308e4ddbfe359332b3c27ad5235052342 -libLLVM.v18.1.7+3.x86_64-linux-gnu-cxx03-llvm_version+18.tar.gz/md5/bc9d5637fe30f21d2231a98371e798e4 -libLLVM.v18.1.7+3.x86_64-linux-gnu-cxx03-llvm_version+18.tar.gz/sha512/4efbc2823322abe80d0134d35926767bd9cab717cde9308726a6a8891e5a707476138888c695ed399e3dddb57baf17abbc43a0a338cea2e5c0f472ab427c12e3 -libLLVM.v18.1.7+3.x86_64-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/md5/8492ff91e6dbd1a66edd8aaf0390a582 -libLLVM.v18.1.7+3.x86_64-linux-gnu-cxx11-llvm_version+18.asserts.tar.gz/sha512/6443bd2fa9c5beecc2b002c26595f2cf3a8e2ea5eb49aa4c00f7252a6623fe0f8c01824941ebe5475460641285c4e56a5203056c1b93a78250b7e48fb5ac9e00 -libLLVM.v18.1.7+3.x86_64-linux-gnu-cxx11-llvm_version+18.tar.gz/md5/6918c9978fd8b5887c66eee76950478d -libLLVM.v18.1.7+3.x86_64-linux-gnu-cxx11-llvm_version+18.tar.gz/sha512/d455a4f433bf3ea1b5100b9d45199bc785e4b6fbc7659bf06cbde6ada471134e7d4243d3a3a1f71d579126ef8371d70e59f174e124b3ff8d4842e9ee83e2dea4 -libLLVM.v18.1.7+3.x86_64-linux-musl-cxx03-llvm_version+18.asserts.tar.gz/md5/075f87d106dd95c8e9c6e7e157b5e9db -libLLVM.v18.1.7+3.x86_64-linux-musl-cxx03-llvm_version+18.asserts.tar.gz/sha512/8132379d8f44a21082c7a90f58a7dffb0c6ee725efd58a959d4023787411b080d72913bb1e89a35072f97aaf1ca512ab1d027b37eaed819e3c053d7a0cf64269 -libLLVM.v18.1.7+3.x86_64-linux-musl-cxx03-llvm_version+18.tar.gz/md5/4cfc2838a77f05883f82e50b3723dcfe -libLLVM.v18.1.7+3.x86_64-linux-musl-cxx03-llvm_version+18.tar.gz/sha512/20079c81cd6a4020b087485be1ab4928b3bd3e1a53728cc98137a35b969484278093bc75a9e51ddfd8331556577c5fb3109d74dc2eccffa93b5390e0fabff2b1 -libLLVM.v18.1.7+3.x86_64-linux-musl-cxx11-llvm_version+18.asserts.tar.gz/md5/5b8cbf00631bd4540b7335a86302a1fe -libLLVM.v18.1.7+3.x86_64-linux-musl-cxx11-llvm_version+18.asserts.tar.gz/sha512/51ba9a4b74b740905cee4baf7f4e5f3620ed81e0746f49cd352d874ebedab95277c5031123f880c9239b7dbf505b10f6531f79c8a6b0482a652b8324f4137cf5 -libLLVM.v18.1.7+3.x86_64-linux-musl-cxx11-llvm_version+18.tar.gz/md5/11010cc2d58b1a8c6a6e7bc24df0c0db -libLLVM.v18.1.7+3.x86_64-linux-musl-cxx11-llvm_version+18.tar.gz/sha512/a6bdd9a2a2fa9a572e74ced69c3ce9d1b84cde18155ec9bc7dfbaba411ee6c43d229e6fb333eff66fb63b632b485b46b7cb1657c0c49d9d9bb849fa13f0bbc7b -libLLVM.v18.1.7+3.x86_64-unknown-freebsd-llvm_version+18.asserts.tar.gz/md5/566390f0f0fa92c4a9a400e25e7086d0 -libLLVM.v18.1.7+3.x86_64-unknown-freebsd-llvm_version+18.asserts.tar.gz/sha512/31981cc3be65117d8dfcb0254dcdecd79b0f141a61864db4e50b81fbe7a1db431b71f9ef43bbeb320e4ae33bb00f2db42d83f849ce6ca5044445cd5de9572566 -libLLVM.v18.1.7+3.x86_64-unknown-freebsd-llvm_version+18.tar.gz/md5/b753aba58a0704da416bb06cd97acdd7 -libLLVM.v18.1.7+3.x86_64-unknown-freebsd-llvm_version+18.tar.gz/sha512/99358ace0ef20138284c3f8b28b46dd431b460d1c92034fc918233a266c9be398eba63d1758a388fb39935123c65f72969e01231e54b27cff771cdabef9171c2 -libLLVM.v18.1.7+3.x86_64-w64-mingw32-cxx03-llvm_version+18.asserts.tar.gz/md5/52cee10b0dd37d9a4487d3762e1902c3 -libLLVM.v18.1.7+3.x86_64-w64-mingw32-cxx03-llvm_version+18.asserts.tar.gz/sha512/c44d305ffcb2939779a071a5a78ca9469654e36c5e4cf3e0e78603c85ec30eae3c8ab2594df19812d51dba7cea565c16a70f514faf30bc43b8f37592f57aa059 -libLLVM.v18.1.7+3.x86_64-w64-mingw32-cxx03-llvm_version+18.tar.gz/md5/eef5f1bc5a0026bf96f33e2254b93711 -libLLVM.v18.1.7+3.x86_64-w64-mingw32-cxx03-llvm_version+18.tar.gz/sha512/df39558259dd59f7b602581e7afdf67e77c854c1192b53b24a5c2d133a4a74b3f44e74682f9f02745ef97a969de92566a7633c46816a031b14cb04006af845de -libLLVM.v18.1.7+3.x86_64-w64-mingw32-cxx11-llvm_version+18.asserts.tar.gz/md5/bbe95b31b958f187d49692d4856d84af -libLLVM.v18.1.7+3.x86_64-w64-mingw32-cxx11-llvm_version+18.asserts.tar.gz/sha512/3035b3b8b1cd1349c893aa47f066a1b8b7610f69ff0c4f2f3325a377818fd8bb12ad5485730be354bc2a9982db405b5954dbda39bc7cff38dc22966a6d86c5d5 -libLLVM.v18.1.7+3.x86_64-w64-mingw32-cxx11-llvm_version+18.tar.gz/md5/0e21a6d22dd45d125d0e98fe8f72e8c7 -libLLVM.v18.1.7+3.x86_64-w64-mingw32-cxx11-llvm_version+18.tar.gz/sha512/efbbad538c6f8b773d7ef1019a9b754e1ce7da59ea5f00f452fa7f7cc93c40f248762eb7f708e3d2fa7f9bdbc0b680d6e6502a07bbca0d4e701b51b0565d625e -llvm-julia-18.1.7-2.tar.gz/md5/5c0ae4abc4ce31a86d5d6d4ecabc2683 -llvm-julia-18.1.7-2.tar.gz/sha512/b4d1dde929a8670eec1a9b25abe23fbc926a922e61b60ed99b52b440cd07cb026e7f746878292db4cd0cb422d9b87ecc4ee4b2b141f8e9411855d18da51facb9 +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 llvm-project-19.1.4.tar.xz/md5/1e13043b18558e4346ea3769094c9737 llvm-project-19.1.4.tar.xz/sha512/a586f8a41dde5e0d9ca6d8c58e9ef2a2e59b70a86d2e2c46106dc31b5c096bb80af0cdbdb486179e9cc676a540099f49a1c2db9e5e84c50362db1f72e9af6906 diff --git a/deps/llvm.version b/deps/llvm.version index be03d1529ce7c..27250f008cd8e 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+3 +LLVM_ASSERT_JLL_VER := 18.1.7+4 ## 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-2 +LLVM_BRANCH=julia-18.1.7-3 # Git ref in `LLVM_GIT_URL` repository -LLVM_SHA1=julia-18.1.7-2 +LLVM_SHA1=julia-18.1.7-3 ## 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-2 +LLVM_JULIA_REF := JuliaLang:julia-18.1.7-3 diff --git a/stdlib/libLLVM_jll/Project.toml b/stdlib/libLLVM_jll/Project.toml index 13669ec173678..f6c343d878abb 100644 --- a/stdlib/libLLVM_jll/Project.toml +++ b/stdlib/libLLVM_jll/Project.toml @@ -1,13 +1,13 @@ name = "libLLVM_jll" uuid = "8f36deef-c2a5-5394-99ed-8e07531fb29a" -version = "18.1.7+3" +version = "18.1.7+4" [deps] Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb" Artifacts = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" [compat] -julia = "1.11" +julia = "1.12" [extras] Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" From 34e68cd87471eb800305ce767fb2f578d786c8a8 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Tue, 13 May 2025 13:01:43 -0400 Subject: [PATCH 11/46] Fix signedness typo in world range update (#58390) This manifested itself as a missing invalidation downstream, but I don't know if this is visible from Base. In general, we don't set the InferenceState's max_world to `typemax(UInt)`, but rather to the maximum world age at start of inference, and then we check at the end of inference if the world age is still the same, and only then raise it to `typemax(UInt)` (which arms the backedges). The downstream setup is a bit more complex, and I don't entirely know where this leaked out, but this change fixed it regardless. (cherry picked from commit f0a8dd8ea32aee6b0ace6025513a03981c12d551) --- Compiler/src/abstractinterpretation.jl | 2 +- Compiler/src/typeinfer.jl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Compiler/src/abstractinterpretation.jl b/Compiler/src/abstractinterpretation.jl index 9bdd5b50e512e..8585938b050f8 100644 --- a/Compiler/src/abstractinterpretation.jl +++ b/Compiler/src/abstractinterpretation.jl @@ -3497,7 +3497,7 @@ function merge_override_effects!(interp::AbstractInterpreter, effects::Effects, # N.B.: We'd like deleted_world here, but we can't add an appropriate edge at this point. # However, in order to reach here in the first place, ordinary method lookup would have # had to add an edge and appropriate invalidation trigger. - valid_worlds = WorldRange(m.primary_world, typemax(Int)) + valid_worlds = WorldRange(m.primary_world, typemax(UInt)) if sv.world.this in valid_worlds update_valid_age!(sv, valid_worlds) else diff --git a/Compiler/src/typeinfer.jl b/Compiler/src/typeinfer.jl index debae93089c02..b965093a1ebef 100644 --- a/Compiler/src/typeinfer.jl +++ b/Compiler/src/typeinfer.jl @@ -362,7 +362,7 @@ function adjust_effects(ipo_effects::Effects, def::Method, world::UInt) valid_worlds = WorldRange(0, typemax(UInt)) if is_effect_overridden(override, :consistent) # See note on `typemax(Int)` instead of `deleted_world` in adjust_effects! - override_valid_worlds = WorldRange(def.primary_world, typemax(Int)) + override_valid_worlds = WorldRange(def.primary_world, typemax(UInt)) if world in override_valid_worlds ipo_effects = Effects(ipo_effects; consistent=ALWAYS_TRUE) valid_worlds = override_valid_worlds From e6371c94fafc0675c7e8ebf1c36591580c809773 Mon Sep 17 00:00:00 2001 From: Cody Tapscott Date: Tue, 13 May 2025 12:52:38 -0400 Subject: [PATCH 12/46] Add `Compiler._verify_trim_world_age` for better printing The `juliac-buildscript` is quite aggressive in how it modifies type printing, so caching the pre-buildscript world like this allows us to print stacktraces in their usual fidelity. Before: ``` [1] get_size_dict!(ne::StaticNestedEinsum{Char, ?, ?}, xs::Any, size_info::Dict{Char, Int64}) @ OMEinsum ~/.julia/dev/OMEinsum/src/einsequence.jl:269 ... ``` After: ``` [1] get_size_dict!(ne::StaticNestedEinsum{Char, nothing, ('j','k','l')}, xs::Any, size_info::Dict{Char, Int64}) @ OMEinsum ~/.julia/dev/OMEinsum/src/einsequence.jl:269 ... ``` (cherry picked from commit 87ef4b338662172bf4dcd7961fcb338eb507f2ff) --- Compiler/src/typeinfer.jl | 3 ++- contrib/juliac-buildscript.jl | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Compiler/src/typeinfer.jl b/Compiler/src/typeinfer.jl index b965093a1ebef..2e7c7a5018e06 100644 --- a/Compiler/src/typeinfer.jl +++ b/Compiler/src/typeinfer.jl @@ -1523,7 +1523,8 @@ function typeinf_ext_toplevel(methods::Vector{Any}, worlds::Vector{UInt}, trim_m return codeinfos end -verify_typeinf_trim(codeinfos::Vector{Any}, onlywarn::Bool) = invokelatest(verify_typeinf_trim, stdout, codeinfos, onlywarn) +const _verify_trim_world_age = RefValue{UInt}(typemax(UInt)) +verify_typeinf_trim(codeinfos::Vector{Any}, onlywarn::Bool) = Core._call_in_world(_verify_trim_world_age[], verify_typeinf_trim, stdout, codeinfos, onlywarn) function return_type(@nospecialize(f), t::DataType) # this method has a special tfunc world = tls_world_age() diff --git a/contrib/juliac-buildscript.jl b/contrib/juliac-buildscript.jl index 0549afc0e1508..4bfbfd2272220 100644 --- a/contrib/juliac-buildscript.jl +++ b/contrib/juliac-buildscript.jl @@ -4,6 +4,10 @@ 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() + # Initialize some things not usually initialized when output is requested Sys.__init__() Base.init_depot_path() From 8feef5239a521f267dbc473621721932142fde38 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Wed, 14 May 2025 17:36:33 -0400 Subject: [PATCH 13/46] fix `hasmethod` with kwargs to exclude positional arg names (#58410) (cherry picked from commit 7df60f480df8c6aed874b35eb7c8a26fc769a4cc) --- base/reflection.jl | 2 +- test/reflection.jl | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/base/reflection.jl b/base/reflection.jl index 528202a9196ba..51a781002469d 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -1035,11 +1035,11 @@ function hasmethod(f, t, kwnames::Tuple{Vararg{Symbol}}; world::UInt=get_world_c match = ccall(:jl_gf_invoke_lookup, Any, (Any, Any, UInt), tt, nothing, world) match === nothing && return false kws = ccall(:jl_uncompress_argnames, Array{Symbol,1}, (Any,), (match::Method).slot_syms) + kws = kws[((match::Method).nargs + 1):end] # remove positional arguments isempty(kws) && return true # some kwfuncs simply forward everything directly for kw in kws endswith(String(kw), "...") && return true end - kwnames = collect(kwnames) return issubset(kwnames, kws) end diff --git a/test/reflection.jl b/test/reflection.jl index b9d1eaa1c86f9..d6b2161619b26 100644 --- a/test/reflection.jl +++ b/test/reflection.jl @@ -931,6 +931,7 @@ f(x::Int; y=3) = x + y @test hasmethod(f, Tuple{Int}) @test hasmethod(f, Tuple{Int}, ()) @test hasmethod(f, Tuple{Int}, (:y,)) +@test !hasmethod(f, Tuple{Int}, (:x,)) @test !hasmethod(f, Tuple{Int}, (:jeff,)) @test !hasmethod(f, Tuple{Int}, (:y,), world=typemin(UInt)) g(; b, c, a) = a + b + c From c585f7ee7075cabf048f9d945fcfbf4f9bdccca3 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Wed, 14 May 2025 22:54:15 -0400 Subject: [PATCH 14/46] [REPL] fix type confusion resulting in nonsensical errors (#58414) (cherry picked from commit a87b05665fa58dd0360b2a69e4468404a552cd00) --- stdlib/REPL/src/REPL.jl | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/stdlib/REPL/src/REPL.jl b/stdlib/REPL/src/REPL.jl index 66b46154e78f1..9eaecf44c7633 100644 --- a/stdlib/REPL/src/REPL.jl +++ b/stdlib/REPL/src/REPL.jl @@ -445,8 +445,8 @@ function repl_backend_loop(backend::REPLBackend, get_module::Function) try ret = f() put!(backend.response_channel, Pair{Any, Bool}(ret, false)) - catch err - put!(backend.response_channel, Pair{Any, Bool}(err, true)) + catch + put!(backend.response_channel, Pair{Any, Bool}(current_exceptions(), true)) end else ast = ast_or_func @@ -587,11 +587,11 @@ function print_response(errio::IO, response, backend::Union{REPLBackendRef,Nothi if val !== nothing && show_value val2, iserr = if specialdisplay === nothing # display calls may require being run on the main thread - eval_with_backend(backend) do + call_on_backend(backend) do Base.invokelatest(display, val) end else - eval_with_backend(backend) do + call_on_backend(backend) do Base.invokelatest(display, specialdisplay, val) end end @@ -708,7 +708,7 @@ function run_frontend(repl::BasicREPL, backend::REPLBackendRef) (isa(ast,Expr) && ast.head === :incomplete) || break end if !isempty(line) - response = eval_with_backend(ast, backend) + response = eval_on_backend(ast, backend) print_response(repl, response, !ends_with_semicolon(line), false) end write(repl.terminal, '\n') @@ -1153,21 +1153,23 @@ find_hist_file() = get(ENV, "JULIA_HISTORY", backend(r::AbstractREPL) = hasproperty(r, :backendref) ? r.backendref : nothing -function eval_with_backend(ast::Expr, backend::REPLBackendRef) +function eval_on_backend(ast, backend::REPLBackendRef) put!(backend.repl_channel, (ast, 1)) # (f, show_value) return take!(backend.response_channel) # (val, iserr) end -function eval_with_backend(f, backend::REPLBackendRef) +function call_on_backend(f, backend::REPLBackendRef) + applicable(f) || error("internal error: f is not callable") put!(backend.repl_channel, (f, 2)) # (f, show_value) 2 indicates function (rather than ast) return take!(backend.response_channel) # (val, iserr) end # if no backend just eval (used by tests) -function eval_with_backend(f, backend::Nothing) +eval_on_backend(ast, backend::Nothing) = error("no backend for eval ast") +function call_on_backend(f, backend::Nothing) try ret = f() return (ret, false) # (val, iserr) - catch err - return (err, true) + catch + return (current_exceptions(), true) end end @@ -1183,7 +1185,7 @@ function respond(f, repl, main; pass_empty::Bool = false, suppress_on_semicolon: local response try ast = Base.invokelatest(f, line) - response = eval_with_backend(ast, backend(repl)) + response = eval_on_backend(ast, backend(repl)) catch response = Pair{Any, Bool}(current_exceptions(), true) end @@ -1823,7 +1825,7 @@ function run_frontend(repl::StreamREPL, backend::REPLBackendRef) if have_color print(repl.stream, Base.color_normal) end - response = eval_with_backend(ast, backend) + response = eval_on_backend(ast, backend) print_response(repl, response, !ends_with_semicolon(line), have_color) end end From 369ed27a63ef835a112e6022e90532b40df0c312 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Thu, 15 May 2025 10:14:43 -0400 Subject: [PATCH 15/46] [REPL] more reliable extension loading (#58415) A weird edge case of loading, if REPL is loaded explicitly and does not come from a require_stdlib call, it should not be getting REPLExt from a require_stdlib call either. This is a convoluted bit of hackery specific to work around problems with the way Pkg's REPLExt is designed to mutate the REPL in unsafe ways. No other stdlib should ever want to access an extension, particularly of a different module, as that is a private API violation on multiple counts, so this only needs to be made to work specifically for that REPL-Pkg scenario, even if it looks seemingly more general. Refs https://github.com/JuliaLang/julia/issues/58373 Reproducer: ``` JULIA_DEPOT_PATH=tmpdir/.julia ./julia --hist=no -qie 'using REPL' ] status ``` (cherry picked from commit 94570e1bac838faa6e5a900769b4562dd047a57c) --- base/loading.jl | 39 ++++++++++++++++++++++--------- stdlib/REPL/src/Pkg_beforeload.jl | 4 +++- 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/base/loading.jl b/base/loading.jl index ea2cf35395540..49179fa73447d 100644 --- a/base/loading.jl +++ b/base/loading.jl @@ -2710,7 +2710,7 @@ end # load a serialized file directly from append_bundled_depot_path for uuidkey without stalechecks """ - require_stdlib(package_uuidkey::PkgId, ext::Union{Nothing, String}=nothing) + require_stdlib(package_uuidkey::PkgId, [ext::String, from::Module]) !!! warning "May load duplicate copies of stdlib packages." @@ -2749,7 +2749,8 @@ end [1] https://github.com/JuliaLang/Pkg.jl/issues/4017#issuecomment-2377589989 [2] https://github.com/JuliaLang/StyledStrings.jl/issues/91#issuecomment-2379602914 """ -function require_stdlib(package_uuidkey::PkgId, ext::Union{Nothing, String}=nothing) +require_stdlib(package_uuidkey::PkgId) = require_stdlib(package_uuidkey, nothing, Base) +function require_stdlib(package_uuidkey::PkgId, ext::Union{Nothing, String}, from::Module) if generating_output(#=incremental=#true) # Otherwise this would lead to awkward dependency issues by loading a package that isn't in the Project/Manifest error("This interactive function requires a stdlib to be loaded, and package code should instead use it directly from that stdlib.") @@ -2761,15 +2762,29 @@ function require_stdlib(package_uuidkey::PkgId, ext::Union{Nothing, String}=noth newm = start_loading(this_uuidkey, UInt128(0), true) newm === nothing || return newm try - # first since this is a stdlib, try to look there directly first - if ext === nothing - sourcepath = normpath(env, this_uuidkey.name, "src", this_uuidkey.name * ".jl") - else - sourcepath = find_ext_path(normpath(joinpath(env, package_uuidkey.name)), ext) - end depot_path = append_bundled_depot_path!(empty(DEPOT_PATH)) - set_pkgorigin_version_path(this_uuidkey, sourcepath) - newm = _require_search_from_serialized(this_uuidkey, sourcepath, UInt128(0), false; DEPOT_PATH=depot_path) + from_stdlib = true # set to false if `from` is a normal package so we do not want the internal loader for the extension either + if ext isa String + from_uuid = PkgId(from) + from_m = get(loaded_modules, from_uuid, nothing) + if from_m === from + # if from_uuid is either nothing or points to something else, assume we should use require_stdlib + # otherwise check cachepath for from to see if it looks like it is from depot_path, since try_build_ids + cachepath = get(PkgOrigin, pkgorigins, from_uuid).cachepath + entrypath, entryfile = cache_file_entry(from_uuid) + from_stdlib = any(x -> startswith(entrypath, x), depot_path) + end + end + if from_stdlib + # first since this is a stdlib, try to look there directly first + if ext === nothing + sourcepath = normpath(env, this_uuidkey.name, "src", this_uuidkey.name * ".jl") + else + sourcepath = find_ext_path(normpath(joinpath(env, package_uuidkey.name)), ext) + end + set_pkgorigin_version_path(this_uuidkey, sourcepath) + newm = _require_search_from_serialized(this_uuidkey, sourcepath, UInt128(0), false; DEPOT_PATH=depot_path) + end finally end_loading(this_uuidkey, newm) end @@ -2779,10 +2794,12 @@ function require_stdlib(package_uuidkey::PkgId, ext::Union{Nothing, String}=noth run_package_callbacks(this_uuidkey) else # if the user deleted their bundled depot, next try to load it completely normally + # if it is an extension, we first need to indicate where to find its parant via EXT_PRIMED + ext isa String && (EXT_PRIMED[this_uuidkey] = PkgId[package_uuidkey]) newm = _require_prelocked(this_uuidkey) end return newm - end + end # release lock end # relative-path load diff --git a/stdlib/REPL/src/Pkg_beforeload.jl b/stdlib/REPL/src/Pkg_beforeload.jl index 86b5cd35abd2f..e51cf7550bce5 100644 --- a/stdlib/REPL/src/Pkg_beforeload.jl +++ b/stdlib/REPL/src/Pkg_beforeload.jl @@ -1,7 +1,9 @@ +# This file is a part of Julia. License is MIT: https://julialang.org/license + ## Pkg stuff needed before Pkg has loaded const Pkg_pkgid = Base.PkgId(Base.UUID("44cfe95a-1eb2-52ea-b672-e2afdf69b78f"), "Pkg") -load_pkg() = Base.require_stdlib(Pkg_pkgid, "REPLExt") +load_pkg() = Base.require_stdlib(Pkg_pkgid, "REPLExt", REPL) ## Below here copied/tweaked from Pkg Types.jl so that the dummy Pkg prompt # can populate the env correctly before Pkg loads From b49b35214d702259d7cacd5cc03d403e281e830c Mon Sep 17 00:00:00 2001 From: Cody Tapscott <84105208+topolarity@users.noreply.github.com> Date: Thu, 15 May 2025 21:33:30 -0400 Subject: [PATCH 16/46] reflection: Label "dynamic invoke" in `code_typed` (#58411) (cherry picked from commit 43ead4774248b1cf9cb84a349e9e90b3595c9ecd) --- Compiler/src/abstractinterpretation.jl | 4 ++-- Compiler/src/ssair/show.jl | 19 +++++++++---------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/Compiler/src/abstractinterpretation.jl b/Compiler/src/abstractinterpretation.jl index 8585938b050f8..3b9b5f34bf3cb 100644 --- a/Compiler/src/abstractinterpretation.jl +++ b/Compiler/src/abstractinterpretation.jl @@ -2210,7 +2210,7 @@ function abstract_call_unionall(interp::AbstractInterpreter, argtypes::Vector{An return CallMeta(ret, Any, Effects(EFFECTS_TOTAL; nothrow), call.info) end -function ci_abi(ci::CodeInstance) +function get_ci_abi(ci::CodeInstance) def = ci.def isa(def, ABIOverride) && return def.abi (def::MethodInstance).specTypes @@ -2233,7 +2233,7 @@ function abstract_invoke(interp::AbstractInterpreter, arginfo::ArgInfo, si::Stmt if isa(method_or_ci, CodeInstance) our_world = sv.world.this argtype = argtypes_to_type(pushfirst!(argtype_tail(argtypes, 4), ft)) - specsig = ci_abi(method_or_ci) + specsig = get_ci_abi(method_or_ci) defdef = get_ci_mi(method_or_ci).def exct = method_or_ci.exctype if !hasintersect(argtype, specsig) diff --git a/Compiler/src/ssair/show.jl b/Compiler/src/ssair/show.jl index 0688c02eb6440..1b6eeca57f3f9 100644 --- a/Compiler/src/ssair/show.jl +++ b/Compiler/src/ssair/show.jl @@ -12,7 +12,8 @@ using .Compiler: ALWAYS_FALSE, ALWAYS_TRUE, argextype, BasicBlock, block_for_ins CachedMethodTable, CFG, compute_basic_blocks, DebugInfoStream, Effects, EMPTY_SPTYPES, getdebugidx, IncrementalCompact, InferenceResult, InferenceState, InvalidIRError, IRCode, LimitedAccuracy, NativeInterpreter, scan_ssa_use!, - singleton_type, sptypes_from_meth_instance, StmtRange, Timings, VarState, widenconst + singleton_type, sptypes_from_meth_instance, StmtRange, Timings, VarState, widenconst, + get_ci_mi, get_ci_abi @nospecialize @@ -95,16 +96,14 @@ function print_stmt(io::IO, idx::Int, @nospecialize(stmt), code::Union{IRCode,Co elseif isexpr(stmt, :invoke) && length(stmt.args) >= 2 && isa(stmt.args[1], Union{MethodInstance,CodeInstance}) stmt = stmt::Expr # TODO: why is this here, and not in Base.show_unquoted - printstyled(io, " invoke "; color = :light_black) - mi = stmt.args[1] - if !(mi isa Core.MethodInstance) - mi = (mi::Core.CodeInstance).def - end - if isa(mi, Core.ABIOverride) - abi = mi.abi - mi = mi.def + ci = stmt.args[1] + if ci isa Core.CodeInstance + printstyled(io, " invoke "; color = :light_black) + mi = get_ci_mi(ci) + abi = get_ci_abi(ci) else - abi = mi.specTypes + printstyled(io, "dynamic invoke "; color = :yellow) + abi = (ci::Core.MethodInstance).specTypes end show_unquoted(io, stmt.args[2], indent) print(io, "(") From 1d4065e59fc0cc36a97acc26de3f8f07fa196486 Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Fri, 16 May 2025 19:15:46 -0400 Subject: [PATCH 17/46] Add some precompiles to help loading time (#58436) (cherry picked from commit fc456bdd04d6d391381554e5c8e5d9a1e3ca6ce3) --- contrib/generate_precompile.jl | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/contrib/generate_precompile.jl b/contrib/generate_precompile.jl index 13ad25e620b02..46827f20453ba 100644 --- a/contrib/generate_precompile.jl +++ b/contrib/generate_precompile.jl @@ -105,6 +105,7 @@ precompile(Base.CoreLogging.current_logger_for_env, (Base.CoreLogging.LogLevel, precompile(Base.CoreLogging.env_override_minlevel, (Symbol, Module)) precompile(Base.StackTraces.lookup, (Ptr{Nothing},)) precompile(Tuple{typeof(Base.run_module_init), Module, Int}) +precompile(Tuple{Type{Base.VersionNumber}, Int32, Int32, Int32}) # Presence tested in the tests precompile(Tuple{typeof(Base.print), Base.IOStream, String}) @@ -142,6 +143,9 @@ for match = Base._methods(+, (Int, Int), -1, Base.get_world_counter()) end empty!(Set()) push!(push!(Set{Union{GlobalRef,Symbol}}(), :two), GlobalRef(Base, :two)) +get!(ENV, "___DUMMY", "") +ENV["___DUMMY"] +delete!(ENV, "___DUMMY") (setindex!(Dict{String,Base.PkgId}(), Base.PkgId(Base), "file.jl"))["file.jl"] (setindex!(Dict{Symbol,Vector{Int}}(), [1], :two))[:two] (setindex!(Dict{Base.PkgId,String}(), "file.jl", Base.PkgId(Base)))[Base.PkgId(Base)] @@ -211,6 +215,9 @@ if Artifacts !== nothing end dlopen("libjulia$(Base.isdebugbuild() ? "-debug" : "")", RTLD_LAZY | RTLD_DEEPBIND) """ + hardcoded_precompile_statements *= """ + precompile(Tuple{typeof(Artifacts._artifact_str), Module, String, Base.SubString{String}, String, Base.Dict{String, Any}, Base.SHA1, Base.BinaryPlatforms.Platform, Base.Val{Artifacts}}) + """ end FileWatching = get(Base.loaded_modules, From ab198f9f2bdd9f397071cb33e6875b9c289ee387 Mon Sep 17 00:00:00 2001 From: Gabriel Baraldi Date: Mon, 19 May 2025 12:15:46 -0300 Subject: [PATCH 18/46] Fix layout flags for types that have oddly sized primitive type fields (#58435) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is caused because for LLVMs sake we have to say that the oddly typed field is smaller than it actually is. (I wonder if we could represent it as an iN field in a struct and have it work but the result would be the same for now) Fix #58434, fix #49318, close #49362. --------- Co-authored-by: Mosè Giordano <765740+giordano@users.noreply.github.com> Co-authored-by: Sukera <11753998+Seelengrab@users.noreply.github.com> (cherry picked from commit 1b0b02869daef1d2a1b8e8105075132357ee6897) --- src/datatype.c | 6 ++++++ test/core.jl | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/src/datatype.c b/src/datatype.c index 3f9679ec54618..677f0d0bff65b 100644 --- a/src/datatype.c +++ b/src/datatype.c @@ -702,6 +702,7 @@ void jl_compute_field_offsets(jl_datatype_t *st) // Should never happen throw_ovf(should_malloc, desc, st, fsz); desc[i].isptr = 0; + if (jl_is_uniontype(fld)) { fsz += 1; // selector byte zeroinit = 1; @@ -709,6 +710,11 @@ void jl_compute_field_offsets(jl_datatype_t *st) isbitsegal = 0; } else { + if (fsz > jl_datatype_size(fld)) { + // We have to pad the size to integer size class, but it means this has some padding + isbitsegal = 0; + haspadding = 1; + } uint32_t fld_npointers = ((jl_datatype_t*)fld)->layout->npointers; if (((jl_datatype_t*)fld)->layout->flags.haspadding) haspadding = 1; diff --git a/test/core.jl b/test/core.jl index c6ca43bd0079b..1e015b19e4a91 100644 --- a/test/core.jl +++ b/test/core.jl @@ -8518,3 +8518,9 @@ module GlobalBindingMulti using .M.C end @test GlobalBindingMulti.S === GlobalBindingMulti.M.C.S + +#58434 bitsegal comparison of oddly sized fields +primitive type ByteString58434 (18 * 8) end + +@test Base.datatype_isbitsegal(Tuple{ByteString58434}) == false +@test Base.datatype_haspadding(Tuple{ByteString58434}) == (length(Base.padding(Tuple{ByteString58434})) > 0) From 916f4c2a43fe77d0bd0da9710364a733147ce7d4 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 19 May 2025 16:49:16 -0400 Subject: [PATCH 19/46] avoid deadlock if crashing inside profile_wr_lock (#58452) The rd/wr lock distinction here was supposed to help prevent deadlocks by allowing recursion (even over signals), but did not account for crashes causing recursion while holding the wr lock. Make these lock acquires fail-able if they would cause deadlock. (cherry picked from commit 2e2fac5beafd5596cbb3933728c12bd141349c5e) --- src/debuginfo.cpp | 18 +++++++++-------- src/julia_internal.h | 5 ++--- src/signal-handling.c | 45 ++++++++++++++++++++++++++++++++++++------- src/threading.c | 8 +++++--- 4 files changed, 55 insertions(+), 21 deletions(-) diff --git a/src/debuginfo.cpp b/src/debuginfo.cpp index 17e093cecb89a..8625b82aedff8 100644 --- a/src/debuginfo.cpp +++ b/src/debuginfo.cpp @@ -145,8 +145,8 @@ struct unw_table_entry template static void jl_profile_atomic(T f) JL_NOTSAFEPOINT { - assert(0 == jl_lock_profile_rd_held()); - jl_lock_profile_wr(); + int havelock = jl_lock_profile_wr(); + assert(havelock); #ifndef _OS_WINDOWS_ sigset_t sset; sigset_t oset; @@ -157,7 +157,8 @@ static void jl_profile_atomic(T f) JL_NOTSAFEPOINT #ifndef _OS_WINDOWS_ pthread_sigmask(SIG_SETMASK, &oset, NULL); #endif - jl_unlock_profile_wr(); + if (havelock) + jl_unlock_profile_wr(); } @@ -464,8 +465,8 @@ static int lookup_pointer( // DWARFContext/DWARFUnit update some internal tables during these queries, so // a lock is needed. - assert(0 == jl_lock_profile_rd_held()); - jl_lock_profile_wr(); + if (!jl_lock_profile_wr()) + return lookup_pointer(object::SectionRef(), NULL, frames, pointer, slide, demangle, noInline); auto inlineInfo = context->getInliningInfoForAddress(makeAddress(Section, pointer + slide), infoSpec); jl_unlock_profile_wr(); @@ -490,7 +491,8 @@ static int lookup_pointer( info = inlineInfo.getFrame(i); } else { - jl_lock_profile_wr(); + int havelock = jl_lock_profile_wr(); + assert(havelock); (void)havelock; info = context->getLineInfoForAddress(makeAddress(Section, pointer + slide), infoSpec); jl_unlock_profile_wr(); } @@ -1195,8 +1197,8 @@ int jl_DI_for_fptr(uint64_t fptr, uint64_t *symsize, int64_t *slide, object::SectionRef *Section, llvm::DIContext **context) JL_NOTSAFEPOINT { int found = 0; - assert(0 == jl_lock_profile_rd_held()); - jl_lock_profile_wr(); + if (!jl_lock_profile_wr()) + return 0; if (symsize) *symsize = 0; diff --git a/src/julia_internal.h b/src/julia_internal.h index bf37716c1e3ae..f4ceb3113ee54 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -207,10 +207,9 @@ JL_DLLEXPORT double jl_get_profile_peek_duration(void); JL_DLLEXPORT void jl_set_profile_peek_duration(double); JL_DLLEXPORT void jl_init_profile_lock(void); -JL_DLLEXPORT uintptr_t jl_lock_profile_rd_held(void) JL_NOTSAFEPOINT; -JL_DLLEXPORT void jl_lock_profile(void) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_ENTER; +JL_DLLEXPORT int jl_lock_profile(void) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_ENTER; JL_DLLEXPORT void jl_unlock_profile(void) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_LEAVE; -JL_DLLEXPORT void jl_lock_profile_wr(void) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_ENTER; +JL_DLLEXPORT int jl_lock_profile_wr(void) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_ENTER; JL_DLLEXPORT void jl_unlock_profile_wr(void) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_LEAVE; void jl_with_stackwalk_lock(void (*f)(void*) JL_NOTSAFEPOINT, void *ctx) JL_NOTSAFEPOINT; diff --git a/src/signal-handling.c b/src/signal-handling.c index ff073cc82a0a5..6e19028ca7940 100644 --- a/src/signal-handling.c +++ b/src/signal-handling.c @@ -102,7 +102,7 @@ void jl_init_profile_lock(void) #endif } -uintptr_t jl_lock_profile_rd_held(void) +static uintptr_t jl_lock_profile_rd_held(void) JL_NOTSAFEPOINT { #ifndef _OS_WINDOWS_ return (uintptr_t)pthread_getspecific(debuginfo_asyncsafe_held); @@ -111,38 +111,69 @@ uintptr_t jl_lock_profile_rd_held(void) #endif } -void jl_lock_profile(void) +int jl_lock_profile(void) { uintptr_t held = jl_lock_profile_rd_held(); - if (held++ == 0) + if (held == -1) + return 0; + if (held == 0) { + held = -1; +#ifndef _OS_WINDOWS_ + pthread_setspecific(debuginfo_asyncsafe_held, (void*)held); +#else + TlsSetValue(debuginfo_asyncsafe_held, (void*)held); +#endif uv_rwlock_rdlock(&debuginfo_asyncsafe); + held = 0; + } + held++; #ifndef _OS_WINDOWS_ pthread_setspecific(debuginfo_asyncsafe_held, (void*)held); #else TlsSetValue(debuginfo_asyncsafe_held, (void*)held); #endif + return 1; } JL_DLLEXPORT void jl_unlock_profile(void) { uintptr_t held = jl_lock_profile_rd_held(); - assert(held); - if (--held == 0) - uv_rwlock_rdunlock(&debuginfo_asyncsafe); + assert(held && held != -1); + held--; #ifndef _OS_WINDOWS_ pthread_setspecific(debuginfo_asyncsafe_held, (void*)held); #else TlsSetValue(debuginfo_asyncsafe_held, (void*)held); #endif + if (held == 0) + uv_rwlock_rdunlock(&debuginfo_asyncsafe); } -void jl_lock_profile_wr(void) +int jl_lock_profile_wr(void) { + uintptr_t held = jl_lock_profile_rd_held(); + if (held) + return 0; + held = -1; +#ifndef _OS_WINDOWS_ + pthread_setspecific(debuginfo_asyncsafe_held, (void*)held); +#else + TlsSetValue(debuginfo_asyncsafe_held, (void*)held); +#endif uv_rwlock_wrlock(&debuginfo_asyncsafe); + return 1; } void jl_unlock_profile_wr(void) { + uintptr_t held = jl_lock_profile_rd_held(); + assert(held == -1); + held = 0; +#ifndef _OS_WINDOWS_ + pthread_setspecific(debuginfo_asyncsafe_held, (void*)held); +#else + TlsSetValue(debuginfo_asyncsafe_held, (void*)held); +#endif uv_rwlock_wrunlock(&debuginfo_asyncsafe); } diff --git a/src/threading.c b/src/threading.c index ecdc4ac1d51e8..4ab0f7630f560 100644 --- a/src/threading.c +++ b/src/threading.c @@ -554,18 +554,20 @@ static void jl_delete_thread(void *value) JL_NOTSAFEPOINT_ENTER // this here by blocking. This also synchronizes our read of `current_task` // (which is the flag we currently use to check the liveness state of a thread). #ifdef _OS_WINDOWS_ - jl_lock_profile_wr(); + int havelock = jl_lock_profile_wr(); + assert(havelock); (void)havelock; #elif defined(JL_DISABLE_LIBUNWIND) // nothing #elif defined(__APPLE__) - jl_lock_profile_wr(); + int havelock = jl_lock_profile_wr(); + assert(havelock); (void)havelock; #else pthread_mutex_lock(&in_signal_lock); #endif jl_atomic_store_relaxed(&ptls->current_task, NULL); // indicate dead // finally, release all of the locks we had grabbed #ifdef _OS_WINDOWS_ - jl_unlock_profile_wr(); + if (havelock) jl_unlock_profile_wr(); #elif defined(JL_DISABLE_LIBUNWIND) // nothing #elif defined(__APPLE__) From e358d9694ea64ddc6627e3b595e569c77b996b70 Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> Date: Fri, 2 May 2025 15:00:42 +0900 Subject: [PATCH 20/46] inference: prevent nested slot wrappers in abstract_call_builtin (#58249) --- Compiler/src/abstractinterpretation.jl | 9 +++++---- Compiler/test/inference.jl | 19 +++++++++++++++++-- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/Compiler/src/abstractinterpretation.jl b/Compiler/src/abstractinterpretation.jl index 3b9b5f34bf3cb..01faba6b37d1f 100644 --- a/Compiler/src/abstractinterpretation.jl +++ b/Compiler/src/abstractinterpretation.jl @@ -1402,8 +1402,9 @@ function matching_cache_argtypes(𝕃::AbstractLattice, mi::MethodInstance, if slotid !== nothing # using union-split signature, we may be able to narrow down `Conditional` sigt = widenconst(slotid > nargs ? argtypes[slotid] : cache_argtypes[slotid]) - thentype = tmeet(cnd.thentype, sigt) - elsetype = tmeet(cnd.elsetype, sigt) + ⊓ = meet(𝕃) + thentype = cnd.thentype ⊓ sigt + elsetype = cnd.elsetype ⊓ sigt if thentype === Bottom && elsetype === Bottom # we accidentally proved this method match is impossible # TODO bail out here immediately rather than just propagating Bottom ? @@ -2119,7 +2120,7 @@ function abstract_call_builtin(interp::AbstractInterpreter, f::Builtin, (; fargs else thentype = form_partially_defined_struct(argtype2, argtypes[3]) if thentype !== nothing - elsetype = argtype2 + elsetype = widenslotwrapper(argtype2) if rt === Const(false) thentype = Bottom elseif rt === Const(true) @@ -3229,7 +3230,7 @@ function abstract_eval_isdefined_expr(interp::AbstractInterpreter, e::Expr, ssta elseif !vtyp.undef rt = Const(true) # definitely assigned previously else # form `Conditional` to refine `vtyp.undef` in the then branch - rt = Conditional(sym, vtyp.typ, vtyp.typ; isdefined=true) + rt = Conditional(sym, widenslotwrapper(vtyp.typ), widenslotwrapper(vtyp.typ); isdefined=true) end return RTEffects(rt, Union{}, EFFECTS_TOTAL) end diff --git a/Compiler/test/inference.jl b/Compiler/test/inference.jl index e8a10d537c1ad..7eba4b683463c 100644 --- a/Compiler/test/inference.jl +++ b/Compiler/test/inference.jl @@ -2262,12 +2262,18 @@ struct AliasableFields{S,T} f1::S f2::T end +struct NullableAliasableFields{S,T} + f1::S + f2::T + NullableAliasableFields(f1::S, f2::T) where {S,T} = new{S,T}(f1, f2) + NullableAliasableFields(f1::S) where {S} = new{S,Union{}}(f1) +end mutable struct AliasableConstField{S,T} const f1::S f2::T end -import .Compiler: +using .Compiler: InferenceLattice, MustAliasesLattice, InterMustAliasesLattice, BaseInferenceLattice, SimpleInferenceLattice, IPOResultLattice, typeinf_lattice, ipo_lattice, optimizer_lattice @@ -2280,7 +2286,7 @@ Compiler.optimizer_lattice(::MustAliasInterpreter) = SimpleInferenceLattice.inst # lattice # ------- -import .Compiler: MustAlias, Const, PartialStruct, ⊑, tmerge +using .Compiler: MustAlias, Const, PartialStruct, ⊑, tmerge let 𝕃ᵢ = InferenceLattice(MustAliasesLattice(BaseInferenceLattice.instance)) ⊑(@nospecialize(a), @nospecialize(b)) = Compiler.:⊑(𝕃ᵢ, a, b) tmerge(@nospecialize(a), @nospecialize(b)) = Compiler.tmerge(𝕃ᵢ, a, b) @@ -2518,6 +2524,15 @@ jet509_hasitems(list) = length(list) >= 1 error("list is empty") end |> only == Vector{Int} +# don't form nested slot wrappers +@test Base.infer_return_type((NullableAliasableFields{NullableAliasableFields},); interp=MustAliasInterpreter()) do x + y = getfield(x, :f1) + if isdefined(y, :f2) && isa(getfield(y, :f2), Int) + return getfield(y, :f2) + end + return 0 +end == Int + # === constraint # -------------- From 4dde5ec6e96485f69e6119224b1fc763427bd082 Mon Sep 17 00:00:00 2001 From: DilumAluthgeBot <43731525+DilumAluthgeBot@users.noreply.github.com> Date: Tue, 27 May 2025 04:51:05 -0400 Subject: [PATCH 21/46] =?UTF-8?q?=F0=9F=A4=96=20[backports-release-1.12]?= =?UTF-8?q?=20Bump=20the=20LinearAlgebra=20stdlib=20from=204e7c3f4=20to=20?= =?UTF-8?q?7264a49=20(#58527)?= 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: 4e7c3f4 New commit: 7264a49 Julia version: 1.12.0-beta3 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/4e7c3f40316a956119ac419a97c4b8aad7a17e6c...7264a497869f2232eaa3d740ba3b145ade3fc9f4 ``` $ git log --oneline 4e7c3f4..7264a49 7264a49 Backports release 1.12 (#1353) ``` 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(-) delete mode 100644 deps/checksums/LinearAlgebra-4e7c3f40316a956119ac419a97c4b8aad7a17e6c.tar.gz/md5 delete mode 100644 deps/checksums/LinearAlgebra-4e7c3f40316a956119ac419a97c4b8aad7a17e6c.tar.gz/sha512 create mode 100644 deps/checksums/LinearAlgebra-7264a497869f2232eaa3d740ba3b145ade3fc9f4.tar.gz/md5 create mode 100644 deps/checksums/LinearAlgebra-7264a497869f2232eaa3d740ba3b145ade3fc9f4.tar.gz/sha512 diff --git a/deps/checksums/LinearAlgebra-4e7c3f40316a956119ac419a97c4b8aad7a17e6c.tar.gz/md5 b/deps/checksums/LinearAlgebra-4e7c3f40316a956119ac419a97c4b8aad7a17e6c.tar.gz/md5 deleted file mode 100644 index d96f9c1708089..0000000000000 --- a/deps/checksums/LinearAlgebra-4e7c3f40316a956119ac419a97c4b8aad7a17e6c.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -a622992fb673fc417e588f262b679b00 diff --git a/deps/checksums/LinearAlgebra-4e7c3f40316a956119ac419a97c4b8aad7a17e6c.tar.gz/sha512 b/deps/checksums/LinearAlgebra-4e7c3f40316a956119ac419a97c4b8aad7a17e6c.tar.gz/sha512 deleted file mode 100644 index ba63ad3cb9264..0000000000000 --- a/deps/checksums/LinearAlgebra-4e7c3f40316a956119ac419a97c4b8aad7a17e6c.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -48ce73841c0a766d0e0310beac77033a694f7fcc30b939241d0c04f35f079dd8f932f1973c002180f178a9f2bdf99535f09bea4f20151e09948f21549bfa1490 diff --git a/deps/checksums/LinearAlgebra-7264a497869f2232eaa3d740ba3b145ade3fc9f4.tar.gz/md5 b/deps/checksums/LinearAlgebra-7264a497869f2232eaa3d740ba3b145ade3fc9f4.tar.gz/md5 new file mode 100644 index 0000000000000..809e00b6e137d --- /dev/null +++ b/deps/checksums/LinearAlgebra-7264a497869f2232eaa3d740ba3b145ade3fc9f4.tar.gz/md5 @@ -0,0 +1 @@ +1e348930bff6c7075dd4a5a29a24ab60 diff --git a/deps/checksums/LinearAlgebra-7264a497869f2232eaa3d740ba3b145ade3fc9f4.tar.gz/sha512 b/deps/checksums/LinearAlgebra-7264a497869f2232eaa3d740ba3b145ade3fc9f4.tar.gz/sha512 new file mode 100644 index 0000000000000..411324a140622 --- /dev/null +++ b/deps/checksums/LinearAlgebra-7264a497869f2232eaa3d740ba3b145ade3fc9f4.tar.gz/sha512 @@ -0,0 +1 @@ +f362aa184dcfa71dbca347ae91784a83ec8317bef6b5a31ee9be9318f1d2a6cbc89283421661f916fc8478d9143f4d7f1a0ce3e54fbb64d7e98156050b80a333 diff --git a/stdlib/LinearAlgebra.version b/stdlib/LinearAlgebra.version index 0aa71a8804660..ae590e6655aa8 100644 --- a/stdlib/LinearAlgebra.version +++ b/stdlib/LinearAlgebra.version @@ -1,4 +1,4 @@ LINEARALGEBRA_BRANCH = release-1.12 -LINEARALGEBRA_SHA1 = 4e7c3f40316a956119ac419a97c4b8aad7a17e6c +LINEARALGEBRA_SHA1 = 7264a497869f2232eaa3d740ba3b145ade3fc9f4 LINEARALGEBRA_GIT_URL := https://github.com/JuliaLang/LinearAlgebra.jl.git LINEARALGEBRA_TAR_URL = https://api.github.com/repos/JuliaLang/LinearAlgebra.jl/tarball/$1 From 92dbdad5ede28cbd45a4025276a0eb3fc787fd83 Mon Sep 17 00:00:00 2001 From: Gabriel Baraldi Date: Wed, 21 May 2025 23:46:59 -0300 Subject: [PATCH 22/46] Fix tbaa usage when storing into heap allocated immutable structs (#58483) (cherry picked from commit e3982cd84030e4baf7b8e97119bbeec0fa982935) --- Compiler/test/codegen.jl | 22 ++++++++++++++++++++++ src/cgutils.cpp | 4 ++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/Compiler/test/codegen.jl b/Compiler/test/codegen.jl index 8f5a47c5efa62..7c985727d001f 100644 --- a/Compiler/test/codegen.jl +++ b/Compiler/test/codegen.jl @@ -1036,3 +1036,25 @@ f57872() = (Core.isdefinedglobal(@__MODULE__, Base.compilerbarrier(:const, :x578 @noinline f_mutateany(@nospecialize x) = x[] = 1 g_mutateany() = (y = Ref(0); f_mutateany(y); y[]) @test g_mutateany() === 1 + +# 58470 tbaa for unionselbyte of heap allocated mutables +mutable struct Wrapper58470 + x::Union{Nothing,Int} +end + +function findsomething58470(dict, inds) + default = Wrapper58470(nothing) + for i in inds + x = get(dict, i, default).x + if !isnothing(x) + return x + end + end + return nothing +end + +let io = IOBuffer() + code_llvm(io, findsomething58470, Tuple{Dict{Int64, Wrapper58470}, Vector{Int}}, dump_module=true, raw=true, optimize=false) + str = String(take!(io)) + @test !occursin("jtbaa_unionselbyte", str) +end diff --git a/src/cgutils.cpp b/src/cgutils.cpp index f3425d058841a..beaad5f85fec3 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -4083,7 +4083,7 @@ static jl_cgval_t emit_setfield(jl_codectx_t &ctx, size_t fsz1 = jl_field_size(sty, idx0) - 1; Value *ptindex = emit_ptrgep(ctx, addr, fsz1); setNameWithField(ctx.emission_context, ptindex, get_objname, sty, idx0, Twine(".tindex_ptr")); - return union_store(ctx, addr, ptindex, rhs, cmp, jfty, tbaa, ctx.tbaa().tbaa_unionselbyte, + return union_store(ctx, addr, ptindex, rhs, cmp, jfty, tbaa, strct.tbaa, Order, FailOrder, needlock, issetfield, isreplacefield, isswapfield, ismodifyfield, issetfieldonce, modifyop, fname); @@ -4351,7 +4351,7 @@ static jl_cgval_t emit_new_struct(jl_codectx_t &ctx, jl_value_t *ty, size_t narg undef_derived_strct(ctx, strct, sty, strctinfo.tbaa); for (size_t i = nargs; i < nf; i++) { if (!jl_field_isptr(sty, i) && jl_is_uniontype(jl_field_type(sty, i))) { - jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_unionselbyte); + jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA(ctx, strctinfo.tbaa); ai.decorateInst(ctx.builder.CreateAlignedStore( ConstantInt::get(getInt8Ty(ctx.builder.getContext()), 0), emit_ptrgep(ctx, strct, jl_field_offset(sty, i) + jl_field_size(sty, i) - 1), From 9fce6367eaeb7f91867607aa412f6467c46d4f60 Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Tue, 20 May 2025 15:53:25 -0500 Subject: [PATCH 23/46] Add some loading precompiles (#58473) (cherry picked from commit 4d96cb43ab1efafa323256a545a63a7b51a2c32f) --- contrib/generate_precompile.jl | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/contrib/generate_precompile.jl b/contrib/generate_precompile.jl index 46827f20453ba..d84757faaf8a4 100644 --- a/contrib/generate_precompile.jl +++ b/contrib/generate_precompile.jl @@ -34,13 +34,22 @@ hardcoded_precompile_statements = """ precompile(Base.unsafe_string, (Ptr{UInt8},)) precompile(Base.unsafe_string, (Ptr{Int8},)) -# loading.jl +# loading.jl - without these each precompile worker would precompile these because they're hit before pkgimages are loaded precompile(Base.__require, (Module, Symbol)) precompile(Base.__require, (Base.PkgId,)) precompile(Base.indexed_iterate, (Pair{Symbol, Union{Nothing, String}}, Int)) precompile(Base.indexed_iterate, (Pair{Symbol, Union{Nothing, String}}, Int, Int)) precompile(Tuple{typeof(Base.Threads.atomic_add!), Base.Threads.Atomic{Int}, Int}) precompile(Tuple{typeof(Base.Threads.atomic_sub!), Base.Threads.Atomic{Int}, Int}) +precompile(Tuple{Type{Pair{A, B} where B where A}, Base.PkgId, UInt128}) +precompile(Tuple{typeof(Base.in!), Tuple{Module, String, UInt64, UInt32, Float64}, Base.Set{Any}}) +precompile(Tuple{typeof(Core.kwcall), NamedTuple{(:allow_typevars, :volatile_inf_result), Tuple{Bool, Nothing}}, typeof(Base.Compiler.handle_match!), Array{Base.Compiler.InliningCase, 1}, Core.MethodMatch, Array{Any, 1}, Base.Compiler.CallInfo, UInt32, Base.Compiler.InliningState{Base.Compiler.NativeInterpreter}}) +precompile(Tuple{typeof(Base.Compiler.ir_to_codeinf!), Base.Compiler.OptimizationState{Base.Compiler.NativeInterpreter}}) +precompile(Tuple{typeof(Core.kwcall), NamedTuple{(:allow_typevars, :volatile_inf_result), Tuple{Bool, Base.Compiler.VolatileInferenceResult}}, typeof(Base.Compiler.handle_match!), Array{Base.Compiler.InliningCase, 1}, Core.MethodMatch, Array{Any, 1}, Base.Compiler.CallInfo, UInt32, Base.Compiler.InliningState{Base.Compiler.NativeInterpreter}}) +precompile(Tuple{typeof(Base.getindex), Type{Pair{Base.PkgId, UInt128}}, Pair{Base.PkgId, UInt128}, Pair{Base.PkgId, UInt128}, Pair{Base.PkgId, UInt128}, Vararg{Pair{Base.PkgId, UInt128}}}) +precompile(Tuple{typeof(Base.Compiler.ir_to_codeinf!), Base.Compiler.OptimizationState{Base.Compiler.NativeInterpreter}, Core.SimpleVector}) +precompile(Tuple{typeof(Base.Compiler.ir_to_codeinf!), Base.Compiler.OptimizationState{Base.Compiler.NativeInterpreter}}) +precompile(Tuple{Base.IncludeInto, RelocatableFolders.Path}) # LazyArtifacts (but more generally helpful) precompile(Tuple{Type{Base.Val{x} where x}, Module}) @@ -217,6 +226,7 @@ if Artifacts !== nothing """ hardcoded_precompile_statements *= """ precompile(Tuple{typeof(Artifacts._artifact_str), Module, String, Base.SubString{String}, String, Base.Dict{String, Any}, Base.SHA1, Base.BinaryPlatforms.Platform, Base.Val{Artifacts}}) + precompile(Tuple{typeof(Base.tryparse), Type{Base.BinaryPlatforms.Platform}, String}) """ end From 29c5883fe816a4002b69fde7fceaee8d9c7ff4d1 Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Tue, 20 May 2025 20:01:09 -0500 Subject: [PATCH 24/46] Fail when precompiles fail during build on CI (and fix bad precompile) (#58474) (cherry picked from commit 720d0f5fa08d46017075e6159aea9a5d56935cf5) --- contrib/generate_precompile.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contrib/generate_precompile.jl b/contrib/generate_precompile.jl index d84757faaf8a4..01c32593a72c5 100644 --- a/contrib/generate_precompile.jl +++ b/contrib/generate_precompile.jl @@ -49,7 +49,6 @@ precompile(Tuple{typeof(Core.kwcall), NamedTuple{(:allow_typevars, :volatile_inf precompile(Tuple{typeof(Base.getindex), Type{Pair{Base.PkgId, UInt128}}, Pair{Base.PkgId, UInt128}, Pair{Base.PkgId, UInt128}, Pair{Base.PkgId, UInt128}, Vararg{Pair{Base.PkgId, UInt128}}}) precompile(Tuple{typeof(Base.Compiler.ir_to_codeinf!), Base.Compiler.OptimizationState{Base.Compiler.NativeInterpreter}, Core.SimpleVector}) precompile(Tuple{typeof(Base.Compiler.ir_to_codeinf!), Base.Compiler.OptimizationState{Base.Compiler.NativeInterpreter}}) -precompile(Tuple{Base.IncludeInto, RelocatableFolders.Path}) # LazyArtifacts (but more generally helpful) precompile(Tuple{Type{Base.Val{x} where x}, Module}) @@ -400,6 +399,7 @@ generate_precompile_statements() = try # Make sure `ansi_enablecursor` is printe if precompile(ps...) n_succeeded += 1 else + Base.get_bool_env("CI", false) && error("Precompilation failed for $statement") @warn "Failed to precompile expression" form=statement _module=nothing _file=nothing _line=0 end failed = length(statements) - n_succeeded @@ -407,6 +407,7 @@ generate_precompile_statements() = try # Make sure `ansi_enablecursor` is printe print_state("step3" => string("R$n_succeeded", failed > 0 ? " ($failed failed)" : "")) catch ex # See #28808 + Base.get_bool_env("CI", false) && error("Precompilation failed for $statement") @warn "Failed to precompile expression" form=statement exception=(ex,catch_backtrace()) _module=nothing _file=nothing _line=0 end end From 3c4d20722a9f21a3e0fd38243fdb76c562e9509c Mon Sep 17 00:00:00 2001 From: Erik Schnetter Date: Thu, 22 May 2025 14:30:39 -0400 Subject: [PATCH 25/46] MozillaCACerts: Update to 2025-05-20 (#58496) (cherry picked from commit 053c739862919545f6e04e2a488c3692e881e7f4) --- deps/checksums/cacert-2025-02-25.pem/md5 | 1 - deps/checksums/cacert-2025-02-25.pem/sha512 | 1 - deps/checksums/cacert-2025-05-20.pem/md5 | 1 + deps/checksums/cacert-2025-05-20.pem/sha512 | 1 + deps/libgit2.version | 2 +- stdlib/MozillaCACerts_jll/Project.toml | 2 +- 6 files changed, 4 insertions(+), 4 deletions(-) delete mode 100644 deps/checksums/cacert-2025-02-25.pem/md5 delete mode 100644 deps/checksums/cacert-2025-02-25.pem/sha512 create mode 100644 deps/checksums/cacert-2025-05-20.pem/md5 create mode 100644 deps/checksums/cacert-2025-05-20.pem/sha512 diff --git a/deps/checksums/cacert-2025-02-25.pem/md5 b/deps/checksums/cacert-2025-02-25.pem/md5 deleted file mode 100644 index 3dced8d2bee6b..0000000000000 --- a/deps/checksums/cacert-2025-02-25.pem/md5 +++ /dev/null @@ -1 +0,0 @@ -1a7de82bb9f0fcc779ca18a7a9310898 diff --git a/deps/checksums/cacert-2025-02-25.pem/sha512 b/deps/checksums/cacert-2025-02-25.pem/sha512 deleted file mode 100644 index bb59a65af401e..0000000000000 --- a/deps/checksums/cacert-2025-02-25.pem/sha512 +++ /dev/null @@ -1 +0,0 @@ -e5fe41820460e6b65e8cd463d1a5f01b7103e1ef66cb75fedc15ebcba3ba6600d77e5e7c2ab94cbb1f11c63b688026a04422bbe2d7a861f7a988f67522ffae3c diff --git a/deps/checksums/cacert-2025-05-20.pem/md5 b/deps/checksums/cacert-2025-05-20.pem/md5 new file mode 100644 index 0000000000000..06a21e784fc78 --- /dev/null +++ b/deps/checksums/cacert-2025-05-20.pem/md5 @@ -0,0 +1 @@ +a4e2b0c77e807b80a4b8a58c411e4a15 diff --git a/deps/checksums/cacert-2025-05-20.pem/sha512 b/deps/checksums/cacert-2025-05-20.pem/sha512 new file mode 100644 index 0000000000000..4e5117cbf9f49 --- /dev/null +++ b/deps/checksums/cacert-2025-05-20.pem/sha512 @@ -0,0 +1 @@ +97bc802a7c055e6e58384920feb593596bc30bc9493a7550a168f4d7337d34166dc8f350713c468c605f81ed1c3b6380050f04e31b86b4877c9de90ce3512867 diff --git a/deps/libgit2.version b/deps/libgit2.version index 3f1f7a66fe972..ffba640e3b24e 100644 --- a/deps/libgit2.version +++ b/deps/libgit2.version @@ -11,4 +11,4 @@ LIBGIT2_SHA1=338e6fb681369ff0537719095e22ce9dc602dbf0 # The versions of cacert.pem are identified by the date (YYYY-MM-DD) of their changes. # See https://curl.haxx.se/docs/caextract.html for more details. # Keep in sync with `stdlib/MozillaCACerts_jll/Project.toml`. -MOZILLA_CACERT_VERSION := 2025-02-25 +MOZILLA_CACERT_VERSION := 2025-05-20 diff --git a/stdlib/MozillaCACerts_jll/Project.toml b/stdlib/MozillaCACerts_jll/Project.toml index a951435168922..57c5526a6f1f2 100644 --- a/stdlib/MozillaCACerts_jll/Project.toml +++ b/stdlib/MozillaCACerts_jll/Project.toml @@ -1,7 +1,7 @@ name = "MozillaCACerts_jll" uuid = "14a3606d-f60d-562e-9121-12d972cd8159" # Keep in sync with `deps/libgit2.version`. -version = "2025.02.25" +version = "2025.05.20" [extras] Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" From f7136c98d8deebdd58fa520209aafc9d80744f1e Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Thu, 22 May 2025 17:00:12 -0400 Subject: [PATCH 26/46] don't strip keyword argument names with --strip-metadata (#58412) These are used by `hasmethod`, and in any case including keyword argument symbols is unavoidable so there is no cost to keeping these. (cherry picked from commit c5df01807e3b3549b2669afdea11526b80049f3a) --- src/staticdata.c | 14 +++++++++----- test/cmdlineargs.jl | 10 ++++++++++ 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/staticdata.c b/src/staticdata.c index eac3bba62f01a..1ed933107dd46 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -2612,12 +2612,12 @@ static void jl_prune_module_bindings(jl_module_t * m) JL_GC_DISABLED jl_gc_wb(m, jl_atomic_load_relaxed(&bindingkeyset2)); } -static void strip_slotnames(jl_array_t *slotnames) +static void strip_slotnames(jl_array_t *slotnames, int n) { // replace slot names with `?`, except unused_sym since the compiler looks at it jl_sym_t *questionsym = jl_symbol("?"); - int i, l = jl_array_len(slotnames); - for (i = 0; i < l; i++) { + int i; + for (i = 0; i < n; i++) { jl_value_t *s = jl_array_ptr_ref(slotnames, i); if (s != (jl_value_t*)jl_unused_sym) jl_array_ptr_set(slotnames, i, questionsym); @@ -2636,7 +2636,7 @@ static jl_value_t *strip_codeinfo_meta(jl_method_t *m, jl_value_t *ci_, jl_code_ else { ci = (jl_code_info_t*)ci_; } - strip_slotnames(ci->slotnames); + strip_slotnames(ci->slotnames, jl_array_len(ci->slotnames)); ci->debuginfo = jl_nulldebuginfo; jl_gc_wb(ci, ci->debuginfo); jl_value_t *ret = (jl_value_t*)ci; @@ -2710,7 +2710,11 @@ static int strip_all_codeinfos__(jl_typemap_entry_t *def, void *_env) } jl_array_t *slotnames = jl_uncompress_argnames(m->slot_syms); JL_GC_PUSH1(&slotnames); - strip_slotnames(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)) + tostrip = m->nargs; + strip_slotnames(slotnames, tostrip); m->slot_syms = jl_compress_argnames(slotnames); jl_gc_wb(m, m->slot_syms); JL_GC_POP(); diff --git a/test/cmdlineargs.jl b/test/cmdlineargs.jl index 7934d9c60d54d..f5325c9eb67ce 100644 --- a/test/cmdlineargs.jl +++ b/test/cmdlineargs.jl @@ -1271,3 +1271,13 @@ end timeout = 120 @test parse(Int,read(`$exename --timeout-for-safepoint-straggler=$timeout -E "Base.JLOptions().timeout_for_safepoint_straggler_s"`, String)) == timeout end + +@testset "--strip-metadata" begin + mktempdir() do dir + @test success(pipeline(`$(Base.julia_cmd()) --strip-metadata -t1,0 --output-o $(dir)/sys.o.a -e 0`, stderr=stderr, stdout=stdout)) + if isfile(joinpath(dir, "sys.o.a")) + Base.Linking.link_image(joinpath(dir, "sys.o.a"), joinpath(dir, "sys.so")) + @test readchomp(`$(Base.julia_cmd()) -t1,0 -J $(dir)/sys.so -E 'hasmethod(sort, (Vector{Int},), (:dims,))'`) == "true" + end + end +end From 4d6feceaa950d936111382cff8926f3cab6eab12 Mon Sep 17 00:00:00 2001 From: Cody Tapscott <84105208+topolarity@users.noreply.github.com> Date: Tue, 27 May 2025 09:00:44 -0400 Subject: [PATCH 27/46] Don't filter `Core` methods from newly-inferred list (#58510) This allows constructors like `Tuple{Type{Vector{Foo}}, UndefInitializer, Tuple{Int}}` to precompile as usual Appears to have a minimal effect on the stdlib pkgimages: ```julia --- before.txt 2025-05-23 08:36:20.171870043 -0400 +++ after.txt 2025-05-22 14:48:49.003869097 -0400 @@ -47,7 +47,7 @@ 20K ../julia/usr/share/julia/compiled/v1.13/Logging/pkgimage.so 20K ../julia/usr/share/julia/compiled/v1.13/Logging/pkgimage.so 3.5M ../julia/usr/share/julia/compiled/v1.13/Markdown/pkgimage.so -3.5M ../julia/usr/share/julia/compiled/v1.13/Markdown/pkgimage.so +3.6M ../julia/usr/share/julia/compiled/v1.13/Markdown/pkgimage.so 184K ../julia/usr/share/julia/compiled/v1.13/Mmap/pkgimage.so 184K ../julia/usr/share/julia/compiled/v1.13/Mmap/pkgimage.so 28K ../julia/usr/share/julia/compiled/v1.13/MozillaCACerts_jll/pkgimage.so ``` Resolves #58497. (cherry picked from commit f8ece052b0ad98ed27316b63218b32c0877e69da) --- Compiler/src/cicache.jl | 2 +- test/precompile.jl | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/Compiler/src/cicache.jl b/Compiler/src/cicache.jl index 9c528bc0ae822..4d188dbbc3450 100644 --- a/Compiler/src/cicache.jl +++ b/Compiler/src/cicache.jl @@ -14,7 +14,7 @@ end function setindex!(cache::InternalCodeCache, ci::CodeInstance, mi::MethodInstance) @assert ci.owner === cache.owner m = mi.def - if isa(m, Method) && m.module != Core + if isa(m, Method) ccall(:jl_push_newly_inferred, Cvoid, (Any,), ci) end ccall(:jl_mi_cache_insert, Cvoid, (Any, Any), mi, ci) diff --git a/test/precompile.jl b/test/precompile.jl index 18e66e3172d2d..c1ac8e03b2d1a 100644 --- a/test/precompile.jl +++ b/test/precompile.jl @@ -2119,6 +2119,29 @@ precompile_test_harness("No backedge precompile") do load_path end end +precompile_test_harness("Pre-compile Core methods") do load_path + # Core methods should support pre-compilation as external CI's like anything else + # https://github.com/JuliaLang/julia/issues/58497 + write(joinpath(load_path, "CorePrecompilation.jl"), + """ + module CorePrecompilation + struct Foo end + precompile(Tuple{Type{Vector{Foo}}, UndefInitializer, Tuple{Int}}) + end + """) + ji, ofile = Base.compilecache(Base.PkgId("CorePrecompilation")) + @eval using CorePrecompilation + invokelatest() do + let tt = Tuple{Type{Vector{CorePrecompilation.Foo}}, UndefInitializer, Tuple{Int}}, + match = first(Base._methods_by_ftype(tt, -1, Base.get_world_counter())), + mi = Base.specialize_method(match) + @test isdefined(mi, :cache) + @test mi.cache.max_world === typemax(UInt) + @test mi.cache.invoke != C_NULL + end + end +end + # Test precompilation of generated functions that return opaque closures # (with constprop marker set to false). precompile_test_harness("Generated Opaque") do load_path From 4589ed03a7a6fe8c1bb4ee35a7c19b970cd71495 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Tue, 27 May 2025 10:39:35 -0400 Subject: [PATCH 28/46] avoid error just computing coverage of generated functions (#58488) We only put debuginfo here if we ran the optimizer, so if there isn't debuginfo here, then we either didn't run the optimizer or were the result of const-prop. In the former case, we don't need to invalidate the code for instrumentation (it cannot have code from it). In the later case, we should already have an edge from the non-const-prop result. This only matters for generated functions, since otherwise we have Method's source's accurate debuginfo already and this is just a duplicate reference to it. Fix #58227 (cherry picked from commit d5442db00dbdc36d8bffbb528207b95fcceb48ef) --- base/staticdata.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/base/staticdata.jl b/base/staticdata.jl index 0b65d97750194..c9983c72064de 100644 --- a/base/staticdata.jl +++ b/base/staticdata.jl @@ -91,9 +91,9 @@ end function needs_instrumentation(codeinst::CodeInstance, mi::MethodInstance, def::Method, validation_world::UInt) if JLOptions().code_coverage != 0 || JLOptions().malloc_log != 0 # test if the code needs to run with instrumentation, in which case we cannot use existing generated code - if isdefined(def, :debuginfo) ? # generated_only functions do not have debuginfo, so fall back to considering their codeinst debuginfo though this may be slower (and less accurate?) + if isdefined(def, :debuginfo) ? # generated_only functions do not have debuginfo, so fall back to considering their codeinst debuginfo though this may be slower and less reliable Compiler.should_instrument(def.module, def.debuginfo) : - Compiler.should_instrument(def.module, codeinst.debuginfo) + isdefined(codeinst, :debuginfo) && Compiler.should_instrument(def.module, codeinst.debuginfo) return true end gensig = gen_staged_sig(def, mi) From a430f2e2cee82c58deb68af77080ea8eb001abae Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Wed, 28 May 2025 00:46:03 -0400 Subject: [PATCH 29/46] docs: Add missing compat annotation for `isdefinedglobal` (#58542) Add missing compatibility annotation for `isdefinedglobal`. Fixes #58528. (cherry picked from commit 953903b05d16bba5ebab10eec85e83b791eea5c3) --- base/docs/basedocs.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/base/docs/basedocs.jl b/base/docs/basedocs.jl index 88ed34de02b64..83e0bab4cc730 100644 --- a/base/docs/basedocs.jl +++ b/base/docs/basedocs.jl @@ -2796,6 +2796,9 @@ a value set. If `allow_import` is `false`, the global variable must be defined inside `m` and may not be imported from another module. +!!! compat "Julia 1.12" + This function requires Julia 1.12 or later. + See also [`@isdefined`](@ref). # Examples From 1628ac834e8f87307c9c5c79abb872b58f735557 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Wed, 14 May 2025 10:06:32 -0400 Subject: [PATCH 30/46] fix isconst definition/accessor issues with binding partitions (#58261) (cherry picked from commit 58daba4765a46ef13a7f1b04d05e2e277aaf60ae) --- src/codegen.cpp | 4 ++-- src/gf.c | 2 +- src/julia.h | 6 +++--- src/julia_internal.h | 4 ++++ src/method.c | 2 +- src/module.c | 36 ++++++++++++++++++------------------ src/rtutils.c | 4 ++-- src/toplevel.c | 2 +- test/syntax.jl | 2 +- 9 files changed, 33 insertions(+), 29 deletions(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index ee40596a82701..6f6328c2a5758 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3240,7 +3240,7 @@ static jl_cgval_t emit_globalref(jl_codectx_t &ctx, jl_module_t *mod, jl_sym_t * if (!jl_get_binding_leaf_partitions_restriction_kind(bnd, &rkp, ctx.min_world, ctx.max_world)) { return emit_globalref_runtime(ctx, bnd, mod, name); } - if (jl_bkind_is_some_constant(rkp.kind) && rkp.kind != PARTITION_KIND_BACKDATED_CONST) { + if (jl_bkind_is_real_constant(rkp.kind) || rkp.kind == PARTITION_KIND_UNDEF_CONST) { if (rkp.maybe_depwarn) { Value *bp = julia_binding_gv(ctx, bnd); ctx.builder.CreateCall(prepare_call(jldepcheck_func), { bp }); @@ -3826,7 +3826,7 @@ static jl_cgval_t emit_isdefinedglobal(jl_codectx_t &ctx, jl_module_t *modu, jl_ jl_binding_t *bnd = allow_import ? jl_get_binding(modu, name) : jl_get_module_binding(modu, name, 0); struct restriction_kind_pair rkp = { NULL, NULL, PARTITION_KIND_GUARD, 0 }; if (allow_import && jl_get_binding_leaf_partitions_restriction_kind(bnd, &rkp, ctx.min_world, ctx.max_world)) { - if (jl_bkind_is_some_constant(rkp.kind) && rkp.restriction) + if (jl_bkind_is_real_constant(rkp.kind)) return mark_julia_const(ctx, jl_true); if (rkp.kind == PARTITION_KIND_GLOBAL) { Value *bp = julia_binding_gv(ctx, rkp.binding_if_global); diff --git a/src/gf.c b/src/gf.c index f1deffc954b41..7b2f996563dda 100644 --- a/src/gf.c +++ b/src/gf.c @@ -780,7 +780,7 @@ int foreach_mtable_in_module( if ((void*)b == jl_nothing) break; jl_sym_t *name = b->globalref->name; - jl_value_t *v = jl_get_binding_value_if_const(b); + 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)) { diff --git a/src/julia.h b/src/julia.h index 13348fa9b153d..1d7e599302e69 100644 --- a/src/julia.h +++ b/src/julia.h @@ -1956,9 +1956,9 @@ JL_DLLEXPORT jl_sym_t *jl_tagged_gensym(const char *str, size_t len); JL_DLLEXPORT jl_sym_t *jl_get_root_symbol(void); JL_DLLEXPORT jl_value_t *jl_get_binding_value(jl_binding_t *b JL_PROPAGATES_ROOT); JL_DLLEXPORT jl_value_t *jl_get_binding_value_in_world(jl_binding_t *b JL_PROPAGATES_ROOT, size_t world); -JL_DLLEXPORT jl_value_t *jl_get_binding_value_if_const(jl_binding_t *b JL_PROPAGATES_ROOT); -JL_DLLEXPORT jl_value_t *jl_get_binding_value_if_resolved_debug_only(jl_binding_t *b JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT; -JL_DLLEXPORT jl_value_t *jl_get_binding_value_if_latest_resolved_and_const_debug_only(jl_binding_t *b JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_get_latest_binding_value_if_const(jl_binding_t *b JL_PROPAGATES_ROOT); +JL_DLLEXPORT jl_value_t *jl_get_latest_binding_value_if_resolved_debug_only(jl_binding_t *b JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_get_latest_binding_value_if_resolved_and_const_debug_only(jl_binding_t *b JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT; JL_DLLEXPORT jl_value_t *jl_declare_const_gf(jl_module_t *mod, jl_sym_t *name); JL_DLLEXPORT jl_method_t *jl_method_def(jl_svec_t *argdata, jl_methtable_t *mt, jl_code_info_t *f, jl_module_t *module); JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *linfo, size_t world, jl_code_instance_t **cache); diff --git a/src/julia_internal.h b/src/julia_internal.h index f4ceb3113ee54..8a4b9d42c4c20 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -989,6 +989,10 @@ STATIC_INLINE int jl_bkind_is_defined_constant(enum jl_partition_kind kind) JL_N return kind == PARTITION_KIND_IMPLICIT_CONST || kind == PARTITION_KIND_CONST || kind == PARTITION_KIND_CONST_IMPORT || kind == PARTITION_KIND_BACKDATED_CONST; } +STATIC_INLINE int jl_bkind_is_real_constant(enum jl_partition_kind kind) JL_NOTSAFEPOINT { + return kind == PARTITION_KIND_IMPLICIT_CONST || kind == PARTITION_KIND_CONST || kind == PARTITION_KIND_CONST_IMPORT; +} + JL_DLLEXPORT jl_binding_partition_t *jl_get_binding_partition(jl_binding_t *b JL_PROPAGATES_ROOT, size_t world) JL_GLOBALLY_ROOTED; JL_DLLEXPORT jl_binding_partition_t *jl_get_binding_partition_with_hint(jl_binding_t *b JL_PROPAGATES_ROOT, jl_binding_partition_t *previous_part, size_t world) JL_GLOBALLY_ROOTED; JL_DLLEXPORT jl_binding_partition_t *jl_get_binding_partition_all(jl_binding_t *b JL_PROPAGATES_ROOT, size_t min_world, size_t max_world) JL_GLOBALLY_ROOTED; diff --git a/src/method.c b/src/method.c index 1f195a5eef979..09d9eae9ad037 100644 --- a/src/method.c +++ b/src/method.c @@ -225,7 +225,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_binding_value_if_const(b) == jl_builtin_tuple) { + if (jl_get_latest_binding_value_if_const(b) == jl_builtin_tuple) { size_t j; for (j = 1; j < nargs; j++) { if (!jl_is_quotenode(jl_exprarg(e, j))) diff --git a/src/module.c b/src/module.c index 9a456de0b11d8..0bfa2148f5465 100644 --- a/src/module.c +++ b/src/module.c @@ -463,7 +463,7 @@ JL_DLLEXPORT jl_value_t *jl_get_binding_leaf_partitions_value_if_const(jl_bindin struct restriction_kind_pair rkp = { NULL, NULL, PARTITION_KIND_GUARD, 0 }; if (!jl_get_binding_leaf_partitions_restriction_kind(b, &rkp, min_world, max_world)) return NULL; - if (jl_bkind_is_some_constant(rkp.kind) && rkp.kind != PARTITION_KIND_BACKDATED_CONST) { + if (jl_bkind_is_real_constant(rkp.kind)) { *maybe_depwarn = rkp.maybe_depwarn; return rkp.restriction; } @@ -581,7 +581,7 @@ JL_DLLEXPORT jl_binding_partition_t *jl_declare_constant_val3( for (;;) { enum jl_partition_kind prev_kind = jl_binding_kind(prev_bpart); if (jl_bkind_is_some_constant(prev_kind) || prev_kind == PARTITION_KIND_GLOBAL || - (jl_bkind_is_some_import(prev_kind))) { + jl_bkind_is_some_import(prev_kind)) { need_backdate = 0; break; } @@ -923,22 +923,23 @@ JL_DLLEXPORT jl_value_t *jl_get_binding_value_seqcst(jl_binding_t *b) return jl_atomic_load(&b->value); } -JL_DLLEXPORT jl_value_t *jl_get_binding_value_if_const(jl_binding_t *b) +JL_DLLEXPORT jl_value_t *jl_get_latest_binding_value_if_const(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); + // 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); + 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; - if (!jl_bkind_is_some_constant(kind)) + if (!jl_bkind_is_real_constant(kind)) return NULL; - check_backdated_binding(b, kind); return bpart->restriction; } -JL_DLLEXPORT jl_value_t *jl_get_binding_value_if_latest_resolved_and_const_debug_only(jl_binding_t *b) +JL_DLLEXPORT jl_value_t *jl_get_latest_binding_value_if_resolved_and_const_debug_only(jl_binding_t *b) { - // Unlike jl_get_binding_value_if_const this doesn't try to allocate new binding partitions if they + // Unlike jl_get_latest_binding_value_if_const this doesn't try to allocate new binding partitions if they // don't already exist, making this JL_NOTSAFEPOINT. However, as a result, this may fail to return // a value - even if one does exist. It should only be used for reflection/debugging when the integrity // of the runtime is not guaranteed. @@ -948,18 +949,17 @@ JL_DLLEXPORT jl_value_t *jl_get_binding_value_if_latest_resolved_and_const_debug if (!bpart) return NULL; size_t max_world = jl_atomic_load_relaxed(&bpart->max_world); - if (jl_atomic_load_relaxed(&bpart->min_world) > jl_current_task->world_age || jl_current_task->world_age > max_world) + if (max_world != ~(size_t)0) return NULL; enum jl_partition_kind kind = jl_binding_kind(bpart); if (jl_bkind_is_some_guard(kind)) return NULL; - if (!jl_bkind_is_some_constant(kind)) + if (!jl_bkind_is_real_constant(kind)) return NULL; - check_backdated_binding(b, kind); return bpart->restriction; } -JL_DLLEXPORT jl_value_t *jl_get_binding_value_if_resolved_debug_only(jl_binding_t *b) +JL_DLLEXPORT jl_value_t *jl_get_latest_binding_value_if_resolved_debug_only(jl_binding_t *b) { // See note above. Use for debug/reflection purposes only. if (!b) @@ -968,7 +968,7 @@ JL_DLLEXPORT jl_value_t *jl_get_binding_value_if_resolved_debug_only(jl_binding_ if (!bpart) return NULL; size_t max_world = jl_atomic_load_relaxed(&bpart->max_world); - if (jl_atomic_load_relaxed(&bpart->min_world) > jl_current_task->world_age || jl_current_task->world_age > max_world) + if (max_world != ~(size_t)0) return NULL; enum jl_partition_kind kind = jl_binding_kind(bpart); if (jl_bkind_is_some_guard(kind)) @@ -976,7 +976,6 @@ JL_DLLEXPORT jl_value_t *jl_get_binding_value_if_resolved_debug_only(jl_binding_ if (jl_bkind_is_some_import(kind)) return NULL; if (jl_bkind_is_some_constant(kind)) { - check_backdated_binding(b, kind); return bpart->restriction; } return jl_atomic_load_relaxed(&b->value); @@ -1011,6 +1010,7 @@ static jl_module_t *jl_binding_dbgmodule(jl_binding_t *b) // along the way. JL_DLLEXPORT jl_value_t *jl_get_existing_strong_gf(jl_binding_t *b, size_t new_world) { + assert(new_world > jl_atomic_load_relaxed(&jl_world_counter)); jl_binding_partition_t *bpart = jl_get_binding_partition(b, new_world); enum jl_partition_kind kind = jl_binding_kind(bpart); if (jl_bkind_is_some_constant(kind) && kind != PARTITION_KIND_IMPLICIT_CONST) @@ -1032,7 +1032,7 @@ JL_DLLEXPORT jl_value_t *jl_get_existing_strong_gf(jl_binding_t *b, size_t new_w check_safe_newbinding(b->globalref->mod, b->globalref->name); return NULL; } - jl_module_t *from = jl_binding_dbgmodule(b);\ + jl_module_t *from = jl_binding_dbgmodule(b); assert(from); // Can only be NULL if implicit, which we excluded above jl_errorf("invalid method definition in %s: exported function %s.%s does not exist", jl_module_debug_name(b->globalref->mod), jl_module_debug_name(from), jl_symbol_name(b->globalref->name)); @@ -1725,7 +1725,7 @@ JL_DLLEXPORT int jl_globalref_is_const(jl_globalref_t *gr) b = jl_get_module_binding(gr->mod, gr->name, 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); - return jl_bkind_is_some_constant(jl_binding_kind(bpart)); + return jl_bkind_is_real_constant(jl_binding_kind(bpart)); } JL_DLLEXPORT void jl_disable_binding(jl_globalref_t *gr) @@ -1750,7 +1750,7 @@ JL_DLLEXPORT int jl_is_const(jl_module_t *m, jl_sym_t *var) jl_binding_t *b = jl_get_binding(m, var); 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); - return b && jl_bkind_is_some_constant(jl_binding_kind(bpart)); + return b && jl_bkind_is_real_constant(jl_binding_kind(bpart)); } // set the deprecated flag for a binding: diff --git a/src/rtutils.c b/src/rtutils.c index 5966497ec331c..4baf0ee5e6e9c 100644 --- a/src/rtutils.c +++ b/src/rtutils.c @@ -579,7 +579,7 @@ JL_DLLEXPORT jl_value_t *jl_stderr_obj(void) JL_NOTSAFEPOINT if (jl_base_module == NULL) return NULL; jl_binding_t *stderr_obj = jl_get_module_binding(jl_base_module, jl_symbol("stderr"), 0); - return stderr_obj ? jl_get_binding_value_if_resolved_debug_only(stderr_obj) : NULL; + return stderr_obj ? jl_get_latest_binding_value_if_resolved_debug_only(stderr_obj) : NULL; } // toys for debugging --------------------------------------------------------- @@ -674,7 +674,7 @@ 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; if (globname && dv->name->module) { jl_binding_t *b = jl_get_module_binding(dv->name->module, globname, 0); - jl_value_t *bv = jl_get_binding_value_if_latest_resolved_and_const_debug_only(b); + jl_value_t *bv = jl_get_latest_binding_value_if_resolved_and_const_debug_only(b); if (bv && ((jl_value_t*)dv == v ? jl_typeof(bv) == v : bv == v)) return 1; } diff --git a/src/toplevel.c b/src/toplevel.c index f1fff694926ba..b7479e2d1c24b 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -417,7 +417,7 @@ static void expr_attributes(jl_value_t *v, jl_array_t *body, int *has_ccall, int jl_module_t *mod = jl_globalref_mod(f); jl_sym_t *name = jl_globalref_name(f); jl_binding_t *b = jl_get_binding(mod, name); - called = jl_get_binding_value_if_const(b); + called = jl_get_latest_binding_value_if_const(b); } else if (jl_is_quotenode(f)) { called = jl_quotenode_value(f); diff --git a/test/syntax.jl b/test/syntax.jl index 08472fce7a803..c78e8ea1806cc 100644 --- a/test/syntax.jl +++ b/test/syntax.jl @@ -1935,7 +1935,7 @@ end # eval'ing :const exprs eval(Expr(:const, :_var_30877)) @test !isdefined(@__MODULE__, :_var_30877) -@test isconst(@__MODULE__, :_var_30877) +@test !isconst(@__MODULE__, :_var_30877) # anonymous kw function in value position at top level f30926 = function (;k=0) From 10c7bd2cd66be865f34300eab706d97c93830104 Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Wed, 14 May 2025 06:15:38 +0200 Subject: [PATCH 31/46] check that hashing of types does not foreigncall (`jl_type_hash` is concrete evaluated) (#58401) (cherry picked from commit 86a3e1a90b39e01fffb0441fb1262d25c9a69b86) --- base/hashing.jl | 3 ++- test/hashing.jl | 8 +++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/base/hashing.jl b/base/hashing.jl index 868f5e1ad9abf..36990f7837e70 100644 --- a/base/hashing.jl +++ b/base/hashing.jl @@ -29,7 +29,8 @@ hash(x::Any) = hash(x, zero(UInt)) hash(w::WeakRef, h::UInt) = hash(w.value, h) # Types can't be deleted, so marking as total allows the compiler to look up the hash -hash(T::Type, h::UInt) = hash_uint(3h - @assume_effects :total ccall(:jl_type_hash, UInt, (Any,), T)) +@noinline _jl_type_hash(T::Type) = @assume_effects :total ccall(:jl_type_hash, UInt, (Any,), T) +hash(T::Type, h::UInt) = hash_uint(3h - _jl_type_hash(T)) ## hashing general objects ## diff --git a/test/hashing.jl b/test/hashing.jl index 173a31d10a6a9..3eec25f4ce5b4 100644 --- a/test/hashing.jl +++ b/test/hashing.jl @@ -303,4 +303,10 @@ struct AUnionParam{T<:Union{Nothing,Float32,Float64}} end @test hash(5//3) == hash(big(5)//3) end -@test Core.Compiler.is_foldable_nothrow(Base.infer_effects(hash, Tuple{Type{Int}, UInt})) +@testset "concrete eval type hash" begin + @test Core.Compiler.is_foldable_nothrow(Base.infer_effects(hash, Tuple{Type{Int}, UInt})) + + f(h...) = hash(Char, h...); + src = only(code_typed(f, Tuple{UInt}))[1] + @test count(stmt -> Meta.isexpr(stmt, :foreigncall), src.code) == 0 +end From e90c949dec9d3367b10e1025d619ca22b94bd94c Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Wed, 28 May 2025 15:07:42 +0200 Subject: [PATCH 32/46] remove invalid precompile signature --- contrib/generate_precompile.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/contrib/generate_precompile.jl b/contrib/generate_precompile.jl index 01c32593a72c5..45b4a9a485a4d 100644 --- a/contrib/generate_precompile.jl +++ b/contrib/generate_precompile.jl @@ -47,7 +47,6 @@ precompile(Tuple{typeof(Core.kwcall), NamedTuple{(:allow_typevars, :volatile_inf precompile(Tuple{typeof(Base.Compiler.ir_to_codeinf!), Base.Compiler.OptimizationState{Base.Compiler.NativeInterpreter}}) precompile(Tuple{typeof(Core.kwcall), NamedTuple{(:allow_typevars, :volatile_inf_result), Tuple{Bool, Base.Compiler.VolatileInferenceResult}}, typeof(Base.Compiler.handle_match!), Array{Base.Compiler.InliningCase, 1}, Core.MethodMatch, Array{Any, 1}, Base.Compiler.CallInfo, UInt32, Base.Compiler.InliningState{Base.Compiler.NativeInterpreter}}) precompile(Tuple{typeof(Base.getindex), Type{Pair{Base.PkgId, UInt128}}, Pair{Base.PkgId, UInt128}, Pair{Base.PkgId, UInt128}, Pair{Base.PkgId, UInt128}, Vararg{Pair{Base.PkgId, UInt128}}}) -precompile(Tuple{typeof(Base.Compiler.ir_to_codeinf!), Base.Compiler.OptimizationState{Base.Compiler.NativeInterpreter}, Core.SimpleVector}) precompile(Tuple{typeof(Base.Compiler.ir_to_codeinf!), Base.Compiler.OptimizationState{Base.Compiler.NativeInterpreter}}) # LazyArtifacts (but more generally helpful) From e05fc006b4e2170f7618f363cb9c6f95af99eecf Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> Date: Sat, 31 May 2025 14:28:40 +0900 Subject: [PATCH 33/46] REPLCompletions: remove `builtin_tfunction(::REPLInterpreter)` overload (#58585) This overload was necessary in the past, but in the current compiler implementation, all `getglobal` calls that were aggressively concretized by this overload are already concretized by `concrete_eval_call`. So this overload is no longer necessary. - closes JuliaLang/julia#58537 --- stdlib/REPL/src/REPLCompletions.jl | 30 ++++-------------------------- 1 file changed, 4 insertions(+), 26 deletions(-) diff --git a/stdlib/REPL/src/REPLCompletions.jl b/stdlib/REPL/src/REPLCompletions.jl index 5b211d95b5385..2f3fefc6ec2c7 100644 --- a/stdlib/REPL/src/REPLCompletions.jl +++ b/stdlib/REPL/src/REPLCompletions.jl @@ -563,18 +563,18 @@ CC.bail_out_toplevel_call(::REPLInterpreter, ::CC.InferenceLoopState, ::CC.Infer # be employed, for instance, by `typeinf_ext_toplevel`. is_repl_frame(sv::CC.InferenceState) = sv.linfo.def isa Module && sv.cache_mode === CC.CACHE_MODE_NULL -function is_call_graph_uncached(sv::CC.InferenceState) +function is_call_stack_uncached(sv::CC.InferenceState) CC.is_cached(sv) && return false parent = CC.frame_parent(sv) parent === nothing && return true - return is_call_graph_uncached(parent::CC.InferenceState) + return is_call_stack_uncached(parent::CC.InferenceState) end # aggressive global binding resolution within `repl_frame` function CC.abstract_eval_globalref(interp::REPLInterpreter, g::GlobalRef, bailed::Bool, sv::CC.InferenceState) # Ignore saw_latestworld - if (interp.limit_aggressive_inference ? is_repl_frame(sv) : is_call_graph_uncached(sv)) + if (interp.limit_aggressive_inference ? is_repl_frame(sv) : is_call_stack_uncached(sv)) partition = CC.abstract_eval_binding_partition!(interp, g, sv) if CC.is_defined_const_binding(CC.binding_kind(partition)) return CC.RTEffects(Const(CC.partition_restriction(partition)), Union{}, CC.EFFECTS_TOTAL) @@ -598,33 +598,11 @@ function is_repl_frame_getproperty(sv::CC.InferenceState) return is_repl_frame(CC.frame_parent(sv)) end -# aggressive global binding resolution for `getproperty(::Module, ::Symbol)` calls within `repl_frame` -function CC.builtin_tfunction(interp::REPLInterpreter, @nospecialize(f), - argtypes::Vector{Any}, sv::CC.InferenceState) - if f === Core.getglobal && (interp.limit_aggressive_inference ? is_repl_frame_getproperty(sv) : is_call_graph_uncached(sv)) - if length(argtypes) == 2 - a1, a2 = argtypes - if isa(a1, Const) && isa(a2, Const) - a1val, a2val = a1.val, a2.val - if isa(a1val, Module) && isa(a2val, Symbol) - g = GlobalRef(a1val, a2val) - if isdefined_globalref(g) - return Const(ccall(:jl_get_globalref_value, Any, (Any,), g)) - end - return Union{} - end - end - end - end - return @invoke CC.builtin_tfunction(interp::CC.AbstractInterpreter, f::Any, - argtypes::Vector{Any}, sv::CC.InferenceState) -end - # aggressive concrete evaluation for `:inconsistent` frames within `repl_frame` function CC.concrete_eval_eligible(interp::REPLInterpreter, @nospecialize(f), result::CC.MethodCallResult, arginfo::CC.ArgInfo, sv::CC.InferenceState) - if (interp.limit_aggressive_inference ? is_repl_frame(sv) : is_call_graph_uncached(sv)) + if (interp.limit_aggressive_inference ? is_repl_frame(sv) : is_call_stack_uncached(sv)) neweffects = CC.Effects(result.effects; consistent=CC.ALWAYS_TRUE) result = CC.MethodCallResult(result.rt, result.exct, neweffects, result.edge, result.edgecycle, result.edgelimited, result.volatile_inf_result) From 7bea4c5073864700b600b04fcb2cd5b87789bc16 Mon Sep 17 00:00:00 2001 From: Sam Schweigel <33556084+xal-0@users.noreply.github.com> Date: Thu, 29 May 2025 08:08:40 -0700 Subject: [PATCH 34/46] Make more types jl_static_show unambiguously (#58512) Makes more types survive `jl_static_show` unambiguously: - Symbols - Symbols printed in the `:var"foo"` form use raw string escaping, fixing `:var"a\b"`, `:var"a\\"`, `:var"$a"`, etc. - Symbols that require parens use parens (`:(=)`, ...) - Signed integers: Except for `Int`, signed integers print like `Int8(1)`. - Floats: floats are printed in a naive but reversible (TODO: double check) way. `Inf(16|32|)` and `NaN(16|32|)` are printed, and `Float16`/`Float32` print the type (`Float32(1.5)`). `Float64`s are printed with a trailing `.0` if it is necessary to disambiguate from `Int`. Fixes #52677, https://github.com/JuliaLang/julia/issues/58484#issuecomment-2902468354, https://github.com/JuliaLang/julia/issues/58484#issuecomment-2898733637, and the specific case mentioned in #58484. Improves the situation for #38902 but does not close it, because a few cases still do not round-trip (inexhaustive list): - Non-canonical NaNs - BFloat16 - User-defined primitive types. This one is tricky, because they can have a size different from any type we have literals for. (cherry picked from commit b03ef6b680703267e48d56b1e7b2dbbe81e52be2) --- src/rtutils.c | 123 ++++++++++++++++++++++++++++++++++++++++++-------- test/show.jl | 54 +++++++++++++++++++++- 2 files changed, 157 insertions(+), 20 deletions(-) diff --git a/src/rtutils.c b/src/rtutils.c index 4baf0ee5e6e9c..44c133ce6faf2 100644 --- a/src/rtutils.c +++ b/src/rtutils.c @@ -5,6 +5,8 @@ */ #include "platform.h" +#include +#include #include #include #include @@ -691,12 +693,12 @@ static int is_globfunction(jl_value_t *v, jl_datatype_t *dv, jl_sym_t **globname return 0; } -static size_t jl_static_show_string(JL_STREAM *out, const char *str, size_t len, int wrap) JL_NOTSAFEPOINT +static size_t jl_static_show_string(JL_STREAM *out, const char *str, size_t len, int wrap, int raw) JL_NOTSAFEPOINT { size_t n = 0; if (wrap) n += jl_printf(out, "\""); - if (!u8_isvalid(str, len)) { + if (!raw && !u8_isvalid(str, len)) { // alternate print algorithm that preserves data if it's not UTF-8 static const char hexdig[] = "0123456789abcdef"; for (size_t i = 0; i < len; i++) { @@ -713,7 +715,11 @@ static size_t jl_static_show_string(JL_STREAM *out, const char *str, size_t len, int special = 0; for (size_t i = 0; i < len; i++) { uint8_t c = str[i]; - if (c < 32 || c == 0x7f || c == '\\' || c == '"' || c == '$') { + if (raw && ((c == '\\' && i == len-1) || c == '"')) { + special = 1; + break; + } + else if (!raw && (c < 32 || c == 0x7f || c == '\\' || c == '"' || c == '$')) { special = 1; break; } @@ -722,6 +728,25 @@ static size_t jl_static_show_string(JL_STREAM *out, const char *str, size_t len, jl_uv_puts(out, str, len); n += len; } + else if (raw) { + // REF: Base.escape_raw_string + int escapes = 0; + for (size_t i = 0; i < len; i++) { + uint8_t c = str[i]; + if (c == '\\') { + escapes++; + } + else { + if (c == '"') + for (escapes++; escapes > 0; escapes--) + n += jl_printf(out, "\\"); + escapes = 0; + } + n += jl_printf(out, "%c", str[i]); + } + for (; escapes > 0; escapes--) + n += jl_printf(out, "\\"); + } else { char buf[512]; size_t i = 0; @@ -737,18 +762,28 @@ static size_t jl_static_show_string(JL_STREAM *out, const char *str, size_t len, return n; } +static int jl_is_quoted_sym(const char *sn) +{ + static const char *const quoted_syms[] = {":", "::", ":=", "=", "==", "===", "=>", "`"}; + for (int i = 0; i < sizeof quoted_syms / sizeof *quoted_syms; i++) + if (!strcmp(sn, quoted_syms[i])) + return 1; + return 0; +} + +// TODO: in theory, we need a separate function for showing symbols in an +// expression context (where `Symbol("foo\x01bar")` is ok) and a syntactic +// context (where var"" must be used). static size_t jl_static_show_symbol(JL_STREAM *out, jl_sym_t *name) JL_NOTSAFEPOINT { size_t n = 0; const char *sn = jl_symbol_name(name); - int quoted = !jl_is_identifier(sn) && !jl_is_operator(sn); - if (quoted) { - n += jl_printf(out, "var"); - // TODO: this is not quite right, since repr uses String escaping rules, and Symbol uses raw string rules - n += jl_static_show_string(out, sn, strlen(sn), 1); + if (jl_is_identifier(sn) || (jl_is_operator(sn) && !jl_is_quoted_sym(sn))) { + n += jl_printf(out, "%s", sn); } else { - n += jl_printf(out, "%s", sn); + n += jl_printf(out, "var"); + n += jl_static_show_string(out, sn, strlen(sn), 1, 1); } return n; } @@ -777,6 +812,51 @@ static int jl_static_is_function_(jl_datatype_t *vt) JL_NOTSAFEPOINT { return 0; } +static size_t jl_static_show_float(JL_STREAM *out, double v, + jl_datatype_t *vt) JL_NOTSAFEPOINT +{ + size_t n = 0; + // TODO: non-canonical NaNs do not round-trip + // TOOD: BFloat16 + const char *size_suffix = vt == jl_float16_type ? "16" : + vt == jl_float32_type ? "32" : + ""; + // Requires minimum 1 (sign) + 17 (sig) + 1 (dot) + 5 ("e-123") + 1 (null) + char buf[32]; + // Base B significand digits required to print n base-b significand bits + // (including leading 1): N = 2 + floor(n/log(b, B)) + // Float16 5 + // Float32 9 + // Float64 17 + // REF: https://dl.acm.org/doi/pdf/10.1145/93542.93559 + if (isnan(v)) { + n += jl_printf(out, "NaN%s", size_suffix); + } + else if (isinf(v)) { + n += jl_printf(out, "%sInf%s", v < 0 ? "-" : "", size_suffix); + } + else if (vt == jl_float64_type) { + n += jl_printf(out, "%#.17g", v); + } + else if (vt == jl_float32_type) { + size_t m = snprintf(buf, sizeof buf, "%.9g", v); + // If the exponent was printed, replace it with 'f' + char *p = (char *)memchr(buf, 'e', m); + if (p) + *p = 'f'; + jl_uv_puts(out, buf, m); + n += m; + // If no exponent was printed, we must add one + if (!p) + n += jl_printf(out, "f0"); + } + else { + assert(vt == jl_float16_type); + n += jl_printf(out, "Float16(%#.5g)", v); + } + return n; +} + // `v` might be pointing to a field inlined in a structure therefore // `jl_typeof(v)` may not be the same with `vt` and only `vt` should be // used to determine the type of the value. @@ -954,17 +1034,21 @@ static size_t jl_static_show_x_(JL_STREAM *out, jl_value_t *v, jl_datatype_t *vt int f = *(uint32_t*)jl_data_ptr(v); n += jl_printf(out, "#", f, jl_intrinsic_name(f)); } + else if (vt == jl_long_type) { + // Avoid unnecessary Int64(x)/Int32(x) + n += jl_printf(out, "%" PRIdPTR, *(intptr_t*)v); + } else if (vt == jl_int64_type) { - n += jl_printf(out, "%" PRId64, *(int64_t*)v); + n += jl_printf(out, "Int64(%" PRId64 ")", *(int64_t*)v); } else if (vt == jl_int32_type) { - n += jl_printf(out, "%" PRId32, *(int32_t*)v); + n += jl_printf(out, "Int32(%" PRId32 ")", *(int32_t*)v); } else if (vt == jl_int16_type) { - n += jl_printf(out, "%" PRId16, *(int16_t*)v); + n += jl_printf(out, "Int16(%" PRId16 ")", *(int16_t*)v); } else if (vt == jl_int8_type) { - n += jl_printf(out, "%" PRId8, *(int8_t*)v); + n += jl_printf(out, "Int8(%" PRId8 ")", *(int8_t*)v); } else if (vt == jl_uint64_type) { n += jl_printf(out, "0x%016" PRIx64, *(uint64_t*)v); @@ -985,11 +1069,14 @@ static size_t jl_static_show_x_(JL_STREAM *out, jl_value_t *v, jl_datatype_t *vt n += jl_printf(out, "0x%08" PRIx32, *(uint32_t*)v); #endif } + else if (vt == jl_float16_type) { + n += jl_static_show_float(out, julia_half_to_float(*(uint16_t *)v), vt); + } else if (vt == jl_float32_type) { - n += jl_printf(out, "%gf", *(float*)v); + n += jl_static_show_float(out, *(float *)v, vt); } else if (vt == jl_float64_type) { - n += jl_printf(out, "%g", *(double*)v); + n += jl_static_show_float(out, *(double *)v, vt); } else if (vt == jl_bool_type) { n += jl_printf(out, "%s", *(uint8_t*)v ? "true" : "false"); @@ -998,7 +1085,7 @@ static size_t jl_static_show_x_(JL_STREAM *out, jl_value_t *v, jl_datatype_t *vt n += jl_printf(out, "nothing"); } else if (vt == jl_string_type) { - n += jl_static_show_string(out, jl_string_data(v), jl_string_len(v), 1); + n += jl_static_show_string(out, jl_string_data(v), jl_string_len(v), 1, 0); } else if (v == jl_bottom_type) { n += jl_printf(out, "Union{}"); @@ -1528,10 +1615,10 @@ void jl_log(int level, jl_value_t *module, jl_value_t *group, jl_value_t *id, } jl_printf(str, "\n@ "); if (jl_is_string(file)) { - jl_static_show_string(str, jl_string_data(file), jl_string_len(file), 0); + jl_static_show_string(str, jl_string_data(file), jl_string_len(file), 0, 0); } else if (jl_is_symbol(file)) { - jl_static_show_string(str, jl_symbol_name((jl_sym_t*)file), strlen(jl_symbol_name((jl_sym_t*)file)), 0); + jl_static_show_string(str, jl_symbol_name((jl_sym_t*)file), strlen(jl_symbol_name((jl_sym_t*)file)), 0, 0); } jl_printf(str, ":"); jl_static_show(str, line); diff --git a/test/show.jl b/test/show.jl index 99bb14df15b23..a24ef2e6a3783 100644 --- a/test/show.jl +++ b/test/show.jl @@ -703,7 +703,7 @@ let oldout = stdout, olderr = stderr redirect_stderr(olderr) close(wrout) close(wrerr) - @test fetch(out) == "primitive type Int64 <: Signed\nTESTA\nTESTB\nΑ1Β2\"A\"\nA\n123\"C\"\n" + @test fetch(out) == "primitive type Int64 <: Signed\nTESTA\nTESTB\nΑ1Β2\"A\"\nA\n123.0000000000000000\"C\"\n" @test fetch(err) == "TESTA\nTESTB\nΑ1Β2\"A\"\n" finally redirect_stdout(oldout) @@ -1570,8 +1570,58 @@ struct var"%X%" end # Invalid name without '#' typeof(+), var"#f#", typeof(var"#f#"), + + # Integers should round-trip (#52677) + 1, UInt(1), + Int8(1), Int16(1), Int32(1), Int64(1), + UInt8(1), UInt16(1), UInt32(1), UInt64(1), + + # Float round-trip + Float16(1), Float32(1), Float64(1), + Float16(1.5), Float32(1.5), Float64(1.5), + Float16(0.4893243538921085), Float32(0.4893243538921085), Float64(0.4893243538921085), + # Examples that require the full 5, 9, and 17 digits of precision + Float16(0.00010014), Float32(1.00000075f-36), Float64(-1.561051336605761e-182), + floatmax(Float16), floatmax(Float32), floatmax(Float64), + floatmin(Float16), floatmin(Float32), floatmin(Float64), + Float16(0.0), 0.0f0, 0.0, + Float16(-0.0), -0.0f0, -0.0, + Inf16, Inf32, Inf, + -Inf16, -Inf32, -Inf, + nextfloat(Float16(0)), nextfloat(Float32(0)), nextfloat(Float64(0)), + NaN16, NaN32, NaN, + Float16(1e3), 1f7, 1e16, + Float16(-1e3), -1f7, -1e16, + Float16(1e4), 1f8, 1e17, + Float16(-1e4), -1f8, -1e17, + + # :var"" escaping rules differ from strings (#58484) + :foo, + :var"bar baz", + :var"a $b", # No escaping for $ in raw string + :var"a\b", # No escaping for backslashes in middle + :var"a\\", # Backslashes must be escaped at the end + :var"a\\\\", + :var"a\"b", + :var"a\"", + :var"\\\"", + :+, :var"+-", + :(=), :(:), :(::), # Requires quoting + Symbol("a\nb"), + + Val(Float16(1.0)), Val(1f0), Val(1.0), + Val(:abc), Val(:(=)), Val(:var"a\b"), + + Val(1), Val(Int8(1)), Val(Int16(1)), Val(Int32(1)), Val(Int64(1)), Val(Int128(1)), + Val(UInt(1)), Val(UInt8(1)), Val(UInt16(1)), Val(UInt32(1)), Val(UInt64(1)), Val(UInt128(1)), + + # BROKEN + # Symbol("a\xffb"), + # User-defined primitive types + # Non-canonical NaNs + # BFloat16 ) - @test v == eval(Meta.parse(static_shown(v))) + @test v === eval(Meta.parse(static_shown(v))) end end From 0f7d95e0cc8c3bdeaa6b1844545cb85bd3c0275f Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Thu, 29 May 2025 14:35:34 -0400 Subject: [PATCH 35/46] remove workaround for controlling terminal behavior in repl_cmd (#58554) This was originally added as a workaround for the behavior of sh to try to become the terminal process group leader, but no longer relevant since #25006 removed that flag again: ``` julia> run(detach(`bash -i -c "sleep 0"`)) bash: cannot set terminal process group (-1): Inappropriate ioctl for device bash: no job control in this shell Process(`bash -i -c 'sleep 0'`, ProcessExited(0)) ``` Long explanation: Julia recieves SIGTTOU when a process like "sh -i -c" exits (at least for bash and zsh, but not dash, ksh, or csh), since "sh -i" sometimes takes over the controlling terminal, causing julia to stop once the bash process exits. This can be quite annoying, but julia goes through some pains (in libuv) to ensure it doesn't steal the controlling terminal from the parent, and apparently bash is not so careful about it. However, since PR #25006, julia hasn't needed this workaround for this issue, so we can now follow the intended behavior when the child is in the same session group and steals the controlling terminal from the parent. Even if such behavior seems odd, this seems to be the intended behavior per posix design implementation that it gets SIGTTOU when julia later tries to change mode (from cooked -> raw after printing the prompt): http://curiousthing.org/sigttin-sigttou-deep-dive-linux. For some background on why this is a useful signal and behavior and should not be just blocked, see nodejs/node#35536. According to glibc, there's a half page of code for how to correctly implement a REPL mode change call: https://www.gnu.org/software/libc/manual/html_node/Initializing-the-Shell.html ``` $ ./julia -q shell> bash -i -c "sleep 1" [1]+ Stopped ./julia julia> run(`zsh -i -c "sleep 0"`) Process(`zsh -i -c 'sleep 0'`, ProcessExited(0)) julia> [1]+ Stopped ./julia ``` (cherry picked from commit 0cbe4669079249e3d8ff48688b45ed3b39db20d5) --- base/client.jl | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/base/client.jl b/base/client.jl index 70d564a54615a..34c0fb828e978 100644 --- a/base/client.jl +++ b/base/client.jl @@ -32,9 +32,6 @@ stackframe_lineinfo_color() = repl_color("JULIA_STACKFRAME_LINEINFO_COLOR", :bol stackframe_function_color() = repl_color("JULIA_STACKFRAME_FUNCTION_COLOR", :bold) function repl_cmd(cmd, out) - shell = shell_split(get(ENV, "JULIA_SHELL", get(ENV, "SHELL", "/bin/sh"))) - shell_name = Base.basename(shell[1]) - # Immediately expand all arguments, so that typing e.g. ~/bin/foo works. cmd.exec .= expanduser.(cmd.exec) @@ -64,19 +61,15 @@ function repl_cmd(cmd, out) cd(dir) println(out, pwd()) else - @static if !Sys.iswindows() - if shell_name == "fish" - shell_escape_cmd = "begin; $(shell_escape_posixly(cmd)); and true; end" - else - shell_escape_cmd = "($(shell_escape_posixly(cmd))) && true" - end + if !Sys.iswindows() + shell = shell_split(get(ENV, "JULIA_SHELL", get(ENV, "SHELL", "/bin/sh"))) + shell_escape_cmd = shell_escape_posixly(cmd) cmd = `$shell -c $shell_escape_cmd` end try run(ignorestatus(cmd)) catch - # Windows doesn't shell out right now (complex issue), so Julia tries to run the program itself - # Julia throws an exception if it can't find the program, but the stack trace isn't useful + # Julia throws an exception if it can't find the cmd (which may be the shell itself), but the stack trace isn't useful lasterr = current_exceptions() lasterr = ExceptionStack([(exception = e[1], backtrace = [] ) for e in lasterr]) invokelatest(display_error, lasterr) From 4fc2dea2a66a301c6190d2118963d36b3cf185d1 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Thu, 29 May 2025 14:53:35 -0400 Subject: [PATCH 36/46] fix Module for Base.jl for Revise.jl (#58549) Just happened to notice in passing that `_included_files[1]` did not get fixed when Base_compiler.jl was split from Base.jl so it causes warnings sometimes in Revise.jl CI (cherry picked from commit 488be228cd628294b1c3eb25fe54613264b9fb3d) --- base/Base.jl | 19 +++++++------------ base/Base_compiler.jl | 4 ++++ base/sysimg.jl | 2 +- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/base/Base.jl b/base/Base.jl index c6e33df751782..6d798d69014ea 100644 --- a/base/Base.jl +++ b/base/Base.jl @@ -23,7 +23,7 @@ include(strcat(BUILDROOT, "version_git.jl")) # include($BUILDROOT/base/version_g # a slightly more verbose fashion than usual, because we're running so early. let os = ccall(:jl_get_UNAME, Any, ()) if os === :Darwin || os === :Apple - if Base.DARWIN_FRAMEWORK + if DARWIN_FRAMEWORK push!(DL_LOAD_PATH, "@loader_path/Frameworks") end push!(DL_LOAD_PATH, "@loader_path") @@ -306,8 +306,8 @@ a_method_to_overwrite_in_test() = inferencebarrier(1) (this::IncludeInto)(mapexpr::Function, fname::AbstractString) = include(mapexpr, this.m, fname) # Compatibility with when Compiler was in Core -@eval Core const Compiler = Main.Base.Compiler -@eval Compiler const fl_parse = Core.Main.Base.fl_parse +@eval Core const Compiler = $Base.Compiler +@eval Compiler const fl_parse = $Base.fl_parse # External libraries vendored into Base Core.println("JuliaSyntax/src/JuliaSyntax.jl") @@ -323,13 +323,13 @@ if is_primary_base_module # Profiling helper # triggers printing the report and (optionally) saving a heap snapshot after a SIGINFO/SIGUSR1 profile request # Needs to be in Base because Profile is no longer loaded on boot -function profile_printing_listener(cond::Base.AsyncCondition) +function profile_printing_listener(cond::AsyncCondition) profile = nothing try while _trywait(cond) profile = @something(profile, require_stdlib(PkgId(UUID("9abbd945-dff8-562f-b5e8-e1ebf5ef1b79"), "Profile")))::Module invokelatest(profile.peek_report[]) - if Base.get_bool_env("JULIA_PROFILE_PEEK_HEAP_SNAPSHOT", false) === true + if get_bool_env("JULIA_PROFILE_PEEK_HEAP_SNAPSHOT", false) === true println(stderr, "Saving heap snapshot...") fname = invokelatest(profile.take_heap_snapshot) println(stderr, "Heap snapshot saved to `$(fname)`") @@ -344,8 +344,8 @@ function profile_printing_listener(cond::Base.AsyncCondition) end function start_profile_listener() - cond = Base.AsyncCondition() - Base.uv_unref(cond.handle) + cond = AsyncCondition() + uv_unref(cond.handle) t = errormonitor(Threads.@spawn(profile_printing_listener(cond))) atexit() do # destroy this callback when exiting @@ -405,7 +405,6 @@ end const _compiler_require_dependencies = Any[] @Core.latestworld for i = 1:length(_included_files) - isassigned(_included_files, i) || continue (mod, file) = _included_files[i] if mod === Compiler || parentmodule(mod) === Compiler || endswith(file, "/Compiler.jl") _include_dependency!(_compiler_require_dependencies, true, mod, file, true, false) @@ -421,7 +420,3 @@ end @assert length(_compiler_require_dependencies) >= 15 end - -# Ensure this file is also tracked -@assert !isassigned(_included_files, 1) -_included_files[1] = (parentmodule(Base), abspath(@__FILE__)) diff --git a/base/Base_compiler.jl b/base/Base_compiler.jl index 702a00c8b8b07..16633ba01a17b 100644 --- a/base/Base_compiler.jl +++ b/base/Base_compiler.jl @@ -384,5 +384,9 @@ Core._setparser!(fl_parse) # Further definition of Base will happen in Base.jl if loaded. +# Ensure this file is also tracked +@assert !isassigned(_included_files, 1) +_included_files[1] = (@__MODULE__, ccall(:jl_prepend_cwd, Any, (Any,), "Base_compiler.jl")) + end # module Base using .Base diff --git a/base/sysimg.jl b/base/sysimg.jl index 8adb05ece0b2c..4a99f7a9f337e 100644 --- a/base/sysimg.jl +++ b/base/sysimg.jl @@ -1,6 +1,6 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license -Base.Core.include(Base, "Base.jl") # finish populating Base (currently just has the Compiler) +Base.include("Base.jl") # finish populating Base (currently just has the Compiler) # Set up Main module by importing from Base using .Base From 6e8340b9023e07fc86806226d4622454adbc68e7 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Fri, 30 May 2025 14:07:41 -0400 Subject: [PATCH 37/46] make typejoin nothrow (#58578) Fixes #50985 (cherry picked from commit aa06976c29fb0a9659d9dc194b58ef4ec61d8d2c) --- base/promotion.jl | 5 +++++ test/core.jl | 19 +++---------------- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/base/promotion.jl b/base/promotion.jl index 719cd2dc32b61..f935c546915be 100644 --- a/base/promotion.jl +++ b/base/promotion.jl @@ -23,11 +23,16 @@ typejoin(@nospecialize(t), @nospecialize(s), @nospecialize(u)) = (@_foldable_met typejoin(@nospecialize(t), @nospecialize(s), @nospecialize(u), ts...) = (@_foldable_meta; @_nospecializeinfer_meta; afoldl(typejoin, typejoin(t, s, u), ts...)) function typejoin(@nospecialize(a), @nospecialize(b)) @_foldable_meta + @_nothrow_meta @_nospecializeinfer_meta if isa(a, TypeVar) return typejoin(a.ub, b) elseif isa(b, TypeVar) return typejoin(a, b.ub) + elseif a === b + return a + elseif !isa(a, Type) || !isa(b, Type) + return Any elseif a <: b return b elseif b <: a diff --git a/test/core.jl b/test/core.jl index 1e015b19e4a91..5f7f857ad6e35 100644 --- a/test/core.jl +++ b/test/core.jl @@ -307,22 +307,9 @@ end |> only == Type{typejoin(Int, UInt)} typejoin(Int, UInt, Float64) end |> only == Type{typejoin(Int, UInt, Float64)} -let res = @test_throws TypeError let - Base.Experimental.@force_compile - typejoin(1, 2) - nothing - end - err = res.value - @test err.func === :<: -end -let res = @test_throws TypeError let - Base.Experimental.@force_compile - typejoin(1, 2, 3) - nothing - end - err = res.value - @test err.func === :<: -end +@test typejoin(1, 2) === Any +@test typejoin(1, 2, 3) === Any +@test typejoin(Int, Int, 3) === Any # promote_typejoin returns a Union only with Nothing/Missing combined with concrete types for T in (Nothing, Missing) From 505789cd61084cda06969d005615e918131ad654 Mon Sep 17 00:00:00 2001 From: Cody Tapscott <84105208+topolarity@users.noreply.github.com> Date: Fri, 30 May 2025 17:32:18 -0400 Subject: [PATCH 38/46] Make `Ptr` values static-show w/ type-information (#58584) Small follow-up to https://github.com/JuliaLang/julia/pull/58512/ (cherry picked from commit 36bd3ad86b2962e2ffe497e756d68e0aa432d867) --- src/rtutils.c | 7 ------- test/show.jl | 3 +++ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/rtutils.c b/src/rtutils.c index 44c133ce6faf2..3b71a3ed42b59 100644 --- a/src/rtutils.c +++ b/src/rtutils.c @@ -1062,13 +1062,6 @@ static size_t jl_static_show_x_(JL_STREAM *out, jl_value_t *v, jl_datatype_t *vt else if (vt == jl_uint8_type) { n += jl_printf(out, "0x%02" PRIx8, *(uint8_t*)v); } - else if (jl_pointer_type && jl_is_cpointer_type((jl_value_t*)vt)) { -#ifdef _P64 - n += jl_printf(out, "0x%016" PRIx64, *(uint64_t*)v); -#else - n += jl_printf(out, "0x%08" PRIx32, *(uint32_t*)v); -#endif - } else if (vt == jl_float16_type) { n += jl_static_show_float(out, julia_half_to_float(*(uint16_t *)v), vt); } diff --git a/test/show.jl b/test/show.jl index a24ef2e6a3783..ffc9e228f5b39 100644 --- a/test/show.jl +++ b/test/show.jl @@ -1595,6 +1595,9 @@ struct var"%X%" end # Invalid name without '#' Float16(1e4), 1f8, 1e17, Float16(-1e4), -1f8, -1e17, + # Pointers should round-trip + Ptr{Cvoid}(0), Ptr{Cvoid}(typemax(UInt)), Ptr{Any}(0), Ptr{Any}(typemax(UInt)), + # :var"" escaping rules differ from strings (#58484) :foo, :var"bar baz", From 9fd0ba2de1b40ee66cb9ba8eb4cc629b6bd5548d Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Sat, 31 May 2025 00:51:28 -0400 Subject: [PATCH 39/46] Add world age hint for UndefVarError (#58572) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Similar to the existing world age hint for MethodError, this adds a helpful message when an UndefVarError occurs because a binding was defined in a newer world age than the code trying to access it. The implementation checks if a binding that was undefined at the error's world age is now defined in the current world, and displays: "The binding may be too new: running in world age X, while current world is Y." Additionally, for all binding kinds, the error hint now notes when the binding state has changed between the error's world and the current world. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-authored-by: Claude (cherry picked from commit 2e39f646241ea0510b6286d88873a1d656168fee) --- base/errorshow.jl | 38 +++++++++++++++++++++++++++++--------- test/errorshow.jl | 18 ++++++++++++++++++ 2 files changed, 47 insertions(+), 9 deletions(-) diff --git a/base/errorshow.jl b/base/errorshow.jl index de315914c8b5c..6aab526f87c6c 100644 --- a/base/errorshow.jl +++ b/base/errorshow.jl @@ -1144,22 +1144,42 @@ function UndefVarError_hint(io::IO, ex::UndefVarError) if isdefined(ex, :scope) scope = ex.scope if scope isa Module - bpart = Base.lookup_binding_partition(ex.world, GlobalRef(scope, var)) - kind = Base.binding_kind(bpart) - if kind === Base.PARTITION_KIND_GLOBAL || kind === Base.PARTITION_KIND_UNDEF_CONST || kind == Base.PARTITION_KIND_DECLARED + bpart = lookup_binding_partition(ex.world, GlobalRef(scope, var)) + kind = binding_kind(bpart) + + # Get the current world's binding partition for comparison + curworld = tls_world_age() + cur_bpart = lookup_binding_partition(curworld, GlobalRef(scope, var)) + cur_kind = binding_kind(cur_bpart) + + # Track if we printed the "too new" message + printed_too_new = false + + # Check if the binding exists in the current world but was undefined in the error's world + if kind === PARTITION_KIND_GUARD + if isdefinedglobal(scope, var) + print(io, "\nThe binding may be too new: running in world age $(ex.world), while current world is $(curworld).") + printed_too_new = true + else + print(io, "\nSuggestion: check for spelling errors or missing imports.") + end + elseif kind === PARTITION_KIND_GLOBAL || kind === PARTITION_KIND_UNDEF_CONST || kind == PARTITION_KIND_DECLARED print(io, "\nSuggestion: add an appropriate import or assignment. This global was declared but not assigned.") - elseif kind === Base.PARTITION_KIND_FAILED + elseif kind === PARTITION_KIND_FAILED print(io, "\nHint: It looks like two or more modules export different ", "bindings with this name, resulting in ambiguity. Try explicitly ", "importing it from a particular module, or qualifying the name ", "with the module it should come from.") - elseif kind === Base.PARTITION_KIND_GUARD - print(io, "\nSuggestion: check for spelling errors or missing imports.") - elseif Base.is_some_explicit_imported(kind) - print(io, "\nSuggestion: this global was defined as `$(Base.partition_restriction(bpart).globalref)` but not assigned a value.") - elseif kind === Base.PARTITION_KIND_BACKDATED_CONST + elseif is_some_explicit_imported(kind) + print(io, "\nSuggestion: this global was defined as `$(partition_restriction(bpart).globalref)` but not assigned a value.") + elseif kind === PARTITION_KIND_BACKDATED_CONST print(io, "\nSuggestion: define the const at top-level before running function that uses it (stricter Julia v1.12+ rule).") end + + # Check if binding kind changed between the error's world and current world + if !printed_too_new && kind !== cur_kind + print(io, "\nNote: the binding state changed since the error occurred (was: $(kind), now: $(cur_kind)).") + end elseif scope === :static_parameter print(io, "\nSuggestion: run Test.detect_unbound_args to detect method arguments that do not fully constrain a type parameter.") elseif scope === :local diff --git a/test/errorshow.jl b/test/errorshow.jl index ef65d70513c0d..bca5475b07901 100644 --- a/test/errorshow.jl +++ b/test/errorshow.jl @@ -938,6 +938,24 @@ end @test_throws expected_message X.x end +# Module for UndefVarError world age testing +module TestWorldAgeUndef end + +@testset "UndefVarError world age hint" begin + ex = try + TestWorldAgeUndef.newvar + catch e + e + end + @test ex isa UndefVarError + + Core.eval(TestWorldAgeUndef, :(newvar = 42)) + + err_str = sprint(Base.showerror, ex) + @test occursin("The binding may be too new: running in world age", err_str) + @test occursin("while current world is", err_str) +end + # test showing MethodError with type argument struct NoMethodsDefinedHere; end let buf = IOBuffer() From a00e1b25145233a3e3a3d71565c2be72d3162c0d Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Sat, 31 May 2025 08:08:12 -0400 Subject: [PATCH 40/46] ensure Type{T} gets inserted with the right key when T is a TypeVar (#58577) Fix #58479 (cherry picked from commit 345c6ecfc98fee70a3ffbed6eb2c20ba5dea152f) --- src/typemap.c | 2 +- test/reflection.jl | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/typemap.c b/src/typemap.c index 8c0e585601944..8e67428391aef 100644 --- a/src/typemap.c +++ b/src/typemap.c @@ -31,7 +31,7 @@ static jl_value_t *jl_type_extract_name(jl_value_t *t1 JL_PROPAGATES_ROOT, int i return jl_type_extract_name(jl_unwrap_vararg(t1), invariant); } else if (jl_is_typevar(t1)) { - return jl_type_extract_name(((jl_tvar_t*)t1)->ub, invariant); + return jl_type_extract_name(((jl_tvar_t*)t1)->ub, 0); } else if (t1 == jl_bottom_type || t1 == (jl_value_t*)jl_typeofbottom_type || t1 == (jl_value_t*)jl_typeofbottom_type->super) { return (jl_value_t*)jl_typeofbottom_type->name; // put Union{} and typeof(Union{}) and Type{Union{}} together for convenience diff --git a/test/reflection.jl b/test/reflection.jl index d6b2161619b26..fdb3c329c58da 100644 --- a/test/reflection.jl +++ b/test/reflection.jl @@ -572,6 +572,32 @@ fLargeTable(::Union, ::Union) = "b" @test length(methods(fLargeTable)) == 205 @test fLargeTable(Union{Int, Missing}, Union{Int, Missing}) == "b" +# issue #58479 +fLargeTable(::Type) = "Type" +fLargeTable(::Type{<:DataType}) = "DataType" +@test fLargeTable(Type) == "Type" +@test fLargeTable(DataType) == "DataType" +@test fLargeTable(Type{DataType}) == "DataType" +@test fLargeTable(Type{UnionAll}) == "DataType" +@test fLargeTable(Type{Int}) == "DataType" +@test fLargeTable(Type{Vector}) == "Type" +@test fLargeTable(Type{Type{Union{}}}) == "DataType" +@test fLargeTable(Type{Union{}}) == "Type" +@test fLargeTable(Union{}) == "DataType" +@test fLargeTable(Type{<:DataType}) == "Type" +fLargeTable(::Type{<:UnionAll}) = "UnionAll" +@test fLargeTable(UnionAll) == "UnionAll" +@test fLargeTable(Type{Vector}) == "UnionAll" +@test fLargeTable(Type{Int}) == "DataType" +@test fLargeTable(Type{Type{Union{}}}) == "DataType" +@test fLargeTable(Type{Union{}}) == "Type" +@test_throws MethodError fLargeTable(Union{}) +@test fLargeTable(Type{<:DataType}) == "Type" +@test fLargeTable(Type{Vector{T}} where T) == "DataType" +@test fLargeTable(Union{DataType,Type{Vector{T}} where T}) == "DataType" +@test fLargeTable(Union{DataType,UnionAll,Type{Vector{T}} where T}) == "Type" +@test fLargeTable(Union{Type{Vector},Type{Vector{T}} where T}) == "Type" + # issue #15280 function f15280(x) end @test functionloc(f15280)[2] > 0 From a6394cd1ef5238ed35b82619d7cb97c9ba9a38a1 Mon Sep 17 00:00:00 2001 From: Neven Sajko <4944410+nsajko@users.noreply.github.com> Date: Sat, 31 May 2025 18:58:56 +0200 Subject: [PATCH 41/46] relax dispatch for the `IteratorSize` method for `Generator` (#58110) Fixes #58109 (cherry picked from commit 805f85f6e957af6d8ecdfd1ef0f5887ae4c44467) --- base/generator.jl | 2 +- test/iterators.jl | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/base/generator.jl b/base/generator.jl index 1f981de8dc788..86daefd13b378 100644 --- a/base/generator.jl +++ b/base/generator.jl @@ -98,7 +98,7 @@ IteratorSize(::Type{Any}) = SizeUnknown() IteratorSize(::Type{<:Tuple}) = HasLength() IteratorSize(::Type{<:AbstractArray{<:Any,N}}) where {N} = HasShape{N}() -IteratorSize(::Type{Generator{I,F}}) where {I,F} = IteratorSize(I) +IteratorSize(::Type{<:Generator{I}}) where {I} = (@isdefined I) ? IteratorSize(I) : SizeUnknown() haslength(iter) = IteratorSize(iter) isa Union{HasShape, HasLength} diff --git a/test/iterators.jl b/test/iterators.jl index df4fa63b433b8..a6ab4720c0d0c 100644 --- a/test/iterators.jl +++ b/test/iterators.jl @@ -988,6 +988,12 @@ end @test accumulate(+, (x^2 for x in 1:3); init=100) == [101, 105, 114] end +@testset "issue #58109" begin + i = Iterators.map(identity, 3) + j = Iterators.map(sqrt, 7) + @test (@inferred Base.IteratorSize(i)) === @inferred Base.IteratorSize(eltype([i, j])) +end + @testset "IteratorSize trait for zip" begin @test (@inferred Base.IteratorSize(zip())) == Base.IsInfinite() # for zip of empty tuple @test (@inferred Base.IteratorSize(zip((1,2,3), repeated(0)))) == Base.HasLength() # for zip of ::HasLength and ::IsInfinite From 6ab22e4f28ae2ef86b39d8e3133a95c9c54dc5d2 Mon Sep 17 00:00:00 2001 From: Neven Sajko <4944410+nsajko@users.noreply.github.com> Date: Mon, 2 Jun 2025 03:14:22 +0200 Subject: [PATCH 42/46] fix Markdown in the `Lockable` doc strings (#58603) (cherry picked from commit 9da64559e3046cf9215c1cc752d301e735996473) --- base/lock.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/base/lock.jl b/base/lock.jl index b6d633d7907a2..79e0ba264df15 100644 --- a/base/lock.jl +++ b/base/lock.jl @@ -398,7 +398,7 @@ macro lock_nofail(l, expr) end """ - Lockable(value, lock = ReentrantLock()) + Lockable(value, lock = ReentrantLock()) Creates a `Lockable` object that wraps `value` and associates it with the provided `lock`. This object @@ -431,7 +431,7 @@ Lockable(value) = Lockable(value, ReentrantLock()) getindex(l::Lockable) = (assert_havelock(l.lock); l.value) """ - lock(f::Function, l::Lockable) + lock(f::Function, l::Lockable) Acquire the lock associated with `l`, execute `f` with the lock held, and release the lock when `f` returns. `f` will receive one positional From 31151e5c7b88ceb5f637c88eaf8fcad1b330e320 Mon Sep 17 00:00:00 2001 From: Fredrik Ekre Date: Mon, 2 Jun 2025 21:47:28 +0200 Subject: [PATCH 43/46] Update readlines(::Cmd) test to not rely on the filesystem (#58607) (cherry picked from commit 48c0e7f99c4e83d98761898e090ca3b5c6d3be90) --- test/spawn.jl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/spawn.jl b/test/spawn.jl index 099f0670ce5f7..bfb7c9a83ffb6 100644 --- a/test/spawn.jl +++ b/test/spawn.jl @@ -620,7 +620,9 @@ end @test reduce(&, [`$echocmd abc`, `$echocmd def`, `$echocmd hij`]) == `$echocmd abc` & `$echocmd def` & `$echocmd hij` # readlines(::Cmd), accidentally broken in #20203 -@test sort(readlines(`$lscmd -A`)) == sort(readdir()) +let str = "foo\nbar" + @test readlines(`$echocmd $str`) == split(str) +end # issue #19864 (PR #20497) let c19864 = readchomp(pipeline(ignorestatus( From c8a4fd2f5df9e3f8d404842b4ccb801add18cf61 Mon Sep 17 00:00:00 2001 From: Matt Bauman Date: Mon, 2 Jun 2025 10:55:07 -0400 Subject: [PATCH 44/46] Re-enable tab completion of kwargs for large method tables (#58012) while testing to ensure that ~~absurdly large method tables~~ tab completing over an abstract function call doesn't tank the performance of the REPL Fixes #57836 (cherry picked from commit 6f129571004beac33a5cbc4aa7cbb6fcca4f5769) --- stdlib/REPL/src/REPLCompletions.jl | 8 +++++++- stdlib/REPL/test/replcompletions.jl | 29 +++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/stdlib/REPL/src/REPLCompletions.jl b/stdlib/REPL/src/REPLCompletions.jl index 2f3fefc6ec2c7..13f9f93c0da16 100644 --- a/stdlib/REPL/src/REPLCompletions.jl +++ b/stdlib/REPL/src/REPLCompletions.jl @@ -883,7 +883,13 @@ function complete_keyword_argument!(suggestions::Vector{Completion}, kwargs_flag == 2 && false # one of the previous kwargs is invalid methods = Completion[] - complete_methods!(methods, funct, Any[Vararg{Any}], kwargs_ex, shift ? -1 : MAX_METHOD_COMPLETIONS, kwargs_flag == 1) + # Limit kwarg completions to cases when function is concretely known; looking up + # matching methods for abstract functions — particularly `Any` or `Function` — can + # take many seconds to run over the thousands of possible methods. Note that + # isabstracttype would return naively return true for common constructor calls + # like Array, but the REPL's introspection here may know their Type{T}. + isconcretetype(funct) || return false + complete_methods!(methods, funct, Any[Vararg{Any}], kwargs_ex, -1, arg_pos == :kwargs) # TODO: use args_ex instead of Any[Vararg{Any}] and only provide kwarg completion for # method calls compatible with the current arguments. diff --git a/stdlib/REPL/test/replcompletions.jl b/stdlib/REPL/test/replcompletions.jl index 5569b93640bd8..7c50daf8d0d15 100644 --- a/stdlib/REPL/test/replcompletions.jl +++ b/stdlib/REPL/test/replcompletions.jl @@ -2632,6 +2632,35 @@ const issue57780_orig = copy(issue57780) test_complete_context("empty!(issue57780).", Main) @test issue57780 == issue57780_orig +function g54131 end +for i in 1:498 + @eval g54131(::Val{$i}) = i +end +g54131(::Val{499}; kwarg=true) = 499*kwarg +struct F54131; end +Base.getproperty(::F54131, ::Symbol) = Any[cos, sin, g54131][rand(1:3)] +f54131 = F54131() +@testset "performance of kwarg completion with large method tables" begin + # The goal here is to simply ensure we aren't hitting catestrophically bad + # behaviors when shift isn't pressed. The difference between good and bad + # is on the order of tens of milliseconds vs tens of seconds; using 1 sec as + # a very rough canary that is hopefully robust even in the noisy CI coalmines + s = "g54131(kwa" + a, b, c = completions(s, lastindex(s), @__MODULE__, #= shift =# false) + @test REPLCompletions.KeywordArgumentCompletion("kwarg") in a + @test (@elapsed completions(s, lastindex(s), @__MODULE__, false)) < 1 + + s = "f54131.x(" + a, b, c = completions(s, lastindex(s), @__MODULE__, false) + @test only(a) isa REPLCompletions.TextCompletion + @test (@elapsed completions(s, lastindex(s), @__MODULE__, false)) < 1 + + s = "f54131.x(kwa" + a, b, c = completions(s, lastindex(s), @__MODULE__, false) + @test_broken REPLCompletions.KeywordArgumentCompletion("kwarg") in a + @test (@elapsed completions(s, lastindex(s), @__MODULE__, false)) < 1 +end + # Completion inside string interpolation let s = "\"example: \$varflo" c, r = test_complete_foo(s) From 9aa677ceba1780556d964bb8f30a6be6e0f9d29e Mon Sep 17 00:00:00 2001 From: Em Chu <61633163+mlechu@users.noreply.github.com> Date: Tue, 3 Jun 2025 02:03:24 -0700 Subject: [PATCH 45/46] Fix `linearize` of global with complex type (#58611) (cherry picked from commit 050284ceed86aa47b34d39ebccdee0beaf026146) --- src/julia-syntax.scm | 2 +- test/syntax.jl | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 16120c3696b99..b2da8c4afdd2a 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -4972,7 +4972,7 @@ f(x) = yt(x) (if value (error "misplaced \"global\" declaration")) (if (or (length= e 2) (atom? (caddr e))) (emit e) (let ((rr (make-ssavalue))) - (emit `(= ,rr ,(caddr e))) + (emit `(= ,rr ,(compile (caddr e) break-labels #t #f))) (emit `(globaldecl ,(cadr e) ,rr)))) (if (null? (cadr lam)) (emit `(latestworld)))) diff --git a/test/syntax.jl b/test/syntax.jl index c78e8ea1806cc..9be2dff6c3cfa 100644 --- a/test/syntax.jl +++ b/test/syntax.jl @@ -4237,6 +4237,16 @@ end @test letf_57470(3) == 5 @test letT_57470 === Int64 +end # M57470_sub + +# lowering globaldecl with complex type +module M58609 +using Test +global x::T where T +global y::Type{<:Number} + +@test Core.get_binding_type(M58609, :x) === Any +@test Core.get_binding_type(M58609, :y) == Type{<:Number} end # #57574 From 59ad720694f6bbf9c86a227300bebc5cfb45d8de Mon Sep 17 00:00:00 2001 From: Sam Schweigel <33556084+xal-0@users.noreply.github.com> Date: Mon, 5 May 2025 15:33:36 -0700 Subject: [PATCH 46/46] Fix completing positional arguments if a semicolon exists beyond the cursor (#58298) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a stopgap solution. For now, have `find_prefix_call` tell us whether the cursor is before the `;` (:positional) or after (:kwargs), and set `exact_nargs` only when it is :kwargs. Eventually, we should remove kwargs_flag entirely and have the method completions use our precise position information. Fixes #58296, and the related issue I mention in https://github.com/JuliaLang/julia/issues/58296#issuecomment-2845310701. --------- Co-authored-by: Mosè Giordano <765740+giordano@users.noreply.github.com> Co-authored-by: Jameson Nash (cherry picked from commit da6356bdf42bbd7219c20b1e08fb13b76b686fe4) --- stdlib/REPL/src/REPLCompletions.jl | 34 ++++++++++++++++++----------- stdlib/REPL/test/replcompletions.jl | 14 ++++++++++++ 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/stdlib/REPL/src/REPLCompletions.jl b/stdlib/REPL/src/REPLCompletions.jl index 13f9f93c0da16..4244111f0aa36 100644 --- a/stdlib/REPL/src/REPLCompletions.jl +++ b/stdlib/REPL/src/REPLCompletions.jl @@ -697,9 +697,12 @@ function _complete_methods(ex_org::Expr, context_module::Module, shift::Bool) return kwargs_flag, funct, args_ex, kwargs_ex end -function complete_methods(ex_org::Expr, context_module::Module=Main, shift::Bool=false) +# cursor_pos: either :positional (complete either kwargs or positional) or :kwargs (beyond semicolon) +function complete_methods(ex_org::Expr, context_module::Module=Main, shift::Bool=false, cursor_pos::Symbol=:positional) kwargs_flag, funct, args_ex, kwargs_ex = _complete_methods(ex_org, context_module, shift)::Tuple{Int, Any, Vector{Any}, Set{Symbol}} out = Completion[] + # Allow more arguments when cursor before semicolon, even if kwargs are present + cursor_pos == :positional && kwargs_flag == 1 && (kwargs_flag = 0) kwargs_flag == 2 && return out # one of the kwargs is invalid kwargs_flag == 0 && push!(args_ex, Vararg{Any}) # allow more arguments if there is no semicolon complete_methods!(out, funct, args_ex, kwargs_ex, shift ? -2 : MAX_METHOD_COMPLETIONS, kwargs_flag == 1) @@ -876,11 +879,13 @@ end end # Provide completion for keyword arguments in function calls +# Returns true if the current argument must be a keyword because the cursor is beyond the semicolon function complete_keyword_argument!(suggestions::Vector{Completion}, ex::Expr, last_word::String, - context_module::Module; shift::Bool=false) + context_module::Module, + arg_pos::Symbol; shift::Bool=false) kwargs_flag, funct, args_ex, kwargs_ex = _complete_methods(ex, context_module, true)::Tuple{Int, Any, Vector{Any}, Set{Symbol}} - kwargs_flag == 2 && false # one of the previous kwargs is invalid + kwargs_flag == 2 && return false # one of the previous kwargs is invalid methods = Completion[] # Limit kwarg completions to cases when function is concretely known; looking up @@ -919,7 +924,7 @@ function complete_keyword_argument!(suggestions::Vector{Completion}, for kwarg in kwargs push!(suggestions, KeywordArgumentCompletion(kwarg)) end - return kwargs_flag != 0 + return kwargs_flag != 0 && arg_pos == :kwargs end function get_loading_candidates(pkgstarts::String, project_file::String) @@ -1055,7 +1060,8 @@ function completions(string::String, pos::Int, context_module::Module=Main, shif (kind(cur) in KSet"String Comment ErrorEofMultiComment" || inside_cmdstr) && return Completion[], 1:0, false - if (n = find_prefix_call(cur_not_ws)) !== nothing + n, arg_pos = find_prefix_call(cur_not_ws) + if n !== nothing func = first(children_nt(n)) e = Expr(n) # Remove arguments past the first parse error (allows unclosed parens) @@ -1072,7 +1078,7 @@ function completions(string::String, pos::Int, context_module::Module=Main, shif # foo(x, TAB => list of methods signatures for foo with x as first argument if kind(cur_not_ws) in KSet"( , ;" # Don't provide method completions unless the cursor is after: '(' ',' ';' - return complete_methods(e, context_module, shift), char_range(func), false + return complete_methods(e, context_module, shift, arg_pos), char_range(func), false # Keyword argument completion: # foo(ar TAB => keyword arguments like `arg1=` @@ -1080,7 +1086,7 @@ function completions(string::String, pos::Int, context_module::Module=Main, shif r = char_range(cur) s = string[intersect(r, 1:pos)] # Return without adding more suggestions if kwargs only - complete_keyword_argument!(suggestions, e, s, context_module; shift) && + complete_keyword_argument!(suggestions, e, s, context_module, arg_pos; shift) && return sort_suggestions(), r, true end end @@ -1168,18 +1174,20 @@ function find_str(cur::CursorNode) end # Is the cursor directly inside of the arguments of a prefix call (no nested -# expressions)? +# expressions)? If so, return: +# - The call node +# - Either :positional or :kwargs, if the cursor is before or after the `;` function find_prefix_call(cur::CursorNode) n = cur.parent - n !== nothing || return nothing + n !== nothing || return nothing, nothing is_call(n) = kind(n) in KSet"call dotcall" && is_prefix_call(n) if kind(n) == K"parameters" - is_call(n.parent) || return nothing - n.parent + is_call(n.parent) || return nothing, nothing + n.parent, :kwargs else # Check that we are beyond the function name. - is_call(n) && cur.index > children_nt(n)[1].index || return nothing - n + is_call(n) && cur.index > children_nt(n)[1].index || return nothing, nothing + n, :positional end end diff --git a/stdlib/REPL/test/replcompletions.jl b/stdlib/REPL/test/replcompletions.jl index 7c50daf8d0d15..5f2990e970d97 100644 --- a/stdlib/REPL/test/replcompletions.jl +++ b/stdlib/REPL/test/replcompletions.jl @@ -2679,3 +2679,17 @@ let s = "\"example: \$(named.len" @test "len2" in c @test r == 19:21 end + +# #58296 - complete positional arguments before semicolon +let s = "string(findfi|; base=16)" + c, r = test_complete_pos(s) + @test "findfirst" in c + @test r == 8:13 +end + +# Unknown functions should not cause completions to fail +let s = "foo58296(findfi" + c, r = test_complete(s) + @test "findfirst" in c + @test r == 10:15 +end