diff --git a/src/Makefile b/src/Makefile index ed0cbaf9c8c9a..d2f8810879722 100644 --- a/src/Makefile +++ b/src/Makefile @@ -95,8 +95,8 @@ endif # headers are used for dependency tracking, while public headers will be part of the dist UV_HEADERS := -HEADERS := $(BUILDDIR)/julia_version.h $(wildcard $(SRCDIR)/support/*.h) $(addprefix $(SRCDIR)/,julia.h julia_assert.h julia_threads.h julia_fasttls.h locks.h atomics.h julia_internal.h options.h timing.h) $(addprefix $(BUILDDIR)/, $(DTRACE_HEADERS)) -PUBLIC_HEADERS := $(BUILDDIR)/julia_version.h $(wildcard $(SRCDIR)/support/*.h) $(addprefix $(SRCDIR)/,julia.h julia_assert.h julia_threads.h julia_fasttls.h locks.h atomics.h julia_gcext.h) +HEADERS := $(BUILDDIR)/julia_version.h $(wildcard $(SRCDIR)/support/*.h) $(addprefix $(SRCDIR)/,julia.h julia_assert.h julia_threads.h julia_fasttls.h julia_locks.h julia_atomics.h julia_internal.h options.h timing.h) $(addprefix $(BUILDDIR)/, $(DTRACE_HEADERS)) +PUBLIC_HEADERS := $(BUILDDIR)/julia_version.h $(wildcard $(SRCDIR)/support/*.h) $(addprefix $(SRCDIR)/,julia.h julia_assert.h julia_threads.h julia_fasttls.h julia_locks.h julia_atomics.h julia_gcext.h) ifeq ($(USE_SYSTEM_LIBUV),0) UV_HEADERS += uv.h UV_HEADERS += uv/*.h @@ -376,15 +376,23 @@ endif clangsa: $(build_shlibdir)/libGCCheckerPlugin.$(SHLIB_EXT) -clang-sa-%: $(SRCDIR)/%.c $(build_shlibdir)/libGCCheckerPlugin.$(SHLIB_EXT) | analyzegc-deps-check - @$(call PRINT_ANALYZE, $(build_bindir)/clang --analyze -Xanalyzer -analyzer-werror -Xanalyzer -analyzer-output=text -Xclang -load -Xclang $(build_shlibdir)/libGCCheckerPlugin.$(SHLIB_EXT) $(CLANGSA_FLAGS) $(JCPPFLAGS) $(JCFLAGS) $(DEBUGFLAGS) -Xclang -analyzer-checker=core$(COMMA)julia.GCChecker --analyzer-no-default-checks -fcolor-diagnostics -Werror -x c $<) -clang-sa-%: $(SRCDIR)/%.cpp $(build_shlibdir)/libGCCheckerPlugin.$(SHLIB_EXT) | analyzegc-deps-check - @$(call PRINT_ANALYZE, $(build_bindir)/clang --analyze -Xanalyzer -analyzer-werror -Xanalyzer -analyzer-output=text -Xclang -load -Xclang $(build_shlibdir)/libGCCheckerPlugin.$(SHLIB_EXT) $(CLANGSA_FLAGS) $(CLANGSA_CXXFLAGS) $(LLVM_CXXFLAGS) $(JCPPFLAGS) $(JCXXFLAGS) $(DEBUGFLAGS) -Xclang -analyzer-checker=core$(COMMA)julia.GCChecker --analyzer-no-default-checks -fcolor-diagnostics -Werror -x c++ $<) +clang-sagc-%: $(SRCDIR)/%.c $(build_shlibdir)/libGCCheckerPlugin.$(SHLIB_EXT) .FORCE | analyzegc-deps-check + @$(call PRINT_ANALYZE, $(build_bindir)/clang -D__clang_gcanalyzer__ --analyze -Xanalyzer -analyzer-werror -Xanalyzer -analyzer-output=text -Xclang -load -Xclang $(build_shlibdir)/libGCCheckerPlugin.$(SHLIB_EXT) $(CLANGSA_FLAGS) $(JCPPFLAGS) $(JCFLAGS) $(DEBUGFLAGS) -Xclang -analyzer-checker=core$(COMMA)julia.GCChecker --analyzer-no-default-checks -fcolor-diagnostics -Werror -x c $<) +clang-sagc-%: $(SRCDIR)/%.cpp $(build_shlibdir)/libGCCheckerPlugin.$(SHLIB_EXT) .FORCE | analyzegc-deps-check + @$(call PRINT_ANALYZE, $(build_bindir)/clang -D__clang_gcanalyzer__ --analyze -Xanalyzer -analyzer-werror -Xanalyzer -analyzer-output=text -Xclang -load -Xclang $(build_shlibdir)/libGCCheckerPlugin.$(SHLIB_EXT) $(CLANGSA_FLAGS) $(CLANGSA_CXXFLAGS) $(LLVM_CXXFLAGS) $(JCPPFLAGS) $(JCXXFLAGS) $(DEBUGFLAGS) -Xclang -analyzer-checker=core$(COMMA)julia.GCChecker --analyzer-no-default-checks -fcolor-diagnostics -Werror -x c++ $<) -# Add C files as a target of `analyzegc` -analyzegc: $(addprefix clang-sa-,$(RUNTIME_SRCS)) +clang-sa-%: $(SRCDIR)/%.c .FORCE | analyzegc-deps-check + @$(call PRINT_ANALYZE, $(build_bindir)/clang --analyze -Xanalyzer -analyzer-werror -Xanalyzer -analyzer-output=text $(CLANGSA_FLAGS) $(JCPPFLAGS) $(JCFLAGS) $(DEBUGFLAGS) --analyzer-no-default-checks -fcolor-diagnostics -Werror -x c $<) +clang-sa-%: $(SRCDIR)/%.cpp .FORCE | analyzegc-deps-check + @$(call PRINT_ANALYZE, $(build_bindir)/clang --analyze -Xanalyzer -analyzer-werror -Xanalyzer -analyzer-output=text $(CLANGSA_FLAGS) $(CLANGSA_CXXFLAGS) $(LLVM_CXXFLAGS) $(JCPPFLAGS) $(JCXXFLAGS) $(DEBUGFLAGS) --analyzer-no-default-checks -fcolor-diagnostics -Werror -x c++ $<) + + +# Add C files as a target of `analyzesrc` and `analyzegc` +analyzesrc: $(addprefix clang-sa-,$(SRCS)) +analyzegc: analyzesrc $(addprefix clang-sagc-,$(RUNTIME_SRCS)) clean-analyzegc: rm -f $(build_shlibdir)/libGCCheckerPlugin.$(SHLIB_EXT) -.PHONY: default all debug release clean cleanall clean-* libccalltest libllvmcalltest julia_flisp.boot.inc.phony analyzegc clang-sa-* +.FORCE: +.PHONY: default all debug release clean cleanall clean-* libccalltest libllvmcalltest julia_flisp.boot.inc.phony analyzegc analyzesrc .FORCE diff --git a/src/array.c b/src/array.c index 43376d8ba222b..a7061a0a4176c 100644 --- a/src/array.c +++ b/src/array.c @@ -26,7 +26,7 @@ static inline void arrayassign_safe(int hasptr, jl_value_t *parent, char *dst, c assert(nb >= jl_datatype_size(jl_typeof(src))); // nb might move some undefined bits, but we should be okay with that if (hasptr) { size_t nptr = nb / sizeof(void*); - memmove_refs((void**)dst, (void**)src, nptr); + memmove_refs((void**)dst, (void* const*)src, nptr); jl_gc_multi_wb(parent, src); } else { @@ -588,7 +588,7 @@ JL_DLLEXPORT jl_value_t *jl_ptrarrayref(jl_array_t *a JL_PROPAGATES_ROOT, size_t { assert(i < jl_array_len(a)); assert(a->flags.ptrarray); - jl_value_t *elt = jl_atomic_load_relaxed(((jl_value_t**)a->data) + i); + jl_value_t *elt = jl_atomic_load_relaxed(((_Atomic(jl_value_t*)*)a->data) + i); if (elt == NULL) jl_throw(jl_undefref_exception); return elt; @@ -617,7 +617,7 @@ JL_DLLEXPORT jl_value_t *jl_arrayref(jl_array_t *a, size_t i) JL_DLLEXPORT int jl_array_isassigned(jl_array_t *a, size_t i) { if (a->flags.ptrarray) { - return jl_atomic_load_relaxed(((jl_value_t**)jl_array_data(a)) + i) != NULL; + return jl_atomic_load_relaxed(((_Atomic(jl_value_t*)*)jl_array_data(a)) + i) != NULL; } else if (a->flags.hasptr) { jl_datatype_t *eltype = (jl_datatype_t*)jl_tparam0(jl_typeof(a)); @@ -656,7 +656,7 @@ JL_DLLEXPORT void jl_arrayset(jl_array_t *a JL_ROOTING_ARGUMENT, jl_value_t *rhs arrayassign_safe(hasptr, jl_array_owner(a), &((char*)a->data)[i * a->elsize], rhs, a->elsize); } else { - jl_atomic_store_relaxed(((jl_value_t**)a->data) + i, rhs); + jl_atomic_store_relaxed(((_Atomic(jl_value_t*)*)a->data) + i, rhs); jl_gc_wb(jl_array_owner(a), rhs); } } @@ -666,7 +666,7 @@ JL_DLLEXPORT void jl_arrayunset(jl_array_t *a, size_t i) if (i >= jl_array_len(a)) jl_bounds_error_int((jl_value_t*)a, i + 1); if (a->flags.ptrarray) - jl_atomic_store_relaxed(((jl_value_t**)a->data) + i, NULL); + jl_atomic_store_relaxed(((_Atomic(jl_value_t*)*)a->data) + i, NULL); else if (a->flags.hasptr) { size_t elsize = a->elsize; jl_assume(elsize >= sizeof(void*) && elsize % sizeof(void*) == 0); @@ -1243,9 +1243,11 @@ static NOINLINE ssize_t jl_array_ptr_copy_forward(jl_value_t *owner, void **src_p, void **dest_p, ssize_t n) JL_NOTSAFEPOINT { + _Atomic(void*) *src_pa = (_Atomic(void*)*)src_p; + _Atomic(void*) *dest_pa = (_Atomic(void*)*)dest_p; for (ssize_t i = 0; i < n; i++) { - void *val = jl_atomic_load_relaxed(src_p + i); - jl_atomic_store_relaxed(dest_p + i, val); + void *val = jl_atomic_load_relaxed(src_pa + i); + jl_atomic_store_relaxed(dest_pa + i, val); // `val` is young or old-unmarked if (val && !(jl_astaggedvalue(val)->bits.gc & GC_MARKED)) { jl_gc_queue_root(owner); @@ -1259,9 +1261,11 @@ static NOINLINE ssize_t jl_array_ptr_copy_backward(jl_value_t *owner, void **src_p, void **dest_p, ssize_t n) JL_NOTSAFEPOINT { + _Atomic(void*) *src_pa = (_Atomic(void*)*)src_p; + _Atomic(void*) *dest_pa = (_Atomic(void*)*)dest_p; for (ssize_t i = 0; i < n; i++) { - void *val = jl_atomic_load_relaxed(src_p + n - i - 1); - jl_atomic_store_relaxed(dest_p + n - i - 1, val); + void *val = jl_atomic_load_relaxed(src_pa + n - i - 1); + jl_atomic_store_relaxed(dest_pa + n - i - 1, val); // `val` is young or old-unmarked if (val && !(jl_astaggedvalue(val)->bits.gc & GC_MARKED)) { jl_gc_queue_root(owner); diff --git a/src/ast.c b/src/ast.c index 05a0a403ccc58..7f720b80cf90f 100644 --- a/src/ast.c +++ b/src/ast.c @@ -125,7 +125,7 @@ typedef struct _jl_ast_context_t { static jl_ast_context_t jl_ast_main_ctx; -#ifdef __clang_analyzer__ +#ifdef __clang_gcanalyzer__ jl_ast_context_t *jl_ast_ctx(fl_context_t *fl) JL_GLOBALLY_ROOTED JL_NOTSAFEPOINT; #else #define jl_ast_ctx(fl_ctx) container_of(fl_ctx, jl_ast_context_t, fl) diff --git a/src/builtins.c b/src/builtins.c index 32afff52e0b5f..97c7301d8728e 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -706,7 +706,7 @@ static jl_value_t *do_apply( jl_value_t **args, uint32_t nargs, jl_value_t *iter } if (arg_heap) { // optimization: keep only the first root, free the others -#ifndef __clang_analyzer__ +#ifndef __clang_gcanalyzer__ ((void**)roots)[-2] = (void*)JL_GC_ENCODE_PUSHARGS(1); #endif } diff --git a/src/codegen.cpp b/src/codegen.cpp index 815b6786d2785..7fe1a51aa32ac 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5748,7 +5748,7 @@ static jl_cgval_t emit_cfunction(jl_codectx_t &ctx, jl_value_t *output_type, con // some sanity checking and check whether there's a vararg size_t nargt = jl_svec_len(argt); bool isVa = (nargt > 0 && jl_is_vararg(jl_svecref(argt, nargt - 1))); - assert(!isVa); + assert(!isVa); (void)isVa; jl_array_t *closure_types = NULL; jl_value_t *sigt = NULL; // dispatch-sig = type signature with Ref{} annotations removed and applied to the env diff --git a/src/datatype.c b/src/datatype.c index 95a4eb4c174ce..c49c74a8dd91c 100644 --- a/src/datatype.c +++ b/src/datatype.c @@ -48,9 +48,9 @@ JL_DLLEXPORT jl_methtable_t *jl_new_method_table(jl_sym_t *name, jl_module_t *mo jl_methtable_type); mt->name = jl_demangle_typename(name); mt->module = module; - mt->defs = jl_nothing; - mt->leafcache = (jl_array_t*)jl_an_empty_vec_any; - mt->cache = jl_nothing; + jl_atomic_store_relaxed(&mt->defs, jl_nothing); + jl_atomic_store_relaxed(&mt->leafcache, (jl_array_t*)jl_an_empty_vec_any); + jl_atomic_store_relaxed(&mt->cache, jl_nothing); mt->max_args = 0; mt->kwsorter = NULL; mt->backedges = NULL; @@ -69,8 +69,8 @@ JL_DLLEXPORT jl_typename_t *jl_new_typename_in(jl_sym_t *name, jl_module_t *modu tn->name = name; tn->module = module; tn->wrapper = NULL; - tn->cache = jl_emptysvec; - tn->linearcache = jl_emptysvec; + jl_atomic_store_relaxed(&tn->cache, jl_emptysvec); + jl_atomic_store_relaxed(&tn->linearcache, jl_emptysvec); tn->names = NULL; tn->hash = bitmix(bitmix(module ? module->build_id : 0, name->hash), 0xa1ada1da); tn->abstract = abstract; diff --git a/src/dlload.c b/src/dlload.c index 0f7914050e8b4..aa7f5d9c7b1dc 100644 --- a/src/dlload.c +++ b/src/dlload.c @@ -309,7 +309,7 @@ JL_DLLEXPORT int jl_dlsym(void *handle, const char *symbol, void ** value, int t char err[256]; win32_formatmessage(GetLastError(), err, sizeof(err)); #endif -#ifndef __clang_analyzer__ +#ifndef __clang_gcanalyzer__ // Hide the error throwing from the analyser since there isn't a way to express // "safepoint only when throwing error" currently. jl_errorf("could not load symbol \"%s\":\n%s", symbol, err); diff --git a/src/dump.c b/src/dump.c index 835c88e92bad1..0290d90ed94db 100644 --- a/src/dump.c +++ b/src/dump.c @@ -350,13 +350,13 @@ static void jl_serialize_module(jl_serializer_state *s, jl_module_t *m) jl_serialize_value(s, (jl_value_t*)table[i]); jl_binding_t *b = (jl_binding_t*)table[i+1]; jl_serialize_value(s, b->name); - jl_value_t *e = b->value; + jl_value_t *e = jl_atomic_load_relaxed(&b->value); if (!b->constp && e && jl_is_cpointer(e) && jl_unbox_voidpointer(e) != (void*)-1 && jl_unbox_voidpointer(e) != NULL) // reset Ptr fields to C_NULL (but keep MAP_FAILED / INVALID_HANDLE) jl_serialize_cnull(s, jl_typeof(e)); else jl_serialize_value(s, e); - jl_serialize_value(s, b->globalref); + jl_serialize_value(s, jl_atomic_load_relaxed(&b->globalref)); jl_serialize_value(s, b->owner); write_int8(s->s, (b->deprecated<<3) | (b->constp<<2) | (b->exportp<<1) | (b->imported)); } @@ -660,7 +660,7 @@ static void jl_serialize_value_(jl_serializer_state *s, jl_value_t *v, int as_li if (!(serialization_mode & METHOD_INTERNAL)) return; jl_serialize_value(s, m->specializations); - jl_serialize_value(s, m->speckeyset); + jl_serialize_value(s, jl_atomic_load_relaxed(&m->speckeyset)); jl_serialize_value(s, (jl_value_t*)m->name); jl_serialize_value(s, (jl_value_t*)m->file); write_int32(s->s, m->line); @@ -1510,8 +1510,9 @@ static jl_value_t *jl_deserialize_value_method(jl_serializer_state *s, jl_value_ } m->specializations = (jl_svec_t*)jl_deserialize_value(s, (jl_value_t**)&m->specializations); jl_gc_wb(m, m->specializations); - m->speckeyset = (jl_array_t*)jl_deserialize_value(s, (jl_value_t**)&m->speckeyset); - jl_gc_wb(m, m->speckeyset); + jl_array_t *speckeyset = (jl_array_t*)jl_deserialize_value(s, (jl_value_t**)&m->speckeyset); + jl_atomic_store_relaxed(&m->speckeyset, speckeyset); + jl_gc_wb(m, speckeyset); m->name = (jl_sym_t*)jl_deserialize_value(s, NULL); jl_gc_wb(m, m->name); m->file = (jl_sym_t*)jl_deserialize_value(s, NULL); @@ -1653,8 +1654,9 @@ static jl_value_t *jl_deserialize_value_module(jl_serializer_state *s) JL_GC_DIS jl_value_t *bvalue = jl_deserialize_value(s, (jl_value_t**)&b->value); *(jl_value_t**)&b->value = bvalue; if (bvalue != NULL) jl_gc_wb(m, bvalue); - b->globalref = jl_deserialize_value(s, &b->globalref); - if (b->globalref != NULL) jl_gc_wb(m, b->globalref); + jl_value_t *bglobalref = jl_deserialize_value(s, (jl_value_t**)&b->globalref); + *(jl_value_t**)&b->globalref = bglobalref; + if (bglobalref != NULL) jl_gc_wb(m, bglobalref); b->owner = (jl_module_t*)jl_deserialize_value(s, (jl_value_t**)&b->owner); if (b->owner != NULL) jl_gc_wb(m, b->owner); int8_t flags = read_int8(s->s); diff --git a/src/gc.c b/src/gc.c index 9f5deec019b53..16381f7409ee1 100644 --- a/src/gc.c +++ b/src/gc.c @@ -2404,8 +2404,8 @@ module_binding: { void *vb = jl_astaggedvalue(b); verify_parent1("module", binding->parent, &vb, "binding_buff"); (void)vb; - jl_value_t *value = b->value; - jl_value_t *globalref = b->globalref; + jl_value_t *value = jl_atomic_load_relaxed(&b->value); + jl_value_t *globalref = jl_atomic_load_relaxed(&b->globalref); if (value) { verify_parent2("module", binding->parent, &b->value, "binding(%s)", jl_symbol_name(b->name)); @@ -2808,9 +2808,11 @@ static void mark_roots(jl_gc_mark_cache_t *gc_cache, jl_gc_mark_sp_t *sp) } } gc_mark_queue_obj(gc_cache, sp, jl_anytuple_type_type); - for (size_t i = 0; i < N_CALL_CACHE; i++) - if (call_cache[i]) - gc_mark_queue_obj(gc_cache, sp, call_cache[i]); + for (size_t i = 0; i < N_CALL_CACHE; i++) { + jl_typemap_entry_t *v = jl_atomic_load_relaxed(&call_cache[i]); + if (v != NULL) + gc_mark_queue_obj(gc_cache, sp, v); + } if (jl_all_methods != NULL) gc_mark_queue_obj(gc_cache, sp, jl_all_methods); if (_jl_debug_method_invalidation != NULL) @@ -2977,8 +2979,8 @@ static void jl_gc_queue_remset(jl_gc_mark_cache_t *gc_cache, jl_gc_mark_sp_t *sp jl_binding_t *ptr = (jl_binding_t*)items[i]; // A null pointer can happen here when the binding is cleaned up // as an exception is thrown after it was already queued (#10221) - if (!ptr->value) continue; - if (gc_mark_queue_obj(gc_cache, sp, ptr->value)) { + jl_value_t *v = jl_atomic_load_relaxed(&ptr->value); + if (v != NULL && gc_mark_queue_obj(gc_cache, sp, v)) { items[n_bnd_refyoung] = ptr; n_bnd_refyoung++; } diff --git a/src/gc.h b/src/gc.h index 06faa64a8b07f..19fe3401665d1 100644 --- a/src/gc.h +++ b/src/gc.h @@ -371,7 +371,7 @@ typedef struct { int ub; } pagetable_t; -#ifdef __clang_analyzer__ +#ifdef __clang_gcanalyzer__ unsigned ffs_u32(uint32_t bitvec) JL_NOTSAFEPOINT; #else STATIC_INLINE unsigned ffs_u32(uint32_t bitvec) diff --git a/src/gf.c b/src/gf.c index d6c9741f3ebf3..f43974a70f5ec 100644 --- a/src/gf.c +++ b/src/gf.c @@ -118,7 +118,7 @@ JL_DLLEXPORT jl_method_instance_t *jl_specializations_get_linfo(jl_method_t *m J } } else { - jl_method_instance_t **data = (jl_method_instance_t**)jl_svec_data(specializations); + _Atomic(jl_method_instance_t*) *data = (_Atomic(jl_method_instance_t*)*)jl_svec_data(specializations); JL_GC_PUSH1(&specializations); // clang-sa doesn't realize this loop uses specializations for (i = cl; i > 0; i--) { jl_method_instance_t *mi = jl_atomic_load_relaxed(&data[i - 1]); @@ -140,7 +140,7 @@ JL_DLLEXPORT jl_method_instance_t *jl_specializations_get_linfo(jl_method_t *m J } else { if (hv) { - jl_method_instance_t **data = (jl_method_instance_t**)jl_svec_data(specializations); + _Atomic(jl_method_instance_t*) *data = (_Atomic(jl_method_instance_t*)*)jl_svec_data(specializations); for (i = 0; i < cl; i++) { jl_method_instance_t *mi = jl_atomic_load_relaxed(&data[i]); if ((jl_value_t*)mi == jl_nothing) @@ -990,7 +990,7 @@ static inline jl_typemap_entry_t *lookup_leafcache(jl_array_t *leafcache JL_PROP } static jl_method_instance_t *cache_method( - jl_methtable_t *mt, jl_typemap_t **cache, jl_value_t *parent JL_PROPAGATES_ROOT, + jl_methtable_t *mt, _Atomic(jl_typemap_t*) *cache, jl_value_t *parent JL_PROPAGATES_ROOT, jl_tupletype_t *tt, // the original tupletype of the signature jl_method_t *definition, size_t world, size_t min_valid, size_t max_valid, @@ -1007,7 +1007,7 @@ static jl_method_instance_t *cache_method( return entry->func.linfo; } struct jl_typemap_assoc search = {(jl_value_t*)tt, world, NULL, 0, ~(size_t)0}; - jl_typemap_entry_t *entry = jl_typemap_assoc_by_type(*cache, &search, offs, /*subtype*/1); + jl_typemap_entry_t *entry = jl_typemap_assoc_by_type(jl_atomic_load_relaxed(cache), &search, offs, /*subtype*/1); if (entry && entry->func.value) return entry->func.linfo; } @@ -1133,7 +1133,7 @@ static jl_method_instance_t *cache_method( // that satisfies our requirements if (cachett != tt) { struct jl_typemap_assoc search = {(jl_value_t*)cachett, world, NULL, 0, ~(size_t)0}; - jl_typemap_entry_t *entry = jl_typemap_assoc_by_type(*cache, &search, offs, /*subtype*/1); + jl_typemap_entry_t *entry = jl_typemap_assoc_by_type(jl_atomic_load_relaxed(cache), &search, offs, /*subtype*/1); if (entry && jl_egal((jl_value_t*)entry->simplesig, simplett ? (jl_value_t*)simplett : jl_nothing) && jl_egal((jl_value_t*)guardsigs, (jl_value_t*)entry->guardsigs)) { JL_GC_POP(); @@ -1177,7 +1177,7 @@ static jl_method_instance_t *jl_mt_assoc_by_type(jl_methtable_t *mt JL_PROPAGATE // caller must hold the mt->writelock assert(tt->isdispatchtuple || tt->hasfreetypevars); if (tt->isdispatchtuple) { - jl_array_t *leafcache = mt->leafcache; + jl_array_t *leafcache = jl_atomic_load_relaxed(&mt->leafcache); jl_typemap_entry_t *entry = lookup_leafcache(leafcache, (jl_value_t*)tt, world); if (entry) return entry->func.linfo; @@ -1525,7 +1525,7 @@ static int typemap_search(jl_typemap_entry_t *entry, void *closure) static jl_typemap_entry_t *do_typemap_search(jl_methtable_t *mt JL_PROPAGATES_ROOT, jl_method_t *method) JL_NOTSAFEPOINT; -#ifndef __clang_analyzer__ +#ifndef __clang_gcanalyzer__ static jl_typemap_entry_t *do_typemap_search(jl_methtable_t *mt JL_PROPAGATES_ROOT, jl_method_t *method) JL_NOTSAFEPOINT { jl_value_t *closure = (jl_value_t*)(method); if (jl_typemap_visitor(mt->defs, typemap_search, &closure)) @@ -1545,7 +1545,7 @@ static void jl_method_table_invalidate(jl_methtable_t *mt, jl_typemap_entry_t *m mt_cache_env.shadowed = NULL; mt_cache_env.invalidated = 0; jl_typemap_visitor(mt->cache, disable_mt_cache, (void*)&mt_cache_env); - jl_array_t *leafcache = mt->leafcache; + jl_array_t *leafcache = jl_atomic_load_relaxed(&mt->leafcache); size_t i, l = jl_array_len(leafcache); for (i = 1; i < l; i += 2) { jl_typemap_entry_t *oldentry = (jl_typemap_entry_t*)jl_array_ptr_ref(leafcache, i); @@ -1725,7 +1725,7 @@ JL_DLLEXPORT void jl_method_table_insert(jl_methtable_t *mt, jl_method_t *method if (morespec[j] == (char)morespec_is) continue; jl_svec_t *specializations = jl_atomic_load_acquire(&m->specializations); - jl_method_instance_t **data = (jl_method_instance_t**)jl_svec_data(specializations); + _Atomic(jl_method_instance_t*) *data = (_Atomic(jl_method_instance_t*)*)jl_svec_data(specializations); size_t i, l = jl_svec_len(specializations); enum morespec_options ambig = morespec_unknown; for (i = 0; i < l; i++) { @@ -1781,7 +1781,7 @@ JL_DLLEXPORT void jl_method_table_insert(jl_methtable_t *mt, jl_method_t *method mt_cache_env.invalidated = 0; jl_typemap_visitor(mt->cache, invalidate_mt_cache, (void*)&mt_cache_env); - jl_array_t *leafcache = mt->leafcache; + jl_array_t *leafcache = jl_atomic_load_relaxed(&mt->leafcache); size_t i, l = jl_array_len(leafcache); for (i = 1; i < l; i += 2) { jl_value_t *entry = jl_array_ptr_ref(leafcache, i); @@ -2272,8 +2272,8 @@ STATIC_INLINE int sig_match_fast(jl_value_t *arg1t, jl_value_t **args, jl_value_ return 1; } -jl_typemap_entry_t *call_cache[N_CALL_CACHE] JL_GLOBALLY_ROOTED; -static uint8_t pick_which[N_CALL_CACHE]; +_Atomic(jl_typemap_entry_t*) call_cache[N_CALL_CACHE] JL_GLOBALLY_ROOTED; +static _Atomic(uint8_t) pick_which[N_CALL_CACHE]; #ifdef JL_GF_PROFILE size_t ncalls; void call_cache_stats() diff --git a/src/iddict.c b/src/iddict.c index 0d67a2b4c82c1..73c2999491c28 100644 --- a/src/iddict.c +++ b/src/iddict.c @@ -43,7 +43,7 @@ static inline int jl_table_assign_bp(jl_array_t **pa, jl_value_t *key, jl_value_ *pa = a; } size_t maxprobe = max_probe(sz); - void **tab = (void **)a->data; + _Atomic(jl_value_t*) *tab = (_Atomic(jl_value_t*)*)a->data; hv = keyhash(key); while (1) { @@ -54,7 +54,7 @@ static inline int jl_table_assign_bp(jl_array_t **pa, jl_value_t *key, jl_value_ empty_slot = -1; do { - jl_value_t *k2 = (jl_value_t*)tab[index]; + jl_value_t *k2 = tab[index]; if (k2 == NULL) { if (empty_slot == -1) empty_slot = index; @@ -102,20 +102,20 @@ static inline int jl_table_assign_bp(jl_array_t **pa, jl_value_t *key, jl_value_ *pa = jl_idtable_rehash(*pa, newsz); a = *pa; - tab = (void **)a->data; + tab = (_Atomic(jl_value_t*)*)a->data; sz = hash_size(a); maxprobe = max_probe(sz); } } /* returns bp if key is in hash, otherwise NULL */ -inline jl_value_t **jl_table_peek_bp(jl_array_t *a, jl_value_t *key) JL_NOTSAFEPOINT +inline _Atomic(jl_value_t*) *jl_table_peek_bp(jl_array_t *a, jl_value_t *key) JL_NOTSAFEPOINT { size_t sz = hash_size(a); if (sz == 0) return NULL; size_t maxprobe = max_probe(sz); - void **tab = (void **)a->data; + _Atomic(jl_value_t*) *tab = (_Atomic(jl_value_t*)*)a->data; uint_t hv = keyhash(key); size_t index = h2index(hv, sz); sz *= 2; @@ -123,12 +123,12 @@ inline jl_value_t **jl_table_peek_bp(jl_array_t *a, jl_value_t *key) JL_NOTSAFEP size_t iter = 0; do { - jl_value_t *k2 = (jl_value_t*)jl_atomic_load_relaxed(&tab[index]); // just to ensure the load doesn't get duplicated + jl_value_t *k2 = jl_atomic_load_relaxed(&tab[index]); // just to ensure the load doesn't get duplicated if (k2 == NULL) return NULL; if (jl_egal(key, k2)) { if (jl_atomic_load_relaxed(&tab[index + 1]) != NULL) - return (jl_value_t**)&tab[index + 1]; + return &tab[index + 1]; // `nothing` is our sentinel value for deletion, so need to keep searching if it's also our search key if (key != jl_nothing) return NULL; // concurrent insertion hasn't completed yet @@ -155,21 +155,21 @@ jl_array_t *jl_eqtable_put(jl_array_t *h, jl_value_t *key, jl_value_t *val, int JL_DLLEXPORT jl_value_t *jl_eqtable_get(jl_array_t *h, jl_value_t *key, jl_value_t *deflt) JL_NOTSAFEPOINT { - jl_value_t **bp = jl_table_peek_bp(h, key); + _Atomic(jl_value_t*) *bp = jl_table_peek_bp(h, key); return (bp == NULL) ? deflt : jl_atomic_load_relaxed(bp); } JL_DLLEXPORT jl_value_t *jl_eqtable_pop(jl_array_t *h, jl_value_t *key, jl_value_t *deflt, int *found) { - jl_value_t **bp = jl_table_peek_bp(h, key); + _Atomic(jl_value_t*) *bp = jl_table_peek_bp(h, key); if (found) *found = (bp != NULL); if (bp == NULL) return deflt; - jl_value_t *val = *bp; - *(bp - 1) = jl_nothing; // clear the key - *bp = NULL; + jl_value_t *val = jl_atomic_load_relaxed(bp); + jl_atomic_store_relaxed(bp - 1, jl_nothing); // clear the key + jl_atomic_store_relaxed(bp, NULL); // and the value (briefly corrupting the table) return val; } diff --git a/src/interpreter.c b/src/interpreter.c index e0284f06d38c2..50946a666ab0c 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -37,7 +37,7 @@ typedef struct { JL_GCC_IGNORE_STOP #endif -#ifdef __clang_analyzer__ +#ifdef __clang_gcanalyzer__ extern void JL_GC_ENABLEFRAME(interpreter_state*) JL_NOTSAFEPOINT; diff --git a/src/intrinsics.cpp b/src/intrinsics.cpp index 1847fc5c60e37..e566c6b6bd731 100644 --- a/src/intrinsics.cpp +++ b/src/intrinsics.cpp @@ -305,8 +305,7 @@ static Value *emit_unboxed_coercion(jl_codectx_t &ctx, Type *to, Value *unboxed) } else if (!ty->isIntOrPtrTy() && !ty->isFloatingPointTy()) { const DataLayout &DL = jl_data_layout; - unsigned nb = DL.getTypeSizeInBits(ty); - assert(nb == DL.getTypeSizeInBits(to)); + assert(DL.getTypeSizeInBits(ty) == DL.getTypeSizeInBits(to)); AllocaInst *cast = ctx.builder.CreateAlloca(ty); ctx.builder.CreateStore(unboxed, cast); unboxed = ctx.builder.CreateLoad(to, ctx.builder.CreateBitCast(cast, to->getPointerTo())); diff --git a/src/jlapi.c b/src/jlapi.c index 4851cebfe15d9..e3c5938d30abf 100644 --- a/src/jlapi.c +++ b/src/jlapi.c @@ -433,7 +433,7 @@ JL_DLLEXPORT jl_value_t *(jl_get_fieldtypes)(jl_value_t *v) } -#ifndef __clang_analyzer__ +#ifndef __clang_gcanalyzer__ JL_DLLEXPORT int8_t (jl_gc_unsafe_enter)(void) { jl_task_t *ct = jl_current_task; diff --git a/src/jltypes.c b/src/jltypes.c index 1330650ee8892..1b6ed84121544 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -19,7 +19,7 @@ extern "C" { #endif -jl_value_t *cmpswap_names JL_GLOBALLY_ROOTED; +_Atomic(jl_value_t*) cmpswap_names JL_GLOBALLY_ROOTED; // compute empirical max-probe for a given size #define max_probe(size) ((size) <= 1024 ? 16 : (size) >> 6) @@ -625,7 +625,7 @@ static jl_datatype_t *lookup_type_set(jl_svec_t *cache, jl_value_t **key, size_t if (sz == 0) return NULL; size_t maxprobe = max_probe(sz); - jl_datatype_t **tab = (jl_datatype_t**)jl_svec_data(cache); + _Atomic(jl_datatype_t*) *tab = (_Atomic(jl_datatype_t*)*)jl_svec_data(cache); size_t index = h2index(hv, sz); size_t orig = index; size_t iter = 0; @@ -648,7 +648,7 @@ static jl_datatype_t *lookup_type_setvalue(jl_svec_t *cache, jl_value_t *key1, j if (sz == 0) return NULL; size_t maxprobe = max_probe(sz); - jl_datatype_t **tab = (jl_datatype_t**)jl_svec_data(cache); + _Atomic(jl_datatype_t*) *tab = (_Atomic(jl_datatype_t*)*)jl_svec_data(cache); size_t index = h2index(hv, sz); size_t orig = index; size_t iter = 0; @@ -671,7 +671,7 @@ static ssize_t lookup_type_idx_linear(jl_svec_t *cache, jl_value_t **key, size_t { if (n == 0) return -1; - jl_datatype_t **data = (jl_datatype_t**)jl_svec_data(cache); + _Atomic(jl_datatype_t*) *data = (_Atomic(jl_datatype_t*)*)jl_svec_data(cache); size_t cl = jl_svec_len(cache); ssize_t i; for (i = 0; i < cl; i++) { @@ -688,7 +688,7 @@ static ssize_t lookup_type_idx_linearvalue(jl_svec_t *cache, jl_value_t *key1, j { if (n == 0) return -1; - jl_datatype_t **data = (jl_datatype_t**)jl_svec_data(cache); + _Atomic(jl_datatype_t*) *data = (_Atomic(jl_datatype_t*)*)jl_svec_data(cache); size_t cl = jl_svec_len(cache); ssize_t i; for (i = 0; i < cl; i++) { @@ -734,7 +734,7 @@ static jl_value_t *lookup_typevalue(jl_typename_t *tn, jl_value_t *key1, jl_valu static int cache_insert_type_set_(jl_svec_t *a, jl_datatype_t *val, uint_t hv) { - jl_datatype_t **tab = (jl_datatype_t**)jl_svec_data(a); + _Atomic(jl_datatype_t*) *tab = (_Atomic(jl_datatype_t*)*)jl_svec_data(a); size_t sz = jl_svec_len(a); if (sz <= 1) return 0; diff --git a/src/julia.h b/src/julia.h index b915ce02721f6..a6b49df4a8c63 100644 --- a/src/julia.h +++ b/src/julia.h @@ -78,7 +78,7 @@ typedef struct _jl_taggedvalue_t jl_taggedvalue_t; -#include "atomics.h" +#include "julia_atomics.h" #include "julia_threads.h" #include "julia_assert.h" @@ -108,7 +108,7 @@ JL_EXTENSION struct _jl_taggedvalue_t { // jl_value_t value; }; -#ifdef __clang_analyzer__ +#ifdef __clang_gcanalyzer__ JL_DLLEXPORT jl_taggedvalue_t *_jl_astaggedvalue(jl_value_t *v JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT; #define jl_astaggedvalue(v) _jl_astaggedvalue((jl_value_t*)(v)) jl_value_t *_jl_valueof(jl_taggedvalue_t *tv JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT; @@ -289,13 +289,13 @@ typedef struct _jl_method_t { jl_value_t *sig; // table of all jl_method_instance_t specializations we have - jl_svec_t *specializations; // allocated as [hashable, ..., NULL, linear, ....] - jl_array_t *speckeyset; // index lookup by hash into specializations + _Atomic(jl_svec_t*) specializations; // allocated as [hashable, ..., NULL, linear, ....] + _Atomic(jl_array_t*) speckeyset; // index lookup by hash into specializations jl_value_t *slot_syms; // compacted list of slot names (String) jl_value_t *external_mt; // reference to the method table this method is part of, null if part of the internal table jl_value_t *source; // original code template (jl_code_info_t, but may be compressed), null for builtins - struct _jl_method_instance_t *unspecialized; // unspecialized executable method instance, or null + _Atomic(struct _jl_method_instance_t*) unspecialized; // unspecialized executable method instance, or null jl_value_t *generator; // executable code-generating function if available jl_array_t *roots; // pointers in generated code (shared to reduce memory), or null jl_svec_t *ccallable; // svec(rettype, sig) if a ccallable entry point is requested for this @@ -303,7 +303,7 @@ typedef struct _jl_method_t { // cache of specializations of this method for invoke(), i.e. // cases where this method was called even though it was not necessarily // the most specific for the argument types. - jl_typemap_t *invokes; + _Atomic(jl_typemap_t*) invokes; // A function that compares two specializations of this method, returning // `true` if the first signature is to be considered "smaller" than the @@ -342,7 +342,7 @@ struct _jl_method_instance_t { jl_value_t *uninferred; // cached uncompressed code, for generated functions, top-level thunks, or the interpreter jl_array_t *backedges; // list of method-instances which contain a call into this method-instance jl_array_t *callbacks; // list of callback functions to inform external caches about invalidations - struct _jl_code_instance_t *cache; + _Atomic(struct _jl_code_instance_t*) cache; uint8_t inInference; // flags to tell if inference is running on this object }; @@ -361,7 +361,7 @@ typedef struct jl_opaque_closure_t { typedef struct _jl_code_instance_t { JL_DATA_TYPE jl_method_instance_t *def; // method this is specialized from - struct _jl_code_instance_t *next; // pointer to the next cache entry + _Atomic(struct _jl_code_instance_t*) next; // pointer to the next cache entry // world range for which this object is valid to use size_t min_world; @@ -376,7 +376,7 @@ typedef struct _jl_code_instance_t { // compilation state cache uint8_t isspecsig; // if specptr is a specialized function signature for specTypes->rettype - uint8_t precompile; // if set, this will be added to the output system image + _Atomic(uint8_t) precompile; // if set, this will be added to the output system image _Atomic(jl_callptr_t) invoke; // jlcall entry point union _jl_generic_specptr_t { _Atomic(void*) fptr; @@ -418,8 +418,8 @@ typedef struct { // `wrapper` is either the only instantiation of the type (if no parameters) // or a UnionAll accepting parameters to make an instantiation. jl_value_t *wrapper; - jl_svec_t *cache; // sorted array - jl_svec_t *linearcache; // unsorted array + _Atomic(jl_svec_t*) cache; // sorted array + _Atomic(jl_svec_t*) linearcache; // unsorted array struct _jl_methtable_t *mt; jl_array_t *partial; // incomplete instantiations of this type intptr_t hash; @@ -509,7 +509,7 @@ typedef struct { // not first-class jl_sym_t *name; _Atomic(jl_value_t*) value; - jl_value_t* globalref; // cached GlobalRef for this binding -- TODO: make _Atomic + _Atomic(jl_value_t*) globalref; // cached GlobalRef for this binding struct _jl_module_t* owner; // for individual imported bindings -- TODO: make _Atomic uint8_t constp:1; uint8_t exportp:1; @@ -544,7 +544,7 @@ typedef struct _jl_module_t { // one Type-to-Value entry typedef struct _jl_typemap_entry_t { JL_DATA_TYPE - struct _jl_typemap_entry_t *next; // invasive linked list + _Atomic(struct _jl_typemap_entry_t*) next; // invasive linked list jl_tupletype_t *sig; // the type signature for this entry jl_tupletype_t *simplesig; // a simple signature for fast rejection jl_svec_t *guardsigs; @@ -569,23 +569,23 @@ typedef struct _jl_typemap_level_t { // next split may be on Type{T} as LeafTypes then TypeName's parents up to Any // next split may be on LeafType // next split may be on TypeName - jl_array_t *arg1; // contains LeafType - jl_array_t *targ; // contains Type{LeafType} - jl_array_t *name1; // contains non-abstract TypeName, for parents up to (excluding) Any - jl_array_t *tname; // contains a dict of Type{TypeName}, for parents up to Any + _Atomic(jl_array_t*) arg1; // contains LeafType + _Atomic(jl_array_t*) targ; // contains Type{LeafType} + _Atomic(jl_array_t*) name1; // contains non-abstract TypeName, for parents up to (excluding) Any + _Atomic(jl_array_t*) tname; // contains a dict of Type{TypeName}, for parents up to Any // next a linear list of things too complicated at this level for analysis (no more levels) - jl_typemap_entry_t *linear; + _Atomic(jl_typemap_entry_t*) linear; // finally, start a new level if the type at offs is Any - jl_typemap_t *any; + _Atomic(jl_typemap_t*) any; } jl_typemap_level_t; // contains the TypeMap for one Type typedef struct _jl_methtable_t { JL_DATA_TYPE jl_sym_t *name; // sometimes a hack used by serialization to handle kwsorter - jl_typemap_t *defs; - jl_array_t *leafcache; - jl_typemap_t *cache; + _Atomic(jl_typemap_t*) defs; + _Atomic(jl_array_t*) leafcache; + _Atomic(jl_typemap_t*) cache; intptr_t max_args; // max # of non-vararg arguments in a signature jl_value_t *kwsorter; // keyword argument sorter function jl_module_t *module; // used for incremental serialization to locate original binding @@ -759,7 +759,7 @@ struct _jl_gcframe_t { #define JL_GC_ENCODE_PUSHARGS(n) (((size_t)(n))<<2) #define JL_GC_ENCODE_PUSH(n) ((((size_t)(n))<<2)|1) -#ifdef __clang_analyzer__ +#ifdef __clang_gcanalyzer__ // When running with the analyzer make these real function calls, that are // easier to detect in the analyzer @@ -890,7 +890,7 @@ JL_DLLEXPORT void *jl_gc_managed_realloc(void *d, size_t sz, size_t oldsz, #define jl_svec_set_len_unsafe(t,n) (((jl_svec_t*)(t))->length=(n)) #define jl_svec_data(t) ((jl_value_t**)((char*)(t) + sizeof(jl_svec_t))) -#ifdef __clang_analyzer__ +#ifdef __clang_gcanalyzer__ STATIC_INLINE jl_value_t *jl_svecref(void *t JL_PROPAGATES_ROOT, size_t i) JL_NOTSAFEPOINT; STATIC_INLINE jl_value_t *jl_svecset( void *t JL_ROOTING_ARGUMENT JL_PROPAGATES_ROOT, @@ -934,7 +934,7 @@ JL_DLLEXPORT size_t jl_array_len_(jl_array_t *a); JL_DLLEXPORT char *jl_array_typetagdata(jl_array_t *a) JL_NOTSAFEPOINT; -#ifdef __clang_analyzer__ +#ifdef __clang_gcanalyzer__ jl_value_t **jl_array_ptr_data(jl_array_t *a JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT; STATIC_INLINE jl_value_t *jl_array_ptr_ref(void *a JL_PROPAGATES_ROOT, size_t i) JL_NOTSAFEPOINT; STATIC_INLINE jl_value_t *jl_array_ptr_set( @@ -1818,13 +1818,13 @@ typedef struct _jl_task_t { uint64_t rngState1; uint64_t rngState2; uint64_t rngState3; - uint8_t _state; + _Atomic(uint8_t) _state; uint8_t sticky; // record whether this Task can be migrated to a new thread - uint8_t _isexception; // set if `result` is an exception to throw or that we exited with + _Atomic(uint8_t) _isexception; // set if `result` is an exception to throw or that we exited with // hidden state: // id of owning thread - does not need to be defined until the task runs - int16_t tid; + _Atomic(uint16_t) tid; // multiqueue priority int16_t prio; // saved gc stack top for context switches @@ -1869,7 +1869,7 @@ JL_DLLEXPORT void JL_NORETURN jl_no_exc_handler(jl_value_t *e); JL_DLLEXPORT JL_CONST_FUNC jl_gcframe_t **(jl_get_pgcstack)(void) JL_GLOBALLY_ROOTED JL_NOTSAFEPOINT; #define jl_current_task (container_of(jl_get_pgcstack(), jl_task_t, gcstack)) -#include "locks.h" // requires jl_task_t definition +#include "julia_locks.h" // requires jl_task_t definition JL_DLLEXPORT void jl_enter_handler(jl_handler_t *eh); JL_DLLEXPORT void jl_eh_restore_state(jl_handler_t *eh); @@ -1908,7 +1908,7 @@ void (jl_longjmp)(jmp_buf _Buf, int _Value); #endif -#ifdef __clang_analyzer__ +#ifdef __clang_gcanalyzer__ // This is hard. Ideally we'd teach the static analyzer about the extra control // flow edges. But for now, just hide this as best we can diff --git a/src/atomics.h b/src/julia_atomics.h similarity index 98% rename from src/atomics.h rename to src/julia_atomics.h index 6ee70f08c69ba..80ac85acfb9f2 100644 --- a/src/atomics.h +++ b/src/julia_atomics.h @@ -221,9 +221,10 @@ extern "C" { #endif #endif -#ifdef __clang_analyzer__ -// for the purposes of the analyzer, we can turn these into non-atomic expressions with similar properties -// (for the sake of the analyzer, we don't care if it is an exact match for behavior) +#ifdef __clang_gcanalyzer__ +// for the purposes of the GC analyzer, we can turn these into non-atomic +// expressions with similar properties (for the sake of the analyzer, we don't +// care if it is an exact match for behavior) #undef _Atomic #define _Atomic(T) T diff --git a/src/julia_internal.h b/src/julia_internal.h index 3006ef27930a8..2736790d5b422 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -4,7 +4,7 @@ #define JL_INTERNAL_H #include "options.h" -#include "locks.h" +#include "julia_locks.h" #include #if !defined(_WIN32) #include @@ -219,7 +219,7 @@ extern jl_array_t *_jl_debug_method_invalidation JL_GLOBALLY_ROOTED; extern size_t jl_page_size; extern jl_function_t *jl_typeinf_func; extern size_t jl_typeinf_world; -extern jl_typemap_entry_t *call_cache[N_CALL_CACHE] JL_GLOBALLY_ROOTED; +extern _Atomic(jl_typemap_entry_t*) call_cache[N_CALL_CACHE] JL_GLOBALLY_ROOTED; extern jl_array_t *jl_all_methods JL_GLOBALLY_ROOTED; JL_DLLEXPORT extern int jl_lineno; @@ -754,7 +754,7 @@ STATIC_INLINE int jl_addr_is_safepoint(uintptr_t addr) uintptr_t safepoint_addr = (uintptr_t)jl_safepoint_pages; return addr >= safepoint_addr && addr < safepoint_addr + jl_page_size * 3; } -extern uint32_t jl_gc_running; +extern _Atomic(uint32_t) jl_gc_running; // All the functions are safe to be called from within a signal handler // provided that the thread will not be interrupted by another asynchronous // signal. @@ -801,7 +801,7 @@ typedef jl_gcframe_t ***(*jl_pgcstack_key_t)(void) JL_NOTSAFEPOINT; #endif void jl_pgcstack_getkey(jl_get_pgcstack_func **f, jl_pgcstack_key_t *k); -#if !defined(__clang_analyzer__) +#if !defined(__clang_gcanalyzer__) static inline void jl_set_gc_and_wait(void) { jl_task_t *ct = jl_current_task; @@ -833,7 +833,7 @@ void jl_get_function_id(void *native_code, jl_code_instance_t *ncode, // the first argument to jl_idtable_rehash is used to return a value // make sure it is rooted if it is used after the function returns JL_DLLEXPORT jl_array_t *jl_idtable_rehash(jl_array_t *a, size_t newsz); -jl_value_t **jl_table_peek_bp(jl_array_t *a, jl_value_t *key) JL_NOTSAFEPOINT; +_Atomic(jl_value_t*) *jl_table_peek_bp(jl_array_t *a, jl_value_t *key) JL_NOTSAFEPOINT; JL_DLLEXPORT jl_method_t *jl_new_method_uninit(jl_module_t*); @@ -1264,11 +1264,11 @@ void jl_mach_gc_end(void); typedef uint_t (*smallintset_hash)(size_t val, jl_svec_t *data); typedef int (*smallintset_eq)(size_t val, const void *key, jl_svec_t *data, uint_t hv); ssize_t jl_smallintset_lookup(jl_array_t *cache, smallintset_eq eq, const void *key, jl_svec_t *data, uint_t hv); -void jl_smallintset_insert(jl_array_t **pcache, jl_value_t *parent, smallintset_hash hash, size_t val, jl_svec_t *data); +void jl_smallintset_insert(_Atomic(jl_array_t*) *pcache, jl_value_t *parent, smallintset_hash hash, size_t val, jl_svec_t *data); // -- typemap.c -- // -void jl_typemap_insert(jl_typemap_t **cache, jl_value_t *parent, +void jl_typemap_insert(_Atomic(jl_typemap_t*) *cache, jl_value_t *parent, jl_typemap_entry_t *newrec, int8_t offs); jl_typemap_entry_t *jl_typemap_alloc( jl_tupletype_t *type, jl_tupletype_t *simpletype, jl_svec_t *guardsigs, @@ -1450,7 +1450,7 @@ jl_sym_t *_jl_symbol(const char *str, size_t len) JL_NOTSAFEPOINT; #define JL_GCC_IGNORE_STOP #endif // _COMPILER_GCC_ -#ifdef __clang_analyzer__ +#ifdef __clang_gcanalyzer__ // Not a safepoint (so it dosn't free other values), but an artificial use. // Usually this is unnecessary because the analyzer can see all real uses, // but sometimes real uses are harder for the analyzer to see, or it may diff --git a/src/locks.h b/src/julia_locks.h similarity index 92% rename from src/locks.h rename to src/julia_locks.h index 0605cefbd1218..6033a70ea2cd3 100644 --- a/src/locks.h +++ b/src/julia_locks.h @@ -28,7 +28,7 @@ static inline void jl_mutex_wait(jl_mutex_t *lock, int safepoint) return; } while (1) { - if (owner == 0 && jl_atomic_cmpswap(&lock->owner, &owner, self)) { + if (owner == (jl_thread_t)0 && jl_atomic_cmpswap(&lock->owner, &owner, self)) { lock->count = 1; return; } @@ -42,7 +42,7 @@ static inline void jl_mutex_wait(jl_mutex_t *lock, int safepoint) static inline void jl_mutex_lock_nogc(jl_mutex_t *lock) JL_NOTSAFEPOINT { -#ifndef __clang_analyzer__ +#ifndef __clang_gcanalyzer__ // Hide this body from the analyzer, otherwise it complains that we're calling // a non-safepoint from this function. The 0 arguments guarantees that we do // not reach the safepoint, but the analyzer can't figure that out @@ -96,7 +96,7 @@ static inline int jl_mutex_trylock_nogc(jl_mutex_t *lock) lock->count++; return 1; } - if (owner == 0 && jl_atomic_cmpswap(&lock->owner, &owner, self)) { + if (owner == (jl_thread_t)0 && jl_atomic_cmpswap(&lock->owner, &owner, self)) { lock->count = 1; return 1; } @@ -114,11 +114,11 @@ static inline int jl_mutex_trylock(jl_mutex_t *lock) } static inline void jl_mutex_unlock_nogc(jl_mutex_t *lock) JL_NOTSAFEPOINT { -#ifndef __clang_analyzer__ +#ifndef __clang_gcanalyzer__ assert(lock->owner == jl_thread_self() && "Unlocking a lock in a different thread."); if (--lock->count == 0) { - jl_atomic_store_release(&lock->owner, 0); + jl_atomic_store_release(&lock->owner, (jl_thread_t)0); jl_cpu_wake(); } #endif @@ -136,7 +136,7 @@ static inline void jl_mutex_unlock(jl_mutex_t *lock) static inline void jl_mutex_init(jl_mutex_t *lock) JL_NOTSAFEPOINT { - lock->owner = 0; + lock->owner = (jl_thread_t)0; lock->count = 0; } diff --git a/src/julia_threads.h b/src/julia_threads.h index 25ca1fb14b2f9..4dee37f863aea 100644 --- a/src/julia_threads.h +++ b/src/julia_threads.h @@ -4,7 +4,7 @@ #ifndef JL_THREADS_H #define JL_THREADS_H -#include +#include "julia_atomics.h" // threading ------------------------------------------------------------------ #ifdef __cplusplus @@ -194,7 +194,7 @@ typedef struct _jl_tls_states_t { int16_t tid; uint64_t rngseed; volatile size_t *safepoint; - int8_t sleep_check_state; // read/write from foreign threads + _Atomic(int8_t) sleep_check_state; // read/write from foreign threads // Whether it is safe to execute GC at the same time. #define JL_GC_STATE_WAITING 1 // gc_state = 1 means the thread is doing GC or is waiting for the GC to @@ -239,7 +239,7 @@ typedef struct _jl_tls_states_t { struct _jl_bt_element_t *bt_data; // JL_MAX_BT_SIZE + 1 elements long size_t bt_size; // Size for backtrace in transit in bt_data // Atomically set by the sender, reset by the handler. - volatile sig_atomic_t signal_request; + volatile _Atomic(sig_atomic_t) signal_request; // TODO: no actual reason for this to be _Atomic // Allow the sigint to be raised asynchronously // this is limited to the few places we do synchronous IO // we can make this more general (similar to defer_signal) if necessary @@ -293,7 +293,7 @@ typedef jl_tls_states_t *jl_ptls_t; JL_DLLEXPORT void (jl_cpu_pause)(void); JL_DLLEXPORT void (jl_cpu_wake)(void); -#ifdef __clang_analyzer__ +#ifdef __clang_gcanalyzer__ // Note that the sigint safepoint can also trigger GC, albeit less likely void jl_gc_safepoint_(jl_ptls_t tls); void jl_sigint_safepoint(jl_ptls_t tls); @@ -328,9 +328,9 @@ STATIC_INLINE int8_t jl_gc_state_set(jl_ptls_t ptls, int8_t state, STATIC_INLINE int8_t jl_gc_state_save_and_set(jl_ptls_t ptls, int8_t state) { - return jl_gc_state_set(ptls, state, ptls->gc_state); + return jl_gc_state_set(ptls, state, jl_atomic_load_relaxed(&ptls->gc_state)); } -#ifdef __clang_analyzer__ +#ifdef __clang_gcanalyzer__ int8_t jl_gc_unsafe_enter(jl_ptls_t ptls); // Can be a safepoint int8_t jl_gc_unsafe_leave(jl_ptls_t ptls, int8_t state) JL_NOTSAFEPOINT; int8_t jl_gc_safe_enter(jl_ptls_t ptls) JL_NOTSAFEPOINT; diff --git a/src/method.c b/src/method.c index 0cb67e3c92c1a..537f44831c997 100644 --- a/src/method.c +++ b/src/method.c @@ -724,8 +724,8 @@ JL_DLLEXPORT jl_method_t *jl_new_method_uninit(jl_module_t *module) jl_task_t *ct = jl_current_task; jl_method_t *m = (jl_method_t*)jl_gc_alloc(ct->ptls, sizeof(jl_method_t), jl_method_type); - m->specializations = jl_emptysvec; - m->speckeyset = (jl_array_t*)jl_an_empty_vec_any; + jl_atomic_store_relaxed(&m->specializations, jl_emptysvec); + jl_atomic_store_relaxed(&m->speckeyset, (jl_array_t*)jl_an_empty_vec_any); m->sig = NULL; m->slot_syms = NULL; m->roots = NULL; @@ -741,7 +741,7 @@ JL_DLLEXPORT jl_method_t *jl_new_method_uninit(jl_module_t *module) m->called = 0xff; m->nospecialize = module->nospecialize; m->nkw = 0; - m->invokes = NULL; + jl_atomic_store_relaxed(&m->invokes, NULL); m->recursion_relation = NULL; m->isva = 0; m->nargs = 0; diff --git a/src/module.c b/src/module.c index 9fd6af2cd575b..72051b62ee159 100644 --- a/src/module.c +++ b/src/module.c @@ -186,7 +186,7 @@ JL_DLLEXPORT jl_binding_t *jl_get_binding_wr(jl_module_t *m JL_PROPAGATES_ROOT, // Hash tables don't generically root their contents, but they do for bindings. // Express this to the analyzer. // NOTE: Must hold m->lock while calling these. -#ifdef __clang_analyzer__ +#ifdef __clang_gcanalyzer__ jl_binding_t *_jl_get_module_binding(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var) JL_NOTSAFEPOINT; jl_binding_t **_jl_get_module_binding_bp(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var) JL_NOTSAFEPOINT; #else @@ -262,7 +262,7 @@ static jl_binding_t *jl_get_binding_(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t static inline jl_module_t *module_usings_getidx(jl_module_t *m JL_PROPAGATES_ROOT, size_t i) JL_NOTSAFEPOINT; -#ifndef __clang_analyzer__ +#ifndef __clang_gcanalyzer__ // The analyzer doesn't like looking through the arraylist, so just model the // access for it using this function static inline jl_module_t *module_usings_getidx(jl_module_t *m JL_PROPAGATES_ROOT, size_t i) JL_NOTSAFEPOINT { @@ -380,12 +380,17 @@ JL_DLLEXPORT jl_value_t *jl_module_globalref(jl_module_t *m, jl_sym_t *var) JL_UNLOCK(&m->lock); return jl_new_struct(jl_globalref_type, m, var); } - if (b->globalref == NULL) { - b->globalref = jl_new_struct(jl_globalref_type, m, var); - jl_gc_wb(m, b->globalref); + jl_value_t *globalref = jl_atomic_load_relaxed(&b->globalref); + if (globalref == NULL) { + jl_value_t *newref = jl_new_struct(jl_globalref_type, m, var); + if (jl_atomic_cmpswap_relaxed(&b->globalref, &globalref, newref)) { + JL_GC_PROMISE_ROOTED(newref); + globalref = newref; + jl_gc_wb(m, globalref); + } } - JL_UNLOCK(&m->lock); - return b->globalref; + JL_UNLOCK(&m->lock); // may GC + return globalref; } static int eq_bindings(jl_binding_t *a, jl_binding_t *b) @@ -775,7 +780,7 @@ JL_DLLEXPORT void jl_checked_assignment(jl_binding_t *b, jl_value_t *rhs) JL_NOT if (jl_egal(rhs, old)) return; if (jl_typeof(rhs) != jl_typeof(old) || jl_is_type(rhs) || jl_is_module(rhs)) { -#ifndef __clang_analyzer__ +#ifndef __clang_gcanalyzer__ jl_errorf("invalid redefinition of constant %s", jl_symbol_name(b->name)); #endif diff --git a/src/partr.c b/src/partr.c index c3de56b80cc92..93bee1c5fcb74 100644 --- a/src/partr.c +++ b/src/partr.c @@ -60,7 +60,7 @@ typedef struct taskheap_tag { jl_mutex_t lock; jl_task_t **tasks; int32_t ntasks; - int16_t prio; + _Atomic(int16_t) prio; } taskheap_t; /* multiqueue parameters */ @@ -479,7 +479,7 @@ JL_DLLEXPORT jl_task_t *jl_task_get_next(jl_value_t *trypoptask, jl_value_t *q) JL_UV_UNLOCK(); // optimization: check again first if we may have work to do if (!may_sleep(ptls)) { - assert(ptls->sleep_check_state == not_sleeping); + assert(jl_atomic_load_relaxed(&ptls->sleep_check_state) == not_sleeping); start_cycles = 0; continue; } @@ -512,7 +512,7 @@ JL_DLLEXPORT jl_task_t *jl_task_get_next(jl_value_t *trypoptask, jl_value_t *q) uv_cond_wait(&ptls->wake_signal, &ptls->sleep_lock); // TODO: help with gc work here, if applicable } - assert(ptls->sleep_check_state == not_sleeping); + assert(jl_atomic_load_relaxed(&ptls->sleep_check_state) == not_sleeping); uv_mutex_unlock(&ptls->sleep_lock); JULIA_DEBUG_SLEEPWAKE( ptls->sleep_leave = cycleclock() ); jl_gc_safe_leave(ptls, gc_state); // contains jl_gc_safepoint diff --git a/src/safepoint.c b/src/safepoint.c index d4f0abda72ab8..dba2387fcde2e 100644 --- a/src/safepoint.c +++ b/src/safepoint.c @@ -19,7 +19,7 @@ extern "C" { // 1: at least one sigint is pending, only the sigint page is enabled. // 2: at least one sigint is pending, both safepoint pages are enabled. JL_DLLEXPORT sig_atomic_t jl_signal_pending = 0; -uint32_t jl_gc_running = 0; +_Atomic(uint32_t) jl_gc_running = 0; char *jl_safepoint_pages = NULL; // The number of safepoints enabled on the three pages. // The first page, is the SIGINT page, only used by the master thread. diff --git a/src/signals-unix.c b/src/signals-unix.c index 460ef4d80518e..e5ebad6676ece 100644 --- a/src/signals-unix.c +++ b/src/signals-unix.c @@ -792,7 +792,7 @@ static void *signal_listener(void *arg) bt_data_prof[bt_size_cur++].uintptr = ptls->tid + 1; // store task id - bt_data_prof[bt_size_cur++].uintptr = ptls->current_task; + bt_data_prof[bt_size_cur++].jlvalue = (jl_value_t*)ptls->current_task; // store cpu cycle clock bt_data_prof[bt_size_cur++].uintptr = cycleclock(); diff --git a/src/smallintset.c b/src/smallintset.c index 7598d8fd85ce4..54fdad616a758 100644 --- a/src/smallintset.c +++ b/src/smallintset.c @@ -130,14 +130,16 @@ static int smallintset_insert_(jl_array_t *a, uint_t hv, size_t val1) return 0; } -static void smallintset_rehash(jl_array_t **cache, jl_value_t *parent, smallintset_hash hash, jl_svec_t *data, size_t newsz, size_t np); +static void smallintset_rehash(_Atomic(jl_array_t*) *pcache, jl_value_t *parent, smallintset_hash hash, jl_svec_t *data, size_t newsz, size_t np); -void jl_smallintset_insert(jl_array_t **cache, jl_value_t *parent, smallintset_hash hash, size_t val, jl_svec_t *data) +void jl_smallintset_insert(_Atomic(jl_array_t*) *pcache, jl_value_t *parent, smallintset_hash hash, size_t val, jl_svec_t *data) { - if (val + 1 > jl_max_int(*cache)) - smallintset_rehash(cache, parent, hash, data, jl_array_len(*cache), val + 1); + jl_array_t *a = jl_atomic_load_relaxed(pcache); + if (val + 1 > jl_max_int(a)) + smallintset_rehash(pcache, parent, hash, data, jl_array_len(a), val + 1); while (1) { - if (smallintset_insert_(*cache, hash(val, data), val + 1)) + a = jl_atomic_load_relaxed(pcache); + if (smallintset_insert_(a, hash(val, data), val + 1)) return; /* table full */ @@ -145,20 +147,21 @@ void jl_smallintset_insert(jl_array_t **cache, jl_value_t *parent, smallintset_h /* it's important to grow the table really fast; otherwise we waste */ /* lots of time rehashing all the keys over and over. */ size_t newsz; - size_t sz = jl_array_len(*cache); + a = jl_atomic_load_relaxed(pcache); + size_t sz = jl_array_len(a); if (sz < HT_N_INLINE) newsz = HT_N_INLINE; else if (sz >= (1 << 19) || (sz <= (1 << 8))) newsz = sz << 1; else newsz = sz << 2; - smallintset_rehash(cache, parent, hash, data, newsz, 0); + smallintset_rehash(pcache, parent, hash, data, newsz, 0); } } -static void smallintset_rehash(jl_array_t **cache, jl_value_t *parent, smallintset_hash hash, jl_svec_t *data, size_t newsz, size_t np) +static void smallintset_rehash(_Atomic(jl_array_t*) *pcache, jl_value_t *parent, smallintset_hash hash, jl_svec_t *data, size_t newsz, size_t np) { - jl_array_t *a = *cache; + jl_array_t *a = jl_atomic_load_relaxed(pcache); size_t sz = jl_array_len(a); size_t i; for (i = 0; i < sz; i += 1) { @@ -179,7 +182,7 @@ static void smallintset_rehash(jl_array_t **cache, jl_value_t *parent, smallints } JL_GC_POP(); if (i == sz) { - *cache = newa; + jl_atomic_store_release(pcache, newa); jl_gc_wb(parent, newa); return; } diff --git a/src/staticdata.c b/src/staticdata.c index f5892d4218e71..d921802455157 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -403,8 +403,8 @@ static void jl_serialize_module(jl_serializer_state *s, jl_module_t *m) jl_serialize_value(s, (jl_value_t*)table[i]); jl_binding_t *b = (jl_binding_t*)table[i+1]; jl_serialize_value(s, b->name); - jl_serialize_value(s, b->value); - jl_serialize_value(s, b->globalref); + jl_serialize_value(s, jl_atomic_load_relaxed(&b->value)); + jl_serialize_value(s, jl_atomic_load_relaxed(&b->globalref)); jl_serialize_value(s, b->owner); } } @@ -655,8 +655,8 @@ static void jl_write_module(jl_serializer_state *s, uintptr_t item, jl_module_t record_gvar(s, jl_get_llvm_gv(native_functions, (jl_value_t*)b), ((uintptr_t)DataRef << RELOC_TAG_OFFSET) + binding_reloc_offset); write_pointerfield(s, (jl_value_t*)b->name); - write_pointerfield(s, b->value); - write_pointerfield(s, b->globalref); + write_pointerfield(s, jl_atomic_load_relaxed(&b->value)); + write_pointerfield(s, jl_atomic_load_relaxed(&b->globalref)); write_pointerfield(s, (jl_value_t*)b->owner); size_t flag_offset = offsetof(jl_binding_t, owner) + sizeof(b->owner); ios_write(s->s, (char*)b + flag_offset, sizeof(*b) - flag_offset); diff --git a/src/subtype.c b/src/subtype.c index c3512eeb17dac..8079c81e3846a 100644 --- a/src/subtype.c +++ b/src/subtype.c @@ -107,7 +107,7 @@ typedef struct jl_stenv_t { // state manipulation utilities // look up a type variable in an environment -#ifdef __clang_analyzer__ +#ifdef __clang_gcanalyzer__ static jl_varbinding_t *lookup(jl_stenv_t *e, jl_tvar_t *v) JL_GLOBALLY_ROOTED JL_NOTSAFEPOINT; #else static jl_varbinding_t *lookup(jl_stenv_t *e, jl_tvar_t *v) JL_GLOBALLY_ROOTED JL_NOTSAFEPOINT @@ -171,7 +171,7 @@ static void save_env(jl_stenv_t *e, jl_value_t **root, jl_savedenv_t *se) if (root) *root = (jl_value_t*)jl_alloc_svec(len * 3); se->buf = (int8_t*)(len > 8 ? malloc_s(len * 2) : &se->_space); -#ifdef __clang_analyzer__ +#ifdef __clang_gcanalyzer__ memset(se->buf, 0, len * 2); #endif int i=0, j=0; v = e->vars; diff --git a/src/support/analyzer_annotations.h b/src/support/analyzer_annotations.h index 1579584a572a9..70b5a273953f1 100644 --- a/src/support/analyzer_annotations.h +++ b/src/support/analyzer_annotations.h @@ -8,7 +8,7 @@ #endif #define JL_NONNULL _Nonnull -#ifdef __clang_analyzer__ +#ifdef __clang_gcanalyzer__ #define JL_PROPAGATES_ROOT __attribute__((annotate("julia_propagates_root"))) #define JL_NOTSAFEPOINT __attribute__((annotate("julia_not_safepoint"))) diff --git a/src/symbol.c b/src/symbol.c index d23ecdb8012b5..fd5024eefeca2 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -77,7 +77,7 @@ static jl_sym_t *symtab_lookup(_Atomic(jl_sym_t*) *ptree, const char *str, size_ jl_sym_t *_jl_symbol(const char *str, size_t len) JL_NOTSAFEPOINT // (or throw) { -#ifndef __clang_analyzer__ +#ifndef __clang_gcanalyzer__ // Hide the error throwing from the analyser since there isn't a way to express // "safepoint only when throwing error" currently. if (len > MAX_SYM_LEN) diff --git a/src/task.c b/src/task.c index 88d4eac0863c9..9673818e50b55 100644 --- a/src/task.c +++ b/src/task.c @@ -189,7 +189,7 @@ static void restore_stack2(jl_task_t *t, jl_ptls_t ptls, jl_task_t *lastt) #endif /* Rooted by the base module */ -static jl_function_t *task_done_hook_func JL_GLOBALLY_ROOTED = NULL; +static _Atomic(jl_function_t*) task_done_hook_func JL_GLOBALLY_ROOTED = NULL; void JL_NORETURN jl_finish_task(jl_task_t *t) { @@ -736,7 +736,7 @@ JL_DLLEXPORT jl_task_t *jl_new_task(jl_function_t *start, jl_value_t *completion t->next = jl_nothing; t->queue = jl_nothing; t->tls = jl_nothing; - t->_state = JL_TASK_STATE_RUNNABLE; + jl_atomic_store_relaxed(&t->_state, JL_TASK_STATE_RUNNABLE); t->start = start; t->result = jl_nothing; t->donenotify = completion_future; @@ -752,7 +752,7 @@ JL_DLLEXPORT jl_task_t *jl_new_task(jl_function_t *start, jl_value_t *completion t->excstack = NULL; t->started = 0; t->prio = -1; - t->tid = t->copy_stack ? ct->tid : -1; // copy_stacks are always pinned since they can't be moved + jl_atomic_store_relaxed(&t->tid, t->copy_stack ? ct->tid : -1); // copy_stacks are always pinned since they can't be moved t->ptls = NULL; t->world_age = 0; @@ -849,7 +849,7 @@ STATIC_OR_JS void NOINLINE JL_NORETURN start_task(void) CFI_NORETURN // this runs the first time we switch to a task sanitizer_finish_switch_fiber(); -#ifdef __clang_analyzer__ +#ifdef __clang_gcanalyzer__ jl_task_t *ct = jl_get_current_task(); JL_GC_PROMISE_ROOTED(ct); #else @@ -949,7 +949,7 @@ static char *jl_alloc_fiber(jl_ucontext_t *t, size_t *ssize, jl_task_t *owner) char *stkbuf = (char*)jl_malloc_stack(ssize, owner); if (stkbuf == NULL) return NULL; -#ifndef __clang_analyzer__ +#ifndef __clang_gcanalyzer__ ((char**)t)[0] = stkbuf; // stash the stack pointer somewhere for start_fiber ((size_t*)t)[1] = *ssize; // stash the stack size somewhere for start_fiber #endif @@ -1298,7 +1298,7 @@ void jl_init_root_task(jl_ptls_t ptls, void *stack_lo, void *stack_hi) ct->next = jl_nothing; ct->queue = jl_nothing; ct->tls = jl_nothing; - ct->_state = JL_TASK_STATE_RUNNABLE; + jl_atomic_store_relaxed(&ct->_state, JL_TASK_STATE_RUNNABLE); ct->start = NULL; ct->result = jl_nothing; ct->donenotify = jl_nothing; @@ -1307,7 +1307,7 @@ void jl_init_root_task(jl_ptls_t ptls, void *stack_lo, void *stack_hi) ct->eh = NULL; ct->gcstack = NULL; ct->excstack = NULL; - ct->tid = ptls->tid; + jl_atomic_store_relaxed(&ct->tid, ptls->tid); ct->sticky = 1; ct->ptls = ptls; ct->world_age = 1; // OK to run Julia code on this task diff --git a/src/threading.c b/src/threading.c index 5f648f68fd48f..773ef1966725d 100644 --- a/src/threading.c +++ b/src/threading.c @@ -271,7 +271,7 @@ JL_DLLEXPORT void jl_pgcstack_setkey(jl_get_pgcstack_func *f, jl_pgcstack_key_t JL_DLLEXPORT jl_gcframe_t **jl_get_pgcstack(void) JL_GLOBALLY_ROOTED { -#ifndef __clang_analyzer__ +#ifndef __clang_gcanalyzer__ return jl_get_pgcstack_cb(); #endif } @@ -467,7 +467,7 @@ void jl_init_threading(void) } if (jl_n_threads <= 0) jl_n_threads = 1; -#ifndef __clang_analyzer__ +#ifndef __clang_gcanalyzer__ jl_all_tls_states = (jl_ptls_t*)calloc(jl_n_threads, sizeof(void*)); #endif } diff --git a/src/typemap.c b/src/typemap.c index 58dd2b8b13069..13e97a5ada160 100644 --- a/src/typemap.c +++ b/src/typemap.c @@ -259,28 +259,28 @@ static int is_cache_leaf(jl_value_t *ty, int tparam) return (jl_is_concrete_type(ty) && (tparam || !jl_is_kind(ty))); } -static jl_typemap_t **mtcache_hash_lookup_bp(jl_array_t *cache JL_PROPAGATES_ROOT, jl_value_t *ty) JL_NOTSAFEPOINT +static _Atomic(jl_typemap_t*) *mtcache_hash_lookup_bp(jl_array_t *cache JL_PROPAGATES_ROOT, jl_value_t *ty) JL_NOTSAFEPOINT { if (cache == (jl_array_t*)jl_an_empty_vec_any) return NULL; - jl_typemap_t **pml = jl_table_peek_bp(cache, ty); + _Atomic(jl_typemap_t*) *pml = jl_table_peek_bp(cache, ty); JL_GC_PROMISE_ROOTED(pml); // clang-sa doesn't trust our JL_PROPAGATES_ROOT claim return pml; } -static void mtcache_hash_insert(jl_array_t **cache, jl_value_t *parent, jl_value_t *key, jl_typemap_t *val) +static void mtcache_hash_insert(_Atomic(jl_array_t*) *cache, jl_value_t *parent, jl_value_t *key, jl_typemap_t *val) { int inserted = 0; - jl_array_t *a = *cache; + jl_array_t *a = jl_atomic_load_relaxed(cache); if (a == (jl_array_t*)jl_an_empty_vec_any) { a = jl_alloc_vec_any(16); - *cache = a; + jl_atomic_store_release(cache, a); jl_gc_wb(parent, a); } a = jl_eqtable_put(a, key, val, &inserted); assert(inserted); if (a != *cache) { - *cache = a; + jl_atomic_store_release(cache, a); jl_gc_wb(parent, a); } } @@ -299,7 +299,7 @@ static jl_typemap_t *mtcache_hash_lookup(jl_array_t *cache JL_PROPAGATES_ROOT, j static int jl_typemap_array_visitor(jl_array_t *a, jl_typemap_visitor_fptr fptr, void *closure) { size_t i, l = jl_array_len(a); - jl_typemap_t **data = (jl_typemap_t **)jl_array_data(a); + _Atomic(jl_typemap_t*) *data = (_Atomic(jl_typemap_t*)*)jl_array_data(a); for (i = 1; i < l; i += 2) { jl_value_t *d = jl_atomic_load_relaxed(&data[i]); JL_GC_PROMISE_ROOTED(d); @@ -394,7 +394,7 @@ static int jl_typemap_intersection_array_visitor(jl_array_t *a, jl_value_t *ty, { JL_GC_PUSH1(&a); size_t i, l = jl_array_len(a); - jl_typemap_t **data = (jl_typemap_t **)jl_array_data(a); + _Atomic(jl_typemap_t*) *data = (_Atomic(jl_typemap_t*)*)jl_array_data(a); unsigned height = tparam & 2 ? jl_supertype_height((jl_datatype_t*)ty) : 0; for (i = 0; i < l; i += 2) { jl_value_t *t = jl_atomic_load_relaxed(&data[i]); @@ -845,7 +845,7 @@ jl_typemap_entry_t *jl_typemap_assoc_by_type( if (!ty || !jl_has_empty_intersection((jl_value_t*)jl_type_type, ty)) { // couldn't figure out unique `a0` initial point, so scan all for matches size_t i, l = jl_array_len(tname); - jl_typemap_t **data = (jl_typemap_t **)jl_array_ptr_data(tname); + _Atomic(jl_typemap_t*) *data = (_Atomic(jl_typemap_t*)*)jl_array_ptr_data(tname); JL_GC_PUSH1(&tname); for (i = 1; i < l; i += 2) { jl_typemap_t *ml = jl_atomic_load_relaxed(&data[i]); @@ -884,7 +884,7 @@ jl_typemap_entry_t *jl_typemap_assoc_by_type( else { // doing subtype, but couldn't figure out unique `ty`, so scan all for supertypes size_t i, l = jl_array_len(name1); - jl_typemap_t **data = (jl_typemap_t **)jl_array_ptr_data(name1); + _Atomic(jl_typemap_t*) *data = (_Atomic(jl_typemap_t*)*)jl_array_ptr_data(name1); JL_GC_PUSH1(&name1); for (i = 1; i < l; i += 2) { jl_typemap_t *ml = jl_atomic_load_relaxed(&data[i]); @@ -1034,7 +1034,7 @@ jl_typemap_entry_t *jl_typemap_level_assoc_exact(jl_typemap_level_t *cache, jl_v else { // couldn't figure out unique `name` initial point, so must scan all for matches size_t i, l = jl_array_len(tname); - jl_typemap_t **data = (jl_typemap_t **)jl_array_ptr_data(tname); + _Atomic(jl_typemap_t*) *data = (_Atomic(jl_typemap_t*)*)jl_array_ptr_data(tname); JL_GC_PUSH1(&tname); for (i = 1; i < l; i += 2) { jl_typemap_t *ml_or_cache = data[i]; @@ -1122,10 +1122,10 @@ static jl_typemap_level_t *jl_method_convert_list_to_cache( } static void jl_typemap_list_insert_( - jl_typemap_t *map, jl_typemap_entry_t **pml, jl_value_t *parent, + jl_typemap_t *map, _Atomic(jl_typemap_entry_t*) *pml, jl_value_t *parent, jl_typemap_entry_t *newrec) { - jl_typemap_entry_t *l = *pml; + jl_typemap_entry_t *l = jl_atomic_load_relaxed(pml); while ((jl_value_t*)l != jl_nothing) { if (newrec->isleafsig || !l->isleafsig) if (newrec->issimplesig || !l->issimplesig) @@ -1141,37 +1141,39 @@ static void jl_typemap_list_insert_( } static void jl_typemap_insert_generic( - jl_typemap_t *map, jl_typemap_t **pml, jl_value_t *parent, + jl_typemap_t *map, _Atomic(jl_typemap_t*) *pml, jl_value_t *parent, jl_typemap_entry_t *newrec, int8_t offs) { - if (jl_typeof(*pml) == (jl_value_t*)jl_typemap_level_type) { - jl_typemap_level_insert_(map, (jl_typemap_level_t*)*pml, newrec, offs); + jl_typemap_t *ml = jl_atomic_load_relaxed(pml); + if (jl_typeof(ml) == (jl_value_t*)jl_typemap_level_type) { + jl_typemap_level_insert_(map, (jl_typemap_level_t*)ml, newrec, offs); return; } - unsigned count = jl_typemap_list_count_locked((jl_typemap_entry_t*)*pml); + unsigned count = jl_typemap_list_count_locked((jl_typemap_entry_t*)ml); if (count > MAX_METHLIST_COUNT) { - *pml = (jl_typemap_t*)jl_method_convert_list_to_cache( - map, (jl_typemap_entry_t *)*pml, - offs); - jl_gc_wb(parent, *pml); - jl_typemap_level_insert_(map, (jl_typemap_level_t*)*pml, newrec, offs); + ml = (jl_typemap_t*)jl_method_convert_list_to_cache( + map, (jl_typemap_entry_t*)ml, offs); + jl_atomic_store_release(pml, ml); + jl_gc_wb(parent, ml); + jl_typemap_level_insert_(map, (jl_typemap_level_t*)ml, newrec, offs); return; } - jl_typemap_list_insert_(map, (jl_typemap_entry_t **)pml, + jl_typemap_list_insert_(map, (_Atomic(jl_typemap_entry_t*)*)pml, parent, newrec); } static void jl_typemap_array_insert_( - jl_typemap_t *map, jl_array_t **cache, jl_value_t *key, jl_typemap_entry_t *newrec, + jl_typemap_t *map, _Atomic(jl_array_t*) *pcache, jl_value_t *key, jl_typemap_entry_t *newrec, jl_value_t *parent, int8_t offs) { - jl_typemap_t **pml = mtcache_hash_lookup_bp(*cache, key); + jl_array_t *cache = jl_atomic_load_relaxed(pcache); + _Atomic(jl_typemap_t*) *pml = mtcache_hash_lookup_bp(cache, key); if (pml != NULL) - jl_typemap_insert_generic(map, pml, (jl_value_t*)*cache, newrec, offs+1); + jl_typemap_insert_generic(map, pml, (jl_value_t*)cache, newrec, offs+1); else - mtcache_hash_insert(cache, parent, key, (jl_typemap_t*)newrec); + mtcache_hash_insert(pcache, parent, key, (jl_typemap_t*)newrec); } static void jl_typemap_level_insert_( @@ -1276,7 +1278,7 @@ jl_typemap_entry_t *jl_typemap_alloc( newrec->simplesig = simpletype; newrec->func.value = newvalue; newrec->guardsigs = guardsigs; - newrec->next = (jl_typemap_entry_t*)jl_nothing; + jl_atomic_store_relaxed(&newrec->next, (jl_typemap_entry_t*)jl_nothing); newrec->min_world = min_world; newrec->max_world = max_world; newrec->va = isva; @@ -1285,10 +1287,11 @@ jl_typemap_entry_t *jl_typemap_alloc( return newrec; } -void jl_typemap_insert(jl_typemap_t **cache, jl_value_t *parent, +void jl_typemap_insert(_Atomic(jl_typemap_t *) *pcache, jl_value_t *parent, jl_typemap_entry_t *newrec, int8_t offs) { - jl_typemap_insert_generic(*cache, cache, parent, newrec, offs); + jl_typemap_t *cache = jl_atomic_load_relaxed(pcache); + jl_typemap_insert_generic(cache, pcache, parent, newrec, offs); } #ifdef __cplusplus diff --git a/test/clangsa/GCPushPop.cpp b/test/clangsa/GCPushPop.cpp index a992630291bb5..f57f9ba7711df 100644 --- a/test/clangsa/GCPushPop.cpp +++ b/test/clangsa/GCPushPop.cpp @@ -1,6 +1,6 @@ // This file is a part of Julia. License is MIT: https://julialang.org/license -// RUN: clang --analyze -Xanalyzer -analyzer-output=text -Xclang -load -Xclang libGCCheckerPlugin%shlibext -Xclang -verify -I%julia_home/src -I%julia_home/src/support -I%julia_home/usr/include ${CLANGSA_FLAGS} ${CPPFLAGS} ${CFLAGS} -Xclang -analyzer-checker=core,julia.GCChecker -x c++ %s +// RUN: clang -D__clang_gcanalyzer__ --analyze -Xanalyzer -analyzer-output=text -Xclang -load -Xclang libGCCheckerPlugin%shlibext -Xclang -verify -I%julia_home/src -I%julia_home/src/support -I%julia_home/usr/include ${CLANGSA_FLAGS} ${CPPFLAGS} ${CFLAGS} -Xclang -analyzer-checker=core,julia.GCChecker -x c++ %s #include "julia.h" diff --git a/test/clangsa/MissingRoots.c b/test/clangsa/MissingRoots.c index 78dcc195d59ce..f0b32c54bc7b8 100644 --- a/test/clangsa/MissingRoots.c +++ b/test/clangsa/MissingRoots.c @@ -1,6 +1,6 @@ // This file is a part of Julia. License is MIT: https://julialang.org/license -// RUN: clang --analyze -Xanalyzer -analyzer-output=text -Xclang -load -Xclang libGCCheckerPlugin%shlibext -I%julia_home/src -I%julia_home/src/support -I%julia_home/usr/include ${CLANGSA_FLAGS} ${CPPFLAGS} ${CFLAGS} -Xclang -analyzer-checker=core,julia.GCChecker --analyzer-no-default-checks -Xclang -verify -x c %s +// RUN: clang -D__clang_gcanalyzer__ --analyze -Xanalyzer -analyzer-output=text -Xclang -load -Xclang libGCCheckerPlugin%shlibext -I%julia_home/src -I%julia_home/src/support -I%julia_home/usr/include ${CLANGSA_FLAGS} ${CPPFLAGS} ${CFLAGS} -Xclang -analyzer-checker=core,julia.GCChecker --analyzer-no-default-checks -Xclang -verify -x c %s #include "julia.h" #include "julia_internal.h"