diff --git a/base/c.jl b/base/c.jl index 78c48f267ca71..01b7613dbf7c6 100644 --- a/base/c.jl +++ b/base/c.jl @@ -451,6 +451,6 @@ macro ccall(exprs...) return ccall_macro_lower((:ccall), ccall_macro_parse(exprs)...) end -macro ccall_effects(effects::UInt16, expr) - return ccall_macro_lower((:ccall, effects), ccall_macro_parse(expr)...) +macro ccall_effects(effects::UInt16, exprs...) + return ccall_macro_lower((:ccall, effects), ccall_macro_parse(exprs)...) end diff --git a/deps/checksums/Pkg-474c628764d6562453709bff686f7fc65dd23535.tar.gz/md5 b/deps/checksums/Pkg-474c628764d6562453709bff686f7fc65dd23535.tar.gz/md5 deleted file mode 100644 index 022040d7d0009..0000000000000 --- a/deps/checksums/Pkg-474c628764d6562453709bff686f7fc65dd23535.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -b6596d36c153d476101b1db14c5d1400 diff --git a/deps/checksums/Pkg-474c628764d6562453709bff686f7fc65dd23535.tar.gz/sha512 b/deps/checksums/Pkg-474c628764d6562453709bff686f7fc65dd23535.tar.gz/sha512 deleted file mode 100644 index 16c6f4eaafe66..0000000000000 --- a/deps/checksums/Pkg-474c628764d6562453709bff686f7fc65dd23535.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -1bc6f3f3d8a40f4ce51928115e44a46b89a2a1404f0ad9fa0b8cdca4641ab42eab3ff0d9a6a2cbbb57dbaf7effcf399b188716b3fc2d18b32f750d5fb363669f diff --git a/deps/checksums/Pkg-69926e385c878253d62e2588a19b252277196ebf.tar.gz/md5 b/deps/checksums/Pkg-69926e385c878253d62e2588a19b252277196ebf.tar.gz/md5 new file mode 100644 index 0000000000000..faee08623f288 --- /dev/null +++ b/deps/checksums/Pkg-69926e385c878253d62e2588a19b252277196ebf.tar.gz/md5 @@ -0,0 +1 @@ +6e3a44c3870f135953b325a155fecd65 diff --git a/deps/checksums/Pkg-69926e385c878253d62e2588a19b252277196ebf.tar.gz/sha512 b/deps/checksums/Pkg-69926e385c878253d62e2588a19b252277196ebf.tar.gz/sha512 new file mode 100644 index 0000000000000..e09a59d4feb83 --- /dev/null +++ b/deps/checksums/Pkg-69926e385c878253d62e2588a19b252277196ebf.tar.gz/sha512 @@ -0,0 +1 @@ +565bdb1a4e8bda374d08a49b2ba70130762ca06004cc50d07ca58ca9a3741195977f563bc990bd627735b6464162a15a7bfb08570e812abf2f22151713de2210 diff --git a/src/codegen.cpp b/src/codegen.cpp index 81d371d7f0804..6c4543fcf0049 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2838,10 +2838,9 @@ static void visitLine(jl_codectx_t &ctx, uint64_t *ptr, Value *addend, const cha Value *pv = ConstantExpr::getIntToPtr( ConstantInt::get(ctx.types().T_size, (uintptr_t)ptr), getPointerTy(ctx.builder.getContext())); - Value *v = ctx.builder.CreateLoad(getInt64Ty(ctx.builder.getContext()), pv, true, name); - v = ctx.builder.CreateAdd(v, addend); - ctx.builder.CreateStore(v, pv, true); // volatile, not atomic, so this might be an underestimate, - // but it's faster this way + ctx.builder.CreateAtomicRMW(AtomicRMWInst::Add, pv, + addend, MaybeAlign(), + AtomicOrdering::Monotonic); } // Code coverage diff --git a/src/coverage.cpp b/src/coverage.cpp index 685370198ff13..c5e5afb5287bc 100644 --- a/src/coverage.cpp +++ b/src/coverage.cpp @@ -1,5 +1,7 @@ // This file is a part of Julia. License is MIT: https://julialang.org/license +#include +#include #include #include #include @@ -15,7 +17,7 @@ using namespace llvm; -static int codegen_imaging_mode(void) +static int codegen_imaging_mode(void) JL_NOTSAFEPOINT { return jl_options.image_codegen || (jl_generating_output() && jl_options.use_pkgimages); } @@ -26,7 +28,9 @@ const int logdata_blocksize = 32; // target getting nearby lines in the same gen typedef uint64_t logdata_block[logdata_blocksize]; typedef StringMap< SmallVector > logdata_t; -static uint64_t *allocLine(SmallVector &vec, int line) +pthread_mutex_t coverage_lock = PTHREAD_MUTEX_INITIALIZER; + +static uint64_t *allocLine(SmallVector &vec, int line) JL_NOTSAFEPOINT { unsigned block = line / logdata_blocksize; line = line % logdata_blocksize; @@ -45,39 +49,49 @@ static uint64_t *allocLine(SmallVector &vec, int line) static logdata_t coverageData; -JL_DLLEXPORT void jl_coverage_alloc_line(StringRef filename, int line) +JL_DLLEXPORT void jl_coverage_alloc_line(StringRef filename, int line) JL_NOTSAFEPOINT { assert(!codegen_imaging_mode()); if (filename == "" || filename == "none" || filename == "no file" || filename == "" || line < 0) return; + pthread_mutex_lock(&coverage_lock); allocLine(coverageData[filename], line); + pthread_mutex_unlock(&coverage_lock); } -JL_DLLEXPORT uint64_t *jl_coverage_data_pointer(StringRef filename, int line) +JL_DLLEXPORT uint64_t *jl_coverage_data_pointer(StringRef filename, int line) JL_NOTSAFEPOINT { - return allocLine(coverageData[filename], line); + pthread_mutex_lock(&coverage_lock); + uint64_t* ret = allocLine(coverageData[filename], line); + pthread_mutex_unlock(&coverage_lock); + return ret; } -extern "C" JL_DLLEXPORT void jl_coverage_visit_line(const char *filename_, size_t len_filename, int line) +extern "C" JL_DLLEXPORT void jl_coverage_visit_line(const char *filename_, size_t len_filename, int line) JL_NOTSAFEPOINT { StringRef filename = StringRef(filename_, len_filename); if (codegen_imaging_mode() || filename == "" || filename == "none" || filename == "no file" || filename == "" || line < 0) return; + pthread_mutex_lock(&coverage_lock); SmallVector &vec = coverageData[filename]; uint64_t *ptr = allocLine(vec, line); (*ptr)++; + pthread_mutex_unlock(&coverage_lock); } // Memory allocation log (malloc_log) static logdata_t mallocData; -JL_DLLEXPORT uint64_t *jl_malloc_data_pointer(StringRef filename, int line) +JL_DLLEXPORT uint64_t *jl_malloc_data_pointer(StringRef filename, int line) JL_NOTSAFEPOINT { - return allocLine(mallocData[filename], line); + pthread_mutex_lock(&coverage_lock); + uint64_t* ret = allocLine(mallocData[filename], line); + pthread_mutex_unlock(&coverage_lock); + return ret; } -static void clear_log_data(logdata_t &logData, int resetValue) +static void clear_log_data(logdata_t &logData, int resetValue) JL_NOTSAFEPOINT { logdata_t::iterator it = logData.begin(); for (; it != logData.end(); it++) { @@ -97,18 +111,22 @@ static void clear_log_data(logdata_t &logData, int resetValue) } // Resets the malloc counts. -extern "C" JL_DLLEXPORT void jl_clear_malloc_data(void) +extern "C" JL_DLLEXPORT void jl_clear_malloc_data(void) JL_NOTSAFEPOINT { + pthread_mutex_lock(&coverage_lock); clear_log_data(mallocData, 1); + pthread_mutex_unlock(&coverage_lock); } // Resets the code coverage -extern "C" JL_DLLEXPORT void jl_clear_coverage_data(void) +extern "C" JL_DLLEXPORT void jl_clear_coverage_data(void) JL_NOTSAFEPOINT { + pthread_mutex_lock(&coverage_lock); clear_log_data(coverageData, 0); + pthread_mutex_unlock(&coverage_lock); } -static void write_log_data(logdata_t &logData, const char *extension) +static void write_log_data(logdata_t &logData, const char *extension) JL_NOTSAFEPOINT { std::string base = std::string(jl_options.julia_bindir); base = base + "/../share/julia/base/"; @@ -163,7 +181,7 @@ static void write_log_data(logdata_t &logData, const char *extension) } } -static void write_lcov_data(logdata_t &logData, const std::string &outfile) +static void write_lcov_data(logdata_t &logData, const std::string &outfile) JL_NOTSAFEPOINT { std::ofstream outf(outfile.c_str(), std::ofstream::ate | std::ofstream::out | std::ofstream::binary); //std::string base = std::string(jl_options.julia_bindir); @@ -203,8 +221,9 @@ static void write_lcov_data(logdata_t &logData, const std::string &outfile) outf.close(); } -extern "C" JL_DLLEXPORT void jl_write_coverage_data(const char *output) +extern "C" JL_DLLEXPORT void jl_write_coverage_data(const char *output) JL_NOTSAFEPOINT { + pthread_mutex_lock(&coverage_lock); if (output) { StringRef output_pattern(output); if (output_pattern.ends_with(".info")) @@ -215,11 +234,14 @@ extern "C" JL_DLLEXPORT void jl_write_coverage_data(const char *output) raw_string_ostream(stm) << "." << uv_os_getpid() << ".cov"; write_log_data(coverageData, stm.c_str()); } + pthread_mutex_unlock(&coverage_lock); } -extern "C" void jl_write_malloc_log(void) +extern "C" void jl_write_malloc_log(void) JL_NOTSAFEPOINT { + pthread_mutex_lock(&coverage_lock); std::string stm; raw_string_ostream(stm) << "." << uv_os_getpid() << ".mem"; write_log_data(mallocData, stm.c_str()); + pthread_mutex_unlock(&coverage_lock); } diff --git a/src/gf.c b/src/gf.c index 06bf3b62deda0..23b863294b45b 100644 --- a/src/gf.c +++ b/src/gf.c @@ -124,7 +124,7 @@ static int8_t jl_cachearg_offset(void) /// ----- Insertion logic for special entries ----- /// -static uint_t speccache_hash(size_t idx, jl_value_t *data) +uint_t speccache_hash(size_t idx, jl_value_t *data) { jl_method_instance_t *ml = (jl_method_instance_t*)jl_svecref(data, idx); // This must always happen inside the lock jl_value_t *sig = ml->specTypes; @@ -150,7 +150,7 @@ static int speccache_eq(size_t idx, const void *ty, jl_value_t *data, uint_t hv) // get or create the MethodInstance for a specialization static jl_method_instance_t *jl_specializations_get_linfo_(jl_method_t *m JL_PROPAGATES_ROOT, jl_value_t *type, jl_svec_t *sparams, jl_method_instance_t *mi_insert) { - if (m->sig == (jl_value_t*)jl_anytuple_type && jl_atomic_load_relaxed(&m->unspecialized) != NULL && m != jl_opaque_closure_method && !m->is_for_opaque_closure) + if (m->source == NULL && m->generator == NULL && jl_atomic_load_relaxed(&m->unspecialized) != NULL && m != jl_opaque_closure_method && !m->is_for_opaque_closure) return jl_atomic_load_relaxed(&m->unspecialized); // handle builtin methods jl_value_t *ut = jl_is_unionall(type) ? jl_unwrap_unionall(type) : type; JL_TYPECHK(specializations, datatype, ut); @@ -3980,7 +3980,8 @@ STATIC_INLINE jl_value_t *_jl_invoke(jl_value_t *F, jl_value_t **args, uint32_t // manually inlined copy of jl_method_compiled jl_code_instance_t *codeinst = jl_atomic_load_relaxed(&mfunc->cache); while (codeinst) { - if (jl_atomic_load_relaxed(&codeinst->min_world) <= world && world <= jl_atomic_load_relaxed(&codeinst->max_world)) { + if (jl_atomic_load_relaxed(&codeinst->min_world) <= world && world <= jl_atomic_load_relaxed(&codeinst->max_world) + && codeinst->owner == jl_nothing) { jl_callptr_t invoke = jl_atomic_load_acquire(&codeinst->invoke); if (invoke != NULL) { jl_value_t *res = invoke(F, args, nargs, codeinst); diff --git a/src/julia.h b/src/julia.h index 34b2d79259ede..d5ffa9575a69a 100644 --- a/src/julia.h +++ b/src/julia.h @@ -2620,7 +2620,7 @@ JL_DLLEXPORT ssize_t jl_sizeof_jl_options(void); // Parse an argc/argv pair to extract general julia options, passing back out // any arguments that should be passed on to the script. JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp); -JL_DLLEXPORT char *jl_format_filename(const char *output_pattern); +JL_DLLEXPORT char *jl_format_filename(const char *output_pattern) JL_NOTSAFEPOINT; uint64_t parse_heap_size_hint(const char *optarg, const char *option_name); diff --git a/src/runtime_ccall.cpp b/src/runtime_ccall.cpp index f3f1632751c87..3a3a6c15fc888 100644 --- a/src/runtime_ccall.cpp +++ b/src/runtime_ccall.cpp @@ -106,7 +106,7 @@ jl_value_t *jl_get_JIT(void) // %L The local hostname. // %l The local hostname, including the domain name. // %u The local username. -std::string jl_format_filename(StringRef output_pattern) +std::string jl_format_filename(StringRef output_pattern) JL_NOTSAFEPOINT { std::string buf; raw_string_ostream outfile(buf); @@ -168,7 +168,7 @@ std::string jl_format_filename(StringRef output_pattern) return outfile.str(); } -extern "C" JL_DLLEXPORT char *jl_format_filename(const char *output_pattern) +extern "C" JL_DLLEXPORT char *jl_format_filename(const char *output_pattern) JL_NOTSAFEPOINT { return strdup(jl_format_filename(StringRef(output_pattern)).c_str()); } diff --git a/src/staticdata.c b/src/staticdata.c index 49cbb4e6a8296..466bb349fa4e1 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -2624,49 +2624,64 @@ static void jl_prune_binding_backedges(jl_array_t *backedges) jl_array_del_end(backedges, n - ins); } - uint_t bindingkey_hash(size_t idx, jl_value_t *data); +uint_t speccache_hash(size_t idx, jl_value_t *data); -static void jl_prune_module_bindings(jl_module_t * m) JL_GC_DISABLED +static void jl_prune_idset(_Atomic(jl_svec_t*) *pkeys, _Atomic(jl_genericmemory_t*) *pkeyset, uint_t (*key_hash)(size_t, jl_value_t*), jl_value_t *parent) JL_GC_DISABLED { - jl_svec_t *bindings = jl_atomic_load_relaxed(&m->bindings); - size_t l = jl_svec_len(bindings), i; - arraylist_t bindings_list; - arraylist_new(&bindings_list, 0); + jl_svec_t *keys = jl_atomic_load_relaxed(pkeys); + size_t l = jl_svec_len(keys), i; if (l == 0) return; + arraylist_t keys_list; + arraylist_new(&keys_list, 0); for (i = 0; i < l; i++) { - jl_value_t *ti = jl_svecref(bindings, i); - if (ti == jl_nothing) + jl_value_t *k = jl_svecref(keys, i); + if (k == jl_nothing) continue; - jl_binding_t *ref = ((jl_binding_t*)ti); - if (ptrhash_get(&serialization_order, ref) != HT_NOTFOUND) - arraylist_push(&bindings_list, ref); - } - jl_genericmemory_t *bindingkeyset = jl_atomic_load_relaxed(&m->bindingkeyset); - _Atomic(jl_genericmemory_t*)bindingkeyset2; - jl_atomic_store_relaxed(&bindingkeyset2, (jl_genericmemory_t*)jl_an_empty_memory_any); - jl_svec_t *bindings2 = jl_alloc_svec_uninit(bindings_list.len); - for (i = 0; i < bindings_list.len; i++) { - jl_binding_t *ref = (jl_binding_t*)bindings_list.items[i]; - jl_svecset(bindings2, i, ref); - jl_smallintset_insert(&bindingkeyset2, (jl_value_t*)m, bindingkey_hash, i, (jl_value_t*)bindings2); - } - void *idx = ptrhash_get(&serialization_order, bindings); + if (ptrhash_get(&serialization_order, k) != HT_NOTFOUND) + arraylist_push(&keys_list, k); + } + jl_genericmemory_t *keyset = jl_atomic_load_relaxed(pkeyset); + _Atomic(jl_genericmemory_t*)keyset2; + jl_atomic_store_relaxed(&keyset2, (jl_genericmemory_t*)jl_an_empty_memory_any); + jl_svec_t *keys2 = jl_alloc_svec_uninit(keys_list.len); + for (i = 0; i < keys_list.len; i++) { + jl_binding_t *ref = (jl_binding_t*)keys_list.items[i]; + jl_svecset(keys2, i, ref); + jl_smallintset_insert(&keyset2, parent, key_hash, i, (jl_value_t*)keys2); + } + void *idx = ptrhash_get(&serialization_order, keys); assert(idx != HT_NOTFOUND && idx != (void*)(uintptr_t)-1); - assert(serialization_queue.items[(char*)idx - 1 - (char*)HT_NOTFOUND] == bindings); - ptrhash_put(&serialization_order, bindings2, idx); - serialization_queue.items[(char*)idx - 1 - (char*)HT_NOTFOUND] = bindings2; + assert(serialization_queue.items[(char*)idx - 1 - (char*)HT_NOTFOUND] == keys); + ptrhash_put(&serialization_order, keys2, idx); + serialization_queue.items[(char*)idx - 1 - (char*)HT_NOTFOUND] = keys2; - idx = ptrhash_get(&serialization_order, bindingkeyset); + idx = ptrhash_get(&serialization_order, keyset); assert(idx != HT_NOTFOUND && idx != (void*)(uintptr_t)-1); - assert(serialization_queue.items[(char*)idx - 1 - (char*)HT_NOTFOUND] == bindingkeyset); - ptrhash_put(&serialization_order, jl_atomic_load_relaxed(&bindingkeyset2), idx); - serialization_queue.items[(char*)idx - 1 - (char*)HT_NOTFOUND] = jl_atomic_load_relaxed(&bindingkeyset2); - jl_atomic_store_relaxed(&m->bindings, bindings2); - jl_atomic_store_relaxed(&m->bindingkeyset, jl_atomic_load_relaxed(&bindingkeyset2)); - jl_gc_wb(m, bindings2); - jl_gc_wb(m, jl_atomic_load_relaxed(&bindingkeyset2)); + assert(serialization_queue.items[(char*)idx - 1 - (char*)HT_NOTFOUND] == keyset); + ptrhash_put(&serialization_order, jl_atomic_load_relaxed(&keyset2), idx); + serialization_queue.items[(char*)idx - 1 - (char*)HT_NOTFOUND] = jl_atomic_load_relaxed(&keyset2); + jl_atomic_store_relaxed(pkeys, keys2); + jl_gc_wb(parent, keys2); + jl_atomic_store_relaxed(pkeyset, jl_atomic_load_relaxed(&keyset2)); + jl_gc_wb(parent, jl_atomic_load_relaxed(&keyset2)); +} + +static void jl_prune_method_specializations(jl_method_t *m) JL_GC_DISABLED +{ + jl_value_t *specializations_ = jl_atomic_load_relaxed(&m->specializations); + if (!jl_is_svec(specializations_)) { + if (ptrhash_get(&serialization_order, specializations_) == HT_NOTFOUND) + record_field_change((jl_value_t **)&m->specializations, (jl_value_t*)jl_emptysvec); + return; + } + jl_prune_idset((_Atomic(jl_svec_t*)*)&m->specializations, &m->speckeyset, speccache_hash, (jl_value_t*)m); +} + +static void jl_prune_module_bindings(jl_module_t *m) JL_GC_DISABLED +{ + jl_prune_idset(&m->bindings, &m->bindingkeyset, bindingkey_hash, (jl_value_t*)m); } static void strip_slotnames(jl_array_t *slotnames, int n) @@ -3231,32 +3246,15 @@ static void jl_save_system_image_to_stream(ios_t *f, jl_array_t *mod_array, // step 1.5: prune (garbage collect) some special weak references known caches for (i = 0; i < serialization_queue.len; i++) { jl_value_t *v = (jl_value_t*)serialization_queue.items[i]; - if (jl_options.trim) { - if (jl_is_method(v)) { - jl_method_t *m = (jl_method_t*)v; - jl_value_t *specializations_ = jl_atomic_load_relaxed(&m->specializations); - if (!jl_is_svec(specializations_)) { - if (ptrhash_get(&serialization_order, specializations_) == HT_NOTFOUND) - record_field_change((jl_value_t **)&m->specializations, (jl_value_t*)jl_emptysvec); - continue; - } - - jl_svec_t *specializations = (jl_svec_t *)specializations_; - size_t l = jl_svec_len(specializations), i; - for (i = 0; i < l; i++) { - jl_value_t *mi = jl_svecref(specializations, i); - if (mi == jl_nothing) - continue; - if (ptrhash_get(&serialization_order, mi) == HT_NOTFOUND) - jl_svecset(specializations, i, jl_nothing); - } - } - else if (jl_is_module(v)) { + if (jl_is_method(v)) { + if (jl_options.trim) + jl_prune_method_specializations((jl_method_t*)v); + } + else if (jl_is_module(v)) { + if (jl_options.trim) jl_prune_module_bindings((jl_module_t*)v); - } } - // Not else - if (jl_is_typename(v)) { + else if (jl_is_typename(v)) { jl_typename_t *tn = (jl_typename_t*)v; jl_atomic_store_relaxed(&tn->cache, jl_prune_type_cache_hash(jl_atomic_load_relaxed(&tn->cache))); diff --git a/stdlib/Pkg.version b/stdlib/Pkg.version index 4ee99d91a1a77..865c71e8767ac 100644 --- a/stdlib/Pkg.version +++ b/stdlib/Pkg.version @@ -1,4 +1,4 @@ PKG_BRANCH = release-1.12 -PKG_SHA1 = 474c628764d6562453709bff686f7fc65dd23535 +PKG_SHA1 = 69926e385c878253d62e2588a19b252277196ebf PKG_GIT_URL := https://github.com/JuliaLang/Pkg.jl.git PKG_TAR_URL = https://api.github.com/repos/JuliaLang/Pkg.jl/tarball/$1 diff --git a/stdlib/REPL/src/REPL.jl b/stdlib/REPL/src/REPL.jl index f7485c75e95c5..d0473d8f8d6f1 100644 --- a/stdlib/REPL/src/REPL.jl +++ b/stdlib/REPL/src/REPL.jl @@ -1150,7 +1150,7 @@ find_hist_file() = get(ENV, "JULIA_HISTORY", !isempty(DEPOT_PATH) ? joinpath(DEPOT_PATH[1], "logs", "repl_history.jl") : error("DEPOT_PATH is empty and ENV[\"JULIA_HISTORY\"] not set.")) -backend(r::AbstractREPL) = hasproperty(r, :backendref) ? r.backendref : nothing +backend(r::AbstractREPL) = hasproperty(r, :backendref) && isdefined(r, :backendref) ? r.backendref : nothing function eval_on_backend(ast, backend::REPLBackendRef) diff --git a/stdlib/REPL/src/Terminals.jl b/stdlib/REPL/src/Terminals.jl index aba6bff73a607..ee2c97f42e7a4 100644 --- a/stdlib/REPL/src/Terminals.jl +++ b/stdlib/REPL/src/Terminals.jl @@ -123,9 +123,18 @@ cmove_col(t::UnixTerminal, n) = (write(t.out_stream, '\r'); n > 1 && cmove_right if Sys.iswindows() function raw!(t::TTYTerminal,raw::Bool) if Base.ispty(t.in_stream) - run((raw ? `stty raw -echo onlcr -ocrnl opost` : `stty sane`), - t.in_stream, t.out_stream, t.err_stream) - true + try + run((raw ? `stty raw -echo onlcr -ocrnl opost` : `stty sane`), + t.in_stream, t.out_stream, t.err_stream) + true + catch ex + # Fall back to ccall if stty fails (e.g., in some CI environments) + if ex isa ProcessFailedException + ccall(:jl_tty_set_mode, Int32, (Ptr{Cvoid},Int32), t.in_stream.handle::Ptr{Cvoid}, raw) == 0 + else + rethrow() + end + end else ccall(:jl_tty_set_mode, Int32, (Ptr{Cvoid},Int32), t.in_stream.handle::Ptr{Cvoid}, raw) == 0 end diff --git a/stdlib/REPL/test/bad_history_startup.jl b/stdlib/REPL/test/bad_history_startup.jl new file mode 100644 index 0000000000000..09f7a00e1c31a --- /dev/null +++ b/stdlib/REPL/test/bad_history_startup.jl @@ -0,0 +1,74 @@ +# This file is a part of Julia. License is MIT: https://julialang.org/license + +# Test that interactive mode starts up without error when history file is bad + +using Test + +const BASE_TEST_PATH = joinpath(Sys.BINDIR, "..", "share", "julia", "test") +isdefined(Main, :FakePTYs) || @eval Main include(joinpath($(BASE_TEST_PATH), "testhelpers", "FakePTYs.jl")) +import .Main.FakePTYs: with_fake_pty + +@testset "Bad history file startup" begin + mktempdir() do tmpdir + # Create a bad history file + hist_file = joinpath(tmpdir, "repl_history.jl") + write(hist_file, "{ invalid json content\nmore bad content\n") + + julia_exe = Base.julia_cmd()[1] + + # Test interactive Julia startup with bad history file + with_fake_pty() do pts, ptm + # Set up environment with our bad history file + nENV = copy(ENV) + nENV["JULIA_HISTORY"] = hist_file + + # Start Julia in interactive mode + p = run(detach(setenv(`$julia_exe --startup-file=no --color=no -q`, nENV)), pts, pts, pts, wait=false) + Base.close_stdio(pts) + + # Read output until we get the prompt, which indicates successful startup + output = readuntil(ptm, "julia> ", keep=true) + # println("====== subprocess output ======") + # println(output) + # println("====== end subprocess output ======") + + # Test conditions: + # 1. We should see the invalid history file error + has_history_error = occursin("Invalid history file", output) || + occursin("Invalid character", output) + @test has_history_error + + # 2. We should NOT see UndefRefError (the bug being fixed) + has_undef_error = occursin("UndefRefError", output) + @test !has_undef_error + + # 3. We should see the "Disabling history file" message if the fix works + has_disable_message = occursin("Disabling history file for this session", output) + @test has_disable_message + + # Send exit command to clean shutdown + if isopen(ptm) + write(ptm, "exit()\n") + else + @warn "PTY master is already closed before sending exit command" + end + + # Read any remaining output until the process exits + try + read(ptm, String) + catch ex + # Handle platform-specific EOF behavior + if ex isa Base.IOError && ex.code == Base.UV_EIO + # This is expected on some platforms (e.g., Linux) + else + rethrow() + end + end + + # Wait for process to finish + wait(p) + + @test p.exitcode == 0 + end + end +end diff --git a/stdlib/REPL/test/runtests.jl b/stdlib/REPL/test/runtests.jl index d3eb6b9964981..9f3727485f81a 100644 --- a/stdlib/REPL/test/runtests.jl +++ b/stdlib/REPL/test/runtests.jl @@ -22,6 +22,9 @@ end module TerminalMenusTest include("TerminalMenus/runtests.jl") end +module BadHistoryStartupTest + include("bad_history_startup.jl") +end # Restore the original environment for k in keys(ENV) diff --git a/test/ccall.jl b/test/ccall.jl index 5130b7311c9f0..ee5dbcf1dd9d8 100644 --- a/test/ccall.jl +++ b/test/ccall.jl @@ -1970,7 +1970,7 @@ end function gc_safe_ccall() # jl_rand is marked as JL_NOTSAFEPOINT - @ccall gc_safe=true jl_rand()::UInt64 + Base.@assume_effects :nothrow @ccall gc_safe=true jl_rand()::UInt64 end let llvm = sprint(code_llvm, gc_safe_ccall, ()) @@ -1978,6 +1978,7 @@ let llvm = sprint(code_llvm, gc_safe_ccall, ()) @test gc_safe_ccall() isa UInt64 # check for the gc_safe store @test occursin("store atomic i8 2", llvm) + @test Base.infer_effects(gc_safe_ccall, Tuple{}).nothrow == true end # This test is different on master but we need to use zlib on 1.12 diff --git a/test/core.jl b/test/core.jl index db0e0905f12a3..5c4ba7c9722b2 100644 --- a/test/core.jl +++ b/test/core.jl @@ -2816,6 +2816,14 @@ const T24460 = Tuple{T,T} where T g24460() = invoke(f24460, T24460, 1, 2) @test @inferred(g24460()) === 2.0 +@testset "invoke with builtins" begin + @test invoke(getfield, Tuple{Any, Symbol}, (a = 42,), :a) == 42 + @test invoke(setfield!, Tuple{Any, Symbol, Any}, Base.RefValue(1), :x, 2) == 2 + @test invoke(isdefined, Tuple{Any, Symbol}, (a = 1,), :a) == true + @test invoke(isdefined, Tuple{Any, Symbol}, (a = 1,), :b) == false + @test invoke(invoke, Tuple{Any, Type, Vararg}, sin, Tuple{Real}, 0) == 0.0 +end + # issue #30679 @noinline function f30679(::DataType) b = IOBuffer()