From 24d120ac5da305b407253a4d02c33bb0bf752f79 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 6 Jul 2026 17:09:56 +0000 Subject: [PATCH 1/4] clangsa: add thread-safety capability analysis of safepoint annotations Add an Clang Thread Safety Analysis ("capability") model of Julia's safepoints, selected by compiling with `make safesrc` parallel to how -D__clang_gcanalyzer__ enables the GCChecker annotations. This turns the unreliable NOTSAFEPOINT thread-safety checks into mandatory-enforced capabilities. Implementation: the safepoint annotations map onto a zero-sized jl_can_safepoint token capability: JL_CANSAFEPOINT requires it, JL_NOTSAFEPOINT_ENTER and JL_NOTSAFEPOINT_LEAVE release and acquire it, and JL_NOTSAFEPOINT holds nothing, so -Wthread-safety flags a JL_NOTSAFEPOINT function that reaches a safepoint. Because this checker has no implicit default, it requires JL_CANSAFEPOINT on every function that is not JL_NOTSAFEPOINT. To add those annotations in bulk, there was a julia-safepoint-annotations clang-tidy check auto fixit script used, which inserted JL_CANSAFEPOINT on the first declaration of any function that lacks a safepoint dispositio. This then required many manual fixes afterwards, since there were many mistakes in the NOTSAFEPOINT annotations, a few places where the old default-safe analysis wasn't permitted under the new stricter analysis. There are still a few places where the analyzer is disabled due to existing bugs. Also teach the GCChecker to treat any JL_CANSAFEPOINT function as a possible safepoint even when it is inlined and no safepoint is found in its body, so the annotation is honored as a promise rather than re-derived from the body. This is a prelude to erasing JL_NOTSAFPOINT entirely, since it is no longer necessary. Lastly, we teach our clang-tidy first-decl pass to ensure this capability is tracked through function pointers also (upstream LLVM cannot do this). Co-Authored-By: Claude Opus 4.8 (1M context) --- doc/src/devdocs/gc-sa.md | 28 +- src/Makefile | 31 +- src/abi_aarch64.cpp | 18 +- src/abi_arm.cpp | 16 +- src/abi_ppc64le.cpp | 8 +- src/abi_riscv.cpp | 8 +- src/abi_win64.cpp | 2 +- src/abi_x86_64.cpp | 10 +- src/aotcompile.cpp | 22 +- src/array.c | 4 +- src/ast.c | 64 ++- src/builtin_proto.h | 2 +- src/builtins.c | 22 +- src/ccall.cpp | 46 +- src/cgutils.cpp | 213 ++++---- src/clangsa/FirstDeclAnnotations.cpp | 241 +++++++-- src/clangsa/GCCheckerPropagation.cpp | 121 +++-- src/clangsa/HelpersCommon.hpp | 15 +- src/codegen.cpp | 233 +++++---- src/coverage.c | 2 +- src/datatype.c | 30 +- src/debug-registry.h | 4 +- src/debuginfo.cpp | 42 +- src/dlload.c | 45 +- src/gc-common.c | 12 +- src/gc-common.h | 6 +- src/gc-heap-snapshot.h | 2 +- src/gc-interface.h | 24 +- src/gc-page-profiler.c | 2 +- src/gc-pages.c | 2 +- src/gc-stacks.c | 2 +- src/gc-stock.c | 10 +- src/gc-stock.h | 2 +- src/genericmemory.c | 6 +- src/gf.c | 164 +++--- src/iddict.c | 2 +- src/init.c | 31 +- src/interpreter.c | 18 +- src/intrinsics.cpp | 30 +- src/ircode.c | 26 +- src/jitlayers.cpp | 24 +- src/jitlayers.h | 65 ++- src/jl_exported_funcs.inc | 1 - src/jl_uv.c | 24 +- src/jlapi.c | 32 +- src/jltypes.c | 73 ++- src/julia-task-dispatcher.h | 25 +- src/julia.h | 487 +++++++++-------- src/julia_gcext.h | 6 +- src/julia_internal.h | 659 ++++++++++++------------ src/julia_locks.h | 83 ++- src/julia_threads.h | 21 +- src/llvm_api.cpp | 2 +- src/method.c | 22 +- src/module.c | 90 ++-- src/opaque_closure.c | 10 +- src/precompile.c | 2 +- src/precompile_utils.c | 2 +- src/processor.cpp | 6 +- src/processor.h | 20 +- src/rtutils.c | 71 ++- src/runtime_ccall.c | 4 +- src/runtime_intrinsics.c | 24 +- src/safepoint.c | 8 +- src/scheduler.c | 15 +- src/signal-handling.c | 26 +- src/signals-unix.c | 34 +- src/smallintset.c | 2 +- src/stackwalk.c | 96 ++-- src/staticdata.c | 105 ++-- src/staticdata_utils.c | 32 +- src/subtype.c | 128 ++--- src/support/analyzer_annotations.h | 193 ++++++- src/sys.c | 6 +- src/task.c | 24 +- src/threading.c | 36 +- src/threading.h | 10 +- src/toplevel.c | 38 +- src/typemap.c | 32 +- test/clangsa/FirstDeclAnnotationsTest.c | 73 +-- test/clangsa/FirstDeclAnnotationsTest.h | 22 +- test/clangsa/MissingRoots.c | 60 +++ test/clangsa/SafepointCapability.c | 93 ++++ 83 files changed, 2569 insertions(+), 1783 deletions(-) create mode 100644 test/clangsa/SafepointCapability.c diff --git a/doc/src/devdocs/gc-sa.md b/doc/src/devdocs/gc-sa.md index fa32c173739ad..202c6e450a4f3 100644 --- a/doc/src/devdocs/gc-sa.md +++ b/doc/src/devdocs/gc-sa.md @@ -3,11 +3,8 @@ ## Running the analysis The analyzer plugin that drives the analysis ships with julia. Its -source code can be found in `src/clangsa`. Running it requires -the clang dependency to be built. Set the `BUILD_LLVM_CLANG` variable -in your Make.user in order to build an appropriate version of clang. -You may also want to use the prebuilt binaries using the -`USE_BINARYBUILDER_LLVM` options. +source code can be found in `src/clangsa`. Running it uses the +the clang dependency option from deps. Alternatively (or if these do not suffice), try @@ -104,24 +101,21 @@ These annotations are found in src/support/analyzer_annotations.h. They are only active when the analyzer is being used and expand either to nothing (for prototype annotations) or to no-ops (for function like annotations). -### `JL_NOTSAFEPOINT` +### `JL_CANSAFEPOINT` This is perhaps the most common annotation, and should be placed on any function -that is known not to possibly lead to reaching a GC safepoint. In general, it is -only safe for such a function to perform arithmetic, memory accesses and calls to -functions either annotated `JL_NOTSAFEPOINT` or otherwise known not to be safepoints (e.g. -function in the C standard library, which are hardcoded as such in the analyzer) +that needs to interact with a GC safepoint. It has a few variants also, to express +when the function expects to be called in an gc-safe region for example. -It is valid to keep values unrooted across calls to any function annotated with this -attribute: +It is valid to keep values unrooted across calls to any unannotated function: Usage Example: ```c -void jl_get_one() JL_NOTSAFEPOINT { +void jl_get_one() { return 1; } -jl_value_t *example() { +jl_value_t *example() JL_CANSAFEPOINT { jl_value_t *val = jl_alloc_whatever(); // This is valid, even though `val` is unrooted, because // jl_get_one is not a safepoint @@ -143,9 +137,9 @@ The `ROOTS_TEMPORARILY` annotation provides the stronger guarantee that, not only may the value be unrooted when passed, it will also be preserved across any internal safepoints by the callee. -Note that `JL_NOTSAFEPOINT` essentially implies `JL_MAYBE_UNROOTED`/`JL_ROOTS_TEMPORARILY`, -because the rootedness of an argument is irrelevant if the function contains -no safepoints. +Note that not annotating with `JL_CANSAFEPOINT` essentially implies +`JL_MAYBE_UNROOTED`/`JL_ROOTS_TEMPORARILY`, because the rootedness of an +argument is irrelevant if the function contains no safepoints. One additional point to note is that these annotations apply on both the caller and the callee side. On the caller side, they lift rootedness diff --git a/src/Makefile b/src/Makefile index d4bb7d9f8f439..f97dab7d0e430 100644 --- a/src/Makefile +++ b/src/Makefile @@ -632,13 +632,18 @@ $(CODEGEN_OBJS) $(CODEGEN_DOBJS): FLAGS_COMMON += -DJL_LIBRARY_EXPORTS_CODEGEN - # set the exports for the source files based on where they are getting linked $(addprefix clang-sa-,$(SRCS)) \ $(addprefix clang-sagc-,$(SRCS)) \ +$(addprefix clang-safety-,$(SRCS)) \ $(addprefix clang-tidy-,$(SRCS)): \ FLAGS_COMMON += -DJL_LIBRARY_EXPORTS_INTERNAL $(addprefix clang-sa-,$(CODEGEN_SRCS)) \ $(addprefix clang-sagc-,$(CODEGEN_SRCS)) \ +$(addprefix clang-safety-,$(CODEGEN_SRCS)) \ $(addprefix clang-tidy-,$(CODEGEN_SRCS)): \ FLAGS_COMMON += -DJL_LIBRARY_EXPORTS_CODEGEN +$(addprefix clang-safety-,$(SRCS) $(CODEGEN_SRCS)): \ + FLAGS_COMMON += -D__clang_analyzer__ + # Common flag patterns for all clang tooling (clang-sa, clang-tidy, compile-database) CLANG_TOOLING_C_FLAGS = $(CLANGSA_FLAGS) $(LLVM_CFLAGS) $(DEBUGFLAGS_CLANG) $(JCPPFLAGS_CLANG) $(JCFLAGS_CLANG) CLANG_TOOLING_CXX_FLAGS = $(CLANGSA_FLAGS) $(CLANGSA_CXXFLAGS) $(DEBUGFLAGS_CLANG) $(LLVM_CXXFLAGS) $(JCPPFLAGS_CLANG) $(JCXXFLAGS_CLANG) @@ -755,7 +760,7 @@ SA_EXCEPTIONS-gc-stock.c := -Xanalyzer -analyzer-config -Xana SKIP_GC_CHECK := codegen.cpp rtutils.c # make sure LLVM's invariant information is not discarded with -DNDEBUG -clang-sagc-%: JCXXFLAGS_COMMON += -UNDEBUG +clang-sagc-%: JCPPFLAGS_COMMON += -UNDEBUG clang-sagc-%: $(SRCDIR)/%.c $(GCCHECKER_PLUGIN) .FORCE | analyzegc-deps-check @$(call PRINT_ANALYZE, $(build_depsbindir)/clang -D__clang_gcanalyzer__ --analyze -Xanalyzer -analyzer-werror -Xanalyzer -analyzer-output=text --analyzer-no-default-checks \ -Xclang -load -Xclang $(GCCHECKER_PLUGIN) -Xclang -analyzer-checker=core$(COMMA)julia.GCChecker \ @@ -767,7 +772,7 @@ clang-sagc-%: $(SRCDIR)/%.cpp $(GCCHECKER_PLUGIN) .FORCE | analyzegc-deps-check $(SA_EXCEPTIONS-$(notdir $<)) \ $(CLANG_TOOLING_CXX_FLAGS) -fcolor-diagnostics -x c++ $<) -clang-sa-%: JCXXFLAGS_COMMON += -UNDEBUG +clang-sa-%: JCPPFLAGS_COMMON += -UNDEBUG clang-sa-%: $(SRCDIR)/%.c .FORCE | analyzegc-deps-check @$(call PRINT_ANALYZE, $(build_depsbindir)/clang --analyze -Xanalyzer -analyzer-werror -Xanalyzer -analyzer-output=text \ -Xanalyzer -analyzer-disable-checker=deadcode.DeadStores \ @@ -779,6 +784,24 @@ clang-sa-%: $(SRCDIR)/%.cpp .FORCE | analyzegc-deps-check $(SA_EXCEPTIONS-$(notdir $<)) \ $(CLANG_TOOLING_CXX_FLAGS) -fcolor-diagnostics -Werror -x c++ $<) +# Clang Thread Safety Analysis of Julia's safepoint annotations. Compiling with +# -D__clang_safetyanalysis__ makes JL_CANSAFEPOINT and the ENTER/LEAVE annotations expand to +# capability attributes on the reentrant `jl_notsafepoint` token (see +# src/support/analyzer_annotations.h), which -Wthread-safety then checks. +# +# -Wno-ignored-attributes and -Wno-thread-safety-attributes: JL_CANSAFEPOINT (and friends) expand to a +# `requires_capability` attribute, which clang-21's thread-safety analysis only +# accepts on functions and parameters -- not on a function-pointer *typedef*. +# This should be revisisted after clang-23, which added some support for this. +clang-safety-%: JCPPFLAGS_COMMON += -UNDEBUG -D__clang_safetyanalysis__ -fsyntax-only -fcolor-diagnostics \ + -Wthread-safety -Wthread-safety-negative -Werror=thread-safety \ + -Wno-ignored-attributes -Wno-thread-safety-attributes +clang-safety-%: $(SRCDIR)/%.c .FORCE | analyzegc-deps-check + @$(call PRINT_ANALYZE, $(build_depsbindir)/clang $(CLANG_TOOLING_C_FLAGS) -x c $<) +clang-safety-%: $(SRCDIR)/%.cpp .FORCE | analyzegc-deps-check + @$(call PRINT_ANALYZE, $(build_depsbindir)/clang \ + $(CLANG_TOOLING_CXX_FLAGS) --system-header-prefix=llvm -x c++ $<) + # Run clang-tidy with our plugins: `-header-filter='.*'` so the first # (header) declarations participate in the comparison. The annotation macros # only expand to an `annotate` attribute under `-D__clang_gcanalyzer__` (see @@ -807,12 +830,14 @@ clang-tidy-%: $(SRCDIR)/%.cpp $(TIDY_PLUGIN_LIBS) .FORCE | analyzegc-deps-check # Add C files as a target of `analyzesrc` and `analyzegc` and `tidysrc` .PHONY: tidysrc tidysrc: $(addprefix clang-tidy-,$(CODEGEN_SRCS) $(SRCS)) +.PHONY: safesrc +safesrc: $(addprefix clang-safety-,$(CODEGEN_SRCS) $(SRCS)) .PHONY: analyzesrc analyzesrc: $(addprefix clang-sa-,$(CODEGEN_SRCS) $(SRCS)) .PHONY: analyzegc analyzegc: $(addprefix clang-sagc-,$(filter-out $(basename $(SKIP_GC_CHECK)),$(CODEGEN_SRCS) $(SRCS))) .PHONY: analyze -analyze: analyzesrc analyzegc tidysrc +analyze: analyzesrc analyzegc tidysrc safesrc $(addprefix analyze-,$(CODEGEN_SRCS) $(SRCS)) : analyze-% : clang-sa-% $(addprefix analyze-,$(CODEGEN_SRCS) $(SRCS)) : analyze-% : clang-tidy-% diff --git a/src/abi_aarch64.cpp b/src/abi_aarch64.cpp index f55cec72bef8e..9b5c0f0957dc4 100644 --- a/src/abi_aarch64.cpp +++ b/src/abi_aarch64.cpp @@ -13,7 +13,7 @@ struct ABI_AArch64Layout : AbiLayout { -Type *get_llvm_vectype(jl_datatype_t *dt, LLVMContext &ctx) const +Type *get_llvm_vectype(jl_datatype_t *dt, LLVMContext &ctx) const JL_CANSAFEPOINT { // Assume jl_is_datatype(dt) && !jl_is_abstracttype(dt) // `!dt->name->mutabl && dt->pointerfree && !dt->haspadding && dt->isbitsegal && dt->nfields > 0` @@ -59,7 +59,7 @@ Type *get_llvm_vectype(jl_datatype_t *dt, LLVMContext &ctx) const } #define jl_is_floattype(v) jl_subtype(v,(jl_value_t*)jl_floatingpoint_type) -Type *get_llvm_fptype(jl_datatype_t *dt, LLVMContext &ctx) const +Type *get_llvm_fptype(jl_datatype_t *dt, LLVMContext &ctx) const JL_CANSAFEPOINT { // Assume jl_is_datatype(dt) && !jl_is_abstracttype(dt) // `!dt->name->mutabl && dt->pointerfree && !dt->haspadding && dt->isbitsegal && dt->nfields == 0` @@ -85,7 +85,7 @@ Type *get_llvm_fptype(jl_datatype_t *dt, LLVMContext &ctx) const lltype : nullptr); } -Type *get_llvm_fp_or_vectype(jl_datatype_t *dt, LLVMContext &ctx) const +Type *get_llvm_fp_or_vectype(jl_datatype_t *dt, LLVMContext &ctx) const JL_CANSAFEPOINT { // Assume jl_is_datatype(dt) && !jl_is_abstracttype(dt) if (dt->name->mutabl || dt->layout->npointers || !dt->layout->flags.isbitsegal || dt->layout->flags.haspadding) @@ -105,7 +105,7 @@ struct ElementType { // Data Types of the members that compose the type are the same. // Note that it is the fundamental types that are important and not the member // types. -bool isHFAorHVA(jl_datatype_t *dt, size_t dsz, size_t &nele, ElementType &ele, LLVMContext &ctx) const +bool isHFAorHVA(jl_datatype_t *dt, size_t dsz, size_t &nele, ElementType &ele, LLVMContext &ctx) const JL_CANSAFEPOINT { // Assume: // dt is a pointerfree type, (all members are isbits) @@ -172,7 +172,7 @@ bool isHFAorHVA(jl_datatype_t *dt, size_t dsz, size_t &nele, ElementType &ele, L return false; } -Type *isHFAorHVA(jl_datatype_t *dt, size_t &nele, LLVMContext &ctx) const +Type *isHFAorHVA(jl_datatype_t *dt, size_t &nele, LLVMContext &ctx) const JL_CANSAFEPOINT { // Assume jl_is_datatype(dt) && !jl_is_abstracttype(dt) @@ -193,7 +193,7 @@ Type *isHFAorHVA(jl_datatype_t *dt, size_t &nele, LLVMContext &ctx) const return NULL; } -bool needPassByRef(jl_datatype_t *dt, AttrBuilder &ab, LLVMContext &ctx, Type *Ty) override +bool needPassByRef(jl_datatype_t *dt, AttrBuilder &ab, LLVMContext &ctx, Type *Ty) override JL_CANSAFEPOINT { // B.2 // If the argument type is an HFA or an HVA, then the argument is used @@ -226,7 +226,7 @@ bool needPassByRef(jl_datatype_t *dt, AttrBuilder &ab, LLVMContext &ctx, Type *T // // All the out parameters should be default to `false`. Type *classify_arg(jl_datatype_t *dt, bool *fpreg, bool *onstack, - size_t *rewrite_len, LLVMContext &ctx) const + size_t *rewrite_len, LLVMContext &ctx) const JL_CANSAFEPOINT { // Based on section 5.4 C of the Procedure Call Standard // C.1 @@ -350,7 +350,7 @@ Type *classify_arg(jl_datatype_t *dt, bool *fpreg, bool *onstack, // } -bool use_sret(jl_datatype_t *dt, LLVMContext &ctx) override +bool use_sret(jl_datatype_t *dt, LLVMContext &ctx) override JL_CANSAFEPOINT { // Section 5.5 // If the type, T, of the result of a function is such that @@ -368,7 +368,7 @@ bool use_sret(jl_datatype_t *dt, LLVMContext &ctx) override return onstack; } -Type *preferred_llvm_type(jl_datatype_t *dt, bool isret, LLVMContext &ctx) const override +Type *preferred_llvm_type(jl_datatype_t *dt, bool isret, LLVMContext &ctx) const override JL_CANSAFEPOINT { if (Type *fptype = get_llvm_fp_or_vectype(dt, ctx)) return fptype; diff --git a/src/abi_arm.cpp b/src/abi_arm.cpp index 541a266875627..10e486250aeae 100644 --- a/src/abi_arm.cpp +++ b/src/abi_arm.cpp @@ -30,7 +30,7 @@ bool needPassByRef(jl_datatype_t *dt, AttrBuilder &abi, LLVMContext &ctx, Type * #define jl_is_floattype(v) jl_subtype(v,(jl_value_t*)jl_floatingpoint_type) -Type *get_llvm_fptype(jl_datatype_t *dt, LLVMContext &ctx) const +Type *get_llvm_fptype(jl_datatype_t *dt, LLVMContext &ctx) const JL_CANSAFEPOINT { // Assume jl_is_datatype(dt) && !jl_is_abstracttype(dt) if (dt->name->mutabl || jl_datatype_nfields(dt) != 0) @@ -58,7 +58,7 @@ Type *get_llvm_fptype(jl_datatype_t *dt, LLVMContext &ctx) const // fundamental type. // // Returns the corresponding LLVM type. -Type *isLegalHAType(jl_datatype_t *dt, LLVMContext &ctx) const +Type *isLegalHAType(jl_datatype_t *dt, LLVMContext &ctx) const JL_CANSAFEPOINT { // single- or double-precision floating-point type if (Type *fp = get_llvm_fptype(dt, ctx)) @@ -74,7 +74,7 @@ Type *isLegalHAType(jl_datatype_t *dt, LLVMContext &ctx) const // // Legality of the HA is determined by a nonzero return value. // In case of a non-legal HA, the value of 'base' is undefined. -size_t isLegalHA(jl_datatype_t *dt, Type *&base, LLVMContext &ctx) const +size_t isLegalHA(jl_datatype_t *dt, Type *&base, LLVMContext &ctx) const JL_CANSAFEPOINT { // Homogeneous aggregates are only used for VFP registers, // so use that definition of legality (section 6.1.2.1) @@ -122,7 +122,7 @@ size_t isLegalHA(jl_datatype_t *dt, Type *&base, LLVMContext &ctx) const // Determine if an argument can be passed through a coprocessor register. // // All the out parameters should be default to `false`. -void classify_cprc(jl_datatype_t *dt, bool *vfp, LLVMContext &ctx) const +void classify_cprc(jl_datatype_t *dt, bool *vfp, LLVMContext &ctx) const JL_CANSAFEPOINT { // Based on section 6.1 of the Procedure Call Standard @@ -146,7 +146,7 @@ void classify_cprc(jl_datatype_t *dt, bool *vfp, LLVMContext &ctx) const } void classify_return_arg(jl_datatype_t *dt, bool *reg, bool *onstack, - bool *need_rewrite, LLVMContext &ctx) const + bool *need_rewrite, LLVMContext &ctx) const JL_CANSAFEPOINT { // Based on section 5.4 of the Procedure Call Standard @@ -198,7 +198,7 @@ void classify_return_arg(jl_datatype_t *dt, bool *reg, bool *onstack, *onstack = true; } -bool use_sret(jl_datatype_t *dt, LLVMContext &ctx) override +bool use_sret(jl_datatype_t *dt, LLVMContext &ctx) override JL_CANSAFEPOINT { bool reg = false; bool onstack = false; @@ -220,7 +220,7 @@ bool use_sret(jl_datatype_t *dt, LLVMContext &ctx) override // // All the out parameters should be default to `false`. void classify_arg(jl_datatype_t *dt, bool *reg, - bool *onstack, bool *need_rewrite, LLVMContext &ctx) const + bool *onstack, bool *need_rewrite, LLVMContext &ctx) const JL_CANSAFEPOINT { // Based on section 5.5 of the Procedure Call Standard @@ -241,7 +241,7 @@ void classify_arg(jl_datatype_t *dt, bool *reg, *need_rewrite = true; } -Type *preferred_llvm_type(jl_datatype_t *dt, bool isret, LLVMContext &ctx) const override +Type *preferred_llvm_type(jl_datatype_t *dt, bool isret, LLVMContext &ctx) const override JL_CANSAFEPOINT { if (Type *fptype = get_llvm_fptype(dt, ctx)) return fptype; diff --git a/src/abi_ppc64le.cpp b/src/abi_ppc64le.cpp index f02e1022ddc2d..c953052b29a58 100644 --- a/src/abi_ppc64le.cpp +++ b/src/abi_ppc64le.cpp @@ -42,7 +42,7 @@ struct ABI_PPC64leLayout : AbiLayout { // count the homogeneous floating aggregate size (saturating at max count of 8) -unsigned isHFA(jl_datatype_t *ty, jl_datatype_t **ty0, bool *hva) const +unsigned isHFA(jl_datatype_t *ty, jl_datatype_t **ty0, bool *hva) const JL_CANSAFEPOINT { if (jl_datatype_size(ty) > 128 || ty->layout->npointers || !ty->layout->flags.isbitsegal || ty->layout->flags.haspadding) return 9; @@ -95,7 +95,7 @@ unsigned isHFA(jl_datatype_t *ty, jl_datatype_t **ty0, bool *hva) const return n; } -bool use_sret(jl_datatype_t *dt, LLVMContext &ctx) override +bool use_sret(jl_datatype_t *dt, LLVMContext &ctx) override JL_CANSAFEPOINT { jl_datatype_t *ty0 = NULL; bool hva = false; @@ -104,7 +104,7 @@ bool use_sret(jl_datatype_t *dt, LLVMContext &ctx) override return false; } -bool needPassByRef(jl_datatype_t *dt, AttrBuilder &ab, LLVMContext &ctx, Type *Ty) override +bool needPassByRef(jl_datatype_t *dt, AttrBuilder &ab, LLVMContext &ctx, Type *Ty) override JL_CANSAFEPOINT { jl_datatype_t *ty0 = NULL; bool hva = false; @@ -115,7 +115,7 @@ bool needPassByRef(jl_datatype_t *dt, AttrBuilder &ab, LLVMContext &ctx, Type *T return false; } -Type *preferred_llvm_type(jl_datatype_t *dt, bool isret, LLVMContext &ctx) const override +Type *preferred_llvm_type(jl_datatype_t *dt, bool isret, LLVMContext &ctx) const override JL_CANSAFEPOINT { // Arguments are either scalar or passed by value diff --git a/src/abi_riscv.cpp b/src/abi_riscv.cpp index e140fda9f796e..3d4f7a632112a 100644 --- a/src/abi_riscv.cpp +++ b/src/abi_riscv.cpp @@ -80,7 +80,7 @@ Type *get_llvm_inttype(jl_datatype_t *dt, LLVMContext &ctx) const return Type::getIntNTy(ctx, nb * 8); } -bool should_use_fp_conv(jl_datatype_t *dt, ElementType &ele1, ElementType &ele2) const +bool should_use_fp_conv(jl_datatype_t *dt, ElementType &ele1, ElementType &ele2) const JL_CANSAFEPOINT { if (jl_is_primitivetype(dt)) { size_t dsz = jl_datatype_size(dt); @@ -179,7 +179,7 @@ Type *get_llvm_inttype_byxlen(size_t xlen, LLVMContext &ctx) const } Type *classify_arg(jl_datatype_t *ty, int &avail_gprs, int &avail_fprs, bool &onstack, - LLVMContext &ctx) const + LLVMContext &ctx) const JL_CANSAFEPOINT { onstack = false; if (ty == jl_nothing_type) { @@ -282,7 +282,7 @@ Type *classify_arg(jl_datatype_t *ty, int &avail_gprs, int &avail_fprs, bool &on return get_llvm_inttype(ty, ctx); } -bool use_sret(jl_datatype_t *ty, LLVMContext &ctx) override +bool use_sret(jl_datatype_t *ty, LLVMContext &ctx) override JL_CANSAFEPOINT { bool onstack = false; int gprs = 2; @@ -298,7 +298,7 @@ bool use_sret(jl_datatype_t *ty, LLVMContext &ctx) override } bool needPassByRef(jl_datatype_t *ty, AttrBuilder &ab, LLVMContext &ctx, - Type *Ty) override + Type *Ty) override JL_CANSAFEPOINT { bool onstack = false; this->cached_llvmtype = diff --git a/src/abi_win64.cpp b/src/abi_win64.cpp index ec97203eee5ff..3cc5abca927ce 100644 --- a/src/abi_win64.cpp +++ b/src/abi_win64.cpp @@ -47,7 +47,7 @@ struct ABI_Win64Layout : AbiLayout { int nargs; ABI_Win64Layout() : nargs(0) { } -bool use_sret(jl_datatype_t *dt, LLVMContext &ctx) override +bool use_sret(jl_datatype_t *dt, LLVMContext &ctx) override JL_CANSAFEPOINT { size_t size = jl_datatype_size(dt); if (win64_reg_size(size) || is_native_simd_type(dt)) diff --git a/src/abi_x86_64.cpp b/src/abi_x86_64.cpp index 6a853421dbccd..cb03ce7ef04cc 100644 --- a/src/abi_x86_64.cpp +++ b/src/abi_x86_64.cpp @@ -115,7 +115,7 @@ struct Classification { // make sure other half knows about it too: accum.addField(offset+16, ComplexX87); } */ -void classifyType(Classification& accum, jl_datatype_t *dt, uint64_t offset) const +void classifyType(Classification& accum, jl_datatype_t *dt, uint64_t offset) const JL_CANSAFEPOINT { // Floating point types if (dt == jl_float64_type || dt == jl_float32_type || dt == jl_float16_type || @@ -166,14 +166,14 @@ void classifyType(Classification& accum, jl_datatype_t *dt, uint64_t offset) con } } -Classification classify(jl_datatype_t *dt) const +Classification classify(jl_datatype_t *dt) const JL_CANSAFEPOINT { Classification cl; classifyType(cl, dt, 0); return cl; } -bool use_sret(jl_datatype_t *dt, LLVMContext &ctx) override +bool use_sret(jl_datatype_t *dt, LLVMContext &ctx) override JL_CANSAFEPOINT { int sret = classify(dt).isMemory; if (sret) { @@ -183,7 +183,7 @@ bool use_sret(jl_datatype_t *dt, LLVMContext &ctx) override return sret; } -bool needPassByRef(jl_datatype_t *dt, AttrBuilder &ab, LLVMContext &ctx, Type *Ty) override +bool needPassByRef(jl_datatype_t *dt, AttrBuilder &ab, LLVMContext &ctx, Type *Ty) override JL_CANSAFEPOINT { Classification cl = classify(dt); if (cl.isMemory) { @@ -215,7 +215,7 @@ bool needPassByRef(jl_datatype_t *dt, AttrBuilder &ab, LLVMContext &ctx, Type *T // Called on behalf of ccall to determine preferred LLVM representation // for an argument or return value. -Type *preferred_llvm_type(jl_datatype_t *dt, bool isret, LLVMContext &ctx) const override +Type *preferred_llvm_type(jl_datatype_t *dt, bool isret, LLVMContext &ctx) const override JL_CANSAFEPOINT { (void) isret; // no need to rewrite these types (they are returned as pointers anyways) diff --git a/src/aotcompile.cpp b/src/aotcompile.cpp index 06ca4bc6660fc..5de83829aaf1a 100644 --- a/src/aotcompile.cpp +++ b/src/aotcompile.cpp @@ -451,7 +451,7 @@ class egal_set { egal_set(egal_set&) = delete; egal_set(egal_set&&) = delete; egal_set() = default; - void insert(jl_value_t *val) + void insert(jl_value_t *val) JL_CANSAFEPOINT { // list/keyset are GC-rooted by the caller via JL_GC_PUSH JL_GC_PROMISE_ROOTED(val); @@ -474,7 +474,7 @@ class egal_set { using ::egal_set; typedef DenseMap jl_compiled_functions_t; -static void record_method_roots(egal_set &method_roots, jl_method_instance_t *mi) +static void record_method_roots(egal_set &method_roots, jl_method_instance_t *mi) JL_CANSAFEPOINT { jl_method_t *m = mi->def.method; if (!jl_is_method(m)) @@ -493,14 +493,14 @@ static void record_method_roots(egal_set &method_roots, jl_method_instance_t *mi JL_UNLOCK(&m->writelock); } -static void aot_optimize_roots(jl_codegen_output_t &out, egal_set &method_roots) +static void aot_optimize_roots(jl_codegen_output_t &out, egal_set &method_roots) JL_CANSAFEPOINT { for (size_t i = 0; i < jl_array_dim0(out.temporary_roots); i++) { jl_value_t *val = jl_array_ptr_ref(out.temporary_roots, i); auto ref = out.global_targets.find((void*)val); if (ref == out.global_targets.end()) continue; - auto get_global_root = [val, &method_roots]() { + auto get_global_root = [val, &method_roots]() JL_CANSAFEPOINT { if (jl_is_globally_rooted(val)) return val; jl_value_t *mval = method_roots.get(val); @@ -523,7 +523,7 @@ static void aot_optimize_roots(jl_codegen_output_t &out, egal_set &method_roots) } } -static Function *aot_abi_converter(jl_codegen_output_t &out, jl_abi_t from_abi, jl_code_instance_t *codeinst, Function *func, Function *specfunc, bool target_specsig) +static Function *aot_abi_converter(jl_codegen_output_t &out, jl_abi_t from_abi, jl_code_instance_t *codeinst, Function *func, Function *specfunc, bool target_specsig) JL_CANSAFEPOINT { std::string gf_thunk_name; if (specfunc) @@ -535,7 +535,7 @@ static Function *aot_abi_converter(jl_codegen_output_t &out, jl_abi_t from_abi, return F; } -static void generate_cfunc_thunks(jl_codegen_output_t &out) +static void generate_cfunc_thunks(jl_codegen_output_t &out) JL_CANSAFEPOINT { DenseMap compiled_mi; for (auto &[ci, _] : out.ci_funcs) { @@ -552,7 +552,7 @@ static void generate_cfunc_thunks(jl_codegen_output_t &out) JL_GC_PROMISE_ROOTED(declrt); Function *unspec = aot_abi_converter(out, cfunc.abi, nullptr, nullptr, nullptr, false); jl_code_instance_t *codeinst = nullptr; - auto assign_fptr = [&out, &cfunc, &codeinst, &unspec](Function *f) { + auto assign_fptr = [&out, &cfunc, &codeinst, &unspec](Function *f) JL_CANSAFEPOINT { ConstantArray *init = cast(cfunc.cfuncdata->getInitializer()); SmallVector initvals; for (unsigned i = 0; i < init->getNumOperands(); ++i) @@ -837,7 +837,7 @@ static jl_compiled_functions_t::iterator get_ci_equiv_compiled(jl_code_instance_ } // Static version of JuliaOJIT::linkOutput -static void aot_link_output(jl_codegen_output_t &out) +static void aot_link_output(jl_codegen_output_t &out) JL_CANSAFEPOINT { for (auto &[call, target] : out.call_targets) { auto [ci, api] = call; @@ -878,7 +878,7 @@ static void aot_link_output(jl_codegen_output_t &out) static void jl_emit_native_to_output(jl_native_code_desc_t *data, jl_array_t *codeinfos, jl_array_t *ci_order, const jl_cgparams_t *cgparams, - int external_linkage) + int external_linkage) JL_CANSAFEPOINT { jl_cgparams_t target_cgparams = *cgparams; target_cgparams.sanitize_memory = jl_options.target_sanitize_memory; @@ -1020,7 +1020,7 @@ void *jl_emit_native_impl(jl_array_t *codeinfos, jl_array_t *ci_order, LLVMOrcTh data->TSM_ref = &data->TSM; } - data->TSM_ref->withModuleDo([&](Module &M) { + data->TSM_ref->withModuleDo([&](Module &M) JL_CANSAFEPOINT { data->out = std::make_unique(M); jl_emit_native_to_output(data, codeinfos, ci_order, cgparams, external_linkage); }); @@ -2603,7 +2603,7 @@ void jl_dump_native_impl(void *native_code, // sometimes in GDB you want to find out what code would be created from a mi -extern "C" JL_DLLEXPORT_CODEGEN jl_code_info_t *jl_gdbdumpcode(jl_method_instance_t *mi) +extern "C" JL_DLLEXPORT_CODEGEN jl_code_info_t *jl_gdbdumpcode(jl_method_instance_t *mi) JL_CANSAFEPOINT { jl_llvmf_dump_t llvmf_dump; size_t world = jl_current_task->world_age; diff --git a/src/array.c b/src/array.c index 9804d82c6a300..9eb4e4690bd09 100644 --- a/src/array.c +++ b/src/array.c @@ -56,7 +56,7 @@ static char *jl_array_typetagdata(jl_array_t *a) JL_NOTSAFEPOINT return jl_genericmemory_typetagdata(a->ref.mem) + (uintptr_t)a->ref.ptr_or_offset; } -STATIC_INLINE jl_array_t *_new_array(jl_value_t *atype, jl_genericmemory_t *mem, const jl_datatype_layout_t *layout, uint32_t ndims, size_t *dims) +STATIC_INLINE jl_array_t *_new_array(jl_value_t *atype, jl_genericmemory_t *mem, const jl_datatype_layout_t *layout, uint32_t ndims, size_t *dims) JL_CANSAFEPOINT { jl_task_t *ct = jl_current_task; size_t i; @@ -72,7 +72,7 @@ STATIC_INLINE jl_array_t *_new_array(jl_value_t *atype, jl_genericmemory_t *mem, return a; } -STATIC_INLINE jl_array_t *new_array(jl_value_t *atype, uint32_t ndims, size_t *dims) +STATIC_INLINE jl_array_t *new_array(jl_value_t *atype, uint32_t ndims, size_t *dims) JL_CANSAFEPOINT { size_t nel; if (jl_array_validate_dims(&nel, ndims, dims)) diff --git a/src/ast.c b/src/ast.c index 5a157ba58dcb3..eb6fc3f21e8fc 100644 --- a/src/ast.c +++ b/src/ast.c @@ -55,9 +55,15 @@ struct macroctx_stack { struct macroctx_stack *parent; }; -static jl_value_t *scm_to_julia(fl_context_t *fl_ctx, value_t e, jl_module_t *mod); -static value_t julia_to_scm(fl_context_t *fl_ctx, jl_value_t *v); -static jl_value_t *jl_expand_macros(jl_value_t *expr, jl_module_t *inmodule, struct macroctx_stack *macroctx, int onelevel, size_t world, int throw_load_error); +static jl_value_t *scm_to_julia(fl_context_t *fl_ctx, value_t e, jl_module_t *mod) JL_CANSAFEPOINT; +static value_t julia_to_scm(fl_context_t *fl_ctx, jl_value_t *v) JL_CANSAFEPOINT; +static jl_value_t *jl_expand_macros(jl_value_t *expr, jl_module_t *inmodule, struct macroctx_stack *macroctx, int onelevel, size_t world, int throw_load_error) JL_CANSAFEPOINT; + +#ifdef __clang_gcanalyzer__ +// this definition causes bugs in the new gc-analyzer (because it tracks e->args instead of e) +#undef jl_exprargset +extern void jl_exprargset(jl_array_t *a, size_t i, jl_value_t *v) JL_NOTSAFEPOINT; +#endif static jl_sym_t *scmsym_to_julia(fl_context_t *fl_ctx, value_t s) { @@ -72,7 +78,7 @@ static jl_sym_t *scmsym_to_julia(fl_context_t *fl_ctx, value_t s) return jl_symbol(symbol_name(fl_ctx, s)); } -static value_t fl_defined_julia_global(fl_context_t *fl_ctx, value_t *args, uint32_t nargs) +static value_t fl_defined_julia_global(fl_context_t *fl_ctx, value_t *args, uint32_t nargs) JL_CANSAFEPOINT { // tells whether a var is defined in and *by* the current module argcount(fl_ctx, "defined-julia-global", nargs, 1); @@ -92,7 +98,7 @@ static value_t fl_defined_julia_global(fl_context_t *fl_ctx, value_t *args, uint // If the top of the stack is NIL, we simply return the current module's counter. // This ensures that precompile statements are a bit more stable across different versions // of a codebase. see #53719 -static value_t fl_module_unique_name(fl_context_t *fl_ctx, value_t *args, uint32_t nargs) +static value_t fl_module_unique_name(fl_context_t *fl_ctx, value_t *args, uint32_t nargs) JL_CANSAFEPOINT { argcount(fl_ctx, "julia-module-unique-name", nargs, 1); jl_ast_context_t *ctx = jl_ast_ctx(fl_ctx); @@ -151,11 +157,11 @@ static value_t fl_julia_scalar(fl_context_t *fl_ctx, value_t *args, uint32_t nar return fl_ctx->F; } -static jl_value_t *scm_to_julia_(fl_context_t *fl_ctx, value_t e, jl_module_t *mod); +static jl_value_t *scm_to_julia_(fl_context_t *fl_ctx, value_t e, jl_module_t *mod) JL_CANSAFEPOINT; -static const builtinspec_t julia_flisp_ast_ext[] = { - { "defined-julia-global", fl_defined_julia_global }, // TODO: can we kill this safepoint - { "current-julia-module-counter", fl_module_unique_name }, +static const builtinspec_t julia_flisp_ast_ext[] = { // TODO: can we kill these safepoint? + { "defined-julia-global", fl_defined_julia_global }, // NOLINT(julia-first-decl-annotations) + { "current-julia-module-counter", fl_module_unique_name }, // NOLINT(julia-first-decl-annotations) { "julia-scalar?", fl_julia_scalar }, { NULL, NULL } }; @@ -207,25 +213,29 @@ static jl_ast_context_t *jl_ast_ctx_enter(jl_module_t *m) JL_GLOBALLY_ROOTED JL_ return ctx; } -static void jl_ast_ctx_leave(jl_ast_context_t *ctx) +static void jl_ast_ctx_leave_(jl_ast_context_t *ctx) JL_NOTSAFEPOINT { uv_mutex_lock(&flisp_lock); ctx->module = NULL; ctx->next = jl_ast_ctx_freed; jl_ast_ctx_freed = ctx; uv_mutex_unlock(&flisp_lock); +} + +static void jl_ast_ctx_leave(jl_ast_context_t *ctx) +{ + jl_ast_ctx_leave_(ctx); JL_SIGATOMIC_END(); } + void jl_init_flisp(void) { if (jl_ast_ctx_freed) return; uv_mutex_init(&flisp_lock); jl_init_ast_ctx(&jl_ast_main_ctx); - // To match the one in jl_ast_ctx_leave - JL_SIGATOMIC_BEGIN(); - jl_ast_ctx_leave(&jl_ast_main_ctx); + jl_ast_ctx_leave_(&jl_ast_main_ctx); } void jl_init_common_symbols(void) @@ -345,7 +355,7 @@ void jl_lisp_prompt(void) jl_ast_ctx_leave(ctx); } -JL_DLLEXPORT void fl_show_profile(void) +JL_DLLEXPORT void fl_show_profile(void) JL_CANSAFEPOINT { jl_ast_context_t *ctx = jl_ast_ctx_enter(NULL); fl_context_t *fl_ctx = &ctx->fl; @@ -353,7 +363,7 @@ JL_DLLEXPORT void fl_show_profile(void) jl_ast_ctx_leave(ctx); } -JL_DLLEXPORT void fl_clear_profile(void) +JL_DLLEXPORT void fl_clear_profile(void) JL_CANSAFEPOINT { jl_ast_context_t *ctx = jl_ast_ctx_enter(NULL); fl_context_t *fl_ctx = &ctx->fl; @@ -361,7 +371,7 @@ JL_DLLEXPORT void fl_clear_profile(void) jl_ast_ctx_leave(ctx); } -JL_DLLEXPORT void fl_profile(const char *fname) +JL_DLLEXPORT void fl_profile(const char *fname) JL_CANSAFEPOINT { jl_ast_context_t *ctx = jl_ast_ctx_enter(NULL); fl_context_t *fl_ctx = &ctx->fl; @@ -369,7 +379,7 @@ JL_DLLEXPORT void fl_profile(const char *fname) jl_ast_ctx_leave(ctx); } -static jl_value_t *scm_to_julia(fl_context_t *fl_ctx, value_t e, jl_module_t *mod) +static jl_value_t *scm_to_julia(fl_context_t *fl_ctx, value_t e, jl_module_t *mod) JL_CANSAFEPOINT { jl_value_t *v = NULL; JL_GC_PUSH1(&v); @@ -382,7 +392,7 @@ static jl_value_t *scm_to_julia(fl_context_t *fl_ctx, value_t e, jl_module_t *mo //jlbacktrace(); jl_expr_t *ex = jl_exprn(jl_error_sym, 1); v = (jl_value_t*)ex; - jl_array_ptr_set(ex->args, 0, jl_cstr_to_string("invalid AST")); + jl_exprargset(ex, 0, jl_cstr_to_string("invalid AST")); } JL_GC_POP(); return v; @@ -390,7 +400,7 @@ static jl_value_t *scm_to_julia(fl_context_t *fl_ctx, value_t e, jl_module_t *mo extern int64_t conv_to_int64(void *data, numerictype_t tag); -static jl_value_t *scm_to_julia_(fl_context_t *fl_ctx, value_t e, jl_module_t *mod) +static jl_value_t *scm_to_julia_(fl_context_t *fl_ctx, value_t e, jl_module_t *mod) JL_CANSAFEPOINT { if (fl_isnumber(fl_ctx, e)) { int64_t i64; @@ -580,7 +590,7 @@ static jl_value_t *scm_to_julia_(fl_context_t *fl_ctx, value_t e, jl_module_t *m jl_error("malformed tree"); } -static value_t julia_to_scm_(fl_context_t *fl_ctx, jl_value_t *v, int check_valid); +static value_t julia_to_scm_(fl_context_t *fl_ctx, jl_value_t *v, int check_valid) JL_CANSAFEPOINT; static value_t julia_to_scm(fl_context_t *fl_ctx, jl_value_t *v) { @@ -595,7 +605,7 @@ static value_t julia_to_scm(fl_context_t *fl_ctx, jl_value_t *v) return temp; } -static void array_to_list(fl_context_t *fl_ctx, jl_array_t *a, value_t *pv, int check_valid) +static void array_to_list(fl_context_t *fl_ctx, jl_array_t *a, value_t *pv, int check_valid) JL_CANSAFEPOINT { value_t temp; for (long i = jl_array_nrows(a) - 1; i >= 0; i--) { @@ -606,7 +616,7 @@ static void array_to_list(fl_context_t *fl_ctx, jl_array_t *a, value_t *pv, int } } -static value_t julia_to_list2(fl_context_t *fl_ctx, jl_value_t *a, jl_value_t *b, int check_valid) +static value_t julia_to_list2(fl_context_t *fl_ctx, jl_value_t *a, jl_value_t *b, int check_valid) JL_CANSAFEPOINT { value_t sa = julia_to_scm_(fl_ctx, a, check_valid); fl_gc_handle(fl_ctx, &sa); @@ -747,7 +757,7 @@ static value_t julia_to_scm_(fl_context_t *fl_ctx, jl_value_t *v, int check_vali // `filename`. Return an svec of (parsed_expr, final_offset) JL_DLLEXPORT jl_value_t *jl_fl_parse(const char *text, size_t text_len, jl_value_t *filename, size_t lineno, - size_t offset, jl_value_t *options) + size_t offset, jl_value_t *options) JL_CANSAFEPOINT { JL_TIMING(PARSING, PARSING); jl_timing_show_filename(jl_string_data(filename), JL_TIMING_DEFAULT_BLOCK); @@ -800,7 +810,7 @@ JL_DLLEXPORT jl_value_t *jl_fl_parse(const char *text, size_t text_len, } // returns either an expression or a thunk -static jl_value_t *jl_call_scm_on_ast(const char *funcname, jl_value_t *expr, jl_module_t *inmodule) +static jl_value_t *jl_call_scm_on_ast(const char *funcname, jl_value_t *expr, jl_module_t *inmodule) JL_CANSAFEPOINT { jl_ast_context_t *ctx = jl_ast_ctx_enter(inmodule); fl_context_t *fl_ctx = &ctx->fl; @@ -1005,7 +1015,7 @@ static int need_esc_node(jl_value_t *e) JL_NOTSAFEPOINT return jl_isa_ast_node(e); } -static jl_value_t *jl_invoke_julia_macro(jl_array_t *args, jl_module_t *inmodule, jl_module_t **ctx, jl_value_t **lineinfo, size_t world, int throw_load_error) +static jl_value_t *jl_invoke_julia_macro(jl_array_t *args, jl_module_t *inmodule, jl_module_t **ctx, jl_value_t **lineinfo, size_t world, int throw_load_error) JL_CANSAFEPOINT { jl_task_t *ct = jl_current_task; JL_TIMING(MACRO_INVOCATION, MACRO_INVOCATION); @@ -1180,7 +1190,7 @@ static jl_value_t *jl_expand_macros(jl_value_t *expr, jl_module_t *inmodule, str return expr; } -JL_DLLEXPORT jl_value_t *jl_macroexpand(jl_value_t *expr, jl_module_t *inmodule, int recursive, int inplace, int expand_scope) +JL_DLLEXPORT jl_value_t *jl_macroexpand(jl_value_t *expr, jl_module_t *inmodule, int recursive, int inplace, int expand_scope) JL_CANSAFEPOINT { JL_TIMING(LOWERING, LOWERING); JL_GC_PUSH1(&expr); @@ -1195,7 +1205,7 @@ JL_DLLEXPORT jl_value_t *jl_macroexpand(jl_value_t *expr, jl_module_t *inmodule, // warn: Print any lowering warnings returned; otherwise ignore JL_DLLEXPORT jl_value_t *jl_fl_lower(jl_value_t *expr, jl_module_t *inmodule, - const char *filename, int line, size_t world, bool_t warn) + const char *filename, int line, size_t world, bool_t warn) JL_CANSAFEPOINT { JL_TIMING(LOWERING, LOWERING); jl_timing_show_location(filename, line, inmodule, JL_TIMING_DEFAULT_BLOCK); diff --git a/src/builtin_proto.h b/src/builtin_proto.h index 6c5dc7c4a9d19..dba229cdfdea5 100644 --- a/src/builtin_proto.h +++ b/src/builtin_proto.h @@ -79,7 +79,7 @@ extern "C" { XX(has_free_typevars,"has_free_typevars") #define DECLARE_BUILTIN(cname,jlname) \ - JL_CALLABLE(jl_f_##cname); + JL_CALLABLE(jl_f_##cname) JL_CANSAFEPOINT; JL_BUILTIN_FUNCTIONS(DECLARE_BUILTIN) #undef DECLARE_BUILTIN diff --git a/src/builtins.c b/src/builtins.c index b9cf4e638d963..6af2dc5ebeae5 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -677,7 +677,7 @@ JL_CALLABLE(jl_f_current_scope) // apply ---------------------------------------------------------------------- -static NOINLINE jl_svec_t *_copy_to(size_t newalloc, jl_value_t **oldargs, size_t oldalloc) +static NOINLINE jl_svec_t *_copy_to(size_t newalloc, jl_value_t **oldargs, size_t oldalloc) JL_CANSAFEPOINT { size_t j; jl_svec_t *newheap = jl_alloc_svec_uninit(newalloc); @@ -689,7 +689,7 @@ static NOINLINE jl_svec_t *_copy_to(size_t newalloc, jl_value_t **oldargs, size_ return newheap; } -STATIC_INLINE void _grow_to(jl_value_t **root, jl_value_t ***oldargs, jl_svec_t **arg_heap, size_t *n_alloc, size_t newalloc, size_t extra) +STATIC_INLINE void _grow_to(jl_value_t **root, jl_value_t ***oldargs, jl_svec_t **arg_heap, size_t *n_alloc, size_t newalloc, size_t extra) JL_CANSAFEPOINT { size_t oldalloc = *n_alloc; if (oldalloc >= newalloc) @@ -706,7 +706,7 @@ STATIC_INLINE void _grow_to(jl_value_t **root, jl_value_t ***oldargs, jl_svec_t } -static jl_value_t *jl_arrayref(jl_array_t *a, size_t i) +static jl_value_t *jl_arrayref(jl_array_t *a, size_t i) JL_CANSAFEPOINT { return jl_memoryrefget(jl_memoryrefindex(a->ref, i), 0); } @@ -995,7 +995,7 @@ JL_CALLABLE(jl_f__call_in_world_total) // tuples --------------------------------------------------------------------- -static jl_value_t *arg_tuple(jl_value_t *a1, jl_value_t **args, size_t nargs) +static jl_value_t *arg_tuple(jl_value_t *a1, jl_value_t **args, size_t nargs) JL_CANSAFEPOINT { size_t i; jl_datatype_t *tt = jl_inst_arg_tuple_type(a1, args, nargs, 0); @@ -1057,7 +1057,7 @@ enum jl_memory_order jl_get_atomic_order_checked(jl_sym_t *order, char loading, return mo; } -static inline size_t get_checked_fieldindex(const char *name, jl_datatype_t *st, jl_value_t *v, jl_value_t *arg, int mutabl) +static inline size_t get_checked_fieldindex(const char *name, jl_datatype_t *st, jl_value_t *v, jl_value_t *arg, int mutabl) JL_CANSAFEPOINT { if (mutabl) { if (st == jl_module_type) @@ -1242,7 +1242,7 @@ JL_CALLABLE(jl_f_setfieldonce) return success ? jl_true : jl_false; } -static jl_value_t *get_fieldtype(jl_value_t *t, jl_value_t *f, int dothrow) +static jl_value_t *get_fieldtype(jl_value_t *t, jl_value_t *f, int dothrow) JL_CANSAFEPOINT { if (jl_is_unionall(t)) { jl_value_t *u = t; @@ -2221,7 +2221,7 @@ JL_CALLABLE(jl_f__primitivetype) return dt->name->wrapper; } -static void jl_set_datatype_super(jl_datatype_t *tt, jl_value_t *super) +static void jl_set_datatype_super(jl_datatype_t *tt, jl_value_t *super) JL_CANSAFEPOINT { // Check context-specific conditions first, before jl_check_valid_supertype // which calls jl_subtype and would crash walking the supertype chain of a @@ -2319,7 +2319,7 @@ JL_CALLABLE(jl_f__svec_ref) return jl_svecref(s, idx-1); } -static int equiv_field_types(jl_value_t *old, jl_value_t *ft) +static int equiv_field_types(jl_value_t *old, jl_value_t *ft) JL_CANSAFEPOINT { size_t nf = jl_svec_len(ft); if (jl_svec_len(old) != nf) @@ -2492,7 +2492,7 @@ JL_CALLABLE(jl_f__typebody) } // this is a heuristic for allowing "redefining" a type to something identical -static int equiv_type(jl_value_t *ta, jl_value_t *tb) +static int equiv_type(jl_value_t *ta, jl_value_t *tb) JL_CANSAFEPOINT { jl_datatype_t *dta = (jl_datatype_t*)jl_unwrap_unionall(ta); if (!jl_is_datatype(dta)) @@ -2631,7 +2631,7 @@ static void add_intrinsic_properties(enum intrinsic f, unsigned nargs, void (*pf runtime_fp[f] = pfunc; } -static void add_intrinsic(jl_module_t *inm, const char *name, enum intrinsic f) JL_GC_DISABLED +static void add_intrinsic(jl_module_t *inm, const char *name, enum intrinsic f) JL_CANSAFEPOINT JL_GC_DISABLED { jl_value_t *i = jl_permbox32(jl_intrinsic_type, jl_intrinsic_tag, (int32_t)f); jl_sym_t *sym = jl_symbol(name); @@ -2669,7 +2669,7 @@ void jl_init_intrinsic_functions(void) #undef ALIAS } -static void add_builtin(const char *name, jl_value_t *v) +static void add_builtin(const char *name, jl_value_t *v) JL_CANSAFEPOINT { jl_set_initial_const(jl_core_module, jl_symbol(name), v, 0); } diff --git a/src/ccall.cpp b/src/ccall.cpp index 4756effaf980c..c271a20482e42 100644 --- a/src/ccall.cpp +++ b/src/ccall.cpp @@ -152,7 +152,7 @@ static Value *runtime_sym_lookup( jl_codectx_t *pctx, const native_sym_arg_t &symarg, Function *f, GlobalVariable *libptrgv, - GlobalVariable *llvmgv, bool runtime_lib) + GlobalVariable *llvmgv, bool runtime_lib) JL_CANSAFEPOINT { ++RuntimeSymLookups; // in pseudo-code, this function emits the following if libptrgv is set: @@ -241,7 +241,7 @@ static Value *runtime_sym_lookup( static Value *runtime_sym_lookup( jl_codectx_t &ctx, - const native_sym_arg_t &symarg, Function *f) + const native_sym_arg_t &symarg, Function *f) JL_CANSAFEPOINT { GlobalVariable *libptrgv; GlobalVariable *llvmgv; @@ -260,7 +260,7 @@ static GlobalVariable *emit_plt_thunk( FunctionType *functype, const AttributeList &attrs, CallingConv::ID cc, const native_sym_arg_t &symarg, GlobalVariable *libptrgv, GlobalVariable *llvmgv, - bool runtime_lib) + bool runtime_lib) JL_CANSAFEPOINT { ++PLTThunks; bool shared = libptrgv != nullptr; @@ -341,7 +341,7 @@ static Value *emit_plt( jl_codectx_t &ctx, FunctionType *functype, const AttributeList &attrs, - CallingConv::ID cc, const native_sym_arg_t &symarg) + CallingConv::ID cc, const native_sym_arg_t &symarg) JL_CANSAFEPOINT { ++PLT; // Don't do this for vararg functions so that the `musttail` is only @@ -377,13 +377,13 @@ static Value *emit_plt( class AbiLayout { public: virtual ~AbiLayout() {} - virtual bool use_sret(jl_datatype_t *ty, LLVMContext &ctx) = 0; - virtual bool needPassByRef(jl_datatype_t *ty, AttrBuilder&, LLVMContext &ctx, Type* llvm_t) = 0; - virtual Type *preferred_llvm_type(jl_datatype_t *ty, bool isret, LLVMContext &ctx) const = 0; + virtual bool use_sret(jl_datatype_t *ty, LLVMContext &ctx) JL_CANSAFEPOINT = 0; + virtual bool needPassByRef(jl_datatype_t *ty, AttrBuilder&, LLVMContext &ctx, Type* llvm_t) JL_CANSAFEPOINT = 0; + virtual Type *preferred_llvm_type(jl_datatype_t *ty, bool isret, LLVMContext &ctx) const JL_CANSAFEPOINT = 0; }; // Determine if object of bitstype ty maps to a native x86 SIMD type (__m128, __m256, or __m512) in C -static bool is_native_simd_type(jl_datatype_t *dt) { +static bool is_native_simd_type(jl_datatype_t *dt) JL_CANSAFEPOINT { size_t size = jl_datatype_size(dt); if (size != 16 && size != 32 && size != 64) // Wrong size for xmm, ymm, or zmm register. @@ -496,7 +496,7 @@ static Value *llvm_type_rewrite( // --- argument passing and scratch space utilities --- // Returns ctx.types().T_prjlvalue -static Value *runtime_apply_type_env(jl_codectx_t &ctx, jl_value_t *ty) +static Value *runtime_apply_type_env(jl_codectx_t &ctx, jl_value_t *ty) JL_CANSAFEPOINT { // box if concrete type was not statically known Value *args[] = { @@ -545,7 +545,7 @@ static jl_cgval_t drop_inline_roots(const jl_cgval_t &x) // bitcast whatever Ptr kind x might be (even if it is part of a union) into Ptr{Cvoid}, // emitting a cpointercheck (reporting msg) first if x is not statically known to be a // pointer, so that the conversion is guaranteed to be valid on this runtime branch -static jl_cgval_t voidpointer_update(jl_codectx_t &ctx, const jl_cgval_t &x, const Twine &msg) +static jl_cgval_t voidpointer_update(jl_codectx_t &ctx, const jl_cgval_t &x, const Twine &msg) JL_CANSAFEPOINT { if (x.typ == (jl_value_t*)jl_voidpointer_type) return x; @@ -561,7 +561,7 @@ static jl_cgval_t voidpointer_update(jl_codectx_t &ctx, const jl_cgval_t &x, con return mark_julia_type(ctx, emit_unbox(ctx, ctx.types().T_ptr, drop_inline_roots(x)), false, jl_voidpointer_type); } -static jl_cgval_t typeassert_input(jl_codectx_t &ctx, const jl_cgval_t &jvinfo, jl_value_t *jlto, jl_unionall_t *jlto_env, int argn) +static jl_cgval_t typeassert_input(jl_codectx_t &ctx, const jl_cgval_t &jvinfo, jl_value_t *jlto, jl_unionall_t *jlto_env, int argn) JL_CANSAFEPOINT { if (jlto != (jl_value_t*)jl_any_type && !jl_subtype(jvinfo.typ, jlto)) { if (jlto == (jl_value_t*)jl_voidpointer_type) { @@ -604,7 +604,7 @@ static Value *julia_to_native( jl_codectx_t &ctx, Type *to, bool toboxed, jl_value_t *jlto, jl_unionall_t *jlto_env, jl_cgval_t jvinfo, - bool byRef, int argn) + bool byRef, int argn) JL_CANSAFEPOINT { // We're passing Any if (toboxed) { @@ -626,7 +626,7 @@ static Value *julia_to_native( return slot; } -static void interpret_foreignsymbol(jl_codectx_t &ctx, native_sym_arg_t &out, jl_value_t *arg) +static void interpret_foreignsymbol(jl_codectx_t &ctx, native_sym_arg_t &out, jl_value_t *arg) JL_CANSAFEPOINT { // Initialize all fields to safe defaults out.f_name = nullptr; @@ -715,9 +715,9 @@ static void interpret_foreignsymbol(jl_codectx_t &ctx, native_sym_arg_t &out, jl // --- code generator for cglobal --- -static jl_cgval_t emit_runtime_call(jl_codectx_t &ctx, JL_I::intrinsic f, ArrayRef argv, size_t nargs); +static jl_cgval_t emit_runtime_call(jl_codectx_t &ctx, JL_I::intrinsic f, ArrayRef argv, size_t nargs) JL_CANSAFEPOINT; -static jl_cgval_t emit_cglobal(jl_codectx_t &ctx, jl_value_t **args, size_t nargs) +static jl_cgval_t emit_cglobal(jl_codectx_t &ctx, jl_value_t **args, size_t nargs) JL_CANSAFEPOINT { ++EmittedCGlobals; assert(nargs == 1); @@ -740,7 +740,7 @@ static jl_cgval_t emit_cglobal(jl_codectx_t &ctx, jl_value_t **args, size_t narg // --- code generator for llvmcall --- -static jl_cgval_t emit_llvmcall(jl_codectx_t &ctx, jl_value_t **args, size_t nargs) +static jl_cgval_t emit_llvmcall(jl_codectx_t &ctx, jl_value_t **args, size_t nargs) JL_CANSAFEPOINT { ++EmittedLLVMCalls; // parse and validate arguments @@ -1141,7 +1141,7 @@ static Value *box_ccall_result(jl_codectx_t &ctx, Value *result, Value *runtime_ return strct; } -static jl_cgval_t mark_or_box_ccall_result(jl_codectx_t &ctx, Value *result, bool isboxed, jl_value_t *rt, jl_unionall_t *unionall, bool static_rt) +static jl_cgval_t mark_or_box_ccall_result(jl_codectx_t &ctx, Value *result, bool isboxed, jl_value_t *rt, jl_unionall_t *unionall, bool static_rt) JL_CANSAFEPOINT { if (!static_rt) { assert(!isboxed && jl_is_datatype(rt) && ctx.spvals_ptr && unionall); @@ -1176,7 +1176,7 @@ class function_sig_t { size_t nreqargs; // number of required arguments in ccall function definition jl_codegen_output_t *ctx; - function_sig_t(const char *fname, Type *lrt, jl_value_t *rt, bool retboxed, bool gc_safe, jl_svec_t *at, jl_unionall_t *unionall_env, size_t nreqargs, CallingConv::ID cc, bool llvmcall, jl_codegen_output_t *ctx) + function_sig_t(const char *fname, Type *lrt, jl_value_t *rt, bool retboxed, bool gc_safe, jl_svec_t *at, jl_unionall_t *unionall_env, size_t nreqargs, CallingConv::ID cc, bool llvmcall, jl_codegen_output_t *ctx) JL_CANSAFEPOINT : lrt(lrt), retboxed(retboxed), gc_safe(gc_safe), prt(NULL), sret(0), cc(cc), llvmcall(llvmcall), at(at), rt(rt), unionall_env(unionall_env), @@ -1199,10 +1199,10 @@ class function_sig_t { const native_sym_arg_t &symarg, jl_cgval_t *argv, SmallVectorImpl &gc_uses, - bool static_rt) const; + bool static_rt) const JL_CANSAFEPOINT; private: -std::string generate_func_sig(const char *fname) +std::string generate_func_sig(const char *fname) JL_CANSAFEPOINT { assert(rt && !jl_is_abstract_ref_type(rt)); @@ -1357,7 +1357,7 @@ static std::pair convert_cconv(jl_sym_t *lhd) jl_errorf("ccall: invalid calling convention %s", jl_symbol_name(lhd)); } -static bool verify_ref_type(jl_codectx_t &ctx, jl_value_t* ref, jl_unionall_t *unionall_env, int n, const char *fname) +static bool verify_ref_type(jl_codectx_t &ctx, jl_value_t* ref, jl_unionall_t *unionall_env, int n, const char *fname) JL_CANSAFEPOINT { // emit verification that the tparam for Ref isn't Any or a TypeVar const char rt_err_msg_notany[] = " type Ref{Any} is invalid. Use Any or Ptr{Any} instead."; @@ -1405,7 +1405,7 @@ static const std::string verify_ccall_sig(jl_value_t *&rt, jl_value_t *at, jl_unionall_t *unionall_env, jl_svec_t *sparam_vals, jl_codegen_output_t *ctx, Type *&lrt, LLVMContext &ctxt, - bool &retboxed, bool &static_rt, bool llvmcall=false) + bool &retboxed, bool &static_rt, bool llvmcall=false) JL_CANSAFEPOINT { JL_TYPECHK(ccall, type, rt); JL_TYPECHK(ccall, simplevector, at); @@ -1445,7 +1445,7 @@ static const std::string verify_ccall_sig(jl_value_t *&rt, jl_value_t *at, const int fc_args_start = 6; // Expr(:foreigncall, pointer, rettype, (argtypes...), nreq, gc_safe, [cconv | (cconv, effects)], args..., roots...) -static jl_cgval_t emit_ccall(jl_codectx_t &ctx, jl_value_t **args, size_t nargs) +static jl_cgval_t emit_ccall(jl_codectx_t &ctx, jl_value_t **args, size_t nargs) JL_CANSAFEPOINT { JL_NARGSV(ccall, 5); args -= 1; diff --git a/src/cgutils.cpp b/src/cgutils.cpp index 0d2c6a2b07d4f..5c414ac60f559 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -101,9 +101,9 @@ static Value *mark_callee_rooted(jl_codectx_t &ctx, Value *V) PointerType::get(V->getContext(), AddressSpace::CalleeRooted)); } -static Constant *julia_const_to_llvm(jl_codectx_t &ctx, jl_value_t *e); +static Constant *julia_const_to_llvm(jl_codectx_t &ctx, jl_value_t *e) JL_CANSAFEPOINT; -static Value *data_pointer(jl_codectx_t &ctx, const jl_cgval_t &x) +static Value *data_pointer(jl_codectx_t &ctx, const jl_cgval_t &x) JL_CANSAFEPOINT { assert(x.ispointer()); Value *data; @@ -172,7 +172,7 @@ static Value *stringConstPtr( // --- MDNode --- -Metadata *to_md_tree(jl_value_t *val, LLVMContext &ctxt) { +Metadata *to_md_tree(jl_value_t *val, LLVMContext &ctxt) JL_CANSAFEPOINT { if (val == jl_nothing) return nullptr; Metadata *MD = nullptr; @@ -344,8 +344,8 @@ static Value *emit_pointer_from_objref(jl_codectx_t &ctx, Value *V) return Call; } -static Value *emit_unbox(jl_codectx_t &ctx, Type *to, const jl_cgval_t &x, MaybeAlign align = MaybeAlign()); -static void emit_unbox_store(jl_codectx_t &ctx, const jl_cgval_t &x, Value* dest, MDNode *tbaa_dest, MaybeAlign align_src, Align align_dst, bool isVolatile=false); +static Value *emit_unbox(jl_codectx_t &ctx, Type *to, const jl_cgval_t &x, MaybeAlign align = MaybeAlign()) JL_CANSAFEPOINT; +static void emit_unbox_store(jl_codectx_t &ctx, const jl_cgval_t &x, Value* dest, MDNode *tbaa_dest, MaybeAlign align_src, Align align_dst, bool isVolatile=false) JL_CANSAFEPOINT; static bool type_is_permalloc(jl_value_t *typ) { @@ -361,7 +361,7 @@ static bool type_is_permalloc(jl_value_t *typ) // find the offset of pointer fields which never need a write barrier since their type-analysis // shows they are permanently rooted -static void find_perm_offsets(jl_datatype_t *typ, SmallVectorImpl &res, unsigned offset) +static void find_perm_offsets(jl_datatype_t *typ, SmallVectorImpl &res, unsigned offset) JL_CANSAFEPOINT { // This is a inlined field at `offset`. if (!typ->layout || typ->layout->npointers == 0) @@ -489,7 +489,7 @@ static llvm::SmallVector extract_gc_roots(jl_codectx_t &ctx, Value *da return gcroots; } -static llvm::SmallVector extract_gc_roots(jl_codectx_t &ctx, const jl_cgval_t &val, size_t npointers) +static llvm::SmallVector extract_gc_roots(jl_codectx_t &ctx, const jl_cgval_t &val, size_t npointers) JL_CANSAFEPOINT { SmallVector gcroots; if (npointers) { @@ -531,7 +531,7 @@ static jl_gc_roots_t make_lazy_gc_roots(Value *inline_roots_ptr, size_t npointer } // inlined bool indicates whether this must return the inlined roots inside x separately, or whether x itself may be used as the root (if x is already isboxed) -static llvm::SmallVector get_gc_roots_for(jl_codectx_t &ctx, const jl_cgval_t &x, bool inlined=false) +static llvm::SmallVector get_gc_roots_for(jl_codectx_t &ctx, const jl_cgval_t &x, bool inlined=false) JL_CANSAFEPOINT { if (x.constant || x.typ == jl_bottom_type) return {}; @@ -570,9 +570,6 @@ static llvm::SmallVector get_gc_roots_for(jl_codectx_t &ctx, const jl_ // --- emitting pointers directly into code --- -static void jl_temporary_root(jl_codegen_output_t &ctx, jl_value_t *val); -static void jl_temporary_root(jl_codectx_t &ctx, jl_value_t *val); - static Constant *julia_pgv(jl_codegen_output_t ¶ms, Module *M, const char *cname, void *addr) { // emit a GlobalVariable for a jl_value_t named "cname" @@ -677,7 +674,7 @@ Constant *literal_pointer_val_slot(jl_codegen_output_t ¶ms, jl_value_t *p) return julia_pgv(params, M, "jl_global#", p); } -static size_t dereferenceable_size(jl_value_t *jt) +static size_t dereferenceable_size(jl_value_t *jt) JL_CANSAFEPOINT { if (jl_is_datatype(jt) && jl_struct_try_layout((jl_datatype_t*)jt)) { return jl_datatype_size(jt); @@ -701,7 +698,7 @@ static unsigned julia_alignment(jl_value_t *jt) return alignment; } -static inline void maybe_mark_argument_dereferenceable(AttrBuilder &B, jl_value_t *jt) +static inline void maybe_mark_argument_dereferenceable(AttrBuilder &B, jl_value_t *jt) JL_CANSAFEPOINT { B.addAttribute(Attribute::NonNull); B.addAttribute(Attribute::NoUndef); @@ -733,7 +730,7 @@ static inline Instruction *maybe_mark_load_dereferenceable(Instruction *LI, bool return LI; } -static inline Instruction *maybe_mark_load_dereferenceable(Instruction *LI, bool can_be_null, jl_value_t *jt) +static inline Instruction *maybe_mark_load_dereferenceable(Instruction *LI, bool can_be_null, jl_value_t *jt) JL_CANSAFEPOINT { size_t size = dereferenceable_size(jt); unsigned alignment = 1; @@ -809,7 +806,7 @@ static unsigned convert_struct_offset(jl_codectx_t &ctx, Type *lty, unsigned byt return convert_struct_offset(ctx.builder.GetInsertBlock()->getModule()->getDataLayout(), lty, byte_offset); } -static Type *_julia_struct_to_llvm(jl_codegen_output_t *ctx, LLVMContext &ctxt, jl_value_t *jt, bool *isboxed, bool llvmcall=false); +static Type *_julia_struct_to_llvm(jl_codegen_output_t *ctx, LLVMContext &ctxt, jl_value_t *jt, bool *isboxed, bool llvmcall=false) JL_CANSAFEPOINT; static bool is_typeofbottom_typealias(jl_value_t *jt) { @@ -820,7 +817,7 @@ static bool is_typeofbottom_typealias(jl_value_t *jt) (jl_is_some_Type(jt) && jl_some_Type_T(jt) == jl_bottom_type); } -static Type *_julia_type_to_llvm(jl_codegen_output_t *ctx, LLVMContext &ctxt, jl_value_t *jt, bool *isboxed, bool no_boxing) +static Type *_julia_type_to_llvm(jl_codegen_output_t *ctx, LLVMContext &ctxt, jl_value_t *jt, bool *isboxed, bool no_boxing) JL_CANSAFEPOINT { // this function converts a Julia Type into the equivalent LLVM type if (isboxed) *isboxed = false; @@ -843,14 +840,14 @@ static Type *julia_type_to_llvm(jl_codectx_t &ctx, jl_value_t *jt, bool *isboxed } extern "C" JL_DLLEXPORT_CODEGEN -Type *jl_type_to_llvm_impl(jl_value_t *jt, LLVMContextRef ctxt, bool *isboxed) +Type *jl_type_to_llvm_impl(jl_value_t *jt, LLVMContextRef ctxt, bool *isboxed) JL_CANSAFEPOINT { return _julia_type_to_llvm(NULL, *unwrap(ctxt), jt, isboxed, false); } extern "C" JL_DLLEXPORT_CODEGEN -Type *jl_struct_to_llvm_impl(jl_value_t *jt, LLVMContextRef ctxt, bool *isboxed) +Type *jl_struct_to_llvm_impl(jl_value_t *jt, LLVMContextRef ctxt, bool *isboxed) JL_CANSAFEPOINT { return _julia_type_to_llvm(NULL, *unwrap(ctxt), jt, isboxed, true); } @@ -1082,7 +1079,7 @@ static Type *_julia_struct_to_llvm(jl_codegen_output_t *ctx, LLVMContext &ctxt, return JuliaType::get_prjlvalue_ty(ctxt); } -static Type *julia_struct_to_llvm(jl_codectx_t &ctx, jl_value_t *jt, bool *isboxed) +static Type *julia_struct_to_llvm(jl_codectx_t &ctx, jl_value_t *jt, bool *isboxed) JL_CANSAFEPOINT { return _julia_struct_to_llvm(&ctx.emission_context, ctx.builder.getContext(), jt, isboxed); } @@ -1125,7 +1122,7 @@ static bool is_tupletype_homogeneous(jl_svec_t *t, bool allow_va = false) static bool for_each_uniontype_small( llvm::function_ref f, jl_value_t *ty, - unsigned &counter) + unsigned &counter) JL_CANSAFEPOINT { if (counter > 127) return false; @@ -1144,13 +1141,13 @@ static bool for_each_uniontype_small( return false; } -static bool is_uniontype_allunboxed(jl_value_t *typ) +static bool is_uniontype_allunboxed(jl_value_t *typ) JL_CANSAFEPOINT { unsigned counter = 0; return for_each_uniontype_small([&](unsigned, jl_datatype_t*) {}, typ, counter); } -static bool is_uniontype_anyunboxed(jl_value_t *typ) +static bool is_uniontype_anyunboxed(jl_value_t *typ) JL_CANSAFEPOINT { unsigned counter = 0; for_each_uniontype_small([&](unsigned, jl_datatype_t*) {}, typ, counter); @@ -1158,8 +1155,8 @@ static bool is_uniontype_anyunboxed(jl_value_t *typ) } -static Value *emit_typeof(jl_codectx_t &ctx, Value *v, bool maybenull, bool justtag, bool notag=false); -static Value *emit_typeof(jl_codectx_t &ctx, const jl_cgval_t &p, bool maybenull=false, bool justtag=false); +static Value *emit_typeof(jl_codectx_t &ctx, Value *v, bool maybenull, bool justtag, bool notag=false) JL_CANSAFEPOINT; +static Value *emit_typeof(jl_codectx_t &ctx, const jl_cgval_t &p, bool maybenull=false, bool justtag=false) JL_CANSAFEPOINT; static unsigned get_box_tindex(jl_datatype_t *jt, jl_value_t *ut) { @@ -1215,7 +1212,7 @@ static void emit_memcpy(jl_codectx_t &ctx, Value *dst, jl_aliasinfo_t const &dst template static void emit_memcpy(jl_codectx_t &ctx, Value *dst, jl_aliasinfo_t const &dst_ai, const jl_cgval_t &src, - T1 &&sz, Align align_dst, Align align_src, bool is_volatile=false) + T1 &&sz, Align align_dst, Align align_src, bool is_volatile=false) JL_CANSAFEPOINT { auto src_ai = jl_aliasinfo_t::fromTBAA(ctx, src.tbaa); emit_memcpy_llvm(ctx, dst, dst_ai, data_pointer(ctx, src), src_ai, sz, align_dst, align_src, is_volatile); @@ -1252,7 +1249,7 @@ static void store_all_roots(jl_codectx_t &ctx, const jl_gc_roots_t &inline_roots } // take a value `x` and split its bits into dst and the roots into inline_roots -static void split_value_into(jl_codectx_t &ctx, const jl_cgval_t &x, Align align_src, Value *dst, Align align_dst, jl_aliasinfo_t const &dst_ai, Value *inline_roots_ptr, jl_aliasinfo_t const &roots_ai, bool isVolatileStore=false) +static void split_value_into(jl_codectx_t &ctx, const jl_cgval_t &x, Align align_src, Value *dst, Align align_dst, jl_aliasinfo_t const &dst_ai, Value *inline_roots_ptr, jl_aliasinfo_t const &roots_ai, bool isVolatileStore=false) JL_CANSAFEPOINT { if (x.isghost) return; @@ -1315,7 +1312,7 @@ static void split_value_into(jl_codectx_t &ctx, const jl_cgval_t &x, Align align } } -static void split_value_into(jl_codectx_t &ctx, const jl_cgval_t &x, Align align_src, Value *dst, Align align_dst, jl_aliasinfo_t const &dst_ai, bool isVolatileStore) +static void split_value_into(jl_codectx_t &ctx, const jl_cgval_t &x, Align align_src, Value *dst, Align align_dst, jl_aliasinfo_t const &dst_ai, bool isVolatileStore) JL_CANSAFEPOINT { if (x.isghost) return; @@ -1365,7 +1362,7 @@ static void split_value_into(jl_codectx_t &ctx, const jl_cgval_t &x, Align align } } -static std::tuple split_value(jl_codectx_t &ctx, const jl_cgval_t &x, Align x_alignment, bool copy_required) +static std::tuple split_value(jl_codectx_t &ctx, const jl_cgval_t &x, Align x_alignment, bool copy_required) JL_CANSAFEPOINT { jl_datatype_t *typ = (jl_datatype_t*)x.typ; auto sizes = split_value_size(typ); @@ -1395,7 +1392,7 @@ static std::tuple split_value(jl_codectx_t &ctx, } // Return the offset values corresponding to jl_field_offset, but into the two buffers for a split value (or -1) -static std::pair split_value_field(jl_datatype_t *typ, unsigned idx) +static std::pair split_value_field(jl_datatype_t *typ, unsigned idx) JL_CANSAFEPOINT { size_t fldoff = jl_field_offset(typ, idx); assert(typ->layout->first_ptr >= 0); @@ -1456,7 +1453,7 @@ static void recombine_value(jl_codectx_t &ctx, const jl_cgval_t &x, Value *dst, } } -static Value *emit_tagfrom(jl_codectx_t &ctx, jl_datatype_t *dt) +static Value *emit_tagfrom(jl_codectx_t &ctx, jl_datatype_t *dt) JL_CANSAFEPOINT { if (dt->smalltag) return ConstantInt::get(ctx.types().T_size, dt->smalltag << 4); @@ -1479,7 +1476,7 @@ static Value *emit_typeof(jl_codectx_t &ctx, const jl_cgval_t &p, bool maybenull return emit_tagfrom(ctx, dt); return track_pjlvalue(ctx, literal_pointer_val(ctx, (jl_value_t*)dt)); } - auto notag = [justtag] (jl_value_t *typ) { + auto notag = [justtag] (jl_value_t *typ) JL_CANSAFEPOINT { // compute if the tag is always a type (not a builtin tag) // based on having no intersection with one of the special types // this doesn't matter if the user just wants the tag value @@ -1513,7 +1510,7 @@ static Value *emit_typeof(jl_codectx_t &ctx, const jl_cgval_t &p, bool maybenull Value *datatype_or_p = Constant::getNullValue(PointerType::getUnqual(expr_type->getContext())); unsigned counter = 0; for_each_uniontype_small( - [&](unsigned idx, jl_datatype_t *jt) { + [&](unsigned idx, jl_datatype_t *jt) JL_CANSAFEPOINT { Value *cmp = ctx.builder.CreateICmpEQ(tindex, ConstantInt::get(getInt8Ty(ctx.builder.getContext()), idx)); Constant *ptr; if (justtag && jt->smalltag) { @@ -1760,7 +1757,7 @@ static void raise_exception_unless(jl_codectx_t &ctx, Value *cond, Value *exc) raise_exception(ctx, exc, passBB); } -static void undef_var_error_ifnot(jl_codectx_t &ctx, Value *ok, jl_sym_t *name, jl_value_t *scope) +static void undef_var_error_ifnot(jl_codectx_t &ctx, Value *ok, jl_sym_t *name, jl_value_t *scope) JL_CANSAFEPOINT { ++EmittedUndefVarErrors; BasicBlock *err = BasicBlock::Create(ctx.builder.getContext(), "err", ctx.f); @@ -1804,7 +1801,7 @@ static Value *null_pointer_cmp(jl_codectx_t &ctx, Value *v) // If `nullcheck` is not NULL and a pointer NULL check is necessary // store the pointer to be checked in `*nullcheck` instead of checking it -static void null_pointer_check(jl_codectx_t &ctx, Value *v, Value **nullcheck) +static void null_pointer_check(jl_codectx_t &ctx, Value *v, Value **nullcheck) JL_CANSAFEPOINT { if (nullcheck) { *nullcheck = v; @@ -1815,7 +1812,7 @@ static void null_pointer_check(jl_codectx_t &ctx, Value *v, Value **nullcheck) } -static void null_load_check(jl_codectx_t &ctx, Value *v, jl_module_t *scope, jl_sym_t *name) +static void null_load_check(jl_codectx_t &ctx, Value *v, jl_module_t *scope, jl_sym_t *name) JL_CANSAFEPOINT { Value *notnull = null_pointer_cmp(ctx, v); if (name && scope) @@ -1827,7 +1824,7 @@ static void null_load_check(jl_codectx_t &ctx, Value *v, jl_module_t *scope, jl_ // ifnot == nullptr && return func() // return (ifnot ? func() : defval) template -static void emit_guarded_test(jl_codectx_t &ctx, Value *ifnot, MutableArrayRef defval, Func &&func) +static void emit_guarded_test(jl_codectx_t &ctx, Value *ifnot, MutableArrayRef defval, Func &&func) JL_CANSAFEPOINT { if (ifnot == nullptr) { auto res = func(); @@ -1866,10 +1863,10 @@ static void emit_guarded_test(jl_codectx_t &ctx, Value *ifnot, MutableArrayRef -static Value *emit_guarded_test(jl_codectx_t &ctx, Value *ifnot, Value *defval, Func &&func) +static Value *emit_guarded_test(jl_codectx_t &ctx, Value *ifnot, Value *defval, Func &&func) JL_CANSAFEPOINT { MutableArrayRef res(&defval, defval == nullptr ? 0 : 1); - auto funcwrap = [&func] () -> SmallVector { + auto funcwrap = [&func] () JL_CANSAFEPOINT -> SmallVector { auto res = func(); if (res == nullptr) return {}; @@ -1882,13 +1879,13 @@ static Value *emit_guarded_test(jl_codectx_t &ctx, Value *ifnot, Value *defval, } template -static Value *emit_guarded_test(jl_codectx_t &ctx, Value *ifnot, bool defval, Func &&func) +static Value *emit_guarded_test(jl_codectx_t &ctx, Value *ifnot, bool defval, Func &&func) JL_CANSAFEPOINT { return emit_guarded_test(ctx, ifnot, ConstantInt::get(getInt1Ty(ctx.builder.getContext()), defval), func); } template -static Value *emit_nullcheck_guard(jl_codectx_t &ctx, Value *nullcheck, Func &&func) +static Value *emit_nullcheck_guard(jl_codectx_t &ctx, Value *nullcheck, Func &&func) JL_CANSAFEPOINT { if (!nullcheck) return func(); @@ -1897,7 +1894,7 @@ static Value *emit_nullcheck_guard(jl_codectx_t &ctx, Value *nullcheck, Func &&f template static Value *emit_nullcheck_guard2(jl_codectx_t &ctx, Value *nullcheck1, - Value *nullcheck2, Func &&func) + Value *nullcheck2, Func &&func) JL_CANSAFEPOINT { if (!nullcheck1) return emit_nullcheck_guard(ctx, nullcheck2, func); @@ -1906,7 +1903,7 @@ static Value *emit_nullcheck_guard2(jl_codectx_t &ctx, Value *nullcheck1, nullcheck1 = null_pointer_cmp(ctx, nullcheck1); nullcheck2 = null_pointer_cmp(ctx, nullcheck2); // If both are NULL, return true. - return emit_guarded_test(ctx, ctx.builder.CreateOr(nullcheck1, nullcheck2), true, [&] { + return emit_guarded_test(ctx, ctx.builder.CreateOr(nullcheck1, nullcheck2), true, [&] () JL_CANSAFEPOINT { return emit_guarded_test(ctx, ctx.builder.CreateAnd(nullcheck1, nullcheck2), false, func); }); @@ -1922,7 +1919,7 @@ static Value *emit_typeof(jl_codectx_t &ctx, Value *v, bool maybenull, bool just assert(v != NULL && !isa(v) && "expected a conditionally boxed value"); Value *nonnull = maybenull ? null_pointer_cmp(ctx, v) : ConstantInt::get(getInt1Ty(ctx.builder.getContext()), 1); Function *typeof = prepare_call(jl_typeof_func); - auto val = emit_guarded_test(ctx, nonnull, Constant::getNullValue(justtag ? ctx.types().T_size : typeof->getReturnType()), [&] { + auto val = emit_guarded_test(ctx, nonnull, Constant::getNullValue(justtag ? ctx.types().T_size : typeof->getReturnType()), [&] () JL_CANSAFEPOINT { // e.g. emit_typeof(ctx, v) Value *typetag = ctx.builder.CreateCall(typeof, {v}); if (notag) @@ -1931,7 +1928,7 @@ static Value *emit_typeof(jl_codectx_t &ctx, Value *v, bool maybenull, bool just if (justtag) return tag; auto issmall = ctx.builder.CreateICmpULT(tag, ConstantInt::get(tag->getType(), (uintptr_t)jl_max_tags << 4)); - return emit_guarded_test(ctx, issmall, typetag, [&] { + return emit_guarded_test(ctx, issmall, typetag, [&] () JL_CANSAFEPOINT { // we lied a bit: this wasn't really an object (though it was valid for GC rooting) // and we need to use it as an index to get the real object now Module *M = jl_Module; @@ -1946,16 +1943,16 @@ static Value *emit_typeof(jl_codectx_t &ctx, Value *v, bool maybenull, bool just return val; } -static Value *boxed(jl_codectx_t &ctx, const jl_cgval_t &v, bool is_promotable=false); +static Value *boxed(jl_codectx_t &ctx, const jl_cgval_t &v, bool is_promotable=false) JL_CANSAFEPOINT; -static void just_emit_type_error(jl_codectx_t &ctx, const jl_cgval_t &x, Value *type, const Twine &msg) +static void just_emit_type_error(jl_codectx_t &ctx, const jl_cgval_t &x, Value *type, const Twine &msg) JL_CANSAFEPOINT { Value *msg_val = stringConstPtr(ctx.emission_context, ctx.builder, msg); ctx.builder.CreateCall(prepare_call(jltypeerror_func), { msg_val, maybe_decay_untracked(ctx, type), mark_callee_rooted(ctx, boxed(ctx, x))}); } -static void emit_type_error(jl_codectx_t &ctx, const jl_cgval_t &x, Value *type, const Twine &msg) +static void emit_type_error(jl_codectx_t &ctx, const jl_cgval_t &x, Value *type, const Twine &msg) JL_CANSAFEPOINT { just_emit_type_error(ctx, x, type, msg); ctx.builder.CreateUnreachable(); @@ -1964,7 +1961,7 @@ static void emit_type_error(jl_codectx_t &ctx, const jl_cgval_t &x, Value *type, } // Should agree with `emit_isa` below -static bool _can_optimize_isa(jl_value_t *type, int &counter) +static bool _can_optimize_isa(jl_value_t *type, int &counter) JL_CANSAFEPOINT { if (counter > 127) return false; @@ -1988,7 +1985,7 @@ static bool _can_optimize_isa(jl_value_t *type, int &counter) return false; } -static bool can_optimize_isa_union(jl_uniontype_t *type) +static bool can_optimize_isa_union(jl_uniontype_t *type) JL_CANSAFEPOINT { int counter = 1; return (_can_optimize_isa(type->a, counter) && _can_optimize_isa(type->b, counter)); @@ -2051,7 +2048,7 @@ static Value *emit_exactly_isa(jl_codectx_t &ctx, const jl_cgval_t &arg, jl_data // its sole instance is the pinned type object, which is always boxed if (!arg.isboxed) return Vfalse; - return emit_guarded_test(ctx, isnull, Vfalse, [&]{ + return emit_guarded_test(ctx, isnull, Vfalse, [&] () JL_CANSAFEPOINT { auto isa = ctx.builder.CreateICmpEQ( decay_derived(ctx, arg.Vboxed), decay_derived(ctx, literal_pointer_val(ctx, jl_some_Type_T((jl_value_t*)dt)))); @@ -2059,7 +2056,7 @@ static Value *emit_exactly_isa(jl_codectx_t &ctx, const jl_cgval_t &arg, jl_data return isa; }); } - return emit_guarded_test(ctx, isnull, Vfalse, [&]{ + return emit_guarded_test(ctx, isnull, Vfalse, [&] () JL_CANSAFEPOINT{ auto isa = ctx.builder.CreateICmpEQ(emit_typeof(ctx, arg, false, true), emit_tagfrom(ctx, dt)); setName(ctx.emission_context, isa, "exactly_isa"); return isa; @@ -2067,10 +2064,10 @@ static Value *emit_exactly_isa(jl_codectx_t &ctx, const jl_cgval_t &arg, jl_data } static std::pair emit_isa(jl_codectx_t &ctx, const jl_cgval_t &x, - jl_value_t *type, const Twine &msg); + jl_value_t *type, const Twine &msg) JL_CANSAFEPOINT; static void emit_isa_union(jl_codectx_t &ctx, const jl_cgval_t &x, jl_value_t *type, - SmallVectorImpl,Value*>> &bbs) + SmallVectorImpl,Value*>> &bbs) JL_CANSAFEPOINT { ++EmittedIsaUnions; if (jl_is_uniontype(type)) { @@ -2212,15 +2209,15 @@ static std::pair emit_isa(jl_codectx_t &ctx, const jl_cgval_t &x, // // n.b. It is also possible the value is a ghost of some sort, and we will // declare that the pointer is legal (for zero bytes) even though it might be undef. -static Value *emit_isa_and_defined(jl_codectx_t &ctx, const jl_cgval_t &val, jl_value_t *typ) +static Value *emit_isa_and_defined(jl_codectx_t &ctx, const jl_cgval_t &val, jl_value_t *typ) JL_CANSAFEPOINT { - return emit_nullcheck_guard(ctx, val.inline_roots.empty() && val.ispointer() ? val.V : nullptr, [&] { + return emit_nullcheck_guard(ctx, val.inline_roots.empty() && val.ispointer() ? val.V : nullptr, [&] () JL_CANSAFEPOINT { return emit_isa(ctx, val, typ, Twine()).first; }); } -static void emit_typecheck(jl_codectx_t &ctx, const jl_cgval_t &x, jl_value_t *type, const Twine &msg) +static void emit_typecheck(jl_codectx_t &ctx, const jl_cgval_t &x, jl_value_t *type, const Twine &msg) JL_CANSAFEPOINT { Value *istype; bool handled_msg; @@ -2252,7 +2249,7 @@ static Value *emit_isconcrete(jl_codectx_t &ctx, Value *typ) return isconcrete; } -static void emit_concretecheck(jl_codectx_t &ctx, Value *typ, const Twine &msg) +static void emit_concretecheck(jl_codectx_t &ctx, Value *typ, const Twine &msg) JL_CANSAFEPOINT { ++EmittedConcretechecks; assert(typ->getType() == ctx.types().T_prjlvalue); @@ -2275,7 +2272,7 @@ static bool bounds_check_enabled(jl_codectx_t &ctx, jl_value_t *inbounds) { #endif } -static Value *emit_bounds_check(jl_codectx_t &ctx, const jl_cgval_t &ainfo, jl_value_t *ty, Value *i, Value *len, jl_value_t *boundscheck) +static Value *emit_bounds_check(jl_codectx_t &ctx, const jl_cgval_t &ainfo, jl_value_t *ty, Value *i, Value *len, jl_value_t *boundscheck) JL_CANSAFEPOINT { Value *im1 = ctx.builder.CreateSub(i, ConstantInt::get(ctx.types().T_size, 1)); if (bounds_check_enabled(ctx, boundscheck)) { @@ -2323,8 +2320,8 @@ static Value *emit_bounds_check(jl_codectx_t &ctx, const jl_cgval_t &ainfo, jl_v static void emit_write_barrier(jl_codectx_t&, Value*, ArrayRef); static void emit_write_barrier(jl_codectx_t&, Value*, Value*); -static void emit_write_multibarrier(jl_codectx_t&, Value*, Value*, jl_value_t*); -static void emit_write_multibarrier(jl_codectx_t &ctx, Value *parent, const jl_cgval_t &x); +static void emit_write_multibarrier(jl_codectx_t&, Value*, Value*, jl_value_t*) JL_CANSAFEPOINT; +static void emit_write_multibarrier(jl_codectx_t &ctx, Value *parent, const jl_cgval_t &x) JL_CANSAFEPOINT; SmallVector first_ptr(Type *T) { @@ -2383,7 +2380,7 @@ static void emit_lockstate_value(jl_codectx_t &ctx, Value *strct, bool newstate) static LoadInst *emit_aliased_load(jl_codectx_t &ctx, Type *elty, Value *ptr, Align alignment, MDNode *tbaa, MDNode *aliasscope, AtomicOrdering Order, bool maybe_mark_dereferenceable = false, bool maybe_null = true, - jl_value_t *jltype_for_dereferenceable = nullptr) + jl_value_t *jltype_for_dereferenceable = nullptr) JL_CANSAFEPOINT { LoadInst *load = ctx.builder.CreateAlignedLoad(elty, ptr, alignment, false); load->setOrdering(Order); @@ -2425,7 +2422,7 @@ static jl_cgval_t typed_load(jl_codectx_t &ctx, Value *ptr, Value *idx_0based, j MDNode *tbaa, MDNode *aliasscope, bool isboxed, AtomicOrdering Order, bool maybe_null_if_boxed = true, unsigned alignment = 0, Value **nullcheck = nullptr, - Value *ptindex = nullptr, MDNode *tbaa_ptindex = nullptr) + Value *ptindex = nullptr, MDNode *tbaa_ptindex = nullptr) JL_CANSAFEPOINT { // Handle union types (when ptindex is provided) if (ptindex != nullptr) { @@ -2537,9 +2534,9 @@ static jl_cgval_t typed_load(jl_codectx_t &ctx, Value *ptr, Value *idx_0based, j return mark_julia_slot(intcast, jltype, NULL, ctx.tbaa().tbaa_stack); } -static Function *emit_modifyhelper(jl_codectx_t &ctx2, const jl_cgval_t &op, const jl_cgval_t &modifyop, jl_value_t *jltype, Type *elty, jl_cgval_t rhs, const Twine &fname, bool gcstack_arg); +static Function *emit_modifyhelper(jl_codectx_t &ctx2, const jl_cgval_t &op, const jl_cgval_t &modifyop, jl_value_t *jltype, Type *elty, jl_cgval_t rhs, const Twine &fname, bool gcstack_arg) JL_CANSAFEPOINT; static void emit_unionmove(jl_codectx_t &ctx, Value *dest, jl_value_t *desttype, - MDNode *tbaa_dst, const jl_cgval_t &src, Value *tindex, Value *skip, bool isVolatile=false); + MDNode *tbaa_dst, const jl_cgval_t &src, Value *tindex, Value *skip, bool isVolatile=false) JL_CANSAFEPOINT; static jl_cgval_t typed_store(jl_codectx_t &ctx, Value *ptr, jl_cgval_t rhs, jl_cgval_t cmpop, @@ -2550,9 +2547,9 @@ static jl_cgval_t typed_store(jl_codectx_t &ctx, bool maybe_null_if_boxed, const jl_cgval_t *modifyop, const Twine &fname, jl_module_t *mod, jl_sym_t *var, // Union type support (set ptindex non-null for union stores) - Value *ptindex = nullptr, MDNode *tbaa_ptindex = nullptr) + Value *ptindex = nullptr, MDNode *tbaa_ptindex = nullptr) JL_CANSAFEPOINT { - auto newval = [&](const jl_cgval_t &lhs) { // for ismodifyfield + auto newval = [&](const jl_cgval_t &lhs) JL_CANSAFEPOINT { // for ismodifyfield const jl_cgval_t argv[3] = { cmpop, lhs, rhs }; jl_cgval_t ret; if (modifyop) { @@ -2582,7 +2579,7 @@ static jl_cgval_t typed_store(jl_codectx_t &ctx, return jl_cgval_t(); } } - auto store_union = [&](const jl_cgval_t &val, const jl_cgval_t &val_union) { + auto store_union = [&](const jl_cgval_t &val, const jl_cgval_t &val_union) JL_CANSAFEPOINT { Value *tindex = ctx.builder.CreateAnd(val_union.TIndex, ConstantInt::get(getInt8Ty(ctx.builder.getContext()), ~UNION_BOX_MARKER)); Value *stindex = ctx.builder.CreateNUWSub(tindex, ConstantInt::get(getInt8Ty(ctx.builder.getContext()), 1)); jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA(ctx, tbaa_tindex); @@ -2590,7 +2587,7 @@ static jl_cgval_t typed_store(jl_codectx_t &ctx, if (!val.isghost) emit_unionmove(ctx, ptr, jltype, tbaa, val, tindex, /*skip*/nullptr); }; - auto load_union = [&]() { + auto load_union = [&]() JL_CANSAFEPOINT { return typed_load(ctx, ptr, NULL, jltype, tbaa, nullptr, false, AtomicOrdering::NotAtomic, false, 0, nullptr, ptindex, tbaa_tindex); }; @@ -2678,7 +2675,7 @@ static jl_cgval_t typed_store(jl_codectx_t &ctx, } // This pre-write barrier must be emitted before the store, while also not // holding any local atomic locks. - auto emit_store_pre_barrier = [&](Value *r, const jl_cgval_t &rhs) { + auto emit_store_pre_barrier = [&](Value *r, const jl_cgval_t &rhs) JL_CANSAFEPOINT { if (parent == NULL || !tracked_pointers) return; if (isboxed) { @@ -3027,7 +3024,7 @@ static jl_cgval_t typed_store(jl_codectx_t &ctx, else { // Done = Success || first_ptr == NULL || oldval == cmpop) // Done = !(!Success && (first_ptr != NULL && oldval == cmpop)) - Done = emit_guarded_test(ctx, ctx.builder.CreateNot(Success), false, [&] { + Done = emit_guarded_test(ctx, ctx.builder.CreateNot(Success), false, [&] () JL_CANSAFEPOINT { Value *first_ptr = nullptr; if (maybe_null_if_boxed) first_ptr = isboxed ? realinstr : extract_first_ptr(ctx, realinstr); @@ -3105,7 +3102,7 @@ static jl_cgval_t typed_store(jl_codectx_t &ctx, // --- convert boolean value to julia --- // Returns ctx.types().T_pjlvalue -static Value *julia_bool(jl_codectx_t &ctx, Value *cond) +static Value *julia_bool(jl_codectx_t &ctx, Value *cond) JL_CANSAFEPOINT { auto boolean = ctx.builder.CreateSelect(cond, literal_pointer_val(ctx, jl_true), literal_pointer_val(ctx, jl_false)); @@ -3122,9 +3119,9 @@ static void emit_atomic_error(jl_codectx_t &ctx, const Twine &msg) static jl_cgval_t emit_getfield_knownidx(jl_codectx_t &ctx, const jl_cgval_t &strct, unsigned idx, jl_datatype_t *jt, - enum jl_memory_order order, Value **nullcheck=nullptr); + enum jl_memory_order order, Value **nullcheck=nullptr) JL_CANSAFEPOINT; -static bool field_may_be_null(const jl_cgval_t &strct, jl_datatype_t *stt, size_t idx) +static bool field_may_be_null(const jl_cgval_t &strct, jl_datatype_t *stt, size_t idx) JL_CANSAFEPOINT { size_t nfields = jl_datatype_nfields(stt); if (idx < nfields - (unsigned)stt->name->n_uninitialized) @@ -3138,7 +3135,7 @@ static bool field_may_be_null(const jl_cgval_t &strct, jl_datatype_t *stt, size_ return true; } -static bool field_may_be_null(const jl_cgval_t &strct, jl_datatype_t *stt) +static bool field_may_be_null(const jl_cgval_t &strct, jl_datatype_t *stt) JL_CANSAFEPOINT { size_t nfields = jl_datatype_nfields(stt); for (size_t i = 0; i < (unsigned)stt->name->n_uninitialized; i++) { @@ -3153,12 +3150,12 @@ static bool field_may_be_null(const jl_cgval_t &strct, jl_datatype_t *stt) static bool emit_getfield_unknownidx(jl_codectx_t &ctx, jl_cgval_t *ret, jl_cgval_t strct, Value *idx, jl_datatype_t *stt, jl_value_t *inbounds, - enum jl_memory_order order) + enum jl_memory_order order) JL_CANSAFEPOINT { ++EmittedGetfieldUnknowns; size_t nfields = jl_datatype_nfields(stt); bool maybe_null = field_may_be_null(strct, stt); - auto idx0 = [&]() { + auto idx0 = [&]() JL_CANSAFEPOINT { return emit_bounds_check(ctx, strct, (jl_value_t*)stt, idx, ConstantInt::get(ctx.types().T_size, nfields), inbounds); }; if (nfields == 0) { @@ -3621,7 +3618,7 @@ static Value *emit_n_varargs(jl_codectx_t &ctx) #endif } -static Value *emit_genericmemoryelsize(jl_codectx_t &ctx, Value *v, jl_value_t *typ, bool add_isunion) +static Value *emit_genericmemoryelsize(jl_codectx_t &ctx, Value *v, jl_value_t *typ, bool add_isunion) JL_CANSAFEPOINT { ++EmittedArrayElsize; jl_datatype_t *sty = (jl_datatype_t*)jl_unwrap_unionall(typ); @@ -3700,7 +3697,7 @@ static Value *emit_genericmemoryptr(jl_codectx_t &ctx, Value *mem, const jl_data return ptr; } -static Value *emit_genericmemoryowner(jl_codectx_t &ctx, Value *t) +static Value *emit_genericmemoryowner(jl_codectx_t &ctx, Value *t) JL_CANSAFEPOINT { Value *m = decay_derived(ctx, t); Value *addr = ctx.builder.CreateStructGEP(ctx.types().T_jlgenericmemory, m, 1); @@ -3712,7 +3709,7 @@ static Value *emit_genericmemoryowner(jl_codectx_t &ctx, Value *t) aliasinfo_mem.decorateInst(LI); addr = emit_ptrgep(ctx, m, JL_SMALL_BYTE_ALIGNMENT); Value *foreign = ctx.builder.CreateICmpNE(addr, decay_derived(ctx, LI)); - return emit_guarded_test(ctx, foreign, t, [&] { + return emit_guarded_test(ctx, foreign, t, [&] () JL_CANSAFEPOINT { addr = ctx.builder.CreateConstInBoundsGEP1_32(ctx.types().T_jlgenericmemory, m, 1); LoadInst *owner = ctx.builder.CreateAlignedLoad(ctx.types().T_prjlvalue, addr, Align(sizeof(void*))); jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_memoryptr); @@ -3723,7 +3720,7 @@ static Value *emit_genericmemoryowner(jl_codectx_t &ctx, Value *t) // --- boxing --- -static Value *emit_allocobj(jl_codectx_t &ctx, jl_datatype_t *jt, bool fully_initialized); +static Value *emit_allocobj(jl_codectx_t &ctx, jl_datatype_t *jt, bool fully_initialized) JL_CANSAFEPOINT; static void init_bits_value(jl_codectx_t &ctx, Value *newv, Value *v, MDNode *tbaa, Align alignment = Align(sizeof(void*))) // min alignment in julia's gc is pointer-aligned @@ -3733,7 +3730,7 @@ static void init_bits_value(jl_codectx_t &ctx, Value *newv, Value *v, MDNode *tb ai.decorateInst(ctx.builder.CreateAlignedStore(v, newv, alignment)); } -static void init_bits_cgval(jl_codectx_t &ctx, Value *newv, const jl_cgval_t &v) +static void init_bits_cgval(jl_codectx_t &ctx, Value *newv, const jl_cgval_t &v) JL_CANSAFEPOINT { MDNode *tbaa = jl_is_mutable(v.typ) ? ctx.tbaa().tbaa_mutab : ctx.tbaa().tbaa_immut; unsigned alignment = julia_alignment(v.typ); @@ -3742,7 +3739,7 @@ static void init_bits_cgval(jl_codectx_t &ctx, Value *newv, const jl_cgval_t &v) emit_unbox_store(ctx, v, newv, tbaa, Align(alignment), Align(newv_align)); } -static jl_value_t *static_constant_instance(const llvm::DataLayout &DL, Constant *constant, jl_value_t *jt) +static jl_value_t *static_constant_instance(const llvm::DataLayout &DL, Constant *constant, jl_value_t *jt) JL_CANSAFEPOINT { assert(constant != NULL && jl_is_concrete_type(jt)); jl_datatype_t *jst = (jl_datatype_t*)jt; @@ -3826,13 +3823,13 @@ static Value *call_with_attrs(jl_codectx_t &ctx, JuliaFunction *intr, return Call; } -static Value *as_value(jl_codectx_t &ctx, Type *to, const jl_cgval_t &v) +static Value *as_value(jl_codectx_t &ctx, Type *to, const jl_cgval_t &v) JL_CANSAFEPOINT { assert(!v.isboxed); return emit_unbox(ctx, to, v); } -static Value *load_i8box(jl_codectx_t &ctx, Value *v, jl_datatype_t *ty) +static Value *load_i8box(jl_codectx_t &ctx, Value *v, jl_datatype_t *ty) JL_CANSAFEPOINT { auto jvar = ty == jl_int8_type ? jlboxed_int8_cache : jlboxed_uint8_cache; GlobalVariable *gv = prepare_global_in(jl_Module, jvar); @@ -3846,7 +3843,7 @@ static Value *load_i8box(jl_codectx_t &ctx, Value *v, jl_datatype_t *ty) // some types have special boxing functions with small-value caches // Returns ctx.types().T_prjlvalue -static Value *_boxed_special(jl_codectx_t &ctx, const jl_cgval_t &vinfo, Type *t) +static Value *_boxed_special(jl_codectx_t &ctx, const jl_cgval_t &vinfo, Type *t) JL_CANSAFEPOINT { jl_value_t *jt = vinfo.typ; if (jt == (jl_value_t*)jl_bool_type) @@ -3909,18 +3906,18 @@ static Value *_boxed_special(jl_codectx_t &ctx, const jl_cgval_t &vinfo, Type *t return box; } -static Value *compute_box_tindex(jl_codectx_t &ctx, const jl_cgval_t &val, jl_value_t *ut, bool maybenull=false) +static Value *compute_box_tindex(jl_codectx_t &ctx, const jl_cgval_t &val, jl_value_t *ut, bool maybenull=false) JL_CANSAFEPOINT { jl_value_t *supertype = val.typ; Value *datatype_tag = NULL; - auto maybe_setup_union_isa = [&]() { + auto maybe_setup_union_isa = [&]() JL_CANSAFEPOINT { if (datatype_tag == nullptr) datatype_tag = emit_typeof(ctx, val, maybenull, true); }; Value *tindex = ConstantInt::get(getInt8Ty(ctx.builder.getContext()), 0); unsigned counter = 0; for_each_uniontype_small( - [&](unsigned idx, jl_datatype_t *jt) { + [&](unsigned idx, jl_datatype_t *jt) JL_CANSAFEPOINT { if (jl_subtype((jl_value_t*)jt, supertype)) { maybe_setup_union_isa(); Value *cmp = ctx.builder.CreateICmpEQ(emit_tagfrom(ctx, jt), datatype_tag); @@ -3935,7 +3932,7 @@ static Value *compute_box_tindex(jl_codectx_t &ctx, const jl_cgval_t &val, jl_va } // get the runtime tindex value, assuming val is already converted to type typ if it has a TIndex -static Value *compute_tindex_unboxed(jl_codectx_t &ctx, const jl_cgval_t &val, jl_value_t *typ, bool maybenull=false) +static Value *compute_tindex_unboxed(jl_codectx_t &ctx, const jl_cgval_t &val, jl_value_t *typ, bool maybenull=false) JL_CANSAFEPOINT { if (val.typ == jl_bottom_type) return UndefValue::get(getInt8Ty(ctx.builder.getContext())); @@ -3957,7 +3954,7 @@ static void union_alloca_type(jl_uniontype_t *ut, // compute the size of the union alloca that could hold this type unsigned counter = 0; allunbox = for_each_uniontype_small( - [&](unsigned idx, jl_datatype_t *jt) { + [&](unsigned idx, jl_datatype_t *jt) JL_CANSAFEPOINT { if (!jl_is_datatype_singleton(jt)) { //auto [nb1, n_roots] = split_value_size(jt); // TODO: deal with using this later size_t nb1 = jl_datatype_size(jt); @@ -3981,7 +3978,7 @@ static void union_alloca_type(jl_uniontype_t *ut, align = JL_HEAP_ALIGNMENT; } -static AllocaInst *try_emit_union_alloca(jl_codectx_t &ctx, jl_uniontype_t *ut, bool &allunbox, size_t &min_align, size_t &nbytes, size_t &inline_roots) +static AllocaInst *try_emit_union_alloca(jl_codectx_t &ctx, jl_uniontype_t *ut, bool &allunbox, size_t &min_align, size_t &nbytes, size_t &inline_roots) JL_CANSAFEPOINT { size_t align; union_alloca_type(ut, allunbox, nbytes, align, min_align, inline_roots); @@ -4003,7 +4000,7 @@ static AllocaInst *try_emit_union_alloca(jl_codectx_t &ctx, jl_uniontype_t *ut, * `vinfo` is already an unknown boxed union (union tag UNION_BOX_MARKER). */ // Returns ctx.types().T_prjlvalue -static Value *box_union(jl_codectx_t &ctx, const jl_cgval_t &vinfo, const SmallBitVector &skip) +static Value *box_union(jl_codectx_t &ctx, const jl_cgval_t &vinfo, const SmallBitVector &skip) JL_CANSAFEPOINT { // given vinfo::Union{T, S}, emit IR of the form: // ... @@ -4028,7 +4025,7 @@ static Value *box_union(jl_codectx_t &ctx, const jl_cgval_t &vinfo, const SmallB PHINode *box_merge = ctx.builder.CreatePHI(ctx.types().T_prjlvalue, 2); unsigned counter = 0; for_each_uniontype_small( - [&](unsigned idx, jl_datatype_t *jt) { + [&](unsigned idx, jl_datatype_t *jt) JL_CANSAFEPOINT { if (idx < skip.size() && skip[idx]) return; Type *t = julia_type_to_llvm(ctx, (jl_value_t*)jt); @@ -4218,7 +4215,7 @@ static void emit_unionmove(jl_codectx_t &ctx, Value *dest, jl_value_t *desttype, jl_value_t *typ = jl_typeof(src.constant); assert(skip || deserves_stack(typ)); if (jl_is_concrete_immutable(typ)) { - emit_guarded_test(ctx, skip ? ctx.builder.CreateNot(skip) : nullptr, nullptr, [&] { + emit_guarded_test(ctx, skip ? ctx.builder.CreateNot(skip) : nullptr, nullptr, [&] () JL_CANSAFEPOINT { unsigned alignment = julia_alignment(typ); split_value_into(ctx, mark_julia_const(ctx, src.constant), Align(alignment), dest, Align(alignment), dest_ai, isVolatile); return nullptr; @@ -4228,7 +4225,7 @@ static void emit_unionmove(jl_codectx_t &ctx, Value *dest, jl_value_t *desttype, else if (jl_is_concrete_type(src.typ)) { assert(skip || deserves_stack(src.typ)); if (jl_is_concrete_immutable(src.typ)) { - emit_guarded_test(ctx, skip ? ctx.builder.CreateNot(skip) : nullptr, nullptr, [&] { + emit_guarded_test(ctx, skip ? ctx.builder.CreateNot(skip) : nullptr, nullptr, [&] () JL_CANSAFEPOINT { unsigned alignment = julia_alignment(src.typ); split_value_into(ctx, src, Align(alignment), dest, Align(alignment), dest_ai, isVolatile); return nullptr; @@ -4245,7 +4242,7 @@ static void emit_unionmove(jl_codectx_t &ctx, Value *dest, jl_value_t *desttype, ctx.builder.SetInsertPoint(postBB); unsigned counter = 0; bool allunboxed = for_each_uniontype_small( - [&](unsigned idx, jl_datatype_t *jt) { + [&](unsigned idx, jl_datatype_t *jt) JL_CANSAFEPOINT { if (!jl_subtype((jl_value_t*)jt, src.typ)) return; unsigned nb = jl_datatype_size(jt); @@ -4286,7 +4283,7 @@ static void emit_unionmove(jl_codectx_t &ctx, Value *dest, jl_value_t *desttype, } -static void emit_cpointercheck(jl_codectx_t &ctx, const jl_cgval_t &x, const Twine &msg) +static void emit_cpointercheck(jl_codectx_t &ctx, const jl_cgval_t &x, const Twine &msg) JL_CANSAFEPOINT { ++EmittedCPointerChecks; Value *t = emit_typeof(ctx, x, false, false); @@ -4425,7 +4422,7 @@ static jl_cgval_t emit_setfield(jl_codectx_t &ctx, jl_cgval_t rhs, jl_cgval_t cmp, bool wb, AtomicOrdering Order, AtomicOrdering FailOrder, Value *needlock, StoreKind op, - const jl_cgval_t *modifyop, const Twine &fname) + const jl_cgval_t *modifyop, const Twine &fname) JL_CANSAFEPOINT { auto get_objname = [&]() { return strct.V ? strct.V->getName() : StringRef(""); @@ -4813,7 +4810,7 @@ static void emit_memory_stores(jl_codectx_t &ctx, jl_datatype_t *typ, Value* all } -static jl_cgval_t emit_const_len_memorynew(jl_codectx_t &ctx, jl_datatype_t *typ, size_t nel, jl_genericmemory_t *inst) +static jl_cgval_t emit_const_len_memorynew(jl_codectx_t &ctx, jl_datatype_t *typ, size_t nel, jl_genericmemory_t *inst) JL_CANSAFEPOINT { if (nel == 0) { Value *empty_alloc = track_pjlvalue(ctx, literal_pointer_val(ctx, (jl_value_t*)inst)); @@ -4875,7 +4872,7 @@ static jl_cgval_t emit_const_len_memorynew(jl_codectx_t &ctx, jl_datatype_t *typ return mark_julia_type(ctx, alloc, true, typ); } -static jl_cgval_t emit_memorynew(jl_codectx_t &ctx, jl_datatype_t *typ, jl_cgval_t nel, jl_genericmemory_t *inst) +static jl_cgval_t emit_memorynew(jl_codectx_t &ctx, jl_datatype_t *typ, jl_cgval_t nel, jl_genericmemory_t *inst) JL_CANSAFEPOINT { emit_typecheck(ctx, nel, (jl_value_t*)jl_long_type, "memorynew"); nel = update_julia_type(ctx, nel, (jl_value_t*)jl_long_type); @@ -4956,7 +4953,7 @@ static jl_cgval_t emit_memorynew(jl_codectx_t &ctx, jl_datatype_t *typ, jl_cgval return mark_julia_type(ctx, phi, true, typ); } -static jl_cgval_t _emit_memoryref(jl_codectx_t &ctx, Value *mem, Value *data, const jl_datatype_layout_t *layout, jl_value_t *typ) +static jl_cgval_t _emit_memoryref(jl_codectx_t &ctx, Value *mem, Value *data, const jl_datatype_layout_t *layout, jl_value_t *typ) JL_CANSAFEPOINT { //jl_cgval_t argv[] = { // mark_julia_type(ctx, mem, true, jl_any_type), @@ -4970,7 +4967,7 @@ static jl_cgval_t _emit_memoryref(jl_codectx_t &ctx, Value *mem, Value *data, co return mark_julia_type(ctx, ref, false, typ); } -static jl_cgval_t _emit_memoryref(jl_codectx_t &ctx, const jl_cgval_t &mem, const jl_datatype_layout_t *layout, jl_value_t *typ) +static jl_cgval_t _emit_memoryref(jl_codectx_t &ctx, const jl_cgval_t &mem, const jl_datatype_layout_t *layout, jl_value_t *typ) JL_CANSAFEPOINT { bool isboxed = layout->flags.arrayelem_isboxed; bool isunion = layout->flags.arrayelem_isunion; @@ -4979,7 +4976,7 @@ static jl_cgval_t _emit_memoryref(jl_codectx_t &ctx, const jl_cgval_t &mem, cons return _emit_memoryref(ctx, boxed(ctx, mem), data, layout, typ); } -static jl_cgval_t emit_memoryref_direct(jl_codectx_t &ctx, const jl_cgval_t &mem, jl_cgval_t idx, jl_value_t *typ, jl_value_t *inbounds, const jl_datatype_layout_t *layout) +static jl_cgval_t emit_memoryref_direct(jl_codectx_t &ctx, const jl_cgval_t &mem, jl_cgval_t idx, jl_value_t *typ, jl_value_t *inbounds, const jl_datatype_layout_t *layout) JL_CANSAFEPOINT { bool isboxed = layout->flags.arrayelem_isboxed; bool isunion = layout->flags.arrayelem_isunion; @@ -5024,7 +5021,7 @@ static jl_cgval_t emit_memoryref_direct(jl_codectx_t &ctx, const jl_cgval_t &mem return _emit_memoryref(ctx, boxmem, data, layout, typ); } -static Value *emit_memoryref_FCA(jl_codectx_t &ctx, const jl_cgval_t &ref, const jl_datatype_layout_t *layout) +static Value *emit_memoryref_FCA(jl_codectx_t &ctx, const jl_cgval_t &ref, const jl_datatype_layout_t *layout) JL_CANSAFEPOINT { if (!ref.inline_roots.empty()) { LLVMContext &C = ctx.builder.getContext(); @@ -5053,7 +5050,7 @@ static Value *emit_memoryref_FCA(jl_codectx_t &ctx, const jl_cgval_t &ref, const } } -static jl_cgval_t emit_memoryref(jl_codectx_t &ctx, const jl_cgval_t &ref, jl_cgval_t idx, jl_value_t *inbounds, const jl_datatype_layout_t *layout) +static jl_cgval_t emit_memoryref(jl_codectx_t &ctx, const jl_cgval_t &ref, jl_cgval_t idx, jl_value_t *inbounds, const jl_datatype_layout_t *layout) JL_CANSAFEPOINT { ++EmittedArrayNdIndex; emit_typecheck(ctx, idx, (jl_value_t*)jl_long_type, "memoryrefnew"); @@ -5183,7 +5180,7 @@ static jl_cgval_t emit_memoryref(jl_codectx_t &ctx, const jl_cgval_t &ref, jl_cg return _emit_memoryref(ctx, mem, newdata, layout, ref.typ); } -static jl_cgval_t emit_memoryref_offset(jl_codectx_t &ctx, const jl_cgval_t &ref, const jl_datatype_layout_t *layout) +static jl_cgval_t emit_memoryref_offset(jl_codectx_t &ctx, const jl_cgval_t &ref, const jl_datatype_layout_t *layout) JL_CANSAFEPOINT { Value *offset; Value *V = emit_memoryref_FCA(ctx, ref, layout); @@ -5207,7 +5204,7 @@ static jl_cgval_t emit_memoryref_offset(jl_codectx_t &ctx, const jl_cgval_t &ref return mark_julia_type(ctx, offset, false, jl_long_type); } -static Value *emit_memoryref_mem(jl_codectx_t &ctx, const jl_cgval_t &ref, const jl_datatype_layout_t *layout) +static Value *emit_memoryref_mem(jl_codectx_t &ctx, const jl_cgval_t &ref, const jl_datatype_layout_t *layout) JL_CANSAFEPOINT { Value *V = emit_memoryref_FCA(ctx, ref, layout); V = CreateSimplifiedExtractValue(ctx, V, 1); @@ -5215,7 +5212,7 @@ static Value *emit_memoryref_mem(jl_codectx_t &ctx, const jl_cgval_t &ref, const return V; } -static Value *emit_memoryref_ptr(jl_codectx_t &ctx, const jl_cgval_t &ref, const jl_datatype_layout_t *layout) +static Value *emit_memoryref_ptr(jl_codectx_t &ctx, const jl_cgval_t &ref, const jl_datatype_layout_t *layout) JL_CANSAFEPOINT { assert(!layout->flags.arrayelem_isunion && layout->size != 0); Value *newref = emit_memoryref_FCA(ctx, ref, layout); diff --git a/src/clangsa/FirstDeclAnnotations.cpp b/src/clangsa/FirstDeclAnnotations.cpp index b907f944a7b81..04870ec728177 100644 --- a/src/clangsa/FirstDeclAnnotations.cpp +++ b/src/clangsa/FirstDeclAnnotations.cpp @@ -152,7 +152,7 @@ class FirstDeclAnnotationsCheck : public ClangTidyCheck { checkFnPtrConversion(Conv, Result); else if (const auto *MD = Result.Nodes.getNodeAs("override")) - checkOverride(MD, Result); + checkOverride(MD); } void checkFirstDecl(const FunctionDecl *FD, @@ -182,6 +182,27 @@ class FirstDeclAnnotationsCheck : public ClangTidyCheck { if (SM.isInSystemHeader(First->getLocation())) return; + // The same applies to a first declaration in an upstream dependency + // header that the build does not mark as a system header -- notably + // libuv's uv.h (reached via usr/include), which declares the runtime + // helpers such as uv_mutex_lock. We re-declare those in our own headers + // to add the annotations they need for the analyzer (e.g. julia_locks.h + // adds JL_NOTSAFEPOINT_ENTER to uv_mutex_lock, and julia.h adds + // JL_CANSAFEPOINT to uv_run), but the annotation cannot be hoisted onto + // uv.h. Recognize these declarations as external -- by an `llvm-*` + // header file name or a `uv_`/`unw_`/`_U` runtime-helper name -- so the + // later, annotated re-declaration is not flagged. Unlike GCChecker's + // safepoint reasoning this is a purely lexical test on where the + // declaration lives, so it must include uv_run: its first declaration + // is in uv.h just like the others, and the JL_CANSAFEPOINT we add is + // exactly what cannot be hoisted there. + if (jl_clangsa::isInLLVMHeaderFile(First->getLocation(), SM)) + return; + StringRef FirstName = + First->getDeclName().isIdentifier() ? First->getName() : ""; + if (jl_clangsa::nameIsExternalRuntimeHelper(FirstName)) + return; + // A block-scope redeclaration (a prototype written inside a function // body, i.e. a local extern declaration) is intentionally allowed to // add an annotation that holds only for that specific caller -- e.g. @@ -307,10 +328,16 @@ class FirstDeclAnnotationsCheck : public ClangTidyCheck { } // A function `Conv` (a function-to-pointer decay or `&f`) is being - // converted to a function pointer. Diagnose if the function lacks a Julia - // annotation that the target function-pointer type requires: the analyzer - // assumes calls through that pointer carry the annotation, so the function - // must carry at least the annotations of the type it is assigned to. + // converted to a function pointer. The analyzer assumes calls through that + // pointer carry the pointer type's annotations, so the function and the + // type must be compatible -- but in opposite directions for restrictions + // and capabilities: + // * A restriction the target type requires (e.g. a rooting contract) must + // also be on the function, or calls through the pointer would assume a + // contract the function does not honor. + // * A capability the function has (JL_CANSAFEPOINT) must also be on the + // target type, or calls through the pointer -- trusting the type's + // missing annotation -- would be treated as not safepointing. void checkFnPtrConversion(const Expr *Conv, const MatchFinder::MatchResult &Result) { ASTContext &Ctx = *Result.Context; @@ -325,16 +352,32 @@ class FirstDeclAnnotationsCheck : public ClangTidyCheck { if (Target.isNull() || !Target->isFunctionPointerType()) return; - SourceManager &SM = Ctx.getSourceManager(); - - // Collect the annotations the target type requires, then report each - // one the function does not provide. llvm::SmallVector, 2> - Required; - collectTypedefAnnotations(Target, Ctx, Required); - for (const auto &R : Required) { + TypeAnns; + collectTypedefAnnotations(Target, Ctx, TypeAnns); + llvm::StringSet<> TypeKeys; + for (const auto &R : TypeAnns) + TypeKeys.insert(R.first); + // The annotation may live directly on the target declaration rather + // than on a typedef of its type -- e.g. a function-pointer parameter, + // variable, or field whose raw (non-typedef'd) type carries no + // annotation of its own, as jl_foreach_top_typename_for's `f` parameter + // does. collectTypedefAnnotations only sees typedef sugar, so also fold + // in the target declaration's own annotations. + if (const Decl *TgtDecl = targetDecl(Conv, Ctx)) + for (const auto *A : TgtDecl->attrs()) { + std::string Key = attrKey(A); + if (StringRef(Key).starts_with("annotate:")) + TypeKeys.insert(std::move(Key)); + } + + // Restriction annotations the target type requires but the function + // does not provide. + for (const auto &R : TypeAnns) { StringRef Key = R.first; - if (functionProvidesAnnotation(FD, Key, SM)) + if (isCapabilityAnnotation(Key)) + continue; // capabilities propagate the other way (below) + if (functionProvidesAnnotation(FD, Key)) continue; // Strip the "annotate:" prefix added by attrKey() for the message. StringRef Name = Key; @@ -353,32 +396,72 @@ class FirstDeclAnnotationsCheck : public ClangTidyCheck { "%0 is declared here", DiagnosticIDs::Note) << FD; } + + // Capability annotations on the function that the target type lacks: + // storing a JL_CANSAFEPOINT function in a pointer that is not + // JL_CANSAFEPOINT would let calls through the pointer miss the safepoint. + llvm::StringSet<> Reported; + for (const FunctionDecl *R : FD->redecls()) { + for (const auto *A : R->attrs()) { + std::string Key = attrKey(A); + if (!isCapabilityAnnotation(Key)) + continue; + if (TypeKeys.count(Key)) + continue; + if (!Reported.insert(Key).second) + continue; + StringRef Name = StringRef(Key); + Name.consume_front("annotate:"); + auto Diag = diag(Conv->getExprLoc(), + "%0 is annotated \"%1\" but is converted to a function " + "pointer of type %2 that is not; annotate the " + "function-pointer type so calls through the pointer are " + "analyzed soundly"); + Diag << FD << Name << Target; + diag(FD->getFirstDecl()->getLocation(), + "%0 is declared here", DiagnosticIDs::Note) + << FD; + } + } } // A C++ method `MD` overrides one or more virtual methods. The analyzer // assumes a virtual call dispatched through a base-class reference carries - // the overridden method's annotations, so the override must carry at least - // every annotation of the methods it overrides -- it must be "stronger - // than" the original. - void checkOverride(const CXXMethodDecl *MD, - const MatchFinder::MatchResult &Result) { - SourceManager &SM = Result.Context->getSourceManager(); - + // the overridden method's annotations, so the override and the base must be + // compatible -- but in opposite directions for restrictions and + // capabilities: + // * A restriction on an overridden method must also be on the override, + // or a call dispatched to the override would assume a contract it does + // not honor. + // * A capability on the override (JL_CANSAFEPOINT) must also be on the + // overridden method, or virtual calls through the base -- trusting the + // base's missing annotation -- would be treated as not safepointing. + void checkOverride(const CXXMethodDecl *MD) { llvm::SmallVector, 2> Required; llvm::StringSet<> Seen; - for (const CXXMethodDecl *Base : MD->overridden_methods()) + llvm::StringSet<> BaseKeys; + const CXXMethodDecl *AnyBase = nullptr; + for (const CXXMethodDecl *Base : MD->overridden_methods()) { + if (!AnyBase) + AnyBase = Base; for (const FunctionDecl *R : Base->redecls()) for (const auto *A : R->attrs()) { std::string Key = attrKey(A); if (!StringRef(Key).starts_with("annotate:")) continue; + BaseKeys.insert(Key); + if (isCapabilityAnnotation(Key)) + continue; // capabilities propagate the other way (below) if (Seen.insert(Key).second) Required.emplace_back(std::move(Key), Base); } + } + // Restriction annotations the overridden methods require but the + // override does not provide. for (const auto &R : Required) { StringRef Key = R.first; - if (functionProvidesAnnotation(MD, Key, SM)) + if (functionProvidesAnnotation(MD, Key)) continue; // Strip the "annotate:" prefix added by attrKey() for the message. StringRef Name = Key; @@ -393,6 +476,34 @@ class FirstDeclAnnotationsCheck : public ClangTidyCheck { DiagnosticIDs::Note) << R.second; } + + // Capability annotations on the override that the overridden methods + // lack: a JL_CANSAFEPOINT override of a non-JL_CANSAFEPOINT method would + // let virtual calls through the base miss the safepoint. + llvm::StringSet<> Reported; + for (const FunctionDecl *R : MD->redecls()) { + for (const auto *A : R->attrs()) { + std::string Key = attrKey(A); + if (!isCapabilityAnnotation(Key)) + continue; + if (BaseKeys.count(Key)) + continue; + if (!Reported.insert(Key).second) + continue; + StringRef Name = StringRef(Key); + Name.consume_front("annotate:"); + auto Diag = diag(MD->getLocation(), + "%0 is annotated \"%1\" but overrides a method that is not; " + "annotate the overridden method so virtual calls through " + "the base class are analyzed soundly"); + Diag << MD << Name; + if (AnyBase) + diag(AnyBase->getLocation(), + "overridden method %0 is declared here", + DiagnosticIDs::Note) + << AnyBase; + } + } } // The function referred to by a conversion node (a function-to-pointer @@ -441,6 +552,43 @@ class FirstDeclAnnotationsCheck : public ClangTidyCheck { return QualType(); } + // The declaration `Conv`'s target position resolves to -- the variable, + // field, assigned lvalue, or callee parameter the function pointer is + // stored into -- or null when the target has no such declaration (a return + // position, an unresolved callee, or a computed lvalue). Its own + // annotations complement targetType(), which only sees typedef sugar, so an + // annotation written directly on e.g. a function-pointer parameter is + // honored even when the parameter's type is a raw (non-typedef'd) pointer. + static const Decl *targetDecl(const Expr *Conv, ASTContext &Ctx) { + DynTypedNodeList Parents = Ctx.getParents(*Conv); + if (Parents.empty()) + return nullptr; + const DynTypedNode &P = Parents[0]; + if (const auto *VD = P.get()) + return VD; + if (const auto *FD = P.get()) + return FD; + if (const auto *BO = P.get()) { + if (BO->getOpcode() == BO_Assign && BO->getRHS() == Conv) + if (const auto *DRE = dyn_cast( + BO->getLHS()->IgnoreParenImpCasts())) + return DRE->getDecl(); + return nullptr; + } + if (const auto *CE = P.get()) { + if (CE->getCallee() == Conv) + return nullptr; + const FunctionDecl *Callee = CE->getDirectCallee(); + if (!Callee) + return nullptr; + for (unsigned I = 0, N = CE->getNumArgs(); I < N; ++I) + if (CE->getArg(I) == Conv) + return I < Callee->getNumParams() ? Callee->getParamDecl(I) + : nullptr; + } + return nullptr; + } + // The parameter type (with sugar) that argument `Conv` of call `CE` is // passed to, or null for the callee position, varargs, or an unresolved // callee. @@ -525,38 +673,28 @@ class FirstDeclAnnotationsCheck : public ClangTidyCheck { } // True if the function provides the annotation identified by `Key` (an - // attrKey(), e.g. "annotate:julia_not_safepoint"), either by carrying it on - // some declaration or -- for julia_not_safepoint -- by being a function the - // GC analyzer already treats as a non-safepoint without an explicit - // annotation. The exemptions mirror GCChecker so that conversions the - // analyzer considers sound are not flagged here. + // attrKey(), e.g. "annotate:julia_can_safepoint") by carrying it on some + // declaration. Under the opt-in safepoint model every safepoint-relevant + // annotation is explicit, so there is no implicit exemption here. static bool functionProvidesAnnotation(const FunctionDecl *FD, - StringRef Key, SourceManager &SM) { + StringRef Key) { for (const FunctionDecl *R : FD->redecls()) if (hasAttrLike(R, Key)) return true; - if (Key == "annotate:julia_not_safepoint") - return analyzerTreatsAsNotSafepoint(FD, SM); return false; } - // Mirror of GCChecker's reasoning for callees that are non-safepoints - // without an explicit JL_NOTSAFEPOINT: external declarations we cannot - // annotate (system or `llvm-*` headers, the `llvm`/`std`/`tp` namespaces), - // compiler builtins, and the `uv_`/`unw_`/`_U` runtime helpers. - static bool analyzerTreatsAsNotSafepoint(const FunctionDecl *FD, - SourceManager &SM) { - const FunctionDecl *First = FD->getFirstDecl(); - if (SM.isInSystemHeader(First->getLocation())) - return true; - if (jl_clangsa::isInLLVMHeaderFile(First->getLocation(), SM)) - return true; - if (jl_clangsa::isInNonSafepointNamespace(FD->getDeclContext())) - return true; - if (FD->getBuiltinID() != 0) - return true; - StringRef Name = FD->getDeclName().isIdentifier() ? FD->getName() : ""; - return jl_clangsa::nameIsNonSafepointRuntimeHelper(Name); + // A capability annotation grants a permission (the function MAY do + // something) rather than imposing a restriction (a promise the function + // will NOT do something, or a rooting contract). JL_CANSAFEPOINT is the + // capability: it says the function may reach a safepoint. Capabilities + // propagate in the opposite direction from restrictions across fn-ptr + // conversions and overrides -- a function that HAS the capability may only + // be used where the capability is also declared, because the analyzer + // trusts the (fn-ptr / overridden-method) declaration. See + // checkFnPtrConversion / checkOverride. + static bool isCapabilityAnnotation(StringRef Key) { + return Key == "annotate:julia_can_safepoint"; } // True if the function has a global prototype: some declaration other @@ -623,8 +761,15 @@ class FirstDeclAnnotationsCheck : public ClangTidyCheck { // do not check. Two declarations "have the same attribute" iff their keys // match -- this is what lets us tell a missing attribute from a present one. static std::string attrKey(const Attr *A) { - if (const auto *Ann = dyn_cast(A)) + if (const auto *Ann = dyn_cast(A)) { + // JL_NO_SAFEPOINT_ANALYSIS opts a function body out of the + // thread-safety analysis; it applies to the definition being + // analyzed, not to callers, so it legitimately lives only on the + // definition and must not be required on the first declaration. + if (Ann->getAnnotation() == "julia_no_safepoint_analysis") + return std::string(); return ("annotate:" + Ann->getAnnotation()).str(); + } if (const auto *Vis = dyn_cast(A)) return "visibility:" + std::to_string(Vis->getVisibility()); if (isa(A)) diff --git a/src/clangsa/GCCheckerPropagation.cpp b/src/clangsa/GCCheckerPropagation.cpp index 8c8b4b8620a1d..2664fee69fe9d 100644 --- a/src/clangsa/GCCheckerPropagation.cpp +++ b/src/clangsa/GCCheckerPropagation.cpp @@ -237,7 +237,9 @@ void GCChecker::checkEndFunction(const clang::ReturnStmt *RS, Changed = true; } if (State->get() == CurrentHeight) { - if (!isFDAnnotatedNotSafepoint(FD, getSM(C)) && !(FD && declHasAnnotation(FD, "julia_notsafepoint_enter"))) { + if (!isFDAnnotatedNotSafepoint(FD, getSM(C)) && + !(FD && (declHasAnnotation(FD, "julia_notsafepoint_enter") || + declHasIndexedAnnotation(FD, "julia_notsafepoint_enter_conditional:")))) { report_error(C, "Safepoints disabled at end of function"); } State = State->set((unsigned)-1); @@ -523,21 +525,34 @@ bool GCChecker::isSafepoint(const CallEvent &Call, CheckerContext &C) const { return false; const FunctionDecl *FD = Decl ? Decl->getAsFunction() : nullptr; if (!Decl || !FD) { - if (Callee == nullptr) { - isCalleeSafepoint = true; - } else if (const ElaboratedType *ET = dyn_cast(Callee->getType())){ - if (const TypedefType *TDT = dyn_cast(ET->getNamedType())) { - isCalleeSafepoint = - !declHasAnnotation(TDT->getDecl(), "julia_not_safepoint"); + // Indirect call through a function pointer. A safepoint annotation on the + // callee can live either on the function-pointer typedef (e.g. + // intrinsic_2_t) or, for a raw (non-typedef'd) function pointer, on the + // callee value declaration itself -- a parameter, variable, or struct + // field (as jl_iintrinsic_2's `lambda2` parameter carries it). Consult + // whichever carries it so an annotated function pointer is recognized + // without requiring a typedef; treat the callee as a non-safepoint if + // either source says so. + bool notSafepoint = false; + if (Decl && declHasAnnotation(Decl, "julia_not_safepoint")) + notSafepoint = true; + if (Callee) { + if (const ElaboratedType *ET = + dyn_cast(Callee->getType())) { + if (const TypedefType *TDT = + dyn_cast(ET->getNamedType())) { + if (declHasAnnotation(TDT->getDecl(), "julia_not_safepoint")) + notSafepoint = true; + } + } else if (isa(Callee)) { + // A pseudo-destructor is an expression that looks like a member + // access to a destructor of a scalar type. It has no run-time + // semantics beyond evaluating the base expression (which would have + // its own CallEvent, if applicable). + notSafepoint = true; } - } else if (const CXXPseudoDestructorExpr *PDE = - dyn_cast(Callee)) { - // A pseudo-destructor is an expression that looks like a member - // access to a destructor of a scalar type. A pseudo-destructor - // expression has no run-time semantics beyond evaluating the base - // expression (which would have its own CallEvent, if applicable). - isCalleeSafepoint = false; } + isCalleeSafepoint = !notSafepoint; } else if (FD) { StringRef FDName = FD->getDeclName().isIdentifier() ? FD->getName() : ""; @@ -562,27 +577,6 @@ bool GCChecker::processPotentialSafepoint(const CallEvent &Call, return false; const Decl *D = Call.getDecl(); const FunctionDecl *FD = D ? D->getAsFunction() : nullptr; - GCObjectSet SpeciallyRootedObjects = emptyObjectSet(State); - if (FD) { - for (unsigned i = 0; i < FD->getNumParams(); ++i) { - QualType ParmType = FD->getParamDecl(i)->getType(); - if (declHasAnnotation(FD->getParamDecl(i), "julia_temporarily_roots")) { - if (ParmType->isPointerType() && - ParmType->getPointeeType()->isPointerType() && - isGCTrackedType(ParmType->getPointeeType())) { - // This is probably an out parameter. Find the value it refers to now. - SVal Loaded = - State->getSVal(*(Call.getArgSVal(i).getAs())); - SpeciallyRootedObjects = getObjectsForSVal(State, Loaded); - continue; - } - SVal Test = Call.getArgSVal(i); - SpeciallyRootedObjects = getObjectsForSVal(State, Test); - break; - } - } - } - // Don't free the return value SymbolRef RetSym = Call.getReturnValue().getAsSymbol(); GCObjectSet RetObjects = getObjectsForSymbol(State, RetSym); @@ -592,8 +586,6 @@ bool GCChecker::processPotentialSafepoint(const CallEvent &Call, GCObjectStateMapTy AMap = State->get(); for (auto I = AMap.begin(), E = AMap.end(); I != E; ++I) { if (I.getData().isJustAllocated()) { - if (objectSetContains(SpeciallyRootedObjects, I.getKey())) - continue; if (objectSetContains(RetObjects, I.getKey())) continue; if (Reachable.contains(I.getKey())) @@ -1107,7 +1099,25 @@ bool GCChecker::processAllocationOfResult(const CallEvent &Call, void GCChecker::checkPostCall(const CallEvent &Call, CheckerContext &C) const { ProgramStateRef State = C.getState(); bool didChange = processArgumentRooting(Call, C, State); - if (!C.wasInlined) + // A call is normally modeled as a potential safepoint only when it is not + // inlined; when it is inlined, the safepoints reached inside its body are + // modeled directly as they are encountered. But a function explicitly + // annotated as able to safepoint promises that it may reach one, so honor + // that promise even when its body was inlined and happened to not reach a + // recognized safepoint (e.g. the safepoint is behind a branch the analyzer + // pruned, or behind an opaque call it could not see into). Only + // JL_NOTSAFEPOINT marks a function as unable to safepoint; the + // JL_NOTSAFEPOINT_ENTER/LEAVE transitions (and the conditional enter) run code + // that may safepoint, so they count here too. isSafepoint() below still + // excludes anything additionally annotated JL_NOTSAFEPOINT. + const Decl *D = Call.getDecl(); + const FunctionDecl *FD = D ? D->getAsFunction() : nullptr; + bool annotatedCanSafepoint = + FD && (declHasAnnotation(FD, "julia_can_safepoint") || + declHasAnnotation(FD, "julia_notsafepoint_enter") || + declHasIndexedAnnotation(FD, "julia_notsafepoint_enter_conditional:") || + declHasAnnotation(FD, "julia_notsafepoint_leave")); + if (!C.wasInlined || annotatedCanSafepoint) didChange |= processPotentialSafepoint(Call, C, State); didChange |= processRootPropagatingRegionResult(Call, C, State); didChange |= processAllocationOfResult(Call, C, State); @@ -1733,6 +1743,41 @@ bool GCChecker::evalCall(const CallEvent &Call, CheckerContext &C) const { C.addTransition(State); return true; } + // A conditional enter (e.g. a no-gc trylock) only disables safepoints when + // it succeeds, which it reports through its return value. The annotation + // records which return value means success -- JL_NOTSAFEPOINT_ENTER_CONDITIONAL(success) + // encodes it as julia_notsafepoint_enter_conditional:. Split the + // state on the return value: the branch matching `success` takes the no-gc + // lock and disables safepoints, while the other branch leaves them enabled. + std::optional CondSuccess = + FD ? declHasIndexedAnnotation(FD, "julia_notsafepoint_enter_conditional:") + : std::nullopt; + if (CondSuccess) { + ProgramStateRef State = C.getState(); + SValBuilder &SVB = C.getSValBuilder(); + DefinedOrUnknownSVal RetVal = + SVB.conjureSymbolVal(nullptr, C.getCFGElementRef(), + C.getLocationContext(), CE->getType(), + C.blockCount()) + .castAs(); + State = State->BindExpr(CE, C.getLocationContext(), RetVal); + if (State->get() == (unsigned)-1) { + ProgramStateRef StateNonzero, StateZero; + std::tie(StateNonzero, StateZero) = State->assume(RetVal); + // A nonzero success value means a nonzero (true) return acquired the + // no-gc lock; a zero success value means a zero (false) return did. + ProgramStateRef Acquired = *CondSuccess ? StateNonzero : StateZero; + ProgramStateRef NotAcquired = *CondSuccess ? StateZero : StateNonzero; + unsigned Height = getStackFrameHeight(C.getStackFrame()); + if (Acquired) + C.addTransition(Acquired->set(Height)); + if (NotAcquired) + C.addTransition(NotAcquired); + } else { + C.addTransition(State); + } + return true; + } if (isMutexLock(name) || (FD && declHasAnnotation(FD, "julia_notsafepoint_enter"))) { ProgramStateRef State = C.getState(); diff --git a/src/clangsa/HelpersCommon.hpp b/src/clangsa/HelpersCommon.hpp index eb938b97a21c0..9baad6cb82759 100644 --- a/src/clangsa/HelpersCommon.hpp +++ b/src/clangsa/HelpersCommon.hpp @@ -39,13 +39,22 @@ inline bool isInLLVMHeaderFile(SourceLocation Loc, const SourceManager &SM) { return Name.starts_with("llvm-"); } +// True if `Name` is named like one of the `uv_`/`unw_`/`_U` runtime helpers +// that live in an upstream dependency's headers (libuv, libunwind) which are +// not ours to edit. This is a purely lexical test on the name -- it says +// nothing about whether the function reaches a safepoint (see +// nameIsNonSafepointRuntimeHelper for that narrower question, which excludes +// uv_run). +inline bool nameIsExternalRuntimeHelper(StringRef Name) { + return Name.starts_with("uv_") || Name.starts_with("unw_") || + Name.starts_with("_U") || Name.starts_with("mdb_"); +} + // True if `Name` is one of the `uv_`/`unw_`/`_U` runtime helpers the analyzer // treats as a non-safepoint. `uv_run` is the sole exception: it drives the // event loop and can reach arbitrary safepoints. inline bool nameIsNonSafepointRuntimeHelper(StringRef Name) { - return (Name.starts_with("uv_") || Name.starts_with("unw_") || - Name.starts_with("_U") || Name.starts_with("mdb_")) && - Name != "uv_run"; + return nameIsExternalRuntimeHelper(Name) && Name != "uv_run"; } } // namespace jl_clangsa diff --git a/src/codegen.cpp b/src/codegen.cpp index 1902e97905cd8..eec2ecf3ef5ae 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -178,7 +178,7 @@ static void setName(jl_codegen_output_t &out, Value *V, std::functionsetName(Twine(GetName())); } -static void setNameWithField(jl_codegen_output_t &out, Value *V, std::function GetObjName, jl_datatype_t *jt, unsigned idx, const Twine &suffix) +static void setNameWithField(jl_codegen_output_t &out, Value *V, std::function GetObjName, jl_datatype_t *jt, unsigned idx, const Twine &suffix) JL_CANSAFEPOINT { assert((isa(V) || isa(V)) && "Should only set names on instructions!"); if (!out.get_context().shouldDiscardValueNames() && !isa(V)) { @@ -576,14 +576,14 @@ struct JuliaFunction { }; template -static inline void add_named_global(JuliaFunction *name, T *addr) +static inline void add_named_global(JuliaFunction *name, T *addr JL_CANSAFEPOINT) { // cast through integer to avoid c++ pedantic warning about casting between // data and code pointers add_named_global(name->name, (void*)(uintptr_t)addr); } template -static inline void add_named_global(StringRef name, T *addr) +static inline void add_named_global(StringRef name, T *addr JL_CANSAFEPOINT) { // cast through integer to avoid c++ pedantic warning about casting between // data and code pointers @@ -854,8 +854,9 @@ static const auto jlcheckassign_func = new JuliaFunction<>{ XSTR(jl_checked_assignment), [](LLVMContext &C) { auto T_pjlvalue = JuliaType::get_pjlvalue_ty(C); + auto T_prjlvalue = JuliaType::get_prjlvalue_ty(C); return FunctionType::get(getVoidTy(C), - {T_pjlvalue, T_pjlvalue, T_pjlvalue, PointerType::get(C, AddressSpace::CalleeRooted)}, false); }, + {T_pjlvalue, T_pjlvalue, T_pjlvalue, T_prjlvalue}, false); }, nullptr, }; static const auto jlcheckreplace_func = new JuliaFunction<>{ @@ -882,7 +883,7 @@ static const auto jlcheckswap_func = new JuliaFunction<>{ auto T_pjlvalue = JuliaType::get_pjlvalue_ty(C); auto T_prjlvalue = JuliaType::get_prjlvalue_ty(C); return FunctionType::get(T_prjlvalue, - {T_pjlvalue, T_pjlvalue, T_pjlvalue, PointerType::get(C, AddressSpace::CalleeRooted)}, false); }, + {T_pjlvalue, T_pjlvalue, T_pjlvalue, T_prjlvalue}, false); }, nullptr, }; static const auto jlcheckassignonce_func = new JuliaFunction<>{ @@ -891,7 +892,7 @@ static const auto jlcheckassignonce_func = new JuliaFunction<>{ auto T_pjlvalue = JuliaType::get_pjlvalue_ty(C); auto T_prjlvalue = JuliaType::get_prjlvalue_ty(C); return FunctionType::get(T_prjlvalue, - {T_pjlvalue, T_pjlvalue, T_pjlvalue, PointerType::get(C, AddressSpace::CalleeRooted)}, false); }, + {T_pjlvalue, T_pjlvalue, T_pjlvalue, T_prjlvalue}, false); }, nullptr, }; static const auto jldeclareglobal_func = new JuliaFunction<>{ @@ -1668,28 +1669,28 @@ static bool allpointers(jl_datatype_t *typ) return allpointers(jl_datatype_size(typ), typ->layout->npointers); } -static unsigned get_box_tindex(jl_datatype_t *jt, jl_value_t *ut); +static unsigned get_box_tindex(jl_datatype_t *jt, jl_value_t *ut) JL_CANSAFEPOINT; // these queries are usually related, but we split them out here // for convenience and clarity (and because it changes the calling convention) // n.b. this must include jl_is_datatype_singleton (ghostType) and primitive types -static bool deserves_stack(jl_value_t* t) +static bool deserves_stack(jl_value_t* t) JL_CANSAFEPOINT { if (!jl_is_concrete_immutable(t)) return false; jl_datatype_t *dt = (jl_datatype_t*)t; return jl_is_datatype_singleton(dt) || jl_datatype_isinlinealloc(dt, /* (require) pointerfree */ 0); } -static bool deserves_argbox(jl_value_t* t) +static bool deserves_argbox(jl_value_t* t) JL_CANSAFEPOINT { return !deserves_stack(t); } -static bool deserves_retbox(jl_value_t* t) +static bool deserves_retbox(jl_value_t* t) JL_CANSAFEPOINT { return deserves_argbox(t); } -static bool deserves_unionbox(jl_value_t* t) +static bool deserves_unionbox(jl_value_t* t) JL_CANSAFEPOINT { return !deserves_stack(t); } @@ -1699,7 +1700,7 @@ static bool deserves_sret(jl_value_t *dt, Type *T) return (size_t)jl_datatype_size(dt) > sizeof(void*) && !T->isFloatingPointTy() && !T->isVectorTy(); } static void union_alloca_type(jl_uniontype_t *ut, - bool &allunbox, size_t &nbytes, size_t &align, size_t &min_align, size_t &inline_roots); + bool &allunbox, size_t &nbytes, size_t &align, size_t &min_align, size_t &inline_roots) JL_CANSAFEPOINT; // Alias Analysis Info (analogous to llvm::AAMDNodes) namespace { @@ -1936,7 +1937,7 @@ struct jl_cgval_t { assert(jl_is_datatype(typ)); assert(constant); } - jl_cgval_t(const jl_cgval_t &v, jl_value_t *typ, Value *tindex) : // copy constructor with new type + jl_cgval_t(const jl_cgval_t &v, jl_value_t *typ, Value *tindex) JL_CANSAFEPOINT : // copy constructor with new type V(v.V), Vboxed(v.Vboxed), TIndex(tindex), @@ -2140,7 +2141,8 @@ class jl_codectx_t { }; } // anonymous namespace -static void jl_temporary_root(jl_codectx_t &ctx, jl_value_t *val); +static void jl_temporary_root(jl_codegen_output_t &ctx, jl_value_t *val) JL_CANSAFEPOINT; +static void jl_temporary_root(jl_codectx_t &ctx, jl_value_t *val) JL_CANSAFEPOINT; jl_aliasinfo_t::jl_aliasinfo_t(jl_codectx_t &ctx, Region r, MDNode *tbaa): tbaa(tbaa), tbaa_struct(nullptr) { MDNode *alias_scope = nullptr; @@ -2213,11 +2215,11 @@ jl_aliasinfo_t jl_aliasinfo_t::fromTBAA(jl_codectx_t &ctx, MDNode *tbaa) { return jl_aliasinfo_t(ctx, Region::unknown, tbaa); } -static Type *julia_type_to_llvm(jl_codectx_t &ctx, jl_value_t *jt, bool *isboxed = NULL); -static jl_cgval_t emit_expr(jl_codectx_t &ctx, jl_value_t *expr, ssize_t ssaval = -1); -static jl_cgval_t emit_checked_var(jl_codectx_t &ctx, Value *bp, jl_sym_t *name, jl_value_t *scope, bool isvol, MDNode *tbaa); -static jl_cgval_t emit_sparam(jl_codectx_t &ctx, size_t i); -static Value *emit_condition(jl_codectx_t &ctx, const jl_cgval_t &condV, const Twine &msg); +static Type *julia_type_to_llvm(jl_codectx_t &ctx, jl_value_t *jt, bool *isboxed = NULL) JL_CANSAFEPOINT; +static jl_cgval_t emit_expr(jl_codectx_t &ctx, jl_value_t *expr, ssize_t ssaval = -1) JL_CANSAFEPOINT; +static jl_cgval_t emit_checked_var(jl_codectx_t &ctx, Value *bp, jl_sym_t *name, jl_value_t *scope, bool isvol, MDNode *tbaa) JL_CANSAFEPOINT; +static jl_cgval_t emit_sparam(jl_codectx_t &ctx, size_t i) JL_CANSAFEPOINT; +static Value *emit_condition(jl_codectx_t &ctx, const jl_cgval_t &condV, const Twine &msg) JL_CANSAFEPOINT; static Value *get_current_task(jl_codectx_t &ctx); static Value *get_current_ptls(jl_codectx_t &ctx); static Value *get_tls_world_age(jl_codectx_t &ctx); @@ -2225,17 +2227,17 @@ static Value *get_scope_field(jl_codectx_t &ctx); static Value *get_tls_world_age_field(jl_codectx_t &ctx); static void CreateTrap(IRBuilder<> &irbuilder, bool create_new_block = true); static CallInst *emit_jlcall(jl_codectx_t &ctx, Value *theFptr, Value *theF, - ArrayRef args, size_t nargs, JuliaFunction<> *trampoline); + ArrayRef args, size_t nargs, JuliaFunction<> *trampoline) JL_CANSAFEPOINT; static CallInst *emit_jlcall(jl_codectx_t &ctx, JuliaFunction<> *theFptr, Value *theF, - ArrayRef args, size_t nargs, JuliaFunction<> *trampoline); + ArrayRef args, size_t nargs, JuliaFunction<> *trampoline) JL_CANSAFEPOINT; static Value *emit_f_is(jl_codectx_t &ctx, const jl_cgval_t &arg1, const jl_cgval_t &arg2, - Value *nullcheck1 = nullptr, Value *nullcheck2 = nullptr); -static jl_cgval_t emit_new_struct(jl_codectx_t &ctx, jl_value_t *ty, size_t nargs, ArrayRef argv, bool is_promotable=false); -static jl_cgval_t emit_invoke(jl_codectx_t &ctx, const jl_cgval_t &lival, ArrayRef argv, size_t nargs, jl_value_t *rt, bool always_inline); + Value *nullcheck1 = nullptr, Value *nullcheck2 = nullptr) JL_CANSAFEPOINT; +static jl_cgval_t emit_new_struct(jl_codectx_t &ctx, jl_value_t *ty, size_t nargs, ArrayRef argv, bool is_promotable=false) JL_CANSAFEPOINT; +static jl_cgval_t emit_invoke(jl_codectx_t &ctx, const jl_cgval_t &lival, ArrayRef argv, size_t nargs, jl_value_t *rt, bool always_inline) JL_CANSAFEPOINT; -static Value *literal_pointer_val(jl_codectx_t &ctx, jl_value_t *p); -static unsigned julia_alignment(jl_value_t *jt); -static void recombine_value(jl_codectx_t &ctx, const jl_cgval_t &x, Value *dst, jl_aliasinfo_t const &dst_ai, Align alignment, bool isVolatile); +static Value *literal_pointer_val(jl_codectx_t &ctx, jl_value_t *p) JL_CANSAFEPOINT; +static unsigned julia_alignment(jl_value_t *jt) JL_CANSAFEPOINT; +static void recombine_value(jl_codectx_t &ctx, const jl_cgval_t &x, Value *dst, jl_aliasinfo_t const &dst_ai, Align alignment, bool isVolatile) JL_CANSAFEPOINT; static GlobalVariable *prepare_global_in(Module *M, JuliaVariable *G) { @@ -2410,7 +2412,7 @@ static inline jl_cgval_t ghostValue(jl_codectx_t &ctx, jl_datatype_t *typ) return ghostValue(ctx, (jl_value_t*)typ); } -static inline jl_cgval_t mark_julia_const(jl_codectx_t &ctx, jl_value_t *jv) +static inline jl_cgval_t mark_julia_const(jl_codectx_t &ctx, jl_value_t *jv) JL_CANSAFEPOINT { jl_value_t *typ; if (jl_is_type(jv) && jv != jl_bottom_type) { @@ -2456,7 +2458,7 @@ static Value *zext_struct(jl_codectx_t &ctx, Value *V); // TODO: in the future, assume all callers will handle the interior pointers separately, and have // have zext_struct strip them out, so we aren't saving those to the stack here causing shadow stores // to be necessary too -static inline jl_cgval_t value_to_pointer(jl_codectx_t &ctx, Value *v, jl_value_t *typ, Value *tindex) +static inline jl_cgval_t value_to_pointer(jl_codectx_t &ctx, Value *v, jl_value_t *typ, Value *tindex) JL_CANSAFEPOINT { Value *loc; v = zext_struct(ctx, v); @@ -2476,7 +2478,7 @@ static inline jl_cgval_t value_to_pointer(jl_codectx_t &ctx, Value *v, jl_value_ } return mark_julia_slot(loc, typ, tindex, ctx.tbaa().tbaa_stack); } -static inline jl_cgval_t value_to_pointer(jl_codectx_t &ctx, const jl_cgval_t &v) +static inline jl_cgval_t value_to_pointer(jl_codectx_t &ctx, const jl_cgval_t &v) JL_CANSAFEPOINT { if (!v.inline_roots.empty()) { if (allpointers((jl_datatype_t*)v.typ)) @@ -2511,7 +2513,7 @@ static inline jl_cgval_t value_to_pointer(jl_codectx_t &ctx, const jl_cgval_t &v return value_to_pointer(ctx, v.V, v.typ, v.TIndex); } -static inline jl_cgval_t mark_julia_type(jl_codectx_t &ctx, Value *v, bool isboxed, jl_value_t *typ) +static inline jl_cgval_t mark_julia_type(jl_codectx_t &ctx, Value *v, bool isboxed, jl_value_t *typ) JL_CANSAFEPOINT { if (jl_is_some_Type(typ)) { if (is_uniquerep_Type(typ)) { @@ -2542,16 +2544,16 @@ static inline jl_cgval_t mark_julia_type(jl_codectx_t &ctx, Value *v, bool isbox return jl_cgval_t(v, typ, NULL); } -static inline jl_cgval_t mark_julia_type(jl_codectx_t &ctx, Value *v, bool isboxed, jl_datatype_t *typ) +static inline jl_cgval_t mark_julia_type(jl_codectx_t &ctx, Value *v, bool isboxed, jl_datatype_t *typ) JL_CANSAFEPOINT { return mark_julia_type(ctx, v, isboxed, (jl_value_t*)typ); } -static Value *emit_exactly_isa(jl_codectx_t &ctx, const jl_cgval_t &arg, jl_datatype_t *dt, bool could_be_null=false); -static jl_cgval_t convert_julia_type_to_union(jl_codectx_t &ctx, const jl_cgval_t &v, jl_value_t *typ, bool allow_mismatch); +static Value *emit_exactly_isa(jl_codectx_t &ctx, const jl_cgval_t &arg, jl_datatype_t *dt, bool could_be_null=false) JL_CANSAFEPOINT; +static jl_cgval_t convert_julia_type_to_union(jl_codectx_t &ctx, const jl_cgval_t &v, jl_value_t *typ, bool allow_mismatch) JL_CANSAFEPOINT; // see if it might be profitable (and cheap) to change the type of v to typ, -static inline jl_cgval_t update_julia_type(jl_codectx_t &ctx, const jl_cgval_t &v, jl_value_t *typ, bool allow_mismatch=false) +static inline jl_cgval_t update_julia_type(jl_codectx_t &ctx, const jl_cgval_t &v, jl_value_t *typ, bool allow_mismatch=false) JL_CANSAFEPOINT { if (typ == (jl_value_t*)jl_typeofbottom_type) return ghostValue(ctx, typ); // normalize TypeofBottom to Type{Union{}} @@ -2763,7 +2765,7 @@ static jl_cgval_t convert_julia_type_to_union(jl_codectx_t &ctx, const jl_cgval_ unsigned counter = 0; for_each_uniontype_small( // for each old union-split value - [&](unsigned idx, jl_datatype_t *jt) { + [&](unsigned idx, jl_datatype_t *jt) JL_CANSAFEPOINT { unsigned new_idx = get_box_tindex(jt, typ); bool t; if (new_idx) { @@ -2873,7 +2875,7 @@ static jl_cgval_t convert_julia_type_to_union(jl_codectx_t &ctx, const jl_cgval_ // We lazily create a BB for this, once we decide that we // actually need it. (similar to compute_box_tindex) Value *union_box_dt = NULL; - auto maybe_setup_union_isa = [&]() { + auto maybe_setup_union_isa = [&]() JL_CANSAFEPOINT { if (!union_isaBB) { union_isaBB = BasicBlock::Create(ctx.builder.getContext(), "union_isa", ctx.f); ctx.builder.SetInsertPoint(union_isaBB); @@ -2887,7 +2889,7 @@ static jl_cgval_t convert_julia_type_to_union(jl_codectx_t &ctx, const jl_cgval_ unsigned counter = 0; for_each_uniontype_small( // for each new union-split value - [&](unsigned idx, jl_datatype_t *jt) { + [&](unsigned idx, jl_datatype_t *jt) JL_CANSAFEPOINT { unsigned old_idx = v.TIndex ? get_box_tindex(jt, v.typ) : 0; if (old_idx == 0 && jl_subtype((jl_value_t*)jt, v.typ)) { // present, but didn't handle this item before, select its new union index @@ -2908,7 +2910,7 @@ static jl_cgval_t convert_julia_type_to_union(jl_codectx_t &ctx, const jl_cgval_ unsigned counter = 0; for_each_uniontype_small( // for each new union-split value - [&](unsigned idx, jl_datatype_t *jt) { + [&](unsigned idx, jl_datatype_t *jt) JL_CANSAFEPOINT { unsigned old_idx = v.TIndex ? get_box_tindex(jt, v.typ) : 0; if (old_idx == 0) { if (jl_datatype_layout(jt)->npointers) { @@ -2972,7 +2974,7 @@ static jl_cgval_t convert_julia_type_to_union(jl_codectx_t &ctx, const jl_cgval_ for_each_uniontype_small( // for each new union-split value // n.b. this assumes that split_union_into has the same on-stack format (minus roots) as the un-split value - [&](unsigned idx, jl_datatype_t *jt) { + [&](unsigned idx, jl_datatype_t *jt) JL_CANSAFEPOINT { unsigned old_idx = v.TIndex ? get_box_tindex(jt, v.typ) : 0; if (old_idx == 0) { auto npointers = jl_datatype_layout(jt)->npointers; @@ -3113,7 +3115,7 @@ void jl_init_function(Function *F, const jl_codegen_output_t ¶ms) JL_NOTSAFE F->addFnAttrs(attr); } -static bool uses_specsig(jl_value_t *sig, bool needsparams, jl_value_t *rettype, bool prefer_specsig) +static bool uses_specsig(jl_value_t *sig, bool needsparams, jl_value_t *rettype, bool prefer_specsig) JL_CANSAFEPOINT { if (needsparams) return false; @@ -3155,7 +3157,7 @@ static bool uses_specsig(jl_value_t *sig, bool needsparams, jl_value_t *rettype, return false; // jlcall sig won't require any box allocations } -static std::pair uses_specsig(jl_value_t *abi, jl_method_instance_t *lam, jl_value_t *rettype, bool prefer_specsig) +static std::pair uses_specsig(jl_value_t *abi, jl_method_instance_t *lam, jl_value_t *rettype, bool prefer_specsig) JL_CANSAFEPOINT { bool needsparams = false; if (jl_is_method(lam->def.method)) { @@ -3210,7 +3212,7 @@ static void mallocVisitLine(jl_codectx_t &ctx, StringRef filename, int line, Val // --- constant determination --- -static jl_value_t *static_apply_type(jl_codectx_t &ctx, ArrayRef args, size_t nargs) +static jl_value_t *static_apply_type(jl_codectx_t &ctx, ArrayRef args, size_t nargs) JL_CANSAFEPOINT { assert(nargs > 1); SmallVector v(nargs); @@ -3242,7 +3244,7 @@ static void emit_depwarn_check(jl_codectx_t &ctx, jl_binding_t *b) // try to statically evaluate, NULL if not possible. note that this may allocate, and as // such the resulting value should not be embedded directly in the generated code. -static jl_value_t *static_eval(jl_codectx_t &ctx, jl_value_t *ex) +static jl_value_t *static_eval(jl_codectx_t &ctx, jl_value_t *ex) JL_CANSAFEPOINT { if (jl_is_symbol(ex)) { jl_sym_t *sym = (jl_sym_t*)ex; @@ -3533,7 +3535,7 @@ static void jl_temporary_root(jl_codectx_t &ctx, jl_value_t *val) // --- generating function calls --- -static jl_cgval_t emit_globalref_runtime(jl_codectx_t &ctx, jl_binding_t *bnd, jl_module_t *mod, jl_sym_t *name) +static jl_cgval_t emit_globalref_runtime(jl_codectx_t &ctx, jl_binding_t *bnd, jl_module_t *mod, jl_sym_t *name) JL_CANSAFEPOINT { Value *bp = julia_binding_gv(ctx, bnd); Value *v = ctx.builder.CreateCall(prepare_call(jlgetbindingvalue_func), { bp }); @@ -3565,7 +3567,7 @@ static bool ci_has_binding_edge(jl_code_instance_t *ci, jl_binding_t *bnd) return false; } -static jl_cgval_t emit_globalref(jl_codectx_t &ctx, jl_module_t *mod, jl_sym_t *name, AtomicOrdering order, bool from_literal_globalref = true) +static jl_cgval_t emit_globalref(jl_codectx_t &ctx, jl_module_t *mod, jl_sym_t *name, AtomicOrdering order, bool from_literal_globalref = true) JL_CANSAFEPOINT { jl_binding_t *bnd = jl_get_module_binding(mod, name, 1); struct restriction_kind_pair rkp = { NULL, NULL, PARTITION_KIND_GUARD, 0 }; @@ -3618,7 +3620,7 @@ static jl_cgval_t emit_globalref(jl_codectx_t &ctx, jl_module_t *mod, jl_sym_t * static jl_cgval_t emit_globalop(jl_codectx_t &ctx, jl_module_t *mod, jl_sym_t *sym, jl_cgval_t rval, const jl_cgval_t &cmp, AtomicOrdering Order, AtomicOrdering FailOrder, StoreKind op, - const jl_cgval_t *modifyop, bool alloc) + const jl_cgval_t *modifyop, bool alloc) JL_CANSAFEPOINT { jl_binding_t *bnd = jl_get_module_binding(mod, sym, 1); jl_binding_partition_t *bpart = jl_get_binding_partition_all(bnd, ctx.min_world, ctx.max_world); @@ -3668,7 +3670,7 @@ static jl_cgval_t emit_globalop(jl_codectx_t &ctx, jl_module_t *mod, jl_sym_t *s switch (op) { case StoreKind::Set: ctx.builder.CreateCall(prepare_call(jlcheckassign_func), - { bp, m, s, mark_callee_rooted(ctx, boxed(ctx, rval)) }); + { bp, m, s, boxed(ctx, rval) }); return rval; case StoreKind::Replace: { Value *r = ctx.builder.CreateCall(prepare_call(jlcheckreplace_func), @@ -3677,7 +3679,7 @@ static jl_cgval_t emit_globalop(jl_codectx_t &ctx, jl_module_t *mod, jl_sym_t *s } case StoreKind::Swap: { Value *r = ctx.builder.CreateCall(prepare_call(jlcheckswap_func), - { bp, m, s, mark_callee_rooted(ctx, boxed(ctx, rval)) }); + { bp, m, s, boxed(ctx, rval) }); return mark_julia_type(ctx, r, true, jl_any_type); } case StoreKind::Modify: { @@ -3687,7 +3689,7 @@ static jl_cgval_t emit_globalop(jl_codectx_t &ctx, jl_module_t *mod, jl_sym_t *s } case StoreKind::SetOnce: { Value *r = ctx.builder.CreateCall(prepare_call(jlcheckassignonce_func), - { bp, m, s, mark_callee_rooted(ctx, boxed(ctx, rval)) }); + { bp, m, s, boxed(ctx, rval) }); return mark_julia_type(ctx, r, true, jl_bool_type); } case StoreKind::Unset: @@ -3697,7 +3699,7 @@ static jl_cgval_t emit_globalop(jl_codectx_t &ctx, jl_module_t *mod, jl_sym_t *s } static Value *emit_box_compare(jl_codectx_t &ctx, const jl_cgval_t &arg1, const jl_cgval_t &arg2, - Value *nullcheck1, Value *nullcheck2) + Value *nullcheck1, Value *nullcheck2) JL_CANSAFEPOINT { ++EmittedBoxCompares; if (jl_pointer_egal(arg1.typ) || jl_pointer_egal(arg2.typ)) { @@ -3707,17 +3709,17 @@ static Value *emit_box_compare(jl_codectx_t &ctx, const jl_cgval_t &arg1, const if (!arg1.TIndex && !arg2.TIndex) nullcheck1 = nullcheck2 = nullptr; } - return emit_nullcheck_guard2(ctx, nullcheck1, nullcheck2, [&] { + return emit_nullcheck_guard2(ctx, nullcheck1, nullcheck2, [&] () JL_CANSAFEPOINT { Value *varg1 = decay_derived(ctx, boxed(ctx, arg1)); Value *varg2 = decay_derived(ctx, boxed(ctx, arg2)); if (jl_pointer_egal(arg1.typ) || jl_pointer_egal(arg2.typ)) { return ctx.builder.CreateICmpEQ(varg1, varg2); } Value *neq = ctx.builder.CreateICmpNE(varg1, varg2); - return emit_guarded_test(ctx, neq, true, [&] { + return emit_guarded_test(ctx, neq, true, [&] () JL_CANSAFEPOINT { Value *dtarg = emit_typeof(ctx, arg1, false, true); Value *dt_eq = ctx.builder.CreateICmpEQ(dtarg, emit_typeof(ctx, arg2, false, true)); - return emit_guarded_test(ctx, dt_eq, false, [&] { + return emit_guarded_test(ctx, dt_eq, false, [&] () { return ctx.builder.CreateTrunc(ctx.builder.CreateCall(prepare_call(jlegalx_func), {varg1, varg2, dtarg}), getInt1Ty(ctx.builder.getContext())); }); @@ -3725,9 +3727,9 @@ static Value *emit_box_compare(jl_codectx_t &ctx, const jl_cgval_t &arg1, const }); } -static Value *emit_bits_compare(jl_codectx_t &ctx, const jl_cgval_t &arg1, const jl_cgval_t &arg2); +static Value *emit_bits_compare(jl_codectx_t &ctx, const jl_cgval_t &arg1, const jl_cgval_t &arg2) JL_CANSAFEPOINT; -static Value *emit_bitsunion_compare(jl_codectx_t &ctx, const jl_cgval_t &arg1, const jl_cgval_t &arg2) +static Value *emit_bitsunion_compare(jl_codectx_t &ctx, const jl_cgval_t &arg1, const jl_cgval_t &arg2) JL_CANSAFEPOINT { ++EmittedBitsUnionCompares; assert(jl_egal(arg1.typ, arg2.typ) && arg1.TIndex && arg2.TIndex && jl_is_uniontype(arg1.typ) && "unimplemented"); @@ -3747,7 +3749,7 @@ static Value *emit_bitsunion_compare(jl_codectx_t &ctx, const jl_cgval_t &arg1, phi->addIncoming(ConstantInt::get(getInt1Ty(ctx.builder.getContext()), 0), switchInst->getParent()); unsigned counter = 0; bool allunboxed = for_each_uniontype_small( - [&](unsigned idx, jl_datatype_t *jt) { + [&](unsigned idx, jl_datatype_t *jt) JL_CANSAFEPOINT { BasicBlock *tempBB = BasicBlock::Create(ctx.builder.getContext(), "unionbits_is", ctx.f); ctx.builder.SetInsertPoint(tempBB); switchInst->addCase(ConstantInt::get(getInt8Ty(ctx.builder.getContext()), idx), tempBB); @@ -3911,11 +3913,11 @@ static Value *emit_f_is(jl_codectx_t &ctx, const jl_cgval_t &arg1, const jl_cgva // comparing to a singleton object, special case for value `jl_bottom_type` // since it is normalized to `::Type{Union{}}` instead... if (arg1.TIndex) - return emit_nullcheck_guard(ctx, nullcheck1, [&] { + return emit_nullcheck_guard(ctx, nullcheck1, [&] () JL_CANSAFEPOINT { return emit_exactly_isa(ctx, arg1, (jl_datatype_t*)rt2); // rt2 is a singleton type }); if (arg2.TIndex) - return emit_nullcheck_guard(ctx, nullcheck2, [&] { + return emit_nullcheck_guard(ctx, nullcheck2, [&] () JL_CANSAFEPOINT { return emit_exactly_isa(ctx, arg2, (jl_datatype_t*)rt1); // rt1 is a singleton type }); if (!(arg1.isboxed || arg1.constant) || !(arg2.isboxed || arg2.constant)) @@ -3940,7 +3942,7 @@ static Value *emit_f_is(jl_codectx_t &ctx, const jl_cgval_t &arg1, const jl_cgva bool justbits1 = jl_is_concrete_immutable(rt1) && !jl_is_kind(rt1); bool justbits2 = jl_is_concrete_immutable(rt2) && !jl_is_kind(rt2); if (justbits1 || justbits2) { // whether this type is unique'd by value - return emit_nullcheck_guard2(ctx, nullcheck1, nullcheck2, [&] () -> Value* { + return emit_nullcheck_guard2(ctx, nullcheck1, nullcheck2, [&] () JL_CANSAFEPOINT -> Value* { jl_datatype_t *typ = (jl_datatype_t*)(justbits1 ? rt1 : rt2); if (typ == jl_bool_type) { // aka jl_pointer_egal // some optimizations for bool, since pointer comparison may be better @@ -3975,7 +3977,7 @@ static Value *emit_f_is(jl_codectx_t &ctx, const jl_cgval_t &arg1, const jl_cgva // one of these isn't union, or when the union can be pointer if (arg1.TIndex && arg2.TIndex && jl_egal(arg1.typ, arg2.typ) && jl_is_uniontype(arg1.typ) && is_uniontype_allunboxed(arg1.typ)) - return emit_nullcheck_guard2(ctx, nullcheck1, nullcheck2, [&] { + return emit_nullcheck_guard2(ctx, nullcheck1, nullcheck2, [&] () JL_CANSAFEPOINT { return emit_bitsunion_compare(ctx, arg1, arg2); }); @@ -3983,7 +3985,7 @@ static Value *emit_f_is(jl_codectx_t &ctx, const jl_cgval_t &arg1, const jl_cgva } static bool emit_f_opglobal(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, - ArrayRef argv, size_t nargs, const jl_cgval_t *modifyop) + ArrayRef argv, size_t nargs, const jl_cgval_t *modifyop) JL_CANSAFEPOINT { StoreKind op; if (f == BUILTIN(setglobal)) @@ -4058,7 +4060,7 @@ static bool emit_f_opglobal(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, } static bool emit_f_opfield(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, - ArrayRef argv, size_t nargs, const jl_cgval_t *modifyop) + ArrayRef argv, size_t nargs, const jl_cgval_t *modifyop) JL_CANSAFEPOINT { ++EmittedOpfields; StoreKind op; @@ -4177,7 +4179,7 @@ static bool emit_f_opfield(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, return false; } -static jl_cgval_t emit_isdefinedglobal(jl_codectx_t &ctx, jl_module_t *modu, jl_sym_t *name, int allow_import, enum jl_memory_order order) +static jl_cgval_t emit_isdefinedglobal(jl_codectx_t &ctx, jl_module_t *modu, jl_sym_t *name, int allow_import, enum jl_memory_order order) JL_CANSAFEPOINT { jl_binding_t *bnd = allow_import ? jl_get_binding(modu, name) : jl_get_module_binding(modu, name, 0); struct restriction_kind_pair rkp = { NULL, NULL, PARTITION_KIND_GUARD, 0 }; @@ -4205,7 +4207,7 @@ static jl_cgval_t emit_isdefinedglobal(jl_codectx_t &ctx, jl_module_t *modu, jl_ } static bool emit_f_opmemory(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, - ArrayRef argv, size_t nargs, const jl_cgval_t *modifyop) + ArrayRef argv, size_t nargs, const jl_cgval_t *modifyop) JL_CANSAFEPOINT { StoreKind op; if (f == BUILTIN(memoryrefunset)) @@ -4424,13 +4426,13 @@ static jl_llvm_functions_t jl_code_info_t *src, jl_value_t *abi, jl_value_t *jlrettype, - jl_code_instance_t *codeinst = nullptr); + jl_code_instance_t *codeinst = nullptr) JL_CANSAFEPOINT; -static void emit_hasnofield_error_ifnot(jl_codectx_t &ctx, Value *ok, jl_datatype_t *type, jl_cgval_t name); +static void emit_hasnofield_error_ifnot(jl_codectx_t &ctx, Value *ok, jl_datatype_t *type, jl_cgval_t name) JL_CANSAFEPOINT; static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, ArrayRef argv, size_t nargs, jl_value_t *rt, - jl_expr_t *ex, bool is_promotable) + jl_expr_t *ex, bool is_promotable) JL_CANSAFEPOINT // returns true if the call has been handled { ++EmittedBuiltinCalls; @@ -5473,7 +5475,7 @@ static CallInst *emit_jlcall(jl_codectx_t &ctx, JuliaFunction<> *theFptr, Value return emit_jlcall(ctx, prepare_call(theFptr), theF, argv, nargs, trampoline); } -static jl_cgval_t emit_call_specfun_other(jl_codectx_t &ctx, bool is_opaque_closure, jl_value_t *specTypes, jl_value_t *jlretty, jl_returninfo_t &returninfo, ArrayRef argv, size_t nargs) +static jl_cgval_t emit_call_specfun_other(jl_codectx_t &ctx, bool is_opaque_closure, jl_value_t *specTypes, jl_value_t *jlretty, jl_returninfo_t &returninfo, ArrayRef argv, size_t nargs) JL_CANSAFEPOINT { ++EmittedSpecfunCalls; // emit specialized call site @@ -5627,7 +5629,7 @@ static jl_cgval_t emit_call_specfun_other(jl_codectx_t &ctx, bool is_opaque_clos static jl_cgval_t emit_call_specfun_other(jl_codectx_t &ctx, bool is_opaque_closure, jl_value_t *specTypes, jl_value_t *jlretty, llvm::Value *callee, StringRef specFunctionObject, ArrayRef argv, size_t nargs, jl_returninfo_t::CallingConv *cc, unsigned *nreturn_roots, jl_value_t *inferred_retty, - std::optional effects = std::nullopt) + std::optional effects = std::nullopt) JL_CANSAFEPOINT { ++EmittedSpecfunCalls; // emit specialized call site @@ -5642,7 +5644,7 @@ static jl_cgval_t emit_call_specfun_other(jl_codectx_t &ctx, bool is_opaque_clos } static jl_cgval_t emit_call_specfun_other(jl_codectx_t &ctx, jl_method_instance_t *mi, jl_value_t *jlretty, StringRef specFunctionObject, - ArrayRef argv, size_t nargs, jl_returninfo_t::CallingConv *cc, unsigned *return_roots, jl_value_t *inferred_retty) + ArrayRef argv, size_t nargs, jl_returninfo_t::CallingConv *cc, unsigned *return_roots, jl_value_t *inferred_retty) JL_CANSAFEPOINT { bool is_opaque_closure = jl_is_method(mi->def.value) && mi->def.method->is_for_opaque_closure; return emit_call_specfun_other(ctx, is_opaque_closure, mi->specTypes, jlretty, NULL, @@ -5650,7 +5652,7 @@ static jl_cgval_t emit_call_specfun_other(jl_codectx_t &ctx, jl_method_instance_ } static jl_cgval_t emit_call_specfun_other(jl_codectx_t &ctx, jl_code_instance_t *ci, StringRef specFunctionObject, - ArrayRef argv, size_t nargs, jl_returninfo_t::CallingConv *cc, unsigned *return_roots, jl_value_t *inferred_retty) + ArrayRef argv, size_t nargs, jl_returninfo_t::CallingConv *cc, unsigned *return_roots, jl_value_t *inferred_retty) JL_CANSAFEPOINT { jl_method_instance_t *mi = jl_get_ci_mi(ci); bool is_opaque_closure = jl_is_method(mi->def.value) && mi->def.method->is_for_opaque_closure; @@ -5660,7 +5662,7 @@ static jl_cgval_t emit_call_specfun_other(jl_codectx_t &ctx, jl_code_instance_t } static jl_cgval_t emit_call_specfun_boxed(jl_codectx_t &ctx, jl_value_t *jlretty, StringRef specFunctionObject, - ArrayRef argv, size_t nargs, jl_value_t *inferred_retty) + ArrayRef argv, size_t nargs, jl_value_t *inferred_retty) JL_CANSAFEPOINT { Value *theFptr; theFptr = jl_Module->getOrInsertFunction(specFunctionObject, ctx.types().T_jlfunc).getCallee(); @@ -5669,7 +5671,7 @@ static jl_cgval_t emit_call_specfun_boxed(jl_codectx_t &ctx, jl_value_t *jlretty return update_julia_type(ctx, mark_julia_type(ctx, ret, true, jlretty), inferred_retty); } -static jl_cgval_t emit_invoke(jl_codectx_t &ctx, jl_expr_t *ex, jl_value_t *rt) +static jl_cgval_t emit_invoke(jl_codectx_t &ctx, jl_expr_t *ex, jl_value_t *rt) JL_CANSAFEPOINT { jl_value_t **args = jl_array_data(ex->args, jl_value_t*); size_t arglen = jl_array_dim0(ex->args); @@ -5768,7 +5770,7 @@ static jl_cgval_t emit_invoke(jl_codectx_t &ctx, const jl_cgval_t &lival, ArrayR return result; } -static jl_cgval_t emit_invoke_modify(jl_codectx_t &ctx, jl_expr_t *ex, jl_value_t *rt) +static jl_cgval_t emit_invoke_modify(jl_codectx_t &ctx, jl_expr_t *ex, jl_value_t *rt) JL_CANSAFEPOINT { ++EmittedInvokes; jl_value_t **args = jl_array_data(ex->args, jl_value_t*); @@ -5820,7 +5822,7 @@ static jl_cgval_t emit_invoke_modify(jl_codectx_t &ctx, jl_expr_t *ex, jl_value_ return mark_julia_type(ctx, callval, true, rt); } -static jl_cgval_t emit_specsig_oc_call(jl_codectx_t &ctx, jl_value_t *oc_type, jl_value_t *sigtype, MutableArrayRef argv /*n.b. this mutation is unusual */, size_t nargs) +static jl_cgval_t emit_specsig_oc_call(jl_codectx_t &ctx, jl_value_t *oc_type, jl_value_t *sigtype, MutableArrayRef argv /*n.b. this mutation is unusual */, size_t nargs) JL_CANSAFEPOINT { jl_datatype_t *oc_argt = (jl_datatype_t *)jl_tparam0(oc_type); jl_value_t *oc_rett = jl_tparam1(oc_type); @@ -5850,7 +5852,7 @@ static jl_cgval_t emit_specsig_oc_call(jl_codectx_t &ctx, jl_value_t *oc_type, j return r; } -static jl_cgval_t emit_call(jl_codectx_t &ctx, jl_expr_t *ex, jl_value_t *rt, bool is_promotable) +static jl_cgval_t emit_call(jl_codectx_t &ctx, jl_expr_t *ex, jl_value_t *rt, bool is_promotable) JL_CANSAFEPOINT { ++EmittedCalls; jl_value_t **args = jl_array_data(ex->args, jl_value_t*); @@ -5985,7 +5987,7 @@ static jl_cgval_t emit_sparam(jl_codectx_t &ctx, size_t i) return mark_julia_type(ctx, spval, true, jl_any_type); } -static jl_cgval_t emit_isdefined(jl_codectx_t &ctx, jl_value_t *sym, int allow_import) +static jl_cgval_t emit_isdefined(jl_codectx_t &ctx, jl_value_t *sym, int allow_import) JL_CANSAFEPOINT { Value *isnull = NULL; if (jl_is_slotnumber(sym) || jl_is_argument(sym)) { @@ -6036,7 +6038,7 @@ static jl_cgval_t emit_isdefined(jl_codectx_t &ctx, jl_value_t *sym, int allow_i return mark_julia_type(ctx, isnull, false, jl_bool_type); } -static jl_cgval_t emit_varinfo(jl_codectx_t &ctx, jl_varinfo_t &vi, jl_sym_t *varname) { +static jl_cgval_t emit_varinfo(jl_codectx_t &ctx, jl_varinfo_t &vi, jl_sym_t *varname) JL_CANSAFEPOINT { jl_cgval_t v; Value *isnull = NULL; if (vi.boxroot == NULL || vi.pTIndex != NULL) { @@ -6128,7 +6130,7 @@ static jl_cgval_t emit_varinfo(jl_codectx_t &ctx, jl_varinfo_t &vi, jl_sym_t *va return v; } -static jl_cgval_t emit_local(jl_codectx_t &ctx, jl_value_t *slotload) +static jl_cgval_t emit_local(jl_codectx_t &ctx, jl_value_t *slotload) JL_CANSAFEPOINT { size_t sl = jl_slot_number(slotload) - 1; jl_varinfo_t &vi = ctx.slots[sl]; @@ -6142,7 +6144,7 @@ static jl_cgval_t emit_local(jl_codectx_t &ctx, jl_value_t *slotload) return emit_varinfo(ctx, vi, sym); } -static void emit_vi_assignment_unboxed(jl_codectx_t &ctx, jl_varinfo_t &vi, Value *isboxed, const jl_cgval_t &rval_info) +static void emit_vi_assignment_unboxed(jl_codectx_t &ctx, jl_varinfo_t &vi, Value *isboxed, const jl_cgval_t &rval_info) JL_CANSAFEPOINT { if (vi.usedUndef) store_def_flag(ctx, vi, true); @@ -6177,7 +6179,7 @@ static void emit_vi_assignment_unboxed(jl_codectx_t &ctx, jl_varinfo_t &vi, Valu } } -static void emit_phinode_assign(jl_codectx_t &ctx, ssize_t idx, jl_value_t *r) +static void emit_phinode_assign(jl_codectx_t &ctx, ssize_t idx, jl_value_t *r) JL_CANSAFEPOINT { jl_value_t *ssavalue_types = (jl_value_t*)ctx.source->ssavaluetypes; jl_value_t *phiType = NULL; @@ -6307,7 +6309,7 @@ static void emit_phinode_assign(jl_codectx_t &ctx, ssize_t idx, jl_value_t *r) return; } -static void emit_ssaval_assign(jl_codectx_t &ctx, ssize_t ssaidx_0based, jl_value_t *r) +static void emit_ssaval_assign(jl_codectx_t &ctx, ssize_t ssaidx_0based, jl_value_t *r) JL_CANSAFEPOINT { assert(!ctx.ssavalue_assigned[ssaidx_0based]); if (jl_is_phinode(r)) { @@ -6340,7 +6342,7 @@ static void emit_ssaval_assign(jl_codectx_t &ctx, ssize_t ssaidx_0based, jl_valu ctx.ssavalue_assigned[ssaidx_0based] = true; } -static void emit_varinfo_assign(jl_codectx_t &ctx, jl_varinfo_t &vi, const jl_cgval_t &rhs, jl_value_t *l=NULL, bool allow_mismatch=false) +static void emit_varinfo_assign(jl_codectx_t &ctx, jl_varinfo_t &vi, const jl_cgval_t &rhs, jl_value_t *l=NULL, bool allow_mismatch=false) JL_CANSAFEPOINT { if (!vi.used || vi.value.typ == jl_bottom_type) return; @@ -6393,7 +6395,7 @@ static void emit_varinfo_assign(jl_codectx_t &ctx, jl_varinfo_t &vi, const jl_cg skip = ctx.builder.CreateNot(emit_exactly_isa(ctx, rhs, dt, true)); } } - emit_guarded_test(ctx, skip ? ctx.builder.CreateNot(skip) : nullptr, nullptr, [&] { + emit_guarded_test(ctx, skip ? ctx.builder.CreateNot(skip) : nullptr, nullptr, [&] () JL_CANSAFEPOINT { // internally this skips assignment if isboxed is true emit_vi_assignment_unboxed(ctx, vi, isboxed, rval_info); return nullptr; @@ -6408,7 +6410,7 @@ static void emit_varinfo_assign(jl_codectx_t &ctx, jl_varinfo_t &vi, const jl_cg return; } -static void emit_assignment(jl_codectx_t &ctx, jl_value_t *l, jl_value_t *r, ssize_t ssaval) +static void emit_assignment(jl_codectx_t &ctx, jl_value_t *l, jl_value_t *r, ssize_t ssaval) JL_CANSAFEPOINT { assert(!jl_is_ssavalue(l)); jl_cgval_t rval_info = emit_expr(ctx, r, ssaval); @@ -6441,7 +6443,7 @@ static void emit_assignment(jl_codectx_t &ctx, jl_value_t *l, jl_value_t *r, ssi // its memory location. } -static void emit_upsilonnode(jl_codectx_t &ctx, ssize_t phic, jl_value_t *val) +static void emit_upsilonnode(jl_codectx_t &ctx, ssize_t phic, jl_value_t *val) JL_CANSAFEPOINT { auto it = ctx.phic_slots.find(phic); if (it == ctx.phic_slots.end()) { @@ -6503,7 +6505,7 @@ static void emit_upsilonnode(jl_codectx_t &ctx, ssize_t phic, jl_value_t *val) // --- convert expression to code --- -static jl_cgval_t emit_cfunction(jl_codectx_t &ctx, jl_value_t *output_type, const jl_cgval_t &fexpr, jl_value_t *rt, jl_svec_t *argt); +static jl_cgval_t emit_cfunction(jl_codectx_t &ctx, jl_value_t *output_type, const jl_cgval_t &fexpr, jl_value_t *rt, jl_svec_t *argt) JL_CANSAFEPOINT; static Value *emit_condition(jl_codectx_t &ctx, const jl_cgval_t &condV, const Twine &msg) { @@ -6527,12 +6529,12 @@ static Value *emit_condition(jl_codectx_t &ctx, const jl_cgval_t &condV, const T return UndefValue::get(getInt1Ty(ctx.builder.getContext())); } -static Value *emit_condition(jl_codectx_t &ctx, jl_value_t *cond, const Twine &msg) +static Value *emit_condition(jl_codectx_t &ctx, jl_value_t *cond, const Twine &msg) JL_CANSAFEPOINT { return emit_condition(ctx, emit_expr(ctx, cond), msg); } -static void emit_stmtpos(jl_codectx_t &ctx, jl_value_t *expr, int ssaval_result) +static void emit_stmtpos(jl_codectx_t &ctx, jl_value_t *expr, int ssaval_result) JL_CANSAFEPOINT { if (jl_is_ssavalue(expr) && ssaval_result == -1) return; // value not used, no point in attempting codegen for it @@ -6631,7 +6633,7 @@ static void emit_stmtpos(jl_codectx_t &ctx, jl_value_t *expr, int ssaval_result) } } -static std::pair get_oc_function(jl_codectx_t &ctx, jl_method_t *closure_method, jl_tupletype_t *env_t, jl_tupletype_t *argt_typ, jl_value_t *rettype) +static std::pair get_oc_function(jl_codectx_t &ctx, jl_method_t *closure_method, jl_tupletype_t *env_t, jl_tupletype_t *argt_typ, jl_value_t *rettype) JL_CANSAFEPOINT { jl_svec_t *sig_args = NULL; jl_value_t *sigtype = NULL; @@ -7174,7 +7176,7 @@ static std::string get_function_name(bool specsig, bool needsparams, const char } static void gen_invoke_wrapper(jl_method_instance_t *lam, jl_value_t *abi, jl_value_t *jlretty, jl_value_t *declrt, jl_returninfo_t &f, unsigned nargs, int retarg, bool is_opaque_closure, StringRef funcName, - Module *M, jl_codegen_output_t &out); + Module *M, jl_codegen_output_t &out) JL_CANSAFEPOINT; Function *get_or_emit_fptr1(StringRef preal_decl, Module *M) { @@ -7253,7 +7255,7 @@ static Function *emit_modifyhelper(jl_codectx_t &ctx2, const jl_cgval_t &op, con } -static Function *emit_tojlinvoke(jl_code_instance_t *codeinst, Value *theFunc, jl_codegen_output_t &out) JL_NOTSAFEPOINT +static Function *emit_tojlinvoke(jl_code_instance_t *codeinst, Value *theFunc, jl_codegen_output_t &out) JL_CANSAFEPOINT { ++EmittedToJLInvokes; jl_codectx_t ctx(out, codeinst); @@ -7287,7 +7289,7 @@ static Function *emit_tojlinvoke(jl_code_instance_t *codeinst, Value *theFunc, j return f; } -Function *emit_tojlinvoke(jl_code_instance_t *codeinst, StringRef theFptrName, jl_codegen_output_t &out) JL_NOTSAFEPOINT +Function *emit_tojlinvoke(jl_code_instance_t *codeinst, StringRef theFptrName, jl_codegen_output_t &out) { Value *theFunc = nullptr; auto &M = out.get_module(); @@ -7297,7 +7299,7 @@ Function *emit_tojlinvoke(jl_code_instance_t *codeinst, StringRef theFptrName, j return emit_tojlinvoke(codeinst, theFunc, out); } -static jl_value_t *get_oc_type(jl_value_t *calltype, jl_value_t *rettype) JL_ALWAYS_LEAFTYPE +static jl_value_t *get_oc_type(jl_value_t *calltype, jl_value_t *rettype) JL_CANSAFEPOINT JL_ALWAYS_LEAFTYPE { jl_value_t *argtype = jl_argtype_without_function((jl_value_t*)calltype); JL_GC_PUSH1(&argtype); @@ -7316,7 +7318,7 @@ static void emit_specsig_to_specsig( jl_value_t *targetsig, jl_value_t *targetrt, jl_returninfo_t *targetspec, - jl_value_t *rettype_const) + jl_value_t *rettype_const) JL_CANSAFEPOINT { ++EmittedCFuncInvalidates; jl_codectx_t ctx(out, 0, 0); @@ -7495,7 +7497,7 @@ Function *emit_specsig_to_fptr1(jl_codegen_output_t &out, jl_code_instance_t *ci return spec_func; } -static void emit_fptr1_wrapper(Module *M, StringRef gf_thunk_name, Value *target, jl_value_t *rettype_const, jl_value_t *declrt, jl_value_t *jlrettype, jl_codegen_output_t &out) +static void emit_fptr1_wrapper(Module *M, StringRef gf_thunk_name, Value *target, jl_value_t *rettype_const, jl_value_t *declrt, jl_value_t *jlrettype, jl_codegen_output_t &out) JL_CANSAFEPOINT { Function *w = Function::Create(get_func_sig(M->getContext()), GlobalVariable::ExternalLinkage, gf_thunk_name, M); jl_init_function(w, out); @@ -7538,7 +7540,7 @@ static void emit_specsig_to_specsig( jl_value_t *targetsig, jl_value_t *targetrt, jl_returninfo_t *targetspec, - jl_value_t *rettype_const) + jl_value_t *rettype_const) JL_CANSAFEPOINT { jl_returninfo_t returninfo = get_specsig_function(out, M, nullptr, gf_thunk_name, calltype, rettype, is_for_opaque_closure); Function *gf_thunk = cast(returninfo.decl.getCallee()); @@ -7647,7 +7649,7 @@ std::string emit_abi_constreturn(jl_codegen_output_t &out, bool specsig, jl_code // if (last_world_v != jl_world_counter) // fptr = compute_new_fptr(&last_world_v) // return fptr() -static jl_cgval_t emit_abi_call(jl_codectx_t &ctx, jl_value_t *declrt, jl_value_t *sigt, ArrayRef inputargs, size_t nargs, Value *world_age_field) +static jl_cgval_t emit_abi_call(jl_codectx_t &ctx, jl_value_t *declrt, jl_value_t *sigt, ArrayRef inputargs, size_t nargs, Value *world_age_field) JL_CANSAFEPOINT { jl_cgval_t retval; if (sigt) { @@ -7684,7 +7686,7 @@ static jl_cgval_t emit_abi_call(jl_codectx_t &ctx, jl_value_t *declrt, jl_value_ world_v->setOrdering(AtomicOrdering::Monotonic); ctx.builder.CreateStore(world_v, world_age_field); Value *age_not_ok = ctx.builder.CreateICmpNE(last_world_v, world_v); - Value *target = emit_guarded_test(ctx, age_not_ok, callee, [&] { + Value *target = emit_guarded_test(ctx, age_not_ok, callee, [&] () { Function *getcaller = prepare_call(jlgetabiconverter_func); CallInst *cw = ctx.builder.CreateCall(getcaller, {get_current_task(ctx), cfuncdata}); cw->setAttributes(getcaller->getAttributes()); @@ -7723,7 +7725,7 @@ static Function *gen_cfun_wrapper( Module *into, jl_codegen_output_t &out, const function_sig_t &sig, jl_value_t *ff, const char *aliasname, jl_value_t *declrt, jl_value_t *sigt, - jl_unionall_t *unionall_env, jl_svec_t *sparam_vals, jl_array_t **closure_types) + jl_unionall_t *unionall_env, jl_svec_t *sparam_vals, jl_array_t **closure_types) JL_CANSAFEPOINT { ++GeneratedCFuncWrappers; // Generate a c-callable wrapper @@ -7905,7 +7907,7 @@ static Function *gen_cfun_wrapper( ctx.builder.SetInsertPoint(notanyBB); jl_cgval_t runtime_dt_val = mark_julia_type(ctx, runtime_dt, true, jl_any_type); Value *isrtboxed = // (!jl_is_datatype(runtime_dt) || !jl_is_concrete_datatype(runtime_dt) || jl_is_mutable_datatype(runtime_dt)) - emit_guarded_test(ctx, emit_exactly_isa(ctx, runtime_dt_val, jl_datatype_type), true, [&] { + emit_guarded_test(ctx, emit_exactly_isa(ctx, runtime_dt_val, jl_datatype_type), true, [&] () { return ctx.builder.CreateOr(ctx.builder.CreateNot(emit_isconcrete(ctx, runtime_dt)), emit_datatype_mutabl(ctx, runtime_dt)); }); ctx.builder.CreateCondBr(isrtboxed, boxedBB, unboxedBB); @@ -8602,7 +8604,7 @@ get_specsig_di(jl_codectx_t &ctx, jl_debugcache_t &debuginfo, jl_value_t *rt, jl } /* aka Core.Compiler.tuple_tfunc */ -static jl_datatype_t *compute_va_type(jl_value_t *sig, size_t nreq) +static jl_datatype_t *compute_va_type(jl_value_t *sig, size_t nreq) JL_CANSAFEPOINT { size_t nvargs = jl_nparams(sig)-nreq; jl_svec_t *tupargs = jl_alloc_svec(nvargs); @@ -9102,7 +9104,7 @@ static jl_llvm_functions_t // step 7. allocate local variables slots // must be in the first basic block for the llvm mem2reg pass to work - auto allocate_local = [&ctx, &dbuilder, &debugcache, topdebugloc, va, debug_enabled](jl_varinfo_t &varinfo, jl_sym_t *s, int i) { + auto allocate_local = [&ctx, &dbuilder, &debugcache, topdebugloc, va, debug_enabled](jl_varinfo_t &varinfo, jl_sym_t *s, int i) JL_CANSAFEPOINT { jl_value_t *jt = varinfo.value.typ; assert(!varinfo.boxroot); // variables shouldn't have memory locs already if (varinfo.value.constant) { @@ -9238,7 +9240,7 @@ static jl_llvm_functions_t } // step 8. move args into local variables - auto get_specsig_arg = [&](jl_value_t *argType, Type *llvmArgType, bool isboxed) { + auto get_specsig_arg = [&](jl_value_t *argType, Type *llvmArgType, bool isboxed) JL_CANSAFEPOINT { if (type_is_ghost(llvmArgType)) { // this argument is not actually passed return ghostValue(ctx, argType); } @@ -10052,7 +10054,7 @@ static jl_llvm_functions_t // must be careful to emit undef here (rather than a bitcast or // load of val) if the runtime type of val isn't phiType Value *isvalid = emit_isa_and_defined(ctx, val, phiType); - V = emit_guarded_test(ctx, isvalid, undef_value_for_type(VN->getType()), [&] { + V = emit_guarded_test(ctx, isvalid, undef_value_for_type(VN->getType()), [&] () JL_CANSAFEPOINT { return emit_unbox(ctx, VN->getType(), update_julia_type(ctx, val, phiType)); }); } @@ -10068,7 +10070,7 @@ static jl_llvm_functions_t SmallVector incomingroots(0); if (tracked) incomingroots.resize(tracked, Constant::getNullValue(ctx.types().T_prjlvalue)); - emit_guarded_test(ctx, isvalid, incomingroots, [&] { + emit_guarded_test(ctx, isvalid, incomingroots, [&] () JL_CANSAFEPOINT { jl_cgval_t typedval = update_julia_type(ctx, val, phiType); SmallVector mayberoots; if (typedval.typ != jl_bottom_type) { @@ -10317,30 +10319,30 @@ std::optional jl_emit_code( ret = emit_function(out, li, src, abi_at, abi_rt, codeinst); auto stream = *jl_ExecutionEngine->get_dump_emitted_mi_name_stream(); if (stream) { - jl_printf(stream, "%s\t", ret->specptr->getName().str().c_str()); + ios_printf(stream, "%s\t", ret->specptr->getName().str().c_str()); // NOTE: We print the Type Tuple without surrounding quotes, because the quotes // break CSV parsing if there are any internal quotes in the Type name (e.g. in // Symbol("...")). The \t delineator should be enough to ensure whitespace is // handled correctly. (And we don't need to worry about any tabs in the printed // string, because tabs are printed as "\t" by `show`.) jl_static_show(stream, li->specTypes); - jl_printf(stream, "\n"); + ios_printf(stream, "\n"); } } JL_CATCH { // Something failed! This is very, very bad. // Try to pretend that it isn't and attempt to recover. std::string mname = out.get_module().getModuleIdentifier(); - jl_printf((JL_STREAM*)STDERR_FILENO, "Internal error: encountered unexpected error during compilation of %s:\n", mname.c_str()); - jl_static_show((JL_STREAM*)STDERR_FILENO, jl_current_exception(jl_current_task)); - jl_printf((JL_STREAM*)STDERR_FILENO, "\n"); - jl_fprint_backtrace(ios_safe_stderr); + ios_printf(ios_stderr, "Internal error: encountered unexpected error during compilation of %s:\n", mname.c_str()); + jl_static_show((JL_STREAM*)ios_stderr, jl_current_exception(jl_current_task)); + ios_printf(ios_stderr, "\n"); + jl_fprint_backtrace(ios_stderr); } return ret; } -static jl_llvm_functions_t jl_emit_oc_wrapper(jl_codegen_output_t &out, jl_method_instance_t *mi, jl_value_t *rettype) +static jl_llvm_functions_t jl_emit_oc_wrapper(jl_codegen_output_t &out, jl_method_instance_t *mi, jl_value_t *rettype) JL_CANSAFEPOINT { jl_llvm_functions_t declarations{JL_INVOKE_ARGS}; if (uses_specsig(mi->specTypes, false, rettype, true)) { @@ -10422,9 +10424,7 @@ void emit_always_inline(jl_codegen_output_t &out, } jl_code_info_t *src = nullptr; - jl_task_t *ct = jl_current_task; // codegen may contain safepoints (such as jl_subtype calls) - int8_t gc_state = jl_gc_unsafe_enter(ct->ptls); out.safepoint_on_entry = false; JL_GC_PUSH1(&src); for (auto &[ci, api] : queue) { @@ -10467,7 +10467,6 @@ void emit_always_inline(jl_codegen_output_t &out, out.call_targets[{ci, api}].decl = decls.specptr; } JL_GC_POP(); - jl_gc_unsafe_leave(ct->ptls, gc_state); queue.clear(); } } diff --git a/src/coverage.c b/src/coverage.c index a03138b438a9c..730523d00e909 100644 --- a/src/coverage.c +++ b/src/coverage.c @@ -101,7 +101,7 @@ JL_DLLEXPORT uint64_t *jl_coverage_data_pointer(const char *filename, int line) return ret; } -JL_DLLEXPORT void jl_coverage_visit_line(const char *filename, size_t len, int line) +JL_DLLEXPORT void jl_coverage_visit_line(const char *filename, size_t len, int line) JL_CANSAFEPOINT { // TODO: remove `len` and use C-style strings exclusively // (kept for backwards-compatibility with JuliaInterpreter) diff --git a/src/datatype.c b/src/datatype.c index 582cc111dbacb..3513502da5594 100644 --- a/src/datatype.c +++ b/src/datatype.c @@ -392,7 +392,7 @@ int jl_datatype_isinlinealloc(jl_datatype_t *ty, int pointerfree) return 0; } -static unsigned union_isinlinable(jl_value_t *ty, int pointerfree, size_t *nbytes, size_t *align, int asfield) +static unsigned union_isinlinable(jl_value_t *ty, int pointerfree, size_t *nbytes, size_t *align, int asfield) JL_CANSAFEPOINT { if (jl_is_uniontype(ty)) { unsigned na = union_isinlinable(((jl_uniontype_t*)ty)->a, 1, nbytes, align, asfield); @@ -513,7 +513,7 @@ static int is_type_identityfree(jl_value_t *t) } // make a copy of the layout of st, but with nfields=0 -static void jl_get_genericmemory_layout(jl_datatype_t *st) +static void jl_get_genericmemory_layout(jl_datatype_t *st) JL_CANSAFEPOINT { jl_value_t *kind = jl_tparam0(st); jl_value_t *eltype = normalize_typeofbottom_layout_alias(jl_tparam1(st)); @@ -928,7 +928,7 @@ static void jl_process_field_attrs(jl_svec_t *fattrs, jl_svec_t *fnames, int mut // Create UnionAll wrapper chain for parametric types // wrapper should initially point to the DataType, will be updated to final wrapper // Caller must handle GC rooting of wrapper across this call -static void jl_setup_type_wrapper(jl_typename_t *tn, jl_svec_t *parameters, jl_value_t **wrapper) +static void jl_setup_type_wrapper(jl_typename_t *tn, jl_svec_t *parameters, jl_value_t **wrapper) JL_CANSAFEPOINT { jl_gc_write(tn, tn->wrapper, jl_value_t, *wrapper); int np = jl_svec_len(parameters); @@ -1772,27 +1772,27 @@ JL_DLLEXPORT jl_value_t *jl_new_struct_uninit(jl_datatype_t *type) // field access --------------------------------------------------------------- // TODO(jwn): these lock/unlock pairs must be full seq-cst fences -JL_DLLEXPORT void jl_lock_value(jl_mutex_t *v) JL_NOTSAFEPOINT +JL_DLLEXPORT void jl_lock_value(jl_mutex_t *v) { JL_LOCK_NOGC(v); } -JL_DLLEXPORT void jl_unlock_value(jl_mutex_t *v) JL_NOTSAFEPOINT +JL_DLLEXPORT void jl_unlock_value(jl_mutex_t *v) { JL_UNLOCK_NOGC(v); } -JL_DLLEXPORT void jl_lock_field(jl_mutex_t *v) JL_NOTSAFEPOINT +JL_DLLEXPORT void jl_lock_field(jl_mutex_t *v) { JL_LOCK_NOGC(v); } -JL_DLLEXPORT void jl_unlock_field(jl_mutex_t *v) JL_NOTSAFEPOINT +JL_DLLEXPORT void jl_unlock_field(jl_mutex_t *v) { JL_UNLOCK_NOGC(v); } -static inline char *lock(char *p, jl_value_t *parent, int needlock, enum atomic_kind isatomic) JL_NOTSAFEPOINT +static inline char *lock(char *p, jl_value_t *parent, int needlock, enum atomic_kind isatomic) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_ENTER JL_NO_SAFEPOINT_ANALYSIS { if (needlock) { if (isatomic == isatomic_object) { @@ -1806,7 +1806,7 @@ static inline char *lock(char *p, jl_value_t *parent, int needlock, enum atomic_ return p; } -static inline void unlock(char *p, jl_value_t *parent, int needlock, enum atomic_kind isatomic) JL_NOTSAFEPOINT +static inline void unlock(char *p, jl_value_t *parent, int needlock, enum atomic_kind isatomic) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_LEAVE JL_NO_SAFEPOINT_ANALYSIS { if (needlock) { if (isatomic == isatomic_object) { @@ -2131,8 +2131,10 @@ inline jl_value_t *modify_bits(jl_value_t *ty, char *p, uint8_t *psel, jl_value_ if (!jl_find_union_component(ty, yty, &nth)) assert(0 && "invalid field assignment to isbits union"); *psel = nth; - if (jl_is_datatype_singleton((jl_datatype_t*)yty)) + if (jl_is_datatype_singleton((jl_datatype_t*)yty)) { + unlock(p, parent, needlock, isatomic); break; + } } fsz = jl_datatype_size((jl_datatype_t*)yty); // need to shrink-wrap the final copy } @@ -2251,8 +2253,10 @@ inline jl_value_t *replace_bits(jl_value_t *ty, char *p, uint8_t *psel, jl_value if (!jl_find_union_component(ty, rty, &nth)) assert(0 && "invalid field assignment to isbits union"); *psel = nth; - if (jl_is_datatype_singleton((jl_datatype_t*)rty)) + if (jl_is_datatype_singleton((jl_datatype_t*)rty)) { + unlock(p, parent, needlock, isatomic); return r; + } } if (hasptr) jl_gc_multi_wb(parent, rhs); // rhs is immutable @@ -2362,7 +2366,7 @@ JL_DLLEXPORT int jl_field_isdefined_checked(jl_value_t *v, size_t i) return !!jl_field_isdefined(v, i); } -JL_DLLEXPORT size_t jl_get_field_offset(jl_datatype_t *ty, int field) +JL_DLLEXPORT size_t jl_get_field_offset(jl_datatype_t *ty, int field) JL_CANSAFEPOINT { if (!jl_struct_try_layout(ty) || field > jl_datatype_nfields(ty) || field < 1) jl_bounds_error_int((jl_value_t*)ty, field); @@ -2415,7 +2419,7 @@ JL_DLLEXPORT int jl_nth_pointer_isdefined(jl_value_t *v, size_t i) jl_datatype_t *jl_typeapp_type = NULL; // Forward declaration -static jl_value_t *resolve_type_refs(jl_value_t *t, htable_t *subst_map); +static jl_value_t *resolve_type_refs(jl_value_t *t, htable_t *subst_map) JL_CANSAFEPOINT; // Check if a typename is reachable from a type through struct fields // This is used to detect cycles in type definitions for mayinlinealloc diff --git a/src/debug-registry.h b/src/debug-registry.h index cae3c0899211d..6d3e3185f26f6 100644 --- a/src/debug-registry.h +++ b/src/debug-registry.h @@ -77,7 +77,7 @@ class JITDebugInfoRegistry return ConstLockT(mutex, resource); } - ~Locked() JL_NOTSAFEPOINT JL_NOTSAFEPOINT_LEAVE = default; + ~Locked() JL_NOTSAFEPOINT = default; }; struct image_info_t { @@ -145,7 +145,7 @@ class JITDebugInfoRegistry objectmap_t& getObjectMap() JL_NOTSAFEPOINT; void add_image_info(image_info_t info) JL_NOTSAFEPOINT; bool get_image_info(uint64_t base, image_info_t *info) const JL_NOTSAFEPOINT; - Locked::LockT get_objfile_map() JL_NOTSAFEPOINT; + Locked::LockT get_objfile_map() JL_NOTSAFEPOINT JL_NOTSAFEPOINT_ENTER; std::shared_mutex symbol_mutex; }; diff --git a/src/debuginfo.cpp b/src/debuginfo.cpp index bc0aadc65d3ac..dba9c89878335 100644 --- a/src/debuginfo.cpp +++ b/src/debuginfo.cpp @@ -88,7 +88,8 @@ static void processFDEs(const char *EHFrameAddr, size_t EHFrameSize, callback f) jl_code_instance_t *JITDebugInfoRegistry::lookupCodeInstance(size_t pointer) { - jl_lock_profile(); + if (!jl_trylock_profile()) + return nullptr; auto region = cimap.lower_bound(pointer); jl_code_instance_t *linfo = NULL; if (region != cimap.end() && pointer < region->first + region->second.first) @@ -104,6 +105,25 @@ JITDebugInfoRegistry::getObjectMap() return objectmap; } +#ifdef __clang_safetyanalysis__ +// Clang's thread-safety analysis drops the capability attributes when it +// *implicitly* instantiates a member function of a class template (the +// JL_NOTSAFEPOINT_ENTER on Locked::operator* is lost), so it no longer sees +// the accessor as entering the no-safepoint region. Force explicit +// instantiations that carry the attribute for each Locked accessor used +// below, which the analyzer then honors. This is only needed for -D__clang_safetyanalysis__; +// normal builds instantiate implicitly as usual. +template JL_NOTSAFEPOINT_ENTER +JITDebugInfoRegistry::Locked>::LockT +JITDebugInfoRegistry::Locked>::operator*(); +template JL_NOTSAFEPOINT_ENTER +JITDebugInfoRegistry::Locked>::ConstLockT +JITDebugInfoRegistry::Locked>::operator*() const; +template JL_NOTSAFEPOINT_ENTER +JITDebugInfoRegistry::Locked::LockT +JITDebugInfoRegistry::Locked::operator*(); +#endif + void JITDebugInfoRegistry::add_image_info(image_info_t info) { (**this->image_info)[info.base] = info; } @@ -396,7 +416,7 @@ void JITDebugInfoRegistry::registerJITObject( void jl_register_jit_object(const object::ObjectFile &Object, std::function getLoadAddress, - const jl_linker_info_t &Info) JL_NOTSAFEPOINT_LEAVE JL_NOTSAFEPOINT_ENTER + const jl_linker_info_t &Info) { // Opaque-closure code instances are not otherwise reachable through their // method, so promote them to global roots here, before entering the @@ -513,14 +533,17 @@ static int lookup_pointer( } else { int havelock = jl_lock_profile_wr(); - assert(havelock); (void)havelock; - auto lineinfo = context->getLineInfoForAddress(makeAddress(Section, pointer + slide), infoSpec); - jl_unlock_profile_wr(); + assert(havelock); // we got it earlier on this thread, so we can get it again + if (havelock) { + auto lineinfo = context->getLineInfoForAddress(makeAddress(Section, pointer + slide), infoSpec); + jl_unlock_profile_wr(); #if JL_LLVM_VERSION < 210000 - info = std::move(lineinfo); + info = std::move(lineinfo); #else - info = std::move(lineinfo.value()); + if (lineinfo) + info = std::move(*lineinfo); #endif + } } jl_frame_t *frame = &(*frames)[i]; @@ -1697,10 +1720,11 @@ extern "C" JL_DLLEXPORT_CODEGEN uint64_t jl_getUnwindInfo_impl(uint64_t dwAddr) JL_NOTSAFEPOINT { // Might be called from unmanaged thread - jl_lock_profile(); + uint64_t ipstart = 0; + if (!jl_trylock_profile()) + return ipstart; auto &objmap = getJITDebugRegistry().getObjectMap(); auto it = objmap.lower_bound(dwAddr); - uint64_t ipstart = 0; // ip of the start of the section (if found) if (it != objmap.end() && dwAddr < it->first + it->second.SectionSize) { ipstart = (uint64_t)(uintptr_t)(*it).first; } diff --git a/src/dlload.c b/src/dlload.c index a012dfc9462a4..ac22b6f9129af 100644 --- a/src/dlload.c +++ b/src/dlload.c @@ -97,7 +97,7 @@ void win32_formatmessage(DWORD code, char *reason, int len) JL_NOTSAFEPOINT } #endif -typedef void* (*dlopen_prototype)(const char* filename, int flags) JL_NOTSAFEPOINT; +typedef void* (*dlopen_prototype)(const char* filename, int flags) JL_CANCALLBACK; #if defined(_COMPILER_MSAN_ENABLED_) || defined(_COMPILER_ASAN_ENABLED_) || defined(_COMPILER_TSAN_ENABLED_) struct link_map; @@ -152,7 +152,7 @@ void ForEachMappedRegion(struct link_map *map, void (*cb)(const volatile void *, #endif #if defined(_OS_WINDOWS_) -JL_DLLEXPORT void *jl_dlopen(const char *filename, unsigned flags) JL_NOTSAFEPOINT +void *jl_dlopen(const char *filename, unsigned flags) { ssize_t len = uv_wtf8_length_as_utf16(filename); if (len < 0) return NULL; @@ -218,7 +218,7 @@ static int jl_use_rtld_deepbind(int recheck) JL_NOTSAFEPOINT instead using the real dlopen directly from the current shared library. Of course, this does mean that we need to manually perform the work that the sanitizers would otherwise do. */ -static JL_NO_SANITIZE dlopen_prototype resolve_dlopen(void) JL_NOTSAFEPOINT +static JL_NO_SANITIZE dlopen_prototype resolve_dlopen(void) JL_CANCALLBACK { #if defined(__GLIBC__) // When a sanitizer is active, bypass its dlopen interposition by resolving and @@ -243,7 +243,7 @@ static JL_NO_SANITIZE dlopen_prototype resolve_dlopen(void) JL_NOTSAFEPOINT return &dlopen; } -JL_DLLEXPORT JL_NO_SANITIZE void *jl_dlopen(const char *filename, unsigned flags) JL_NOTSAFEPOINT +JL_NO_SANITIZE void *jl_dlopen(const char *filename, unsigned flags) { dlopen_prototype dlopen_fptr = resolve_dlopen(); if (dlopen_fptr == NULL) @@ -275,8 +275,29 @@ JL_DLLEXPORT JL_NO_SANITIZE void *jl_dlopen(const char *filename, unsigned flags } #endif +static void jl_dlopen_throw(int err, const char *filename) { +#ifdef _OS_WINDOWS_ + char reason[256]; + win32_formatmessage(err, reason, sizeof(reason)); +#else + const char *reason = dlerror(); +#endif + jl_errorf("could not load library \"%s\"\n%s", filename, reason); +} -JL_DLLEXPORT int jl_dlclose(void *handle) JL_NOTSAFEPOINT +extern jl_libhandle jl_dlopen_e(const char *filename, unsigned flags) JL_NO_SAFEPOINT_ANALYSIS +#ifdef __clang_gcanalyzer__ +; // function used when we know that jl_dlopen will not safepoint +#else +{ + void *handle = jl_dlopen(filename, flags); + if (!handle) + jl_dlopen_throw(errno, filename); + return handle; +} +#endif + +int jl_dlclose(void *handle) { #ifdef _OS_WINDOWS_ if (!handle) { @@ -321,13 +342,11 @@ void *jl_find_dynamic_library_by_addr(void *symbol, int throw_err, int close) JL return handle; } -JL_DLLEXPORT void *jl_load_dynamic_library(const char *modname, unsigned flags, int throw_err) +JL_DLLEXPORT void *jl_load_dynamic_library(const char *modname, unsigned flags, int throw_err) JL_CANSAFEPOINT { ios_t path, relocated; int i; -#ifdef _OS_WINDOWS_ - int err; -#endif + int err = 0; uv_stat_t stbuf; void *handle; int abspath; @@ -448,15 +467,9 @@ JL_DLLEXPORT void *jl_load_dynamic_library(const char *modname, unsigned flags, notfound: if (throw_err) { -#ifdef _OS_WINDOWS_ - char reason[256]; - win32_formatmessage(err, reason, sizeof(reason)); -#else - const char *reason = dlerror(); -#endif ios_close(&relocated); ios_close(&path); - jl_errorf("could not load library \"%s\"\n%s", modname, reason); + jl_dlopen_throw(err, modname); } handle = NULL; diff --git a/src/gc-common.c b/src/gc-common.c index 2bf4c0870d7cc..d5256558e0e7e 100644 --- a/src/gc-common.c +++ b/src/gc-common.c @@ -253,7 +253,7 @@ static void jl_gc_push_arraylist(jl_task_t *ct, arraylist_t *list) JL_NOTSAFEPOI // Same assumption as `jl_gc_push_arraylist`. Requires the finalizers lock // to be held for the current thread and will release the lock when the // function returns. -static void jl_gc_run_finalizers_in_list(jl_task_t *ct, arraylist_t *list) JL_NOTSAFEPOINT_LEAVE +static void jl_gc_run_finalizers_in_list(jl_task_t *ct, arraylist_t *list) JL_NOTSAFEPOINT_LEAVE_WITH_CANSAFEPOINT { // Avoid marking `ct` as non-migratable via an `@async` task (as noted in the docstring // of `finalizer`) in a finalizer: @@ -526,7 +526,7 @@ JL_DLLEXPORT void * jl_gc_alloc_typed(jl_ptls_t ptls, size_t sz, void *ty) return jl_gc_alloc(ptls, sz, ty); } -JL_DLLEXPORT jl_value_t *jl_gc_allocobj(size_t sz) +JL_DLLEXPORT jl_value_t *jl_gc_allocobj(size_t sz) JL_CANSAFEPOINT { jl_ptls_t ptls = jl_current_task->ptls; return jl_gc_alloc(ptls, sz, NULL); @@ -539,18 +539,18 @@ JL_DLLEXPORT jl_value_t *(jl_gc_alloc)(jl_ptls_t ptls, size_t sz, void *ty) return jl_gc_alloc_(ptls, sz, ty); } -JL_DLLEXPORT void *jl_malloc(size_t sz) +JL_DLLEXPORT void *jl_malloc(size_t sz) JL_CANSAFEPOINT { return jl_gc_counted_malloc(sz); } //_unchecked_calloc does not check for potential overflow of nm*sz -STATIC_INLINE void *_unchecked_calloc(size_t nm, size_t sz) { +STATIC_INLINE void *_unchecked_calloc(size_t nm, size_t sz) JL_CANSAFEPOINT { size_t nmsz = nm*sz; return jl_gc_counted_calloc(nmsz, 1); } -JL_DLLEXPORT void *jl_calloc(size_t nm, size_t sz) +JL_DLLEXPORT void *jl_calloc(size_t nm, size_t sz) JL_CANSAFEPOINT { if (nm > SSIZE_MAX/sz) return NULL; @@ -565,7 +565,7 @@ JL_DLLEXPORT void jl_free(void *p) } } -JL_DLLEXPORT void *jl_realloc(void *p, size_t sz) +JL_DLLEXPORT void *jl_realloc(void *p, size_t sz) JL_CANSAFEPOINT { size_t old = p ? memory_block_usable_size(p, 0) : 0; return jl_gc_counted_realloc_with_old_size(p, old, sz); diff --git a/src/gc-common.h b/src/gc-common.h index 060abc465935c..0e675d58a04c1 100644 --- a/src/gc-common.h +++ b/src/gc-common.h @@ -194,10 +194,10 @@ extern arraylist_t finalizer_list_marked; extern arraylist_t to_finalize; void schedule_finalization(void *o, void *f) JL_NOTSAFEPOINT; -void run_finalizer(jl_task_t *ct, void *o, void *ff); -void run_finalizers(jl_task_t *ct, int finalizers_thread); +void run_finalizer(jl_task_t *ct, void *o, void *ff) JL_CANSAFEPOINT; +void run_finalizers(jl_task_t *ct, int finalizers_thread) JL_CANSAFEPOINT; JL_DLLEXPORT void jl_gc_add_finalizer_th(jl_ptls_t ptls, jl_value_t *v, jl_value_t *f) JL_NOTSAFEPOINT; -JL_DLLEXPORT void jl_finalize_th(jl_task_t *ct, jl_value_t *o); +JL_DLLEXPORT void jl_finalize_th(jl_task_t *ct, jl_value_t *o) JL_CANSAFEPOINT; // =========================================================================== // diff --git a/src/gc-heap-snapshot.h b/src/gc-heap-snapshot.h index 804aa9cee742f..66e788d330a0e 100644 --- a/src/gc-heap-snapshot.h +++ b/src/gc-heap-snapshot.h @@ -129,7 +129,7 @@ static inline void gc_heap_snapshot_record_finlist(jl_value_t *finlist, size_t i // Functions to call from Julia to take heap snapshot // --------------------------------------------------------------------- JL_DLLEXPORT void jl_gc_take_heap_snapshot(ios_t *nodes, ios_t *edges, - ios_t *strings, ios_t *json, char all_one, char redact_data); + ios_t *strings, ios_t *json, char all_one, char redact_data) JL_CANSAFEPOINT; #ifdef __cplusplus diff --git a/src/gc-interface.h b/src/gc-interface.h index f52b1600779ed..224ddf2e4587f 100644 --- a/src/gc-interface.h +++ b/src/gc-interface.h @@ -106,7 +106,7 @@ typedef struct { // System-wide initialization function. Responsible for initializing global locks as well as // global memory parameters (e.g. target heap size) used by the collector. -void jl_gc_init(void); +void jl_gc_init(void) JL_NOTSAFEPOINT; // Spawns GC threads. void jl_start_gc_threads(void); @@ -138,10 +138,10 @@ JL_DLLEXPORT int jl_gc_enable(int on); // Returns whether the collector is enabled. JL_DLLEXPORT int jl_gc_is_enabled(void); // Sets a soft limit to Julia's heap. -JL_DLLEXPORT void jl_gc_set_max_memory(uint64_t max_mem); +JL_DLLEXPORT void jl_gc_set_max_memory(uint64_t max_mem) JL_NOTSAFEPOINT; // Runs a GC cycle. This function's parameter determines whether we're running an // incremental, full, or automatic (i.e. heuristic driven) collection. -JL_DLLEXPORT void jl_gc_collect(jl_gc_collection_t collection); +JL_DLLEXPORT void jl_gc_collect(jl_gc_collection_t collection) JL_CANSAFEPOINT; // Returns whether the thread with `tid` is a collector thread JL_DLLEXPORT int gc_is_collector_thread(int tid) JL_NOTSAFEPOINT; // Enables or disables automatic full (non-generational) collections. @@ -153,7 +153,7 @@ JL_DLLEXPORT int jl_gc_enable_auto_full_collection(int on); JL_DLLEXPORT int jl_gc_auto_full_collection_is_enabled(void); // Returns which GC implementation is being used and possibly its version according to the list of supported GCs // NB: it should clearly identify the GC by including e.g. 'stock' or 'mmtk' as a substring. -JL_DLLEXPORT const char* jl_gc_active_impl(void); +JL_DLLEXPORT const char* jl_gc_active_impl(void) JL_NOTSAFEPOINT; // Sweep Julia's stack pools and mtarray buffers. Note that this function has been added to the interface as // each GC should implement it but it will most likely not be used by other code in the runtime. // It still needs to be annotated with JL_DLLEXPORT since it is called from Rust by MMTk. @@ -197,7 +197,7 @@ JL_DLLEXPORT uint64_t jl_gc_total_hrtime(void); // to decide whether to allocate a small or a large object. Finally, note that this function // **must** also set the type of the returning object to be `ty`. The type `ty` may also be used to record // an allocation of that type in the allocation profiler. -struct _jl_value_t *jl_gc_alloc_(struct _jl_tls_states_t * ptls, size_t sz, void *ty); +struct _jl_value_t *jl_gc_alloc_(struct _jl_tls_states_t * ptls, size_t sz, void *ty) JL_CANSAFEPOINT; // Allocates small objects and increments Julia allocation counters. Size of the object // header must be included in the object size. The (possibly unused in some implementations) // offset to the arena in which we're allocating is passed in the second parameter, and the @@ -208,7 +208,7 @@ struct _jl_value_t *jl_gc_alloc_(struct _jl_tls_states_t * ptls, size_t sz, void // allocation profiler. JL_DLLEXPORT struct _jl_value_t *jl_gc_small_alloc(struct _jl_tls_states_t *ptls, int offset, int osize, - struct _jl_value_t *type); + struct _jl_value_t *type) JL_CANSAFEPOINT; // Description: Allocates large objects and increments Julia allocation counters. Size of // the object header must be included in the object size. If thread-local allocators are // used, then this function should allocate in the thread-local allocator of the thread @@ -216,15 +216,15 @@ JL_DLLEXPORT struct _jl_value_t *jl_gc_small_alloc(struct _jl_tls_states_t *ptls // information about the type of the object being allocated may be used to record an // allocation of that type in the allocation profiler. JL_DLLEXPORT struct _jl_value_t *jl_gc_big_alloc(struct _jl_tls_states_t *ptls, size_t sz, - struct _jl_value_t *type); + struct _jl_value_t *type) JL_CANSAFEPOINT; // Wrapper around Libc malloc that updates Julia allocation counters. -JL_DLLEXPORT void *jl_gc_counted_malloc(size_t sz); +JL_DLLEXPORT void *jl_gc_counted_malloc(size_t sz) JL_CANSAFEPOINT; // Wrapper around Libc calloc that updates Julia allocation counters. -JL_DLLEXPORT void *jl_gc_counted_calloc(size_t nm, size_t sz); +JL_DLLEXPORT void *jl_gc_counted_calloc(size_t nm, size_t sz) JL_CANSAFEPOINT; // Wrapper around Libc free that updates Julia allocation counters. JL_DLLEXPORT void jl_gc_counted_free_with_size(void *p, size_t sz); // Wrapper around Libc realloc that updates Julia allocation counters. -JL_DLLEXPORT void *jl_gc_counted_realloc_with_old_size(void *p, size_t old, size_t sz); +JL_DLLEXPORT void *jl_gc_counted_realloc_with_old_size(void *p, size_t old, size_t sz) JL_CANSAFEPOINT; // Wrapper around Libc malloc that's used to dynamically allocate memory for Arrays and // Strings. It increments Julia allocation counters and should check whether we're close to // the Julia heap target, and therefore, whether we should run a collection. Note that this @@ -232,12 +232,12 @@ JL_DLLEXPORT void *jl_gc_counted_realloc_with_old_size(void *p, size_t old, size // front of the memory payload): this function is used for Julia object allocations, and we // assume that there is already a field in the Julia object being allocated that we may use // to store the size of the memory buffer. -JL_DLLEXPORT void *jl_gc_managed_malloc(size_t sz); +JL_DLLEXPORT void *jl_gc_managed_malloc(size_t sz) JL_CANSAFEPOINT; // Allocates a new weak-reference, assigns its value and increments Julia allocation // counters. If thread-local allocators are used, then this function should allocate in the // thread-local allocator of the thread referenced by the first jl_ptls_t argument. JL_DLLEXPORT struct _jl_weakref_t *jl_gc_new_weakref_th(struct _jl_tls_states_t *ptls, - struct _jl_value_t *value); + struct _jl_value_t *value) JL_CANSAFEPOINT; // Permanently allocates a memory slot of the size specified by the first parameter. This // block of memory is allocated in an immortal region that is never swept. The second // parameter specifies whether the memory should be filled with zeros. The third and fourth diff --git a/src/gc-page-profiler.c b/src/gc-page-profiler.c index 111b370012880..3c7fc166ccce2 100644 --- a/src/gc-page-profiler.c +++ b/src/gc-page-profiler.c @@ -163,7 +163,7 @@ static void gc_page_profile_write_json_epilogue(ios_t *stream) JL_NOTSAFEPOINT } } -JL_DLLEXPORT void jl_gc_take_page_profile(ios_t *stream) +JL_DLLEXPORT void jl_gc_take_page_profile(ios_t *stream) JL_CANSAFEPOINT { gc_enable_page_profile(); page_profile_pages_written = 0; diff --git a/src/gc-pages.c b/src/gc-pages.c index b2637e79848bf..0a3e4ebf775dc 100644 --- a/src/gc-pages.c +++ b/src/gc-pages.c @@ -72,7 +72,7 @@ static char *jl_gc_try_alloc_pages_(int pg_cnt) JL_NOTSAFEPOINT // smaller `MIN_BLOCK_PG_ALLOC` a `jl_memory_exception` is thrown. // Assumes `gc_pages_lock` is acquired, the lock is released before the // exception is thrown. -static char *jl_gc_try_alloc_pages(void) JL_NOTSAFEPOINT +STATIC_INLINE char *jl_gc_try_alloc_pages(void) JL_NOTSAFEPOINT_LEAVE_ENTER { unsigned pg_cnt = block_pg_cnt; char *mem = NULL; diff --git a/src/gc-stacks.c b/src/gc-stacks.c index 9387c7fb065ec..5f7516eb6add5 100644 --- a/src/gc-stacks.c +++ b/src/gc-stacks.c @@ -232,7 +232,7 @@ arraylist_t *jl_get_all_tasks_arraylist(void) JL_NOTSAFEPOINT return tasks; } -JL_DLLEXPORT jl_array_t *jl_live_tasks(void) +JL_DLLEXPORT jl_array_t *jl_live_tasks(void) JL_CANSAFEPOINT { size_t nthreads = jl_atomic_load_acquire(&jl_n_threads); jl_ptls_t *allstates = jl_atomic_load_relaxed(&jl_all_tls_states); diff --git a/src/gc-stock.c b/src/gc-stock.c index d2e2af20bb171..039e424949f51 100644 --- a/src/gc-stock.c +++ b/src/gc-stock.c @@ -346,7 +346,7 @@ STATIC_INLINE void gc_setmark_buf(jl_ptls_t ptls, void *o, uint8_t mark_mode, si } } -STATIC_INLINE void maybe_collect(jl_ptls_t ptls) +STATIC_INLINE void maybe_collect(jl_ptls_t ptls) JL_CANSAFEPOINT { if (jl_atomic_load_relaxed(&gc_heap_stats.heap_size) >= jl_atomic_load_relaxed(&gc_heap_stats.heap_target) || jl_gc_debug_check_other()) { jl_gc_collect(JL_GC_AUTO); @@ -428,7 +428,7 @@ STATIC_INLINE void jl_batch_accum_free_size(jl_ptls_t ptls, uint64_t sz) JL_NOTS // big value list // Size includes the tag and the tag field is undefined on return (must be set before the next GC safepoint) -STATIC_INLINE jl_value_t *jl_gc_big_alloc_inner(jl_ptls_t ptls, size_t sz) +STATIC_INLINE jl_value_t *jl_gc_big_alloc_inner(jl_ptls_t ptls, size_t sz) JL_CANSAFEPOINT { maybe_collect(ptls); size_t offs = offsetof(bigval_t, header); @@ -716,7 +716,7 @@ static NOINLINE jl_taggedvalue_t *gc_add_page(jl_gc_pool_t *p) JL_NOTSAFEPOINT // Size includes the tag and the tag is not cleared!! STATIC_INLINE jl_value_t *jl_gc_small_alloc_inner(jl_ptls_t ptls, int offset, - int osize) + int osize) JL_CANSAFEPOINT { // Use the pool offset instead of the pool address as the argument // to workaround a llvm bug. @@ -3672,10 +3672,10 @@ void jl_start_gc_threads(void) t->tid = i; t->barrier = &thread_init_done; if (i == nthreads - 1 && jl_n_sweepthreads == 1) { - uv_thread_create(&uvtid, jl_concurrent_gc_threadfun, t); + uv_thread_create(&uvtid, jl_concurrent_gc_threadfun, t); // NOLINT[julia-first-decl-annotations] } else { - uv_thread_create(&uvtid, jl_parallel_gc_threadfun, t); + uv_thread_create(&uvtid, jl_parallel_gc_threadfun, t); // NOLINT[julia-first-decl-annotations] } } } diff --git a/src/gc-stock.h b/src/gc-stock.h index f2f5935f04d27..8ea0ab507c644 100644 --- a/src/gc-stock.h +++ b/src/gc-stock.h @@ -575,7 +575,7 @@ STATIC_INLINE void gc_record_full_sweep_reason(int reason) JL_NOTSAFEPOINT void gc_mark_finlist(jl_gc_markqueue_t *mq, arraylist_t *list, size_t start) JL_NOTSAFEPOINT; void gc_collect_neighbors(jl_ptls_t ptls, jl_gc_markqueue_t *mq) JL_NOTSAFEPOINT; void gc_mark_queue_all_roots(jl_ptls_t ptls, jl_gc_markqueue_t *mq); -void jl_gc_debug_init(void); +void jl_gc_debug_init(void) JL_NOTSAFEPOINT; // GC permanent allocation extern uv_mutex_t gc_perm_lock; diff --git a/src/genericmemory.c b/src/genericmemory.c index 0fa056231c233..a54e9bc169dec 100644 --- a/src/genericmemory.c +++ b/src/genericmemory.c @@ -53,7 +53,7 @@ JL_DLLEXPORT jl_genericmemory_t *jl_alloc_genericmemory_unchecked(jl_ptls_t ptls return m; } -static jl_genericmemory_t *_new_genericmemory_(jl_value_t *mtype, size_t nel, int8_t isunion, int8_t zeroinit, size_t elsz) +static jl_genericmemory_t *_new_genericmemory_(jl_value_t *mtype, size_t nel, int8_t isunion, int8_t zeroinit, size_t elsz) JL_CANSAFEPOINT { if (nel == 0) // zero-sized allocation optimization return (jl_genericmemory_t*)((jl_datatype_t*)mtype)->instance; @@ -102,7 +102,7 @@ JL_DLLEXPORT jl_genericmemory_t *jl_alloc_genericmemory(jl_value_t *mtype, size_ return _new_genericmemory_(mtype, nel, isunion, zi, elsz); } -JL_DLLEXPORT jl_genericmemory_t *jl_string_to_genericmemory(jl_value_t *str) +JL_DLLEXPORT jl_genericmemory_t *jl_string_to_genericmemory(jl_value_t *str) JL_CANSAFEPOINT { if (jl_string_len(str) == 0) return (jl_genericmemory_t*)((jl_datatype_t*)jl_memory_uint8_type)->instance; @@ -180,7 +180,7 @@ JL_DLLEXPORT jl_genericmemory_t *jl_new_genericmemory(jl_value_t *mtype, jl_valu return jl_alloc_genericmemory(mtype, jl_unbox_long(nel)); } -JL_DLLEXPORT jl_genericmemory_t *jl_pchar_to_genericmemory(const char *str, size_t len) +JL_DLLEXPORT jl_genericmemory_t *jl_pchar_to_genericmemory(const char *str, size_t len) JL_CANSAFEPOINT { jl_genericmemory_t *m = jl_alloc_genericmemory(jl_memory_uint8_type, len); memcpy(m->ptr, str, len); diff --git a/src/gf.c b/src/gf.c index a399a3404136d..11804da5df4b7 100644 --- a/src/gf.c +++ b/src/gf.c @@ -152,7 +152,7 @@ uint_t speccache_hash(size_t idx, jl_value_t *data) return ((jl_datatype_t*)sig)->hash; } -static int speccache_eq(size_t idx, const void *ty, jl_value_t *data, uint_t hv) +static int speccache_eq(size_t idx, const void *ty, jl_value_t *data, uint_t hv) JL_CANSAFEPOINT { if (idx >= jl_svec_len(data)) return 0; // We got a OOB access, probably due to a data race @@ -185,7 +185,7 @@ static int jl_is_builtinfunc(jl_method_t *m) // 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) +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) JL_CANSAFEPOINT { if (jl_is_builtinfunc(m)) return jl_atomic_load_relaxed(&m->unspecialized); // handle builtin methods @@ -217,6 +217,7 @@ static jl_method_instance_t *jl_specializations_get_linfo_(jl_method_t *m JL_PRO } cl = jl_svec_len(specializations); if (hv) { + ssize_t jl_smallintset_lookup(jl_genericmemory_t *cache, smallintset_eq eq JL_CANSAFEPOINT, const void *key, jl_value_t *data, uint_t hv, int pop) JL_CANSAFEPOINT; ssize_t idx = jl_smallintset_lookup(speckeyset, speccache_eq, type, specializations, hv, 0); if (idx != -1) { jl_method_instance_t *mi = (jl_method_instance_t*)jl_svecref(specializations, idx); @@ -312,7 +313,7 @@ jl_method_instance_t *jl_specializations_get_or_insert(jl_method_instance_t *mi) return jl_specializations_get_linfo_(m, type, sparams, mi); } -JL_DLLEXPORT jl_value_t *jl_specializations_lookup(jl_method_t *m, jl_value_t *type) +JL_DLLEXPORT jl_value_t *jl_specializations_lookup(jl_method_t *m, jl_value_t *type) JL_CANSAFEPOINT { jl_value_t *mi = (jl_value_t*)jl_specializations_get_linfo(m, type, NULL); if (mi == NULL) @@ -378,7 +379,7 @@ jl_method_t *jl_mk_builtin_func(jl_datatype_t *dt, jl_sym_t *sname, jl_fptr_args } // only relevant for bootstrapping. otherwise fairly broken. -static int emit_codeinst_and_edges(jl_code_instance_t *codeinst) +static int emit_codeinst_and_edges(jl_code_instance_t *codeinst) JL_CANSAFEPOINT { jl_value_t *code = jl_atomic_load_relaxed(&codeinst->inferred); if (code) { @@ -402,7 +403,7 @@ static int emit_codeinst_and_edges(jl_code_instance_t *codeinst) } // Opportunistic SOURCE_MODE_ABI cache lookup, only for bootstrapping. -static jl_code_instance_t *jl_method_inferred_with_abi(jl_method_instance_t *mi JL_PROPAGATES_ROOT, size_t world) +static jl_code_instance_t *jl_method_inferred_with_abi(jl_method_instance_t *mi JL_PROPAGATES_ROOT, size_t world) JL_CANSAFEPOINT { jl_code_instance_t *codeinst = jl_atomic_load_relaxed(&mi->cache); for (; codeinst; codeinst = jl_atomic_load_relaxed(&codeinst->next)) { @@ -565,7 +566,7 @@ JL_DLLEXPORT jl_code_info_t *jl_gdbcodetyped1(jl_method_instance_t *mi, size_t w return ci; } -JL_DLLEXPORT jl_value_t *jl_call_in_typeinf_world(jl_value_t **args, int nargs) +JL_DLLEXPORT jl_value_t *jl_call_in_typeinf_world(jl_value_t **args, int nargs) JL_CANSAFEPOINT { jl_task_t *ct = jl_current_task; size_t last_age = ct->world_age; @@ -823,7 +824,7 @@ enum top_typename_facts { SHORT_TUPLE = 1 << 7, }; -static void foreach_top_nth_typename(void (*f)(jl_typename_t*, int, void*), jl_value_t *a JL_PROPAGATES_ROOT, int n, unsigned *facts, void *env) +static void foreach_top_nth_typename(void (*f)(jl_typename_t*, int, void*) JL_CANSAFEPOINT, jl_value_t *a JL_PROPAGATES_ROOT, int n, unsigned *facts, void *env) JL_CANSAFEPOINT { arraylist_t workqueue; arraylist_new(&workqueue, 0); @@ -918,7 +919,7 @@ static void foreach_top_nth_typename(void (*f)(jl_typename_t*, int, void*), jl_v // This is not capable of walking to all top-typenames for an explicitly encountered // Function or Any, so the caller has a fallback that can scan the entire table in that case. // We do not de-duplicate calls when encountering a Union. -static int jl_foreach_top_typename_for(void (*f)(jl_typename_t*, int, void*), jl_value_t *argtypes JL_PROPAGATES_ROOT, int all_subtypes, void *env) +static int jl_foreach_top_typename_for(void (*f)(jl_typename_t*, int, void*) JL_CANSAFEPOINT, jl_value_t *argtypes JL_PROPAGATES_ROOT, int all_subtypes, void *env) JL_CANSAFEPOINT { unsigned facts = 0; foreach_top_nth_typename(f, argtypes, 1, &facts, env); @@ -1052,7 +1053,7 @@ static int invalidate_all_entries(jl_typemap_entry_t *entry, void *env) return 1; } -static void drop_all_methcache(jl_methcache_t *mc) +static void drop_all_methcache(jl_methcache_t *mc) JL_CANSAFEPOINT { JL_LOCK(&mc->writelock); jl_typemap_visitor(jl_atomic_load_relaxed(&mc->cache), invalidate_all_entries, NULL); @@ -1072,7 +1073,7 @@ static void drop_all_methcache(jl_methcache_t *mc) JL_UNLOCK(&mc->writelock); } -JL_DLLEXPORT void jl_set_typeinf_func(jl_value_t *f) +JL_DLLEXPORT void jl_set_typeinf_func(jl_value_t *f) JL_CANSAFEPOINT { if (jl_typeinf_func == NULL) { // drop the major caches, so that their structure can now be inferred @@ -1087,7 +1088,7 @@ JL_DLLEXPORT void jl_set_compile_and_emit_func(jl_value_t *f) jl_compile_and_emit_func = (jl_value_t*)f; } -static int very_general_type(jl_value_t *t) +static int very_general_type(jl_value_t *t) JL_CANSAFEPOINT { return (t == (jl_value_t*)jl_any_type || jl_types_equal(t, (jl_value_t*)jl_type_type)); } @@ -1122,7 +1123,7 @@ jl_value_t *jl_nth_slot_type(jl_value_t *sig, size_t i) JL_NOTSAFEPOINT // return 1; //} -static jl_value_t *inst_varargp_in_env(jl_value_t *decl, jl_svec_t *sparams) +static jl_value_t *inst_varargp_in_env(jl_value_t *decl, jl_svec_t *sparams) JL_CANSAFEPOINT { jl_value_t *unw = jl_unwrap_unionall(decl); jl_value_t *vm = jl_tparam(unw, jl_nparams(unw) - 1); @@ -1169,7 +1170,7 @@ static jl_value_t *inst_varargp_in_env(jl_value_t *decl, jl_svec_t *sparams) static jl_value_t *ml_matches(jl_methtable_t *mt, jl_methcache_t *mc, jl_tupletype_t *type, int lim, int include_ambiguous, int intersections, size_t world, int cache_result_recursion, - size_t *min_valid, size_t *max_valid, int *ambig); + size_t *min_valid, size_t *max_valid, int *ambig) JL_CANSAFEPOINT; // Widen an egality-keyed slot `TypeEgal{A}` to `Type{A}` when the method // declares the slot as a *concrete* `Type{X}`: there a single `Type{A}`-keyed @@ -1179,7 +1180,7 @@ static jl_value_t *ml_matches(jl_methtable_t *mt, jl_methcache_t *mc, // requests that mean the runtime calls narrow at their entry point instead // (see `jl_get_compile_hint_specialization`). static void egal_normalize_slot(jl_tupletype_t *tt, size_t i, jl_value_t *decl_i, - jl_svec_t **newparams JL_REQUIRE_ROOTED_SLOT) + jl_svec_t **newparams JL_REQUIRE_ROOTED_SLOT) JL_CANSAFEPOINT { jl_value_t *elt = jl_tparam(tt, i); if (jl_is_typeegal(elt) && !jl_has_free_typevars(elt) && @@ -1196,7 +1197,7 @@ static void jl_compilation_sig( jl_method_t *definition, intptr_t max_varargs, // output: - jl_svec_t **const newparams JL_REQUIRE_ROOTED_SLOT) + jl_svec_t **const newparams JL_REQUIRE_ROOTED_SLOT) JL_CANSAFEPOINT { assert(jl_is_tuple_type(tt)); jl_value_t *decl = definition->sig; @@ -1695,7 +1696,7 @@ static inline jl_typemap_entry_t *lookup_leafcache(jl_genericmemory_t *leafcache return NULL; } -static jl_typemap_entry_t *mt_find_cache_entry(_Atomic(jl_typemap_t*) *cache JL_PROPAGATES_ROOT, _Atomic(jl_genericmemory_t*) *leafcache JL_PROPAGATES_ROOT, jl_datatype_t *tt, size_t world, int offs) +static jl_typemap_entry_t *mt_find_cache_entry(_Atomic(jl_typemap_t*) *cache JL_PROPAGATES_ROOT, _Atomic(jl_genericmemory_t*) *leafcache JL_PROPAGATES_ROOT, jl_datatype_t *tt, size_t world, int offs) JL_CANSAFEPOINT { if (leafcache) { jl_typemap_entry_t *entry = lookup_leafcache(jl_atomic_load_relaxed(leafcache), (jl_value_t*)tt, world); @@ -1708,12 +1709,12 @@ static jl_typemap_entry_t *mt_find_cache_entry(_Atomic(jl_typemap_t*) *cache JL_ return entry; } -JL_DLLEXPORT jl_typemap_entry_t *jl_mt_find_cache_entry(jl_methcache_t *cache, jl_datatype_t *tt, size_t world) +JL_DLLEXPORT jl_typemap_entry_t *jl_mt_find_cache_entry(jl_methcache_t *cache, jl_datatype_t *tt, size_t world) JL_CANSAFEPOINT { // exported only for debugging purposes, not for casual use return mt_find_cache_entry(&cache->cache, &cache->leafcache, tt, world, jl_cachearg_offset()); } -static jl_value_t *compute_simplett(jl_tupletype_t *cachett) +static jl_value_t *compute_simplett(jl_tupletype_t *cachett) JL_CANSAFEPOINT { // now scan `cachett` and ensure that `Type{T}` in the cache will be matched exactly by `typeof(T)` // and also reduce the complexity of rejecting this entry in the cache @@ -1757,7 +1758,7 @@ static void cache_insert( jl_tupletype_t *cachett, jl_svec_t *guardsigs, jl_method_instance_t *newmeth, - int offs) + int offs) JL_CANSAFEPOINT { // exact-dispatch lookups (`jl_typemap_entry_assoc_exact`) require datatype sigs assert(jl_is_datatype(cachett)); @@ -1839,7 +1840,7 @@ static jl_method_instance_t *cache_result( // set by callers that have already proven `tt` is absent from the cache // immediately before acquiring the lock and that no insertion can have // happened since, allowing the redundant re-check below to be skipped - int tt_known_absent) + int tt_known_absent) JL_CANSAFEPOINT { // caller must hold the parent->writelock, which this releases int8_t offs = mc ? jl_cachearg_offset() : 1; @@ -1883,7 +1884,7 @@ static void recache_method( size_t world, size_t min_valid, size_t max_valid, size_t current_world, jl_svec_t *sparams, jl_method_instance_t *newmeth, - jl_value_t *compilationsig) + jl_value_t *compilationsig) JL_CANSAFEPOINT { // caller must hold the parent->writelock, which this releases int8_t offs = mc ? jl_cachearg_offset() : 1; @@ -2027,11 +2028,11 @@ static void recache_method( return; } -static jl_method_match_t *_gf_invoke_lookup(jl_value_t *types JL_PROPAGATES_ROOT, jl_methtable_t *mt, size_t world, int cache_result_recursion, size_t *min_valid, size_t *max_valid); +static jl_method_match_t *_gf_invoke_lookup(jl_value_t *types JL_PROPAGATES_ROOT, jl_methtable_t *mt, size_t world, int cache_result_recursion, size_t *min_valid, size_t *max_valid) JL_CANSAFEPOINT; static void promote_cache_method(jl_value_t *F, jl_value_t **args, uint32_t nargs, size_t world, jl_method_instance_t *newmeth, jl_value_t *compilationsig, - enum internal_compilation_triggers cause) + enum internal_compilation_triggers cause) JL_CANSAFEPOINT { if (F == NULL) return; @@ -2073,7 +2074,7 @@ static void promote_cache_method(jl_value_t *F, jl_value_t **args, uint32_t narg // `newmeth` to avoid making unnecessary new types for cache_result. JL_DLLEXPORT void jl_recache_method_by_type(jl_value_t *tt, jl_method_instance_t *newmeth, jl_value_t *compilationsig, size_t world, - size_t min_valid, size_t max_valid, size_t current_world) + size_t min_valid, size_t max_valid, size_t current_world) JL_CANSAFEPOINT { if (newmeth->cache_with_orig) return; @@ -2088,7 +2089,7 @@ JL_DLLEXPORT void jl_recache_method_by_type(jl_value_t *tt, newmeth->sparam_vals, newmeth, compilationsig); } -JL_DLLEXPORT void jl_promote_cis_to_current(jl_code_instance_t **cis, size_t n, size_t validated_world) +JL_DLLEXPORT void jl_promote_cis_to_current(jl_code_instance_t **cis, size_t n, size_t validated_world) JL_CANSAFEPOINT { size_t current_world = jl_atomic_load_relaxed(&jl_world_counter); // No need to acquire the lock if we've been invalidated anyway @@ -2119,12 +2120,12 @@ JL_DLLEXPORT void jl_promote_cis_to_current(jl_code_instance_t **cis, size_t n, JL_UNLOCK(&world_counter_lock); } -JL_DLLEXPORT void jl_promote_ci_to_current(jl_code_instance_t *ci, size_t validated_world) +JL_DLLEXPORT void jl_promote_ci_to_current(jl_code_instance_t *ci, size_t validated_world) JL_CANSAFEPOINT { jl_promote_cis_to_current(&ci, 1, validated_world); } -JL_DLLEXPORT void jl_promote_mi_to_current(jl_method_instance_t *mi, size_t min_world, size_t validated_world) +JL_DLLEXPORT void jl_promote_mi_to_current(jl_method_instance_t *mi, size_t min_world, size_t validated_world) JL_CANSAFEPOINT { size_t current_world = jl_atomic_load_relaxed(&jl_world_counter); // No need to acquire the lock if we've been invalidated anyway @@ -2145,7 +2146,7 @@ JL_DLLEXPORT void jl_promote_mi_to_current(jl_method_instance_t *mi, size_t min_ } static jl_method_instance_t *jl_mt_assoc_by_type( - jl_methtable_t *mt, jl_methcache_t *mc JL_PROPAGATES_ROOT, jl_datatype_t *tt, size_t world) + jl_methtable_t *mt, jl_methcache_t *mc JL_PROPAGATES_ROOT, jl_datatype_t *tt, size_t world) JL_CANSAFEPOINT { size_t cache_insert_generation = jl_method_cache_insert_generation_load(); jl_typemap_entry_t *entry = mt_find_cache_entry(&mc->cache, @@ -2194,7 +2195,7 @@ struct matches_env { jl_typemap_entry_t *replaced; }; -static int get_intersect_visitor(jl_typemap_entry_t *oldentry, struct typemap_intersection_env *closure0) +static int get_intersect_visitor(jl_typemap_entry_t *oldentry, struct typemap_intersection_env *closure0) JL_CANSAFEPOINT { struct matches_env *closure = container_of(closure0, struct matches_env, match); jl_method_t *oldmethod = oldentry->func.method; @@ -2228,7 +2229,7 @@ static int get_intersect_visitor(jl_typemap_entry_t *oldentry, struct typemap_in return 1; } -static jl_value_t *get_intersect_matches(jl_typemap_t *defs, jl_typemap_entry_t *newentry, jl_typemap_entry_t **replaced, size_t world) +static jl_value_t *get_intersect_matches(jl_typemap_t *defs, jl_typemap_entry_t *newentry, jl_typemap_entry_t **replaced, size_t world) JL_CANSAFEPOINT { jl_tupletype_t *type = newentry->sig; jl_tupletype_t *ttypes = (jl_tupletype_t*)jl_unwrap_unionall((jl_value_t*)type); @@ -2265,7 +2266,7 @@ void print_func_loc(JL_STREAM *s, jl_method_t *m) } } -static void method_overwrite(jl_typemap_entry_t *newentry, jl_method_t *oldvalue) +static void method_overwrite(jl_typemap_entry_t *newentry, jl_method_t *oldvalue) JL_CANSAFEPOINT { // method overwritten jl_method_t *method = (jl_method_t*)newentry->func.method; @@ -2314,7 +2315,7 @@ static void update_max_args(jl_value_t *type) } jl_array_t *_jl_debug_method_invalidation JL_GLOBALLY_ROOTED = NULL; -JL_DLLEXPORT jl_value_t *jl_debug_method_invalidation(int state) +JL_DLLEXPORT jl_value_t *jl_debug_method_invalidation(int state) JL_CANSAFEPOINT { /* After calling with `state = 1`, caller is responsible for holding a reference to the returned array until this is called @@ -2329,10 +2330,10 @@ JL_DLLEXPORT jl_value_t *jl_debug_method_invalidation(int state) return jl_nothing; } -static void _invalidate_backedges(jl_method_instance_t *replaced_mi, jl_code_instance_t *replaced_ci, size_t max_world, int depth); +static void _invalidate_backedges(jl_method_instance_t *replaced_mi, jl_code_instance_t *replaced_ci, size_t max_world, int depth) JL_CANSAFEPOINT; // recursively invalidate cached methods that had an edge to a replaced method -static void invalidate_code_instance(jl_code_instance_t *replaced, size_t max_world, int depth) +static void invalidate_code_instance(jl_code_instance_t *replaced, size_t max_world, int depth) JL_CANSAFEPOINT { jl_timing_counter_inc(JL_TIMING_COUNTER_Invalidations, 1); if (_jl_debug_method_invalidation) { @@ -2362,12 +2363,12 @@ static void invalidate_code_instance(jl_code_instance_t *replaced, size_t max_wo JL_UNLOCK(&replaced_mi->def.method->writelock); } -JL_DLLEXPORT void jl_invalidate_code_instance(jl_code_instance_t *replaced, size_t max_world) +JL_DLLEXPORT void jl_invalidate_code_instance(jl_code_instance_t *replaced, size_t max_world) JL_CANSAFEPOINT { invalidate_code_instance(replaced, max_world, 1); } -JL_DLLEXPORT void jl_maybe_log_binding_invalidation(jl_value_t *replaced) +JL_DLLEXPORT void jl_maybe_log_binding_invalidation(jl_value_t *replaced) JL_CANSAFEPOINT { if (_jl_debug_method_invalidation) { if (replaced) { @@ -2433,7 +2434,7 @@ static void _invalidate_backedges(jl_method_instance_t *replaced_mi, jl_code_ins JL_GC_POP(); } -static int jl_type_intersection2(jl_value_t *t1, jl_value_t *t2, jl_value_t **isect JL_REQUIRE_ROOTED_SLOT, jl_value_t **isect2 JL_REQUIRE_ROOTED_SLOT) +static int jl_type_intersection2(jl_value_t *t1, jl_value_t *t2, jl_value_t **isect JL_REQUIRE_ROOTED_SLOT, jl_value_t **isect2 JL_REQUIRE_ROOTED_SLOT) JL_CANSAFEPOINT { *isect2 = NULL; int is_subty = 0; @@ -2461,7 +2462,7 @@ static int jl_type_intersection2(jl_value_t *t1, jl_value_t *t2, jl_value_t **is // check if `type` is replacing `m` with an ambiguity here, given other methods in `d` that already match it -static int is_replacing(char ambig, jl_value_t *type, jl_method_t *m, jl_method_t *const *d, size_t n, jl_value_t *isect, jl_value_t *isect2, char *morespec) +static int is_replacing(char ambig, jl_value_t *type, jl_method_t *m, jl_method_t *const *d, size_t n, jl_value_t *isect, jl_value_t *isect2, char *morespec) JL_CANSAFEPOINT { size_t k; for (k = 0; k < n; k++) { @@ -2487,7 +2488,7 @@ static int is_replacing(char ambig, jl_value_t *type, jl_method_t *m, jl_method_ static int _invalidate_dispatch_backedges(jl_method_instance_t *mi, jl_value_t *type, jl_method_t *m, jl_method_t *const *d, size_t n, int replaced_dispatch, int ambig, - size_t max_world, char *morespec) + size_t max_world, char *morespec) JL_CANSAFEPOINT { uint8_t backedge_recursion_flags = 0; jl_array_t *backedges = jl_mi_get_backedges_mutate(mi, &backedge_recursion_flags); @@ -2531,7 +2532,7 @@ static int _invalidate_dispatch_backedges(jl_method_instance_t *mi, jl_value_t * } // invalidate cached methods that overlap this definition -static void invalidate_backedges(jl_method_instance_t *replaced_mi, size_t max_world, const char *why) +static void invalidate_backedges(jl_method_instance_t *replaced_mi, size_t max_world, const char *why) JL_CANSAFEPOINT { // Reset dispatch_status when method instance is replaced JL_LOCK(&replaced_mi->def.method->writelock); @@ -2572,14 +2573,14 @@ JL_DLLEXPORT void jl_method_instance_add_backedge(jl_method_instance_t *callee, } -static int jl_foreach_top_typename_for(void (*f)(jl_typename_t*, int, void*), jl_value_t *argtypes JL_PROPAGATES_ROOT, int all_subtypes, void *env); +static int jl_foreach_top_typename_for(void (*f)(jl_typename_t*, int, void*) JL_CANSAFEPOINT, jl_value_t *argtypes JL_PROPAGATES_ROOT, int all_subtypes, void *env) JL_CANSAFEPOINT; struct _typename_add_backedge { jl_value_t *typ; jl_value_t *caller; }; -static void _typename_add_backedge(jl_typename_t *tn, int explct, void *env0) +static void _typename_add_backedge(jl_typename_t *tn, int explct, void *env0) JL_CANSAFEPOINT { struct _typename_add_backedge *env = (struct _typename_add_backedge*)env0; JL_GC_PROMISE_ROOTED(env->typ); @@ -2650,7 +2651,7 @@ struct _typename_invalidate_backedge { int invalidated; }; -static void _typename_invalidate_backedges(jl_typename_t *tn, int explct, void *env0) +static void _typename_invalidate_backedges(jl_typename_t *tn, int explct, void *env0) JL_CANSAFEPOINT { struct _typename_invalidate_backedge *env = (struct _typename_invalidate_backedge*)env0; JL_GC_PROMISE_ROOTED(env->type); @@ -2717,7 +2718,7 @@ struct invalidate_mt_env { jl_array_t *shadowed; size_t max_world; }; -static int invalidate_mt_cache(jl_typemap_entry_t *oldentry, void *closure0) +static int invalidate_mt_cache(jl_typemap_entry_t *oldentry, void *closure0) JL_CANSAFEPOINT { struct invalidate_mt_env *env = (struct invalidate_mt_env*)closure0; JL_GC_PROMISE_ROOTED(env->newentry_sig); @@ -2786,14 +2787,15 @@ static int typemap_search(jl_typemap_entry_t *entry, void *closure) return 1; } -static jl_typemap_entry_t *do_typemap_search(jl_methtable_t *mt JL_PROPAGATES_ROOT, jl_method_t *method) { +static jl_typemap_entry_t *do_typemap_search(jl_methtable_t *mt JL_PROPAGATES_ROOT, jl_method_t *method) JL_CANSAFEPOINT +{ jl_value_t *closure = (jl_value_t*)(method); if (jl_typemap_visitor(jl_atomic_load_relaxed(&mt->defs), typemap_search, &closure)) jl_error("method not in method table"); return (jl_typemap_entry_t *)closure; } -static void _method_table_invalidate(jl_methcache_t *mc, void *env0) +static void _method_table_invalidate(jl_methcache_t *mc, void *env0) JL_CANSAFEPOINT { // drop this method from mc->cache jl_typemap_visitor(jl_atomic_load_relaxed(&mc->cache), disable_mt_cache, env0); @@ -2810,7 +2812,7 @@ static void _method_table_invalidate(jl_methcache_t *mc, void *env0) } } -static void jl_method_table_invalidate(jl_method_t *replaced, size_t max_world) +static void jl_method_table_invalidate(jl_method_t *replaced, size_t max_world) JL_CANSAFEPOINT { if (jl_options.incremental && jl_generating_output()) jl_error("Method deletion is not possible during Module precompile."); @@ -2848,7 +2850,7 @@ static void jl_method_table_invalidate(jl_method_t *replaced, size_t max_world) } } -static int erase_method_backedges(jl_typemap_entry_t *def, void *closure) +static int erase_method_backedges(jl_typemap_entry_t *def, void *closure) JL_CANSAFEPOINT { jl_method_t *method = def->func.method; JL_LOCK(&method->writelock); @@ -2872,12 +2874,12 @@ static int erase_method_backedges(jl_typemap_entry_t *def, void *closure) return 1; } -static int erase_all_backedges(jl_methtable_t *mt, void *env) +static int erase_all_backedges(jl_methtable_t *mt, void *env) JL_CANSAFEPOINT { return jl_typemap_visitor(jl_atomic_load_relaxed(&mt->defs), erase_method_backedges, env); } -JL_DLLEXPORT void jl_disable_new_worlds(void) +JL_DLLEXPORT void jl_disable_new_worlds(void) JL_CANSAFEPOINT { if (jl_generating_output()) jl_error("Disabling Method changes is not possible when generating output."); @@ -2894,7 +2896,7 @@ JL_DLLEXPORT void jl_disable_new_worlds(void) JL_GC_POP(); } -JL_DLLEXPORT void jl_method_table_disable(jl_method_t *method) +JL_DLLEXPORT void jl_method_table_disable(jl_method_t *method) JL_CANSAFEPOINT { jl_methtable_t *mt = jl_method_get_table(method); jl_typemap_entry_t *methodentry = do_typemap_search(mt, method); @@ -2971,7 +2973,7 @@ static int find_method_in_matches(jl_array_t *t, jl_method_t *method) } // Recursively check if any method in interferences covers the given type signature -static int check_interferences_covers(jl_method_t *m, jl_value_t *ti, jl_array_t *t, arraylist_t *visited, arraylist_t *seen) +static int check_interferences_covers(jl_method_t *m, jl_value_t *ti, jl_array_t *t, arraylist_t *visited, arraylist_t *seen) JL_CANSAFEPOINT { arraylist_t workqueue; arraylist_new(&workqueue, 0); @@ -3018,7 +3020,7 @@ static int check_interferences_covers(jl_method_t *m, jl_value_t *ti, jl_array_t return result; } -static int check_fully_ambiguous(jl_method_t *m, jl_value_t *ti, jl_array_t *t, int include_ambiguous, int *has_ambiguity) +static int check_fully_ambiguous(jl_method_t *m, jl_value_t *ti, jl_array_t *t, int include_ambiguous, int *has_ambiguity) JL_CANSAFEPOINT { jl_genericmemory_t *interferences = jl_atomic_load_relaxed(&m->interferences); for (size_t i = 0; i < interferences->length; i++) { @@ -3370,7 +3372,7 @@ JL_DLLEXPORT void jl_method_table_insert(jl_methtable_t *mt, jl_method_t *method JL_GC_POP(); } -static void JL_NORETURN jl_method_error_bare(jl_value_t *f, jl_value_t *args, size_t world) +static void JL_NORETURN jl_method_error_bare(jl_value_t *f, jl_value_t *args, size_t world) JL_CANSAFEPOINT { if (jl_methoderror_type) { jl_value_t *e = jl_new_struct_uninit(jl_methoderror_type); @@ -3395,7 +3397,7 @@ static void JL_NORETURN jl_method_error_bare(jl_value_t *f, jl_value_t *args, si // not reached } -void JL_NORETURN jl_method_error(jl_value_t *f, jl_value_t **args, size_t na, size_t world) +void JL_NORETURN JL_NO_SAFEPOINT_ANALYSIS jl_method_error(jl_value_t *f, jl_value_t **args, size_t na, size_t world) { jl_value_t *argtup = jl_f_tuple(NULL, args, na - 1); JL_GC_PUSH1(&argtup); @@ -3408,14 +3410,14 @@ jl_tupletype_t *arg_type_tuple(jl_value_t *arg1, jl_value_t **args, size_t nargs return jl_inst_arg_tuple_type(arg1, args, nargs, 1); } -static jl_tupletype_t *lookup_arg_type_tuple(jl_value_t *arg1 JL_PROPAGATES_ROOT, jl_value_t **args, size_t nargs) +static jl_tupletype_t *lookup_arg_type_tuple(jl_value_t *arg1 JL_PROPAGATES_ROOT, jl_value_t **args, size_t nargs) JL_CANSAFEPOINT { return jl_lookup_arg_tuple_type(arg1, args, nargs, 1); } // hook provided for caching-enhanced fast method instance lookup // for when the expensive caching cost is justified for some reason -JL_DLLEXPORT jl_value_t *jl_method_lookup_by_tt(jl_tupletype_t *tt, size_t world, jl_value_t *_mt) +JL_DLLEXPORT jl_value_t *jl_method_lookup_by_tt(jl_tupletype_t *tt, size_t world, jl_value_t *_mt) JL_CANSAFEPOINT { jl_methtable_t *mt; if (_mt == jl_nothing) { @@ -3433,7 +3435,7 @@ JL_DLLEXPORT jl_value_t *jl_method_lookup_by_tt(jl_tupletype_t *tt, size_t world } // hook provided for legacy staticdata lookups -JL_DLLEXPORT jl_value_t *jl_gf_invoke_lookup(jl_value_t *types, jl_value_t *mt, size_t world); +JL_DLLEXPORT jl_value_t *jl_gf_invoke_lookup(jl_value_t *types, jl_value_t *mt, size_t world) JL_CANSAFEPOINT; jl_method_instance_t *jl_builtin_method_lookup(jl_value_t *builtin) { jl_datatype_t *dt = (jl_datatype_t*)jl_typeof(builtin); @@ -3473,7 +3475,7 @@ JL_DLLEXPORT jl_value_t *jl_matching_methods(jl_tupletype_t *types, jl_value_t * return ml_matches((jl_methtable_t*)mt, mc, types, lim, include_ambiguous, 1, world, 1, min_valid, max_valid, ambig); } -JL_DLLEXPORT jl_method_instance_t *jl_get_unspecialized(jl_method_t *def JL_PROPAGATES_ROOT) +JL_DLLEXPORT jl_method_instance_t *jl_get_unspecialized(jl_method_t *def JL_PROPAGATES_ROOT) JL_CANSAFEPOINT { // one unspecialized version of a function can be shared among all cached specializations if (!jl_is_method(def)) { @@ -3569,7 +3571,7 @@ JL_DLLEXPORT void jl_force_trace_compile_timing_disable(void) jl_atomic_fetch_add(&jl_force_trace_compile_timing_enabled, -1); } -static void record_precompile_statement(jl_method_instance_t *mi, double compilation_time, int is_recompile) +static void record_precompile_statement(jl_method_instance_t *mi, double compilation_time, int is_recompile) JL_CANSAFEPOINT { static ios_t f_precompile; static JL_STREAM* s_precompile = NULL; @@ -3636,7 +3638,7 @@ JL_DLLEXPORT void jl_force_trace_dispatch_disable(void) jl_atomic_fetch_add(&jl_force_trace_dispatch_enabled, -1); } -static void record_dispatch_statement(jl_method_instance_t *mi) +static void record_dispatch_statement(jl_method_instance_t *mi) JL_CANSAFEPOINT { static ios_t f_dispatch; static JL_STREAM* s_dispatch = NULL; @@ -3668,7 +3670,7 @@ static void record_dispatch_statement(jl_method_instance_t *mi) JL_UNLOCK(&dispatch_statement_out_lock); } -static void record_dispatch_statement_on_first_dispatch(jl_method_instance_t *mfunc) { +static void record_dispatch_statement_on_first_dispatch(jl_method_instance_t *mfunc) JL_CANSAFEPOINT { uint8_t force_trace_dispatch = jl_atomic_load_relaxed(&jl_force_trace_dispatch_enabled); if (force_trace_dispatch || jl_options.trace_dispatch != NULL) { uint8_t miflags = jl_atomic_load_relaxed(&mfunc->flags); @@ -3721,7 +3723,7 @@ void jl_read_codeinst_invoke(jl_code_instance_t *ci, uint8_t *specsigflags, jl_c } } -JL_DLLEXPORT jl_method_instance_t *jl_normalize_to_compilable_mi(jl_method_instance_t *mi JL_PROPAGATES_ROOT); +JL_DLLEXPORT jl_method_instance_t *jl_normalize_to_compilable_mi(jl_method_instance_t *mi JL_PROPAGATES_ROOT) JL_CANSAFEPOINT; JL_DLLEXPORT void jl_add_codeinsts_to_jit(jl_array_t *codeinsts, jl_array_t *srcs) { @@ -3784,7 +3786,7 @@ static int need_copy_to_mi_cache(jl_method_instance_t *mi, jl_method_instance_t !jl_egal((jl_value_t*)mi->sparam_vals, (jl_value_t*)mi2->sparam_vals); } -static jl_code_instance_t *copy_to_mi_cache(jl_method_instance_t *mi JL_PROPAGATES_ROOT, jl_code_instance_t *codeinst2) +static jl_code_instance_t *copy_to_mi_cache(jl_method_instance_t *mi JL_PROPAGATES_ROOT, jl_code_instance_t *codeinst2) JL_CANSAFEPOINT { jl_code_instance_t *codeinst = jl_get_method_uninferred( mi, codeinst2->rettype, @@ -3838,7 +3840,7 @@ static jl_code_instance_t *copy_to_mi_cache(jl_method_instance_t *mi JL_PROPAGAT // a cacheable sig is normally the same as a compileable sig // except in the case where we can't execute the compileable sig without copying // (because of jl_fptr_sparam environment usage) -static jl_value_t *normalize_to_cacheable_sig(jl_method_instance_t *mi JL_PROPAGATES_ROOT) +static jl_value_t *normalize_to_cacheable_sig(jl_method_instance_t *mi JL_PROPAGATES_ROOT) JL_CANSAFEPOINT { jl_method_instance_t *mi2 = jl_normalize_to_compilable_mi(mi); if (mi != mi2 && need_copy_to_mi_cache(mi, mi2, TRIGGER_NONE)) // rarely true @@ -3848,7 +3850,7 @@ static jl_value_t *normalize_to_cacheable_sig(jl_method_instance_t *mi JL_PROPAG static jl_code_instance_t *jl_compile_method_very_internal(jl_method_instance_t *mi JL_PROPAGATES_ROOT, size_t world, jl_value_t *F, jl_value_t **args, uint32_t nargs, - enum internal_compilation_triggers cause) + enum internal_compilation_triggers cause) JL_CANSAFEPOINT { // Quick check if we already have a compiled result // (which also catches any builtin functions). @@ -4090,7 +4092,7 @@ jl_value_t *jl_fptr_sparam(jl_value_t *f, jl_value_t **args, uint32_t nargs, jl_ return invoke(f, args, nargs, sparams); } -static jl_value_t *jl_fptr_wait_for_compiled(jl_value_t *f, jl_value_t **args, uint32_t nargs, jl_code_instance_t *m) +static jl_value_t *jl_fptr_wait_for_compiled(jl_value_t *f, jl_value_t **args, uint32_t nargs, jl_code_instance_t *m) JL_CANSAFEPOINT { jl_callptr_t invoke = jl_atomic_load_acquire(&m->invoke); if (invoke == &jl_fptr_wait_for_compiled) { @@ -4141,7 +4143,7 @@ JL_DLLEXPORT int32_t jl_invoke_api(jl_code_instance_t *codeinst) } JL_DLLEXPORT jl_value_t *jl_normalize_to_compilable_sig(jl_tupletype_t *ti, jl_svec_t *env, jl_method_t *m, - int return_if_compileable) + int return_if_compileable) JL_CANSAFEPOINT { jl_tupletype_t *tt = NULL; jl_svec_t *newparams = NULL; @@ -4185,7 +4187,7 @@ JL_DLLEXPORT jl_method_instance_t *jl_normalize_to_compilable_mi(jl_method_insta } // return a MethodInstance for a compileable method_match, if valid -static jl_value_t *jl_method_match_to_mi(jl_method_match_t *match, size_t world, size_t min_valid, size_t max_valid) +static jl_value_t *jl_method_match_to_mi(jl_method_match_t *match, size_t world, size_t min_valid, size_t max_valid) JL_CANSAFEPOINT { jl_method_t *m = match->method; JL_GC_PROMISE_ROOTED(m); @@ -4234,7 +4236,7 @@ jl_value_t *jl_get_specialization1(jl_tupletype_t *types, size_t world) // denotes, and a closed type-valued argument keys runtime dispatch by egality: // narrow such slots to the dispatch spelling `TypeEgal{A}` (#61323). `Type{Union{}}` // stays: the bottom object is the unique instance of its `Type`. -static jl_tupletype_t *egal_normalize_hint_types(jl_tupletype_t *types JL_PROPAGATES_ROOT) +static jl_tupletype_t *egal_normalize_hint_types(jl_tupletype_t *types JL_PROPAGATES_ROOT) JL_CANSAFEPOINT { jl_svec_t *newparams = NULL; JL_GC_PUSH1(&newparams); @@ -4265,7 +4267,7 @@ static jl_tupletype_t *egal_normalize_hint_types(jl_tupletype_t *types JL_PROPAG // egality-slot widening of `jl_compilation_sig` (egality-keyed slots that the // method declares as concrete `Type{X}` are keyed by equality instead). // The caller must root the result. -static jl_tupletype_t *egal_canonical_sig(jl_tupletype_t *types JL_PROPAGATES_ROOT, jl_method_t *m) +static jl_tupletype_t *egal_canonical_sig(jl_tupletype_t *types JL_PROPAGATES_ROOT, jl_method_t *m) JL_CANSAFEPOINT { jl_svec_t *newparams = NULL; JL_GC_PUSH1(&newparams); @@ -4284,7 +4286,7 @@ static jl_tupletype_t *egal_canonical_sig(jl_tupletype_t *types JL_PROPAGATES_RO // Try to get a MethodInstance for a precompile() call. This uses a special kind of lookup that // tries to find a method for which the requested signature is compileable. -JL_DLLEXPORT jl_value_t *jl_get_compile_hint_specialization(jl_tupletype_t *types JL_PROPAGATES_ROOT, size_t world) +JL_DLLEXPORT jl_value_t *jl_get_compile_hint_specialization(jl_tupletype_t *types JL_PROPAGATES_ROOT, size_t world) JL_CANSAFEPOINT { if (jl_has_free_typevars((jl_value_t*)types)) return jl_nothing; // don't poison the cache due to a malformed query @@ -4373,7 +4375,7 @@ JL_DLLEXPORT void jl_compile_method_sig(jl_method_t *m, jl_value_t *types, jl_sv jl_compile_method_instance(mi, NULL, world); } -JL_DLLEXPORT int jl_is_compilable(jl_tupletype_t *types) +JL_DLLEXPORT int jl_is_compilable(jl_tupletype_t *types) JL_CANSAFEPOINT { size_t world = jl_atomic_load_acquire(&jl_world_counter); jl_value_t *mi = jl_get_compile_hint_specialization(types, world); @@ -4454,7 +4456,7 @@ STATIC_INLINE jl_value_t *verify_type(jl_value_t *v) JL_NOTSAFEPOINT } STATIC_INLINE jl_value_t *_jl_invoke(jl_value_t *F, jl_value_t **args, uint32_t nargs, jl_method_instance_t *mfunc, size_t world, - enum internal_compilation_triggers cause) + enum internal_compilation_triggers cause) JL_CANSAFEPOINT { jl_code_instance_t *codeinst = NULL; jl_callptr_t invoke = jl_method_compiled_callptr(mfunc, world, &codeinst); @@ -4566,7 +4568,7 @@ void call_cache_stats() #endif STATIC_INLINE jl_method_instance_t *jl_lookup_generic_(jl_value_t *F, jl_value_t **args, uint32_t nargs, - uint32_t callsite, size_t world, int for_call) + uint32_t callsite, size_t world, int for_call) JL_CANSAFEPOINT { #ifdef JL_GF_PROFILE ncalls++; @@ -4903,7 +4905,7 @@ enum SIGNATURE_FULLY_COVERS { SENTINEL = 2, }; -static jl_method_match_t *make_method_match(jl_tupletype_t *spec_types, jl_svec_t *sparams, jl_method_t *method, enum SIGNATURE_FULLY_COVERS fully_covers) +static jl_method_match_t *make_method_match(jl_tupletype_t *spec_types, jl_svec_t *sparams, jl_method_t *method, enum SIGNATURE_FULLY_COVERS fully_covers) JL_CANSAFEPOINT { jl_task_t *ct = jl_current_task; jl_method_match_t *match = (jl_method_match_t*)jl_gc_alloc(ct->ptls, sizeof(jl_method_match_t), jl_method_match_type); @@ -4920,7 +4922,7 @@ static jl_method_match_t *make_method_match(jl_tupletype_t *spec_types, jl_svec_ // exceeded early. This is only best-effort, since specificity means that many matched methods // may be sorted and removed in the output processing for ml_matches and therefore we can only // conservatively under-approximate the matches during the search. -static int ml_matches_visitor(jl_typemap_entry_t *ml, struct typemap_intersection_env *closure0) +static int ml_matches_visitor(jl_typemap_entry_t *ml, struct typemap_intersection_env *closure0) JL_CANSAFEPOINT { struct ml_matches_env *closure = container_of(closure0, struct ml_matches_env, match); if (closure->intersections == 0 && !closure0->issubty) @@ -5023,7 +5025,7 @@ typedef struct { // * -1: too many matches for lim, other outputs are undefined // * 0: the child(ren) have been added to the output // * 1+: the children are part of this SCC (up to this depth) -static int sort_mlmatches(jl_array_t *t, size_t idx, arraylist_t *visited, arraylist_t *stack, arraylist_t *result, arraylist_t *recursion_stack, int lim, int include_ambiguous, int *has_ambiguity, int *found_minmax) +static int sort_mlmatches(jl_array_t *t, size_t idx, arraylist_t *visited, arraylist_t *stack, arraylist_t *result, arraylist_t *recursion_stack, int lim, int include_ambiguous, int *has_ambiguity, int *found_minmax) JL_CANSAFEPOINT { // Use arraylist_t for explicit stack of processing frames arraylist_t frame_stack; @@ -5628,7 +5630,7 @@ JL_DLLEXPORT void jl_typeinf_timing_end(uint64_t start, int is_recompile) } // declare a C-callable entry point; called during code loading from the toplevel -JL_DLLEXPORT void jl_extern_c(jl_value_t *name, jl_value_t *declrt, jl_tupletype_t *sigt) +JL_DLLEXPORT void jl_extern_c(jl_value_t *name, jl_value_t *declrt, jl_tupletype_t *sigt) JL_CANSAFEPOINT { // validate arguments. try to do as many checks as possible here to avoid // throwing errors later during codegen. @@ -5681,7 +5683,7 @@ static void invalidate_method_instance_caches(jl_method_instance_t *mi, size_t w } } -static int invalidate_all_specializations(jl_typemap_entry_t *def, void *closure) +static int invalidate_all_specializations(jl_typemap_entry_t *def, void *closure) JL_CANSAFEPOINT { size_t world = *(size_t*)closure; jl_method_t *method = def->func.method; @@ -5702,7 +5704,7 @@ static int invalidate_all_specializations(jl_typemap_entry_t *def, void *closure return 1; } -static void invalidate_all_caches(jl_methtable_t *mt, size_t current_world) +static void invalidate_all_caches(jl_methtable_t *mt, size_t current_world) JL_CANSAFEPOINT { jl_typemap_visitor(jl_atomic_load_relaxed(&mt->defs), invalidate_all_specializations, ¤t_world); drop_all_methcache(mt->cache); diff --git a/src/iddict.c b/src/iddict.c index 3b90886dd344d..d451f8981294a 100644 --- a/src/iddict.c +++ b/src/iddict.c @@ -8,7 +8,7 @@ #define keyhash(k) jl_object_id_(jl_typetagof(k), k) #define h2index(hv, sz) (size_t)(((hv) & ((sz)-1)) * 2) -static inline int jl_table_assign_bp(jl_genericmemory_t **pa, jl_value_t *key, jl_value_t *val); +static inline int jl_table_assign_bp(jl_genericmemory_t **pa, jl_value_t *key, jl_value_t *val) JL_CANSAFEPOINT; JL_DLLEXPORT jl_genericmemory_t *jl_idtable_rehash(jl_genericmemory_t *a, size_t newsz) { diff --git a/src/init.c b/src/init.c index 849fbd6699cea..00bb270500e1e 100644 --- a/src/init.c +++ b/src/init.c @@ -103,7 +103,7 @@ void jl_init_stack_limits(int ismaster, void **stack_lo, void **stack_hi) #endif } -static void jl_prep_sanitizers(void) +static void jl_prep_sanitizers(void) JL_NOTSAFEPOINT { #if !defined(_OS_WINDOWS_) #if defined(_COMPILER_ASAN_ENABLED_) || defined(_COMPILER_MSAN_ENABLED_) @@ -155,7 +155,7 @@ static struct uv_shutdown_queue_item *next_shutdown_queue_item(struct uv_shutdow return rv; } -static void jl_close_item_atexit(uv_handle_t *handle) +static void jl_close_item_atexit(uv_handle_t *handle) JL_CANSAFEPOINT { if (handle->type != UV_FILE && uv_is_closing(handle)) return; @@ -226,7 +226,7 @@ JL_DLLEXPORT void jl_raise(int signo) #endif } -JL_DLLEXPORT void jl_atexit_hook(int exitcode) +JL_DLLEXPORT void jl_atexit_hook(int exitcode) JL_NO_SAFEPOINT_ANALYSIS { uv_tty_reset_mode(); @@ -309,10 +309,10 @@ JL_DLLEXPORT void jl_atexit_hook(int exitcode) //error handling -- continue cleanup, as much as possible assert(item); uv_unref(item->h); - jl_printf((JL_STREAM*)STDERR_FILENO, "error during exit cleanup: close: "); - jl_static_show((JL_STREAM*)STDERR_FILENO, jl_current_exception(ct)); - jl_printf((JL_STREAM*)STDERR_FILENO, "\n"); - jl_fprint_backtrace(ios_safe_stderr); + ios_printf(ios_stderr, "error during exit cleanup: close: "); + jl_static_show((JL_STREAM*)ios_stderr, jl_current_exception(ct)); + ios_printf(ios_stderr, "\n"); + jl_fprint_backtrace(ios_stderr); item = next_shutdown_queue_item(item); } } @@ -435,7 +435,7 @@ static int uv_dup(uv_os_fd_t fd, uv_os_fd_t* dupfd) { } #endif -static void *init_stdio_handle(const char *stdio, uv_os_fd_t fd, int readable) +static void *init_stdio_handle(const char *stdio, uv_os_fd_t fd, int readable) JL_NOTSAFEPOINT { void *handle; int err; @@ -510,7 +510,7 @@ static void *init_stdio_handle(const char *stdio, uv_os_fd_t fd, int readable) return handle; } -static void init_stdio(void) +static void init_stdio(void) JL_NOTSAFEPOINT { JL_STDIN = (uv_stream_t*)init_stdio_handle("stdin", UV_STDIN_FD, 1); JL_STDOUT = (uv_stream_t*)init_stdio_handle("stdout", UV_STDOUT_FD, 0); @@ -554,7 +554,7 @@ extern jl_mutex_t newly_inferred_mutex; extern jl_mutex_t global_roots_lock; extern jl_mutex_t profile_show_peek_cond_lock; -static void restore_fp_env(void) +static void restore_fp_env(void) JL_NOTSAFEPOINT { if (jl_set_zero_subnormals(0) || jl_set_default_nans(0)) { jl_error("Failed to configure floating point environment"); @@ -566,7 +566,7 @@ static void restore_fp_env(void) "See: https://github.com/JuliaLang/julia/issues/50278"); } } -static NOINLINE void _finish_jl_init_(jl_image_buf_t sysimage, jl_ptls_t ptls, jl_task_t *ct) +static NOINLINE void _finish_jl_init_(jl_image_buf_t sysimage, jl_ptls_t ptls, jl_task_t *ct) JL_CANSAFEPOINT { JL_TIMING(JULIA_INIT, JULIA_INIT); @@ -680,7 +680,7 @@ JL_DLLEXPORT jl_cgparams_t jl_default_cgparams = { #endif }; -static void init_global_mutexes(void) { +static void init_global_mutexes(void) JL_NOTSAFEPOINT { JL_MUTEX_INIT(&jl_modules_mutex, "jl_modules_mutex"); JL_MUTEX_INIT(&precomp_statement_out_lock, "precomp_statement_out_lock"); JL_MUTEX_INIT(&newly_inferred_mutex, "newly_inferred_mutex"); @@ -746,6 +746,10 @@ JL_DLLEXPORT void jl_init_(jl_image_buf_t sysimage) // have to dlclose() these handles. jl_libjulia_internal_handle = jl_find_dynamic_library_by_addr(&jl_load_dynamic_library, /* throw_err */ 1, 0); jl_libjulia_handle = jl_find_dynamic_library_by_addr(&jl_options, /* throw_err */ 1, 0); +#ifdef __clang_gcanalyzer__ + #define jl_dlopen jl_dlopen_noload + JL_DLLEXPORT jl_libhandle jl_dlopen(const char *filename, unsigned flags) JL_NOTSAFEPOINT; +#endif #ifdef _OS_WINDOWS_ /* If this parameter is NULL, GetModuleHandle returns a handle to the file used to create the calling process (.exe file). */ @@ -762,6 +766,9 @@ JL_DLLEXPORT void jl_init_(jl_image_buf_t sysimage) // RTLD_DEFAULT is mandatory on POSIX jl_RTLD_DEFAULT_handle = RTLD_DEFAULT; #endif +#ifdef __clang_safetyanalysis__ + #undef jl_dlopen +#endif jl_init_rand(); jl_init_coverage(); diff --git a/src/interpreter.c b/src/interpreter.c index 06020321d9ca2..bf5c6437968a6 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -72,12 +72,12 @@ extern void JL_GC_ENABLEFRAME(interpreter_state*) JL_NOTSAFEPOINT; #endif -static jl_value_t *eval_value(jl_value_t *e, interpreter_state *s); -static jl_value_t *eval_body(jl_array_t *stmts, interpreter_state *s, size_t ip, int toplevel); +static jl_value_t *eval_value(jl_value_t *e, interpreter_state *s) JL_CANSAFEPOINT; +static jl_value_t *eval_body(jl_array_t *stmts, interpreter_state *s, size_t ip, int toplevel) JL_CANSAFEPOINT; // method definition form -static jl_value_t *eval_methoddef(jl_expr_t *ex, interpreter_state *s) +static jl_value_t *eval_methoddef(jl_expr_t *ex, interpreter_state *s) JL_CANSAFEPOINT { jl_value_t **args = jl_array_ptr_data(ex->args); @@ -112,7 +112,7 @@ static jl_value_t *eval_methoddef(jl_expr_t *ex, interpreter_state *s) // expression evaluator -static jl_value_t *do_call(jl_value_t **args, size_t nargs, interpreter_state *s) +static jl_value_t *do_call(jl_value_t **args, size_t nargs, interpreter_state *s) JL_CANSAFEPOINT { jl_value_t **argv; assert(nargs >= 1); @@ -125,7 +125,7 @@ static jl_value_t *do_call(jl_value_t **args, size_t nargs, interpreter_state *s return result; } -static jl_value_t *do_invoke(jl_value_t **args, size_t nargs, interpreter_state *s) +static jl_value_t *do_invoke(jl_value_t **args, size_t nargs, interpreter_state *s) JL_CANSAFEPOINT { jl_value_t **argv; assert(nargs >= 2); @@ -189,13 +189,13 @@ static int jl_source_nssavalues(jl_code_info_t *src) JL_NOTSAFEPOINT return jl_is_long(src->ssavaluetypes) ? jl_unbox_long(src->ssavaluetypes) : jl_array_nrows(src->ssavaluetypes); } -static void eval_stmt_value(jl_value_t *stmt, interpreter_state *s) +static void eval_stmt_value(jl_value_t *stmt, interpreter_state *s) JL_CANSAFEPOINT { jl_value_t *res = eval_value(stmt, s); s->locals[jl_source_nslots(s->src) + s->ip] = res; } -static jl_value_t *eval_expr_tuple(jl_expr_t *ex, interpreter_state *s) +static jl_value_t *eval_expr_tuple(jl_expr_t *ex, interpreter_state *s) JL_CANSAFEPOINT { // evaluate Expr(:tuple, ...) // only appears in post-lowered IR in foreignglobal / foreigncall @@ -430,7 +430,7 @@ static jl_value_t *eval_value(jl_value_t *e, interpreter_state *s) } // phi nodes don't behave like proper instructions, so we require a special interpreter to handle them -static size_t eval_phi(jl_array_t *stmts, interpreter_state *s, size_t ns, size_t to) +static size_t eval_phi(jl_array_t *stmts, interpreter_state *s, size_t ns, size_t to) JL_CANSAFEPOINT { size_t from = s->ip; size_t ip = to; @@ -766,7 +766,7 @@ static jl_value_t *eval_body(jl_array_t *stmts, interpreter_state *s, size_t ip, // preparing method IR for interpreter -jl_value_t *jl_code_or_ci_for_interpreter(jl_method_instance_t *mi, size_t world) +jl_value_t *jl_code_or_ci_for_interpreter(jl_method_instance_t *mi JL_PROPAGATES_ROOT, size_t world) { jl_value_t *ret = NULL; jl_code_info_t *src = NULL; diff --git a/src/intrinsics.cpp b/src/intrinsics.cpp index 291605e9a3a9c..62a815a39d42a 100644 --- a/src/intrinsics.cpp +++ b/src/intrinsics.cpp @@ -185,7 +185,7 @@ static Value *uint_cnvt(jl_codectx_t &ctx, Type *to, Value *x) return ctx.builder.CreateZExtOrTrunc(x, to); } -static Constant *julia_const_to_llvm(jl_codectx_t &ctx, const void *ptr, jl_datatype_t *bt) +static Constant *julia_const_to_llvm(jl_codectx_t &ctx, const void *ptr, jl_datatype_t *bt) JL_CANSAFEPOINT { // assumes `jl_is_pointerfree(bt)`. // `ptr` can point to a inline field, do not read the tag from it. @@ -557,7 +557,7 @@ static jl_cgval_t emit_runtime_call(jl_codectx_t &ctx, JL_I::intrinsic f, ArrayR } // put a bits type tag on some value (despite the name, this doesn't necessarily actually change anything about the value however) -static jl_cgval_t generic_bitcast(jl_codectx_t &ctx, ArrayRef argv) +static jl_cgval_t generic_bitcast(jl_codectx_t &ctx, ArrayRef argv) JL_CANSAFEPOINT { // Give the arguments names // const jl_cgval_t &bt_value = argv[0]; @@ -673,7 +673,7 @@ static jl_cgval_t generic_bitcast(jl_codectx_t &ctx, ArrayRef argv) static jl_cgval_t generic_cast( jl_codectx_t &ctx, intrinsic f, Instruction::CastOps Op, - ArrayRef argv, bool toint, bool fromint) + ArrayRef argv, bool toint, bool fromint) JL_CANSAFEPOINT { auto &TT = ctx.emission_context.TargetTriple; auto &DL = ctx.emission_context.DL; @@ -744,12 +744,12 @@ static jl_cgval_t generic_cast( } } -static jl_cgval_t emit_runtime_pointerref(jl_codectx_t &ctx, ArrayRef argv) +static jl_cgval_t emit_runtime_pointerref(jl_codectx_t &ctx, ArrayRef argv) JL_CANSAFEPOINT { return emit_runtime_call(ctx, pointerref, argv, 3); } -static jl_cgval_t emit_pointerref(jl_codectx_t &ctx, ArrayRef argv) +static jl_cgval_t emit_pointerref(jl_codectx_t &ctx, ArrayRef argv) JL_CANSAFEPOINT { const jl_cgval_t &e = argv[0]; const jl_cgval_t &i = argv[1]; @@ -818,13 +818,13 @@ static jl_cgval_t emit_pointerref(jl_codectx_t &ctx, ArrayRef argv) } } -static jl_cgval_t emit_runtime_pointerset(jl_codectx_t &ctx, ArrayRef argv) +static jl_cgval_t emit_runtime_pointerset(jl_codectx_t &ctx, ArrayRef argv) JL_CANSAFEPOINT { return emit_runtime_call(ctx, pointerset, argv, 4); } // e[i] = x -static jl_cgval_t emit_pointerset(jl_codectx_t &ctx, ArrayRef argv) +static jl_cgval_t emit_pointerset(jl_codectx_t &ctx, ArrayRef argv) JL_CANSAFEPOINT { const jl_cgval_t &e = argv[0]; jl_cgval_t x = argv[1]; @@ -897,7 +897,7 @@ static jl_cgval_t emit_pointerset(jl_codectx_t &ctx, ArrayRef argv) // ptr + offset // ptr - offset static jl_cgval_t emit_pointerarith(jl_codectx_t &ctx, intrinsic f, - ArrayRef argv) + ArrayRef argv) JL_CANSAFEPOINT { jl_value_t *ptrtyp = argv[0].typ; jl_value_t *offtyp = argv[1].typ; @@ -922,7 +922,7 @@ static jl_cgval_t emit_pointerarith(jl_codectx_t &ctx, intrinsic f, } } -static jl_cgval_t emit_atomicfence(jl_codectx_t &ctx, ArrayRef argv) +static jl_cgval_t emit_atomicfence(jl_codectx_t &ctx, ArrayRef argv) JL_CANSAFEPOINT { const jl_cgval_t &ord = argv[0]; const jl_cgval_t &ssid_arg = argv[1]; @@ -947,7 +947,7 @@ static jl_cgval_t emit_atomicfence(jl_codectx_t &ctx, ArrayRef argv) return emit_runtime_call(ctx, atomic_fence, argv, 2); } -static jl_cgval_t emit_atomic_pointerref(jl_codectx_t &ctx, ArrayRef argv) +static jl_cgval_t emit_atomic_pointerref(jl_codectx_t &ctx, ArrayRef argv) JL_CANSAFEPOINT { const jl_cgval_t &e = argv[0]; const jl_cgval_t &ord = argv[1]; @@ -1024,7 +1024,7 @@ static jl_cgval_t emit_atomic_pointerref(jl_codectx_t &ctx, ArrayRef // e[i] <= x (swap) // e[i] y => x (replace) // x(e[i], y) (modify) -static jl_cgval_t emit_atomic_pointerop(jl_codectx_t &ctx, intrinsic f, ArrayRef argv, int nargs, const jl_cgval_t *modifyop) +static jl_cgval_t emit_atomic_pointerop(jl_codectx_t &ctx, intrinsic f, ArrayRef argv, int nargs, const jl_cgval_t *modifyop) JL_CANSAFEPOINT { StoreKind op; if (f == atomic_pointerset) @@ -1120,7 +1120,7 @@ static jl_cgval_t emit_atomic_pointerop(jl_codectx_t &ctx, intrinsic f, ArrayRef } } -static Value *emit_checked_srem_int(jl_codectx_t &ctx, Value *x, Value *den) +static Value *emit_checked_srem_int(jl_codectx_t &ctx, Value *x, Value *den) JL_CANSAFEPOINT { Type *t = den->getType(); auto ndivby0 = ctx.builder.CreateICmpNE(den, ConstantInt::get(t, 0)); @@ -1175,10 +1175,10 @@ struct math_builder { }; static Value *emit_untyped_intrinsic(jl_codectx_t &ctx, intrinsic f, ArrayRef argvalues, size_t nargs, - jl_datatype_t **newtyp, jl_value_t *xtyp); + jl_datatype_t **newtyp, jl_value_t *xtyp) JL_CANSAFEPOINT; -static jl_cgval_t emit_ifelse(jl_codectx_t &ctx, jl_cgval_t c, jl_cgval_t x, jl_cgval_t y, jl_value_t *rt_hint) +static jl_cgval_t emit_ifelse(jl_codectx_t &ctx, jl_cgval_t c, jl_cgval_t x, jl_cgval_t y, jl_value_t *rt_hint) JL_CANSAFEPOINT { Value *isfalse = emit_condition(ctx, c, "ifelse"); setName(ctx.emission_context, isfalse, "ifelse_cond"); @@ -1345,7 +1345,7 @@ static jl_cgval_t emit_ifelse(jl_codectx_t &ctx, jl_cgval_t c, jl_cgval_t x, jl_ return mark_julia_type(ctx, ifelse_result, isboxed, jt); } -static jl_cgval_t emit_intrinsic(jl_codectx_t &ctx, intrinsic f, jl_value_t **args, size_t nargs) +static jl_cgval_t emit_intrinsic(jl_codectx_t &ctx, intrinsic f, jl_value_t **args, size_t nargs) JL_CANSAFEPOINT { auto &DL = ctx.emission_context.DL; assert(f < num_intrinsics); diff --git a/src/ircode.c b/src/ircode.c index feecb5d6f8d06..6c55f43377ae3 100644 --- a/src/ircode.c +++ b/src/ircode.c @@ -121,7 +121,7 @@ static jl_value_t *jl_deser_symbol(uint8_t tag) // --- encoding --- -static void jl_encode_value_(jl_ircode_state *s, jl_value_t *v, int as_literal); +static void jl_encode_value_(jl_ircode_state *s, jl_value_t *v, int as_literal) JL_CANSAFEPOINT; #define jl_encode_value(s, v) jl_encode_value_((s), (jl_value_t*)(v), 0) static void tagged_root(rle_reference *rr, jl_ircode_state *s, int i) @@ -130,7 +130,7 @@ static void tagged_root(rle_reference *rr, jl_ircode_state *s, int i) s->relocatability = 0; } -static void literal_val_id(rle_reference *rr, jl_ircode_state *s, jl_value_t *v) +static void literal_val_id(rle_reference *rr, jl_ircode_state *s, jl_value_t *v) JL_CANSAFEPOINT { jl_array_t *rs = s->method->roots; int i, l = jl_array_nrows(rs); @@ -168,7 +168,7 @@ static void jl_encode_int32(jl_ircode_state *s, int32_t x) } } -static void jl_encode_as_indexed_root(jl_ircode_state *s, jl_value_t *v) +static void jl_encode_as_indexed_root(jl_ircode_state *s, jl_value_t *v) JL_CANSAFEPOINT { rle_reference rr = {.key = -1, .index = -1}; @@ -203,7 +203,7 @@ static void jl_encode_as_indexed_root(jl_ircode_state *s, jl_value_t *v) } } -static void jl_encode_memory_slice(jl_ircode_state *s, jl_genericmemory_t *mem, size_t offset, size_t len) +static void jl_encode_memory_slice(jl_ircode_state *s, jl_genericmemory_t *mem, size_t offset, size_t len) JL_CANSAFEPOINT { jl_datatype_t *t = (jl_datatype_t*)jl_typetagof(mem); size_t i; @@ -572,9 +572,9 @@ static jl_code_info_flags_t code_info_flags(uint8_t propagate_inbounds, uint8_t // --- decoding --- -static jl_value_t *jl_decode_value(jl_ircode_state *s); +static jl_value_t *jl_decode_value(jl_ircode_state *s) JL_CANSAFEPOINT; -static jl_value_t *jl_decode_value_svec(jl_ircode_state *s, uint8_t tag) +static jl_value_t *jl_decode_value_svec(jl_ircode_state *s, uint8_t tag) JL_CANSAFEPOINT { size_t i, len; if (tag == TAG_SVEC) @@ -589,7 +589,7 @@ static jl_value_t *jl_decode_value_svec(jl_ircode_state *s, uint8_t tag) return (jl_value_t*)sv; } -static jl_genericmemory_t *jl_decode_value_memory(jl_ircode_state *s, jl_value_t *mty, size_t nel) +static jl_genericmemory_t *jl_decode_value_memory(jl_ircode_state *s, jl_value_t *mty, size_t nel) JL_CANSAFEPOINT { jl_genericmemory_t *m = jl_alloc_genericmemory(mty, nel); JL_GC_PUSH1(&m); @@ -630,7 +630,7 @@ static jl_genericmemory_t *jl_decode_value_memory(jl_ircode_state *s, jl_value_t return m; } -static jl_value_t *jl_decode_value_array1d(jl_ircode_state *s, uint8_t tag) +static jl_value_t *jl_decode_value_array1d(jl_ircode_state *s, uint8_t tag) JL_CANSAFEPOINT { int16_t ndims = 1; size_t dim0 = jl_unbox_long(jl_decode_value(s)); @@ -652,7 +652,7 @@ static jl_value_t *jl_decode_value_array1d(jl_ircode_state *s, uint8_t tag) return (jl_value_t*)a; } -static jl_value_t *jl_decode_value_expr(jl_ircode_state *s, uint8_t tag) +static jl_value_t *jl_decode_value_expr(jl_ircode_state *s, uint8_t tag) JL_CANSAFEPOINT { size_t i, len; jl_sym_t *head = NULL; @@ -683,7 +683,7 @@ static jl_value_t *jl_decode_value_expr(jl_ircode_state *s, uint8_t tag) return (jl_value_t*)e; } -static jl_value_t *jl_decode_value_phi(jl_ircode_state *s, uint8_t tag) +static jl_value_t *jl_decode_value_phi(jl_ircode_state *s, uint8_t tag) JL_CANSAFEPOINT { size_t i, len_e, len_v; if (tag == TAG_PHINODE) { @@ -712,7 +712,7 @@ static jl_value_t *jl_decode_value_phi(jl_ircode_state *s, uint8_t tag) return phi; } -static jl_value_t *jl_decode_value_phic(jl_ircode_state *s, uint8_t tag) +static jl_value_t *jl_decode_value_phic(jl_ircode_state *s, uint8_t tag) JL_CANSAFEPOINT { size_t i, len; if (tag == TAG_PHICNODE) @@ -731,7 +731,7 @@ static jl_value_t *jl_decode_value_phic(jl_ircode_state *s, uint8_t tag) return phic; } -static jl_value_t *jl_decode_value_globalref(jl_ircode_state *s) +static jl_value_t *jl_decode_value_globalref(jl_ircode_state *s) JL_CANSAFEPOINT { jl_module_t *mod = (jl_module_t*)jl_decode_value(s); JL_GC_PROMISE_ROOTED(mod); @@ -740,7 +740,7 @@ static jl_value_t *jl_decode_value_globalref(jl_ircode_state *s) return jl_module_globalref(mod, var); } -static jl_value_t *jl_decode_value_any(jl_ircode_state *s) +static jl_value_t *jl_decode_value_any(jl_ircode_state *s) JL_CANSAFEPOINT { jl_datatype_t *dt = (jl_datatype_t*)jl_decode_value(s); JL_GC_PROMISE_ROOTED(dt); // (JL_ALWAYS_LEAFTYPE) diff --git a/src/jitlayers.cpp b/src/jitlayers.cpp index c5f14aa10ad2d..e05adfe554a49 100644 --- a/src/jitlayers.cpp +++ b/src/jitlayers.cpp @@ -167,7 +167,7 @@ void jl_dump_llvm_opt_impl(void *s) static void decorate_module(Module &M) JL_NOTSAFEPOINT; // convert local roots into global roots, if they are needed -static void jl_promote_method_roots(jl_codegen_output_t &out, jl_method_instance_t *mi) +static void jl_promote_method_roots(jl_codegen_output_t &out, jl_method_instance_t *mi) JL_CANSAFEPOINT { JL_GC_PROMISE_ROOTED(out.temporary_roots); // rooted by caller if (jl_array_dim0(out.temporary_roots) == 0) @@ -181,7 +181,7 @@ static void jl_promote_method_roots(jl_codegen_output_t &out, jl_method_instance auto ref = out.global_targets.find((void*)val); if (ref == out.global_targets.end()) continue; - auto get_global_root = [val, m]() { + auto get_global_root = [val, m]() JL_CANSAFEPOINT { if (jl_is_globally_rooted(val)) return val; if (jl_is_method(m) && m->roots) { @@ -690,7 +690,9 @@ void JLDebuginfoPlugin::notifyMaterializingWithInfo( } } -Error JLDebuginfoPlugin::notifyEmitted(MaterializationResponsibility &MR) +// TODO: analysis disabled since we aren't able to annotate that it was safe to lock +// std::mutex here because we asserted !jl_gcunsaferegion, so we don't need to assert jl_notsafepoint +Error JLDebuginfoPlugin::notifyEmitted(MaterializationResponsibility &MR) JL_NO_SAFEPOINT_ANALYSIS // NOLINT[julia-first-decl-annotations] { { std::lock_guard lock(PluginMutex); @@ -882,7 +884,7 @@ class JLMaterializationUnit : public orc::MaterializationUnit { } // During materialization: finalizers disabled, GC safe - void materialize(std::unique_ptr R) JL_NOTSAFEPOINT_LEAVE JL_NOTSAFEPOINT_ENTER override + void materialize(std::unique_ptr R) JL_CANSAFEPOINT_ENTER_LEAVE override // NOLINT[julia-first-decl-annotations] { auto &ES = R->getExecutionSession(); @@ -983,7 +985,7 @@ class JLTrampolineMaterializationUnit : public orc::MaterializationUnit { }; // During materialization: finalizers disabled, GC safe - void materialize(std::unique_ptr R) JL_NOTSAFEPOINT_ENTER JL_NOTSAFEPOINT_LEAVE override + void materialize(std::unique_ptr R) JL_CANSAFEPOINT_ENTER_LEAVE override // NOLINT[julia-first-decl-annotations] { auto Ctx = std::make_unique(); auto Mod = @@ -1536,7 +1538,9 @@ struct JuliaOJIT::DLSymOptimizer { return addr; } - void *lookup(const char *libname, const char *fname) JL_NOTSAFEPOINT_LEAVE JL_NOTSAFEPOINT_ENTER { + // TODO: analysis disabled since we aren't able to annotate that it was safe to lock + // std::mutex here because we asserted !jl_gcunsaferegion, so we don't need to assert jl_notsafepoint + void *lookup(const char *libname, const char *fname) JL_CANSAFEPOINT_ENTER_LEAVE JL_NO_SAFEPOINT_ANALYSIS { StringRef lib(libname); StringRef f(fname); std::lock_guard lock(symbols_mutex); @@ -1572,7 +1576,7 @@ struct JuliaOJIT::DLSymOptimizer { return handle; } - void operator()(Module &M) JL_NOTSAFEPOINT_LEAVE JL_NOTSAFEPOINT_ENTER { + void operator()(Module &M) JL_CANSAFEPOINT_ENTER_LEAVE { for (auto &GV : M.globals()) { auto Name = GV.getName(); if (Name.starts_with("jlplt") && Name.ends_with("got")) { @@ -2467,8 +2471,14 @@ CISymbolPtr *JuliaOJIT::linkCISymbol(jl_code_instance_t *CI) void *SpecPtr; // Tell the analyzer no safepoint is possible with waitcompile = 0 +#ifdef __clang_safetyanalysis__ + #define jl_read_codeinst_invoke jl_read_codeinst_invoke_nosafepoint +#endif void jl_read_codeinst_invoke(jl_code_instance_t *, uint8_t *, jl_callptr_t *, void **, int) JL_NOTSAFEPOINT; jl_read_codeinst_invoke(CI, &Flags, &Invoke, &SpecPtr, 0); +#ifdef __clang_safetyanalysis__ + #undef jl_read_codeinst_invoke +#endif if (!(Flags & JL_CI_FLAGS_INVOKE_MATCHES_SPECPTR)) return nullptr; diff --git a/src/jitlayers.h b/src/jitlayers.h index 761d6765e7f61..f8e183fe80d95 100644 --- a/src/jitlayers.h +++ b/src/jitlayers.h @@ -309,10 +309,10 @@ struct jl_locked_stream { } }; - jl_locked_stream() JL_NOTSAFEPOINT JL_NOTSAFEPOINT_ENTER = default; - ~jl_locked_stream() JL_NOTSAFEPOINT JL_NOTSAFEPOINT_LEAVE = default; + jl_locked_stream() JL_NOTSAFEPOINT = default; + ~jl_locked_stream() JL_NOTSAFEPOINT = default; - lock operator*() JL_NOTSAFEPOINT { + lock operator*() JL_NOTSAFEPOINT JL_NOTSAFEPOINT_ENTER { return lock(mutex, stream); } }; @@ -446,7 +446,7 @@ class jl_codegen_output_t { std::string make_name(StringRef prefix, StringRef orig_name) JL_NOTSAFEPOINT; std::string make_name(StringRef orig_name) JL_NOTSAFEPOINT; - StringRef get_call_target(jl_code_instance_t *ci, bool specsig, bool always_inline); + StringRef get_call_target(jl_code_instance_t *ci, bool specsig, bool always_inline) JL_CANSAFEPOINT; // Discard all the context that will be invalidated when we compile the // module. The context and module will be moved to the jl_emitted_output_t. @@ -508,7 +508,7 @@ class jl_codegen_output_t { ~jl_codegen_output_t() JL_NOTSAFEPOINT = default; }; -const char *jl_generate_ccallable(jl_codegen_output_t &out, jl_value_t *nameval, jl_value_t *declrt, jl_value_t *sigt); +const char *jl_generate_ccallable(jl_codegen_output_t &out, jl_value_t *nameval, jl_value_t *declrt, jl_value_t *sigt) JL_CANSAFEPOINT; std::optional jl_emit_code( jl_codegen_output_t &out, @@ -516,20 +516,20 @@ std::optional jl_emit_code( jl_code_info_t *src, jl_value_t *abi_at, jl_value_t *abi_rt, - jl_code_instance_t *codeinst = nullptr); + jl_code_instance_t *codeinst = nullptr) JL_CANSAFEPOINT; std::optional jl_emit_codeinst( jl_codegen_output_t &out, jl_code_instance_t *codeinst, - jl_code_info_t *src); + jl_code_info_t *src) JL_CANSAFEPOINT; jl_llvm_functions_t jl_emit_codedecls( jl_codegen_output_t &out, - jl_code_instance_t *codeinst); + jl_code_instance_t *codeinst) JL_CANSAFEPOINT; -jl_code_info_t *jl_get_method_ir(jl_code_instance_t *ci); +jl_code_info_t *jl_get_method_ir(jl_code_instance_t *ci) JL_CANSAFEPOINT; void emit_always_inline(jl_codegen_output_t &out, - unique_function get_src); + unique_function get_src) JL_CANSAFEPOINT; void emit_llvmcall_modules(jl_codegen_output_t &out) JL_NOTSAFEPOINT; enum CompilationPolicy { @@ -542,20 +542,20 @@ Function *jl_cfunction_object(jl_value_t *f, jl_value_t *rt, jl_tupletype_t *arg extern "C" JL_DLLEXPORT_CODEGEN void *jl_jit_abi_convert(jl_task_t *ct, jl_abi_t from_abi, _Atomic(void*) *fptr, _Atomic(size_t) *last_world, void *data); -std::string emit_abi_dispatcher(jl_codegen_output_t &out, jl_abi_t from_abi, jl_code_instance_t *codeinst, Value *invoke); -std::string emit_abi_converter(jl_codegen_output_t &out, jl_abi_t from_abi, jl_code_instance_t *codeinst, Value *target, bool target_specsig); -std::string emit_abi_constreturn(jl_codegen_output_t &out, jl_abi_t from_abi, jl_value_t *rettype_const); -std::string emit_abi_constreturn(jl_codegen_output_t &out, bool specsig, jl_code_instance_t *codeinst); +std::string emit_abi_dispatcher(jl_codegen_output_t &out, jl_abi_t from_abi, jl_code_instance_t *codeinst, Value *invoke) JL_CANSAFEPOINT; +std::string emit_abi_converter(jl_codegen_output_t &out, jl_abi_t from_abi, jl_code_instance_t *codeinst, Value *target, bool target_specsig) JL_CANSAFEPOINT; +std::string emit_abi_constreturn(jl_codegen_output_t &out, jl_abi_t from_abi, jl_value_t *rettype_const) JL_CANSAFEPOINT; +std::string emit_abi_constreturn(jl_codegen_output_t &out, bool specsig, jl_code_instance_t *codeinst) JL_CANSAFEPOINT; -Function *emit_tojlinvoke(jl_code_instance_t *codeinst, StringRef theFptrName, jl_codegen_output_t &out) JL_NOTSAFEPOINT; +Function *emit_tojlinvoke(jl_code_instance_t *codeinst, StringRef theFptrName, jl_codegen_output_t &out) JL_CANSAFEPOINT; void emit_specsig_to_fptr1( Function *gf_thunk, jl_returninfo_t::CallingConv cc, unsigned return_roots, jl_value_t *calltype, jl_value_t *rettype, bool is_for_opaque_closure, size_t nargs, jl_codegen_output_t &out, - Value *target) JL_NOTSAFEPOINT; + Value *target) JL_CANSAFEPOINT; Function *emit_specsig_to_fptr1(jl_codegen_output_t &out, jl_code_instance_t *ci, - Value *func) JL_NOTSAFEPOINT; + Value *func) JL_CANSAFEPOINT; Function *get_or_emit_fptr1(StringRef Name, Module *M) JL_NOTSAFEPOINT; void jl_init_function(Function *F, const jl_codegen_output_t ¶ms) JL_NOTSAFEPOINT; @@ -563,11 +563,11 @@ jl_returninfo_t get_specsig_function(jl_codegen_output_t &ctx, Module *M, Value StringRef name, jl_value_t *sig, jl_value_t *jlrettype, bool is_opaque_closure, ArrayRef ArgNames = {}, - unsigned nreq = 0); + unsigned nreq = 0) JL_CANSAFEPOINT; void add_named_global(StringRef name, void *addr) JL_NOTSAFEPOINT; -Constant *literal_pointer_val_slot(jl_codegen_output_t &out, jl_value_t *p); +Constant *literal_pointer_val_slot(jl_codegen_output_t &out, jl_value_t *p) JL_CANSAFEPOINT; static inline Constant *literal_static_pointer_val(const void *p, Type *T) JL_NOTSAFEPOINT { @@ -658,7 +658,7 @@ class JLDebuginfoPlugin : public orc::ObjectLinkingLayer::Plugin { jitlink::LinkGraph &G, MemoryBufferRef InputObject, std::unique_ptr LinkerInfo) JL_NOTSAFEPOINT; - Error notifyEmitted(orc::MaterializationResponsibility &MR) override JL_NOTSAFEPOINT_ENTER JL_NOTSAFEPOINT_LEAVE; + Error notifyEmitted(orc::MaterializationResponsibility &MR) override JL_CANSAFEPOINT_ENTER_LEAVE; // NOLINT[julia-first-decl-annotations] Error notifyFailed(orc::MaterializationResponsibility &MR) override; Error notifyRemovingResources(orc::JITDylib &JD, orc::ResourceKey K) override; void notifyTransferringResources(orc::JITDylib &JD, orc::ResourceKey DstKey, @@ -814,7 +814,7 @@ class JuliaOJIT { JuliaOJIT() JL_NOTSAFEPOINT; ~JuliaOJIT() JL_NOTSAFEPOINT; - void enableJITDebuggingSupport(); + void enableJITDebuggingSupport() JL_CANSAFEPOINT; void enableIntelJITEventListener() JL_NOTSAFEPOINT; void enableOProfileJITEventListener() JL_NOTSAFEPOINT; void enablePerfJITEventListener() JL_NOTSAFEPOINT; @@ -830,12 +830,12 @@ class JuliaOJIT { orc::ExecutionSession &getExecutionSession() JL_NOTSAFEPOINT { return ES; } orc::JITDylib &createJITDylib(StringRef NamePrefix) JL_NOTSAFEPOINT; - Expected findJDSymbol(orc::JITDylib &JD, StringRef Name, bool ExportedSymbolsOnly); - SmallVector findSymbols(ArrayRef Names); - uint64_t getGlobalValueAddress(StringRef Name); - uint64_t getFunctionAddress(StringRef Name); + Expected findJDSymbol(orc::JITDylib &JD, StringRef Name, bool ExportedSymbolsOnly) JL_CANSAFEPOINT; + SmallVector findSymbols(ArrayRef Names) JL_CANSAFEPOINT; + uint64_t getGlobalValueAddress(StringRef Name) JL_CANSAFEPOINT; + uint64_t getFunctionAddress(StringRef Name) JL_CANSAFEPOINT; - void publishCIs(ArrayRef CIs, bool Wait=false); + void publishCIs(ArrayRef CIs, bool Wait=false) JL_CANSAFEPOINT; void registerCI(jl_code_instance_t *CI) JL_NOTSAFEPOINT; // When a CodeInstance is garbage collected, we must remove any existing @@ -859,13 +859,13 @@ class JuliaOJIT { void addBytes(size_t bytes) JL_NOTSAFEPOINT; void printTimers() JL_NOTSAFEPOINT; - jl_locked_stream &get_dump_emitted_mi_name_stream() JL_NOTSAFEPOINT JL_NOTSAFEPOINT_ENTER { + jl_locked_stream &get_dump_emitted_mi_name_stream() JL_NOTSAFEPOINT { return dump_emitted_mi_name_stream; } - jl_locked_stream &get_dump_compiles_stream() JL_NOTSAFEPOINT JL_NOTSAFEPOINT_ENTER { + jl_locked_stream &get_dump_compiles_stream() JL_NOTSAFEPOINT { return dump_compiles_stream; } - jl_locked_stream &get_dump_llvm_opt_stream() JL_NOTSAFEPOINT JL_NOTSAFEPOINT_ENTER { + jl_locked_stream &get_dump_llvm_opt_stream() JL_NOTSAFEPOINT { return dump_llvm_opt_stream; } std::string getMangledName(StringRef Name) JL_NOTSAFEPOINT; @@ -873,8 +873,7 @@ class JuliaOJIT { // Note that this is a potential safepoint due to jl_get_library_ and jl_dlsym calls // and must be called from inside safe-regions due to internal use of locks - // (this lock strategy is unusual here, so the annotations aren't entirely correct) - void optimizeDLSyms(Module &M) JL_NOTSAFEPOINT_LEAVE JL_NOTSAFEPOINT_ENTER; + void optimizeDLSyms(Module &M) JL_CANSAFEPOINT_ENTER_LEAVE; void shutdown() JL_NOTSAFEPOINT; @@ -966,7 +965,7 @@ extern JuliaOJIT *jl_ExecutionEngine; void fixupTM(TargetMachine &TM) JL_NOTSAFEPOINT; -void optimizeDLSyms(Module &M) JL_NOTSAFEPOINT_LEAVE JL_NOTSAFEPOINT_ENTER; +void optimizeDLSyms(Module &M) JL_CANSAFEPOINT_ENTER_LEAVE; static inline const char *jl_symbol_prefix(jl_symbol_prefix_t type, jl_invoke_api_t api) JL_NOTSAFEPOINT @@ -1020,4 +1019,4 @@ void jl_jit_add_bytes(size_t bytes) JL_NOTSAFEPOINT; void jl_register_jit_object(const object::ObjectFile &Object, std::function getLoadAddress, - const jl_linker_info_t &Info) JL_NOTSAFEPOINT_ENTER JL_NOTSAFEPOINT_LEAVE; + const jl_linker_info_t &Info) JL_CANSAFEPOINT_ENTER_LEAVE; diff --git a/src/jl_exported_funcs.inc b/src/jl_exported_funcs.inc index de86511a2508c..7b432dd64d745 100644 --- a/src/jl_exported_funcs.inc +++ b/src/jl_exported_funcs.inc @@ -20,7 +20,6 @@ XX(jl_apply_type) \ XX(jl_apply_type1) \ XX(jl_apply_type2) \ - XX(jl_arg_slot_type) \ XX(jl_argument_datatype) \ XX(jl_argument_datatypename) \ XX(jl_array_del_end) \ diff --git a/src/jl_uv.c b/src/jl_uv.c index d0ef9ce27eef0..45f6dea809a75 100644 --- a/src/jl_uv.c +++ b/src/jl_uv.c @@ -62,7 +62,7 @@ static void walk_print_cb(uv_handle_t *h, void *arg) jl_safe_printf(" %s[%zd] %s%p->%p\n", type, resource_id, pad, (void*)h, (void*)h->data); } -static void wait_empty_func(uv_timer_t *t) +static void wait_empty_func(uv_timer_t *t) JL_CANSAFEPOINT { // make sure this is hidden now, since we would auto-unref it later uv_unref((uv_handle_t*)&signal_async); @@ -145,7 +145,7 @@ void JL_UV_LOCK(void) /** * @brief Begin an IO lock. */ -JL_DLLEXPORT void jl_iolock_begin(void) +JL_DLLEXPORT void jl_iolock_begin(void) JL_CANSAFEPOINT { JL_UV_LOCK(); } @@ -153,13 +153,13 @@ JL_DLLEXPORT void jl_iolock_begin(void) /** * @brief End an IO lock. */ -JL_DLLEXPORT void jl_iolock_end(void) +JL_DLLEXPORT void jl_iolock_end(void) JL_CANSAFEPOINT { JL_UV_UNLOCK(); } -static void jl_uv_call_close_callback(jl_value_t *val) +static void jl_uv_call_close_callback(jl_value_t *val) JL_CANSAFEPOINT { jl_value_t **args; JL_GC_PUSHARGS(args, 2); // val is "rooted" in the finalizer list only right now @@ -172,7 +172,7 @@ static void jl_uv_call_close_callback(jl_value_t *val) JL_GC_POP(); } -static void jl_uv_closeHandle(uv_handle_t *handle) +static void jl_uv_closeHandle(uv_handle_t *handle) JL_CANSAFEPOINT { // if the user killed a stdio handle, // revert back to direct stdio FILE* writes @@ -453,7 +453,7 @@ JL_DLLEXPORT void jl_close_uv(uv_handle_t *handle) * * @param handle A pointer to `uv_handle_t` to be forcefully closed. */ -JL_DLLEXPORT void jl_forceclose_uv(uv_handle_t *handle) +JL_DLLEXPORT void jl_forceclose_uv(uv_handle_t *handle) JL_CANSAFEPOINT { if (!uv_is_closing(handle)) { // avoid double-closing the stream JL_UV_LOCK(); @@ -517,7 +517,7 @@ JL_DLLEXPORT int jl_spawn(char *name, char **argv, uv_loop_t *loop, uv_process_t *proc, uv_stdio_container_t *stdio, int nstdio, uint32_t flags, char **env, char *cwd, char* cpumask, - size_t cpumask_size, uint32_t uid, uint32_t gid, uv_exit_cb cb) + size_t cpumask_size, uint32_t uid, uint32_t gid, uv_exit_cb cb) JL_CANSAFEPOINT { uv_process_options_t opts = {0}; opts.stdio = stdio; @@ -687,7 +687,7 @@ JL_DLLEXPORT int jl_fs_close(uv_os_fd_t handle) } JL_DLLEXPORT int jl_uv_write(uv_stream_t *stream, const char *data, size_t n, - uv_write_t *uvw, uv_write_cb writecb) + uv_write_t *uvw, uv_write_cb writecb) JL_CANSAFEPOINT { uv_buf_t buf[1]; buf[0].base = (char*)data; @@ -771,12 +771,12 @@ JL_DLLEXPORT void jl_uv_puts(uv_stream_t *stream, const char *str, size_t n) } } -JL_DLLEXPORT void jl_uv_putb(uv_stream_t *stream, uint8_t b) +JL_DLLEXPORT void jl_uv_putb(uv_stream_t *stream, uint8_t b) JL_CANSAFEPOINT { jl_uv_puts(stream, (char*)&b, 1); } -JL_DLLEXPORT void jl_uv_putc(uv_stream_t *stream, uint32_t c) +JL_DLLEXPORT void jl_uv_putc(uv_stream_t *stream, uint32_t c) JL_CANSAFEPOINT { char s[4]; int n = 1; @@ -1107,7 +1107,7 @@ JL_DLLEXPORT int jl_tcp_reuseport(uv_tcp_t *handle) #ifndef _OS_WINDOWS_ JL_DLLEXPORT int jl_uv_unix_fd_is_watched(int fd, uv_poll_t *handle, - uv_loop_t *loop) + uv_loop_t *loop) JL_CANSAFEPOINT { JL_UV_LOCK(); if (fd >= loop->nwatchers) { @@ -1232,7 +1232,7 @@ static void jl_work_notifier(uv_work_t *req, int status) JL_DLLEXPORT int jl_queue_work(work_cb_t work_func, void *work_ctx, notify_cb_t notify_func, void *notify_data1, - void *notify_data2) + void *notify_data2) JL_CANSAFEPOINT { struct work_baton *baton = (struct work_baton*)malloc_s(sizeof(struct work_baton)); baton->req.data = (void*) baton; diff --git a/src/jlapi.c b/src/jlapi.c index b2e6cbf6e7b8c..dac9cd0a57329 100644 --- a/src/jlapi.c +++ b/src/jlapi.c @@ -89,8 +89,10 @@ JL_DLLEXPORT jl_value_t *jl_set_ARGS(int argc, char **argv) } JL_DLLEXPORT void jl_init_with_image_handle(void *handle) { +#if !defined(__clang_safetyanalysis__) && !defined(__clang_gcanalyzer__) if (jl_is_initialized()) return; +#endif const char *image_path = jl_pathname_for_handle(handle); jl_options.image_file = image_path; @@ -119,8 +121,10 @@ JL_DLLEXPORT void jl_init_with_image_handle(void *handle) { JL_DLLEXPORT void jl_init_with_image_file(const char *julia_bindir, const char *image_path) { +#if !defined(__clang_safetyanalysis__) && !defined(__clang_gcanalyzer__) if (jl_is_initialized()) return; +#endif if (image_path != NULL) jl_options.image_file = image_path; else @@ -136,7 +140,7 @@ JL_DLLEXPORT void jl_init_with_image_file(const char *julia_bindir, // Deprecated function, kept for backward compatibility JL_DLLEXPORT void jl_init_with_image(const char *julia_bindir, - const char *image_path) + const char *image_path) JL_CANSAFEPOINT_ENTER { jl_init_with_image_file(julia_bindir, image_path); } @@ -591,7 +595,7 @@ JL_DLLEXPORT int8_t jl_is_memdebug(void) JL_NOTSAFEPOINT { * * @return A pointer to `jl_value_t` representing the directory path as a Julia string. */ -JL_DLLEXPORT jl_value_t *jl_get_julia_bindir(void) +JL_DLLEXPORT jl_value_t *jl_get_julia_bindir(void) JL_CANSAFEPOINT { return jl_cstr_to_string(jl_options.julia_bindir); } @@ -601,7 +605,7 @@ JL_DLLEXPORT jl_value_t *jl_get_julia_bindir(void) * * @return A pointer to `jl_value_t` representing the full path as a Julia string. */ -JL_DLLEXPORT jl_value_t *jl_get_julia_bin(void) +JL_DLLEXPORT jl_value_t *jl_get_julia_bin(void) JL_CANSAFEPOINT { return jl_cstr_to_string(jl_options.julia_bin); } @@ -611,7 +615,7 @@ JL_DLLEXPORT jl_value_t *jl_get_julia_bin(void) * * @return A pointer to `jl_value_t` representing the system image file path as a Julia string. */ -JL_DLLEXPORT jl_value_t *jl_get_image_file(void) +JL_DLLEXPORT jl_value_t *jl_get_image_file(void) JL_CANSAFEPOINT { return jl_cstr_to_string(jl_options.image_file); } @@ -711,7 +715,7 @@ JL_DLLEXPORT jl_value_t *(jl_typeof)(jl_value_t *v) * @param v A pointer to `jl_value_t` representing the Julia value. * @return A pointer to `jl_value_t` representing the field types. */ -JL_DLLEXPORT jl_value_t *(jl_get_fieldtypes)(jl_value_t *v) +JL_DLLEXPORT jl_value_t *(jl_get_fieldtypes)(jl_value_t *v) JL_CANSAFEPOINT { return (jl_value_t*)jl_get_fieldtypes((jl_datatype_t*)v); } @@ -729,7 +733,7 @@ JL_DLLEXPORT int ijl_egal(jl_value_t *a, jl_value_t *b) } -#ifndef __clang_gcanalyzer__ +#if !defined(__clang_gcanalyzer__) && !defined(__clang_analyzer__) /** * @brief Enter a state where concurrent garbage collection (GC) is considered unsafe. * @@ -933,7 +937,7 @@ JL_DLLEXPORT int jl_set_fenv_rounding(int i) return fesetround(i); } -static int exec_program(char *program) +static int exec_program(char *program) JL_CANSAFEPOINT { jl_task_t *ct = jl_current_task; JL_TRY { @@ -966,7 +970,7 @@ static int exec_program(char *program) return 0; } -static NOINLINE int true_main(int argc, char *argv[]) +static NOINLINE int true_main(int argc, char *argv[]) JL_CANSAFEPOINT { jl_set_ARGS(argc, argv); @@ -1098,7 +1102,7 @@ static void rr_detach_teleport(void) JL_NOTSAFEPOINT { * @param argv Array of command-line arguments. * @return An integer indicating the exit status of the REPL session. */ -JL_DLLEXPORT int jl_repl_entrypoint(int argc, char *argv[]) JL_NOTSAFEPOINT_ENTER +JL_DLLEXPORT int jl_repl_entrypoint(int argc, char *argv[]) JL_CANSAFEPOINT_ENTER_LEAVE { #ifdef USE_TRACY if (getenv("JULIA_WAIT_FOR_TRACY")) @@ -1141,13 +1145,17 @@ JL_DLLEXPORT int jl_repl_entrypoint(int argc, char *argv[]) JL_NOTSAFEPOINT_ENTE jl_init_(sysimage); + int ret; if (lisp_prompt) { jl_current_task->world_age = jl_get_world_counter(); jl_lisp_prompt(); - return 0; + ret = 0; + jl_gc_safe_enter(jl_current_task->ptls); // park in gc-safe for analyzer, skipping atexit hook + } + else { + ret = true_main(argc, (char**)new_argv); + jl_atexit_hook(ret); } - int ret = true_main(argc, (char**)new_argv); - jl_atexit_hook(ret); return ret; } diff --git a/src/jltypes.c b/src/jltypes.c index 5b57b26411bc3..1691e09b9833b 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -56,7 +56,7 @@ static int typeenv_has_ne(jl_typeenv_t *env, jl_tvar_t *v) JL_NOTSAFEPOINT } -static int layout_uses_free_typevars(jl_value_t *v, jl_typeenv_t *env) +static int layout_uses_free_typevars(jl_value_t *v, jl_typeenv_t *env) JL_CANSAFEPOINT { while (1) { if (jl_is_typevar(v)) @@ -184,7 +184,7 @@ JL_DLLEXPORT int jl_has_free_typevars(jl_value_t *v) JL_NOTSAFEPOINT return has_free_typevars(v, NULL); } -static void find_free_typevars(jl_value_t *v, jl_typeenv_t *env, jl_array_t *out) +static void find_free_typevars(jl_value_t *v, jl_typeenv_t *env, jl_array_t *out) JL_CANSAFEPOINT { while (1) { if (jl_is_typevar(v)) { @@ -608,7 +608,7 @@ static int count_union_components(jl_value_t **types, size_t n, int widen) return c; } -static void flatten_type_union(jl_value_t **types, size_t n, jl_value_t **out, size_t *idx, int widen) +static void flatten_type_union(jl_value_t **types, size_t n, jl_value_t **out, size_t *idx, int widen) JL_CANSAFEPOINT { size_t i; for (i = 0; i < n; i++) { @@ -689,7 +689,7 @@ int simple_subtype(jl_value_t *a, jl_value_t *b, int hasfree, int isUnion) // merge Union{Tuple{}, Tuple{T}, Tuple{T, T, Vararg{T}}} into Tuple{Vararg{T}} // assumes temp is already sorted by number of type parameters -STATIC_INLINE void merge_vararg_unions(jl_value_t **temp, size_t nt) +STATIC_INLINE void merge_vararg_unions(jl_value_t **temp, size_t nt) JL_CANSAFEPOINT { for (size_t i = nt-1; i > 0; i--) { // match types of form Tuple{T, ..., Vararg{T}} @@ -784,7 +784,7 @@ JL_DLLEXPORT jl_value_t *jl_type_union(jl_value_t **ts, size_t n) return tu; } -static int simple_subtype2(jl_value_t *a, jl_value_t *b, int hasfree, int isUnion) +static int simple_subtype2(jl_value_t *a, jl_value_t *b, int hasfree, int isUnion) JL_CANSAFEPOINT { assert(hasfree == (jl_has_free_typevars(a) | (jl_has_free_typevars(b) << 1))); int subab = 0, subba = 0; @@ -1056,7 +1056,7 @@ JL_DLLEXPORT jl_value_t *jl_type_unionall(jl_tvar_t *v, jl_value_t *body) // --- type instantiation and cache --- -static int typekey_eq(jl_datatype_t *tt, jl_value_t **key, size_t n) +static int typekey_eq(jl_datatype_t *tt, jl_value_t **key, size_t n) JL_CANSAFEPOINT { size_t j; // TODO: This shouldn't be necessary @@ -1086,7 +1086,7 @@ static int typekey_eq(jl_datatype_t *tt, jl_value_t **key, size_t n) // These `value` functions return the same values as the primary functions, // but operate on the typeof/Typeof each object in an array -static int typekeyvalue_eq(jl_datatype_t *tt, jl_value_t *key1, jl_value_t **key, size_t n, int leaf) +static int typekeyvalue_eq(jl_datatype_t *tt, jl_value_t *key1, jl_value_t **key, size_t n, int leaf) JL_CANSAFEPOINT { size_t j; // TODO: This shouldn't be necessary @@ -1130,7 +1130,7 @@ static unsigned typekeyvalue_hash(jl_typename_t *tn, jl_value_t *key1, jl_value_ static jl_value_t *extract_wrapper(jl_value_t *t JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT JL_GLOBALLY_ROOTED; /* returns val if key is in hash, otherwise NULL */ -static jl_datatype_t *lookup_type_set(jl_svec_t *cache, jl_value_t **key, size_t n, uint_t hv) +static jl_datatype_t *lookup_type_set(jl_svec_t *cache, jl_value_t **key, size_t n, uint_t hv) JL_CANSAFEPOINT { size_t sz = jl_svec_len(cache); if (sz == 0) @@ -1153,7 +1153,7 @@ static jl_datatype_t *lookup_type_set(jl_svec_t *cache, jl_value_t **key, size_t } /* returns val if key is in hash, otherwise NULL */ -static jl_datatype_t *lookup_type_setvalue(jl_svec_t *cache, jl_value_t *key1, jl_value_t **key, size_t n, uint_t hv, int leaf) +static jl_datatype_t *lookup_type_setvalue(jl_svec_t *cache, jl_value_t *key1, jl_value_t **key, size_t n, uint_t hv, int leaf) JL_CANSAFEPOINT { size_t sz = jl_svec_len(cache); if (sz == 0) @@ -1178,7 +1178,7 @@ static jl_datatype_t *lookup_type_setvalue(jl_svec_t *cache, jl_value_t *key1, j // look up a type in a cache by binary or linear search. // if found, returns the index of the found item. if not found, returns // ~n, where n is the index where the type should be inserted. -static ssize_t lookup_type_idx_linear(jl_svec_t *cache, jl_value_t **key, size_t n) +static ssize_t lookup_type_idx_linear(jl_svec_t *cache, jl_value_t **key, size_t n) JL_CANSAFEPOINT { if (n == 0) return -1; @@ -1195,7 +1195,7 @@ static ssize_t lookup_type_idx_linear(jl_svec_t *cache, jl_value_t **key, size_t return ~cl; } -static ssize_t lookup_type_idx_linearvalue(jl_svec_t *cache, jl_value_t *key1, jl_value_t **key, size_t n) +static ssize_t lookup_type_idx_linearvalue(jl_svec_t *cache, jl_value_t *key1, jl_value_t **key, size_t n) JL_CANSAFEPOINT { if (n == 0) return -1; @@ -1212,7 +1212,7 @@ static ssize_t lookup_type_idx_linearvalue(jl_svec_t *cache, jl_value_t *key1, j return ~cl; } -static jl_value_t *lookup_type(jl_typename_t *tn JL_PROPAGATES_ROOT, jl_value_t **key, size_t n) +static jl_value_t *lookup_type(jl_typename_t *tn JL_PROPAGATES_ROOT, jl_value_t **key, size_t n) JL_CANSAFEPOINT { JL_TIMING(TYPE_CACHE_LOOKUP, TYPE_CACHE_LOOKUP); if (tn == jl_type_typename) { @@ -1233,7 +1233,7 @@ static jl_value_t *lookup_type(jl_typename_t *tn JL_PROPAGATES_ROOT, jl_value_t } } -static jl_value_t *lookup_typevalue(jl_typename_t *tn, jl_value_t *key1, jl_value_t **key, size_t n, int leaf) +static jl_value_t *lookup_typevalue(jl_typename_t *tn, jl_value_t *key1, jl_value_t **key, size_t n, int leaf) JL_CANSAFEPOINT { JL_TIMING(TYPE_CACHE_LOOKUP, TYPE_CACHE_LOOKUP); unsigned hv = typekeyvalue_hash(tn, key1, key, n, leaf); @@ -1277,7 +1277,7 @@ static int cache_insert_type_set_(jl_svec_t *a, jl_datatype_t *val, uint_t hv, i return 0; } -static void cache_insert_type_set(jl_datatype_t *val, uint_t hv) +static void cache_insert_type_set(jl_datatype_t *val, uint_t hv) JL_CANSAFEPOINT { jl_svec_t *a = jl_atomic_load_relaxed(&val->name->cache); while (1) { @@ -1327,7 +1327,7 @@ jl_svec_t *cache_rehash_set(jl_svec_t *a, size_t newsz) } } -static void cache_insert_type_linear(jl_datatype_t *type, ssize_t insert_at) +static void cache_insert_type_linear(jl_datatype_t *type, ssize_t insert_at) JL_CANSAFEPOINT { jl_svec_t *cache = jl_atomic_load_relaxed(&type->name->linearcache); assert(jl_is_svec(cache)); @@ -1476,7 +1476,7 @@ int jl_type_equality_is_identity(jl_value_t *t1, jl_value_t *t2) JL_NOTSAFEPOINT // type instantiation -static int within_typevar(jl_value_t *t, jl_value_t *vlb, jl_value_t *vub) +static int within_typevar(jl_value_t *t, jl_value_t *vlb, jl_value_t *vub) JL_CANSAFEPOINT { jl_value_t *lb = t, *ub = t; if (jl_is_typevar(t) || jl_has_free_typevars(t)) { @@ -1497,12 +1497,12 @@ struct _jl_typestack_t; typedef struct _jl_typestack_t jl_typestack_t; static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value_t **iparams, size_t ntp, - jl_typestack_t *stack, jl_typeenv_t *env, int check, int nothrow); + jl_typestack_t *stack, jl_typeenv_t *env, int check, int nothrow) JL_CANSAFEPOINT; // Build an environment mapping a TypeName's parameters to parameter values. // This is the environment needed for instantiating a type's supertype and field types. static jl_value_t *inst_datatype_env(jl_value_t *dt, jl_svec_t *p, jl_value_t **iparams, size_t ntp, - jl_typestack_t *stack, jl_typeenv_t *env, int c) + jl_typestack_t *stack, jl_typeenv_t *env, int c) JL_CANSAFEPOINT { if (jl_is_datatype(dt)) return inst_datatype_inner((jl_datatype_t*)dt, p, iparams, ntp, stack, env, 1, 0); @@ -1645,8 +1645,8 @@ JL_EXTENSION struct _jl_typestack_t { struct _jl_typestack_t *prev; }; -static jl_value_t *inst_type_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t *stack, int check, int nothrow); -static jl_svec_t *inst_ftypes(jl_svec_t *p, jl_typeenv_t *env, jl_typestack_t *stack, int cacheable); +static jl_value_t *inst_type_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t *stack, int check, int nothrow) JL_CANSAFEPOINT; +static jl_svec_t *inst_ftypes(jl_svec_t *p, jl_typeenv_t *env, jl_typestack_t *stack, int cacheable) JL_CANSAFEPOINT; JL_DLLEXPORT jl_value_t *jl_instantiate_unionall(jl_unionall_t *u, jl_value_t *p) { @@ -1849,7 +1849,7 @@ jl_value_t *jl_substitute_datatype(jl_value_t *t, jl_datatype_t * x, jl_datatype } static jl_value_t *lookup_type_stack(jl_typestack_t *stack, jl_datatype_t *tt, size_t ntp, - jl_value_t **iparams) + jl_value_t **iparams) JL_CANSAFEPOINT { // if an identical instantiation is already in process somewhere up the // stack, return it. this computes a fixed point for recursive types. @@ -2131,7 +2131,7 @@ void jl_precompute_memoized_dt(jl_datatype_t *dt, int cacheable) dt->hash = typekey_hash(dt->name, jl_svec_data(dt->parameters), l, cacheable); } -static int check_datatype_parameters(jl_typename_t *tn, jl_value_t **params, size_t np, int nothrow) +static int check_datatype_parameters(jl_typename_t *tn, jl_value_t **params, size_t np, int nothrow) JL_CANSAFEPOINT { jl_value_t *wrapper = tn->wrapper; jl_value_t **bounds; @@ -2269,7 +2269,7 @@ static int may_substitute_ub(jl_value_t *v, jl_tvar_t *var) JL_NOTSAFEPOINT return _may_substitute_ub(v, var, 0, &cov_count); } -static jl_value_t *normalize_unionalls(jl_value_t *t) +static jl_value_t *normalize_unionalls(jl_value_t *t) JL_CANSAFEPOINT { if (jl_is_uniontype(t)) { jl_uniontype_t *u = (jl_uniontype_t*)t; @@ -2321,7 +2321,7 @@ static jl_value_t *normalize_unionalls(jl_value_t *t) } // used to expand an NTuple to a flat representation -static jl_value_t *jl_tupletype_fill(size_t n, jl_value_t *t, int check, int nothrow) +static jl_value_t *jl_tupletype_fill(size_t n, jl_value_t *t, int check, int nothrow) JL_CANSAFEPOINT { jl_value_t *p = NULL; JL_GC_PUSH1(&p); @@ -2350,7 +2350,7 @@ static jl_value_t *jl_tupletype_fill(size_t n, jl_value_t *t, int check, int not return p; } -static jl_value_t *_jl_instantiate_type_in_env(jl_value_t *ty, jl_unionall_t *env, jl_value_t **vals, jl_typeenv_t *prev, jl_typestack_t *stack); +static jl_value_t *_jl_instantiate_type_in_env(jl_value_t *ty, jl_unionall_t *env, jl_value_t **vals, jl_typeenv_t *prev, jl_typestack_t *stack) JL_CANSAFEPOINT; static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value_t **iparams, size_t ntp, jl_typestack_t *stack, jl_typeenv_t *env, int check, int nothrow) @@ -2717,7 +2717,7 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value return (jl_value_t*)ndt; } -static jl_value_t *jl_apply_tuple_type_v_(jl_value_t **p, size_t np, jl_svec_t *params, int check) +static jl_value_t *jl_apply_tuple_type_v_(jl_value_t **p, size_t np, jl_svec_t *params, int check) JL_CANSAFEPOINT { return inst_datatype_inner(jl_anytuple_type, params, p, np, NULL, NULL, check, 0); } @@ -2799,7 +2799,7 @@ static jl_svec_t *inst_ftypes(jl_svec_t *p, jl_typeenv_t *env, jl_typestack_t *s return np; } -static jl_value_t *inst_tuple_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t *stack, int check, int nothrow) +static jl_value_t *inst_tuple_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t *stack, int check, int nothrow) JL_CANSAFEPOINT { jl_datatype_t *tt = (jl_datatype_t*)t; jl_svec_t *tp = tt->parameters; @@ -3053,7 +3053,7 @@ static jl_value_t *inst_type_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t return t; } -static jl_value_t *instantiate_with(jl_value_t *t, jl_value_t **env, size_t n, jl_typeenv_t *te) +static jl_value_t *instantiate_with(jl_value_t *t, jl_value_t **env, size_t n, jl_typeenv_t *te) JL_CANSAFEPOINT { if (n > 0) { jl_typeenv_t en = { (jl_tvar_t*)env[0], env[1], te }; @@ -3145,19 +3145,6 @@ jl_value_t *jl_wrap_TypeEgal(jl_value_t *t) return te; } -// The most specific type containing the value `v`, matching the per-argument -// key `jl_inst_arg_tuple_type` uses: egality-pinned closed type values, equality -// keys (`Type{v}`) for free-typevar types (#61242), `typeof` otherwise. -JL_DLLEXPORT jl_value_t *jl_arg_slot_type(jl_value_t *v) -{ - if (jl_is_type(v)) { - if (jl_has_free_typevars(v)) - return (jl_value_t*)jl_wrap_Type(v); - return jl_wrap_TypeEgal(v); - } - return jl_typeof(v); -} - jl_vararg_t *jl_wrap_vararg(jl_value_t *t, jl_value_t *n, int check, int nothrow) { int valid = 1; @@ -3303,7 +3290,7 @@ void jl_reinstantiate_inner_types(jl_datatype_t *t) // can throw! // initialization ------------------------------------------------------------- -static jl_tvar_t *tvar(const char *name) +static jl_tvar_t *tvar(const char *name) JL_CANSAFEPOINT { return jl_new_typevar(jl_symbol(name), (jl_value_t*)jl_bottom_type, (jl_value_t*)jl_any_type); @@ -4324,7 +4311,7 @@ void jl_init_types(void) JL_GC_DISABLED export_jl_sysimg_globals(); } -static jl_value_t *core(const char *name) JL_GLOBALLY_ROOTED +static jl_value_t *core(const char *name) JL_CANSAFEPOINT JL_GLOBALLY_ROOTED { return jl_get_global(jl_core_module, jl_symbol(name)); } diff --git a/src/julia-task-dispatcher.h b/src/julia-task-dispatcher.h index 6b58d51baa64a..0f2d565e44e3c 100644 --- a/src/julia-task-dispatcher.h +++ b/src/julia-task-dispatcher.h @@ -25,12 +25,12 @@ template <> struct future_value_storage { struct JuliaTaskDispatcher : public TaskDispatcher { /// Forward declarations class future_base; - void dispatch(std::unique_ptr T) override; + void dispatch(std::unique_ptr T) override JL_CANSAFEPOINT; // NOLINT(julia-first-decl-annotations) void shutdown() override; - void work_until(future_base &F); + void work_until(future_base &F) JL_CANSAFEPOINT; protected: - void process_tasks(jl_unique_gcsafe_lock &Lock) JL_NOTSAFEPOINT_ENTER JL_NOTSAFEPOINT_LEAVE; + void process_tasks(jl_unique_gcsafe_lock &Lock) JL_CANSAFEPOINT_ENTER_LEAVE; private: /// C++ does not support non-static thread_local variables, so this needs to @@ -85,7 +85,7 @@ class future_base { bool valid() const JL_NOTSAFEPOINT { return state_ != nullptr; } /// Wait for the future to be ready, helping with task dispatch - void wait(JuliaTaskDispatcher &D) { + void wait(JuliaTaskDispatcher &D) JL_CANSAFEPOINT { // Keep helping with task dispatch until our future is ready if (!ready()) { D.work_until(*this); @@ -174,7 +174,7 @@ template class future : public future_base { /// Get the value, helping with task dispatch while waiting. /// This will destroy the underlying value, so this must be called exactly /// once, which returns the future to the initial state. - T get(JuliaTaskDispatcher &D) { + T get(JuliaTaskDispatcher &D) JL_CANSAFEPOINT { if (!valid()) report_fatal_error("get() must only be called once, after get_promise()"); wait(D); @@ -349,7 +349,7 @@ template class promise { }; // class JuliaTaskDispatcher -void JuliaTaskDispatcher::dispatch(std::unique_ptr T) { +void JuliaTaskDispatcher::dispatch(std::unique_ptr T) { // NOLINT(julia-first-decl-annotations) if (!InCooperativeContext) { // Not inside work_until/process_tasks — run inline to prevent deadlock // with callers that block on std::future (e.g. LocalTrampolinePool::reenter). @@ -396,12 +396,13 @@ void JuliaTaskDispatcher::work_until(future_base &F) { InCooperativeContext = WasCooperative; } -void JuliaTaskDispatcher::process_tasks(jl_unique_gcsafe_lock &Lock) { +// not analyzed, since it cannot represent the native unlock (normally implies a notsafepoint_leave) +void JuliaTaskDispatcher::process_tasks(jl_unique_gcsafe_lock &Lock) JL_NO_SAFEPOINT_ANALYSIS { while (!TaskQueue.empty()) { auto T = TaskQueue.pop_back_val(); Lock.native.unlock(); - T->run(); + T->run(); // n.b. JL_CANCALLBACK Lock.native.lock(); WorkFinishedCV.notify_all(); @@ -423,7 +424,7 @@ safelookup(ExecutionSession &ES, const JITDylibSearchOrder &SearchOrder, SymbolLookupSet Symbols, LookupKind K = LookupKind::Static, SymbolState RequiredState = SymbolState::Ready, - RegisterDependenciesFunction RegisterDependencies = NoDependenciesToRegister) { + RegisterDependenciesFunction RegisterDependencies = NoDependenciesToRegister) JL_CANSAFEPOINT { JuliaTaskDispatcher::future> PromisedFuture; auto NotifyComplete = [PromisedResult = PromisedFuture.get_promise()](Expected R) { PromisedResult.set_value(std::move(R)); @@ -437,7 +438,7 @@ Expected safelookup(ExecutionSession &ES, const JITDylibSearchOrder &SearchOrder, SymbolStringPtr Name, - SymbolState RequiredState = SymbolState::Ready) { + SymbolState RequiredState = SymbolState::Ready) JL_CANSAFEPOINT { SymbolLookupSet Names({Name}); if (auto ResultMap = safelookup(ES, SearchOrder, std::move(Names), LookupKind::Static, @@ -452,13 +453,13 @@ safelookup(ExecutionSession &ES, Expected safelookup(ExecutionSession &ES, ArrayRef SearchOrder, SymbolStringPtr Name, - SymbolState RequiredState = SymbolState::Ready) { + SymbolState RequiredState = SymbolState::Ready) JL_CANSAFEPOINT { return safelookup(ES, makeJITDylibSearchOrder(SearchOrder), Name, RequiredState); } Expected safelookup(ExecutionSession &ES, ArrayRef SearchOrder, StringRef Name, - SymbolState RequiredState = SymbolState::Ready) { + SymbolState RequiredState = SymbolState::Ready) JL_CANSAFEPOINT { return safelookup(ES, SearchOrder, ES.intern(Name), RequiredState); } diff --git a/src/julia.h b/src/julia.h index c5069951a600e..3072a9e5e5960 100644 --- a/src/julia.h +++ b/src/julia.h @@ -68,8 +68,70 @@ typedef struct _jl_taggedvalue_t jl_taggedvalue_t; typedef struct _jl_tls_states_t *jl_ptls_t; +/* libuv types */ + +/* Handle types. */ +typedef struct uv_loop_s uv_loop_t; +typedef struct uv_handle_s uv_handle_t; +typedef struct uv_dir_s uv_dir_t; +typedef struct uv_stream_s uv_stream_t; +typedef struct uv_tcp_s uv_tcp_t; +typedef struct uv_udp_s uv_udp_t; +typedef struct uv_pipe_s uv_pipe_t; +typedef struct uv_tty_s uv_tty_t; +typedef struct uv_poll_s uv_poll_t; +typedef struct uv_timer_s uv_timer_t; +typedef struct uv_prepare_s uv_prepare_t; +typedef struct uv_check_s uv_check_t; +typedef struct uv_idle_s uv_idle_t; +typedef struct uv_async_s uv_async_t; +typedef struct uv_process_s uv_process_t; +typedef struct uv_fs_event_s uv_fs_event_t; +typedef struct uv_fs_poll_s uv_fs_poll_t; +typedef struct uv_signal_s uv_signal_t; + +/* Request types. */ +typedef struct uv_req_s uv_req_t; +typedef struct uv_getaddrinfo_s uv_getaddrinfo_t; +typedef struct uv_getnameinfo_s uv_getnameinfo_t; +typedef struct uv_shutdown_s uv_shutdown_t; +typedef struct uv_write_s uv_write_t; +typedef struct uv_connect_s uv_connect_t; +typedef struct uv_udp_send_s uv_udp_send_t; +typedef struct uv_fs_s uv_fs_t; +typedef struct uv_work_s uv_work_t; +typedef struct uv_random_s uv_random_t; + +/* Misc types. */ +typedef struct uv_buf_t uv_buf_t; + +/* Callbacks. */ +typedef void (*uv_alloc_cb)(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf) JL_CANSAFEPOINT; +typedef void (*uv_read_cb)(uv_stream_t* stream, + ssize_t nread, + const uv_buf_t* buf) JL_CANSAFEPOINT; +typedef void (*uv_write_cb)(uv_write_t* req, int status) JL_CANSAFEPOINT; +typedef void (*uv_connect_cb)(uv_connect_t* req, int status) JL_CANSAFEPOINT; +typedef void (*uv_shutdown_cb)(uv_shutdown_t* req, int status) JL_CANSAFEPOINT; +typedef void (*uv_connection_cb)(uv_stream_t* server, int status) JL_CANSAFEPOINT; +typedef void (*uv_close_cb)(uv_handle_t* handle) JL_CANSAFEPOINT; +typedef void (*uv_poll_cb)(uv_poll_t* handle, int status, int events) JL_CANSAFEPOINT; +typedef void (*uv_timer_cb)(uv_timer_t* handle) JL_CANSAFEPOINT; +typedef void (*uv_async_cb)(uv_async_t* handle) JL_CANSAFEPOINT; +typedef void (*uv_prepare_cb)(uv_prepare_t* handle) JL_CANSAFEPOINT; +typedef void (*uv_check_cb)(uv_check_t* handle) JL_CANSAFEPOINT; +typedef void (*uv_idle_cb)(uv_idle_t* handle) JL_CANSAFEPOINT; +typedef void (*uv_exit_cb)(uv_process_t*, int64_t exit_status, int term_signal) JL_CANSAFEPOINT; +typedef void (*uv_walk_cb)(uv_handle_t* handle, void* arg) JL_CANSAFEPOINT; +typedef void (*uv_fs_cb)(uv_fs_t* req) JL_CANSAFEPOINT; +typedef void (*uv_work_cb)(uv_work_t* req) JL_CANSAFEPOINT; +typedef void (*uv_after_work_cb)(uv_work_t* req, int status) JL_CANSAFEPOINT; + #ifdef JL_LIBRARY_EXPORTS #include "uv.h" +UV_EXTERN int uv_run(uv_loop_t*, uv_run_mode mode) JL_CANSAFEPOINT; #endif #include "gc-interface.h" #include "julia_atomics.h" @@ -211,22 +273,22 @@ typedef struct _jl_typemap_entry_t jl_typemap_entry_t; typedef jl_value_t jl_typemap_t; typedef jl_value_t *(jl_call_t)(jl_value_t*, jl_value_t**, uint32_t, struct _jl_code_instance_t*); -typedef jl_call_t *jl_callptr_t; +typedef jl_call_t *jl_callptr_t JL_CANSAFEPOINT; // "speccall" calling convention signatures. // This describes some of the special ABI used by compiled julia functions. -extern jl_call_t jl_fptr_args; +extern jl_call_t jl_fptr_args JL_CANSAFEPOINT; JL_DLLEXPORT extern const jl_callptr_t jl_fptr_args_addr; -typedef jl_value_t *(*jl_fptr_args_t)(jl_value_t*, jl_value_t**, uint32_t); +typedef jl_value_t *(*jl_fptr_args_t)(jl_value_t*, jl_value_t**, uint32_t) JL_CANSAFEPOINT; -extern jl_call_t jl_fptr_const_return; +extern jl_call_t jl_fptr_const_return JL_CANSAFEPOINT; JL_DLLEXPORT extern const jl_callptr_t jl_fptr_const_return_addr; -extern jl_call_t jl_fptr_sparam; +extern jl_call_t jl_fptr_sparam JL_CANSAFEPOINT; JL_DLLEXPORT extern const jl_callptr_t jl_fptr_sparam_addr; -typedef jl_value_t *(*jl_fptr_sparam_t)(jl_value_t*, jl_value_t**, uint32_t, jl_svec_t*); +typedef jl_value_t *(*jl_fptr_sparam_t)(jl_value_t*, jl_value_t**, uint32_t, jl_svec_t*) JL_CANSAFEPOINT; -extern jl_call_t jl_fptr_interpret_call; +extern jl_call_t jl_fptr_interpret_call JL_CANSAFEPOINT; JL_DLLEXPORT extern const jl_callptr_t jl_fptr_interpret_call_addr; JL_DLLEXPORT extern const jl_callptr_t jl_f_opaque_closure_call_addr; @@ -1218,18 +1280,18 @@ extern void JL_GC_POP(void) JL_NOTSAFEPOINT; JL_DLLEXPORT void jl_gc_add_finalizer(jl_value_t *v, jl_value_t *f) JL_NOTSAFEPOINT; JL_DLLEXPORT void jl_gc_add_ptr_finalizer(jl_ptls_t ptls, jl_value_t *v, void *f) JL_NOTSAFEPOINT; JL_DLLEXPORT void jl_gc_add_quiescent(jl_ptls_t ptls, void **v, void *f) JL_NOTSAFEPOINT; -JL_DLLEXPORT void jl_finalize(jl_value_t *o); +JL_DLLEXPORT void jl_finalize(jl_value_t *o) JL_CANSAFEPOINT; JL_DLLEXPORT void *jl_malloc_stack(size_t *bufsz, struct _jl_task_t *owner) JL_NOTSAFEPOINT; JL_DLLEXPORT void jl_free_stack(void *stkbuf, size_t bufsz); // Allocates a new weak-reference, assigns its value and increments Julia allocation // counters. If thread-local allocators are used, then this function should allocate in the // thread-local allocator of the current thread. -JL_DLLEXPORT jl_weakref_t *jl_gc_new_weakref(jl_value_t *value); +JL_DLLEXPORT jl_weakref_t *jl_gc_new_weakref(jl_value_t *value) JL_CANSAFEPOINT; -JL_DLLEXPORT void jl_gc_safepoint(void); -JL_DLLEXPORT int jl_safepoint_suspend_thread(int tid, int waitstate); -JL_DLLEXPORT void jl_safepoint_suspend_all_threads(struct _jl_task_t *ct); +JL_DLLEXPORT void jl_gc_safepoint(void) JL_CANSAFEPOINT; +JL_DLLEXPORT int jl_safepoint_suspend_thread(int tid, int waitstate) JL_CANSAFEPOINT; +JL_DLLEXPORT void jl_safepoint_suspend_all_threads(struct _jl_task_t *ct) JL_CANSAFEPOINT; JL_DLLEXPORT void jl_safepoint_resume_all_threads(struct _jl_task_t *ct); JL_DLLEXPORT int jl_safepoint_resume_thread(int tid) JL_NOTSAFEPOINT; @@ -1479,13 +1541,13 @@ STATIC_INLINE void jl_array_uint32_set(void *a, size_t i, uint32_t x) JL_NOTSAFE #define jl_gf_name(f) (((jl_datatype_t*)jl_typeof(f))->name->singletonname) // struct type info -JL_DLLEXPORT jl_svec_t *jl_compute_fieldtypes(jl_datatype_t *st JL_PROPAGATES_ROOT, void *stack, int cacheable); +JL_DLLEXPORT jl_svec_t *jl_compute_fieldtypes(jl_datatype_t *st JL_PROPAGATES_ROOT, void *stack, int cacheable) JL_CANSAFEPOINT; #define jl_get_fieldtypes(st) ((st)->types ? (st)->types : jl_compute_fieldtypes((st), NULL, 0)) STATIC_INLINE jl_svec_t *jl_field_names(jl_datatype_t *st) JL_NOTSAFEPOINT { return st->name->names; } -STATIC_INLINE jl_value_t *jl_field_type(jl_datatype_t *st JL_PROPAGATES_ROOT, size_t i) +STATIC_INLINE jl_value_t *jl_field_type(jl_datatype_t *st JL_PROPAGATES_ROOT, size_t i) JL_CANSAFEPOINT { return jl_svecref(jl_get_fieldtypes(st), i); } @@ -1709,7 +1771,7 @@ static inline int jl_field_isconst(jl_datatype_t *st, int i) JL_NOTSAFEPOINT #define jl_is_array_any(v) jl_typetagis(v,jl_array_any_type) #define jl_is_debuginfo(v) jl_typetagis(v,jl_debuginfo_type) -JL_DLLEXPORT int jl_subtype(jl_value_t *a, jl_value_t *b); +JL_DLLEXPORT int jl_subtype(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; int is_leaf_bound(jl_value_t *v) JL_NOTSAFEPOINT; @@ -1927,18 +1989,18 @@ JL_DLLEXPORT int jl_has_free_typevars(jl_value_t *v) JL_NOTSAFEPOINT; JL_DLLEXPORT int jl_has_typevar(jl_value_t *t, jl_tvar_t *v) JL_NOTSAFEPOINT; JL_DLLEXPORT int jl_has_typevar_from_unionall(jl_value_t *t, jl_unionall_t *ua); JL_DLLEXPORT int jl_subtype_env_size(jl_value_t *t) JL_NOTSAFEPOINT; -JL_DLLEXPORT int jl_subtype_env(jl_value_t *x, jl_value_t *y, jl_value_t **env, int envsz); -JL_DLLEXPORT int jl_isa(jl_value_t *a, jl_value_t *t); -JL_DLLEXPORT int jl_types_equal(jl_value_t *a, jl_value_t *b); +JL_DLLEXPORT int jl_subtype_env(jl_value_t *x, jl_value_t *y, jl_value_t **env, int envsz) JL_CANSAFEPOINT; +JL_DLLEXPORT int jl_isa(jl_value_t *a, jl_value_t *t) JL_CANSAFEPOINT; +JL_DLLEXPORT int jl_types_equal(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; JL_DLLEXPORT int jl_is_not_broken_subtype(jl_value_t *a, jl_value_t *b); -JL_DLLEXPORT jl_value_t *jl_type_union(jl_value_t **ts, size_t n); -JL_DLLEXPORT jl_value_t *jl_type_intersection(jl_value_t *a, jl_value_t *b); -JL_DLLEXPORT int jl_has_empty_intersection(jl_value_t *x, jl_value_t *y); -JL_DLLEXPORT jl_value_t *jl_type_unionall(jl_tvar_t *v, jl_value_t *body); +JL_DLLEXPORT jl_value_t *jl_type_union(jl_value_t **ts, size_t n) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_type_intersection(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; +JL_DLLEXPORT int jl_has_empty_intersection(jl_value_t *x, jl_value_t *y) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_type_unionall(jl_tvar_t *v, jl_value_t *body) JL_CANSAFEPOINT; JL_DLLEXPORT const char *jl_typename_str(jl_value_t *v) JL_NOTSAFEPOINT; JL_DLLEXPORT const char *jl_typeof_str(jl_value_t *v) JL_NOTSAFEPOINT; -JL_DLLEXPORT int jl_type_morespecific(jl_value_t *a, jl_value_t *b); -JL_DLLEXPORT int jl_method_morespecific(jl_method_t *ma, jl_method_t *mb); +JL_DLLEXPORT int jl_type_morespecific(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; +JL_DLLEXPORT int jl_method_morespecific(jl_method_t *ma, jl_method_t *mb) JL_CANSAFEPOINT; STATIC_INLINE int jl_is_dispatch_tupletype(jl_value_t *v) JL_NOTSAFEPOINT { @@ -1950,20 +2012,20 @@ STATIC_INLINE int jl_is_concrete_type(jl_value_t *v) JL_NOTSAFEPOINT return jl_is_datatype(v) && ((jl_datatype_t*)v)->isconcretetype; } -JL_DLLEXPORT int jl_isa_compileable_sig(jl_tupletype_t *type, jl_svec_t *sparams, jl_method_t *definition); +JL_DLLEXPORT int jl_isa_compileable_sig(jl_tupletype_t *type, jl_svec_t *sparams, jl_method_t *definition) JL_CANSAFEPOINT; // type constructors -JL_DLLEXPORT jl_typename_t *jl_new_typename_in(jl_sym_t *name, jl_module_t *inmodule, int abstract, int mutabl); -JL_DLLEXPORT jl_tvar_t *jl_new_typevar(jl_sym_t *name, jl_value_t *lb, jl_value_t *ub); -JL_DLLEXPORT jl_value_t *jl_instantiate_unionall(jl_unionall_t *u, jl_value_t *p); -JL_DLLEXPORT jl_value_t *jl_apply_type(jl_value_t *tc, jl_value_t **params, size_t n); -JL_DLLEXPORT jl_value_t *jl_apply_type1(jl_value_t *tc, jl_value_t *p1); -JL_DLLEXPORT jl_value_t *jl_apply_type2(jl_value_t *tc, jl_value_t *p1, jl_value_t *p2); -JL_DLLEXPORT jl_value_t *jl_apply_type3(jl_value_t *tc, jl_value_t *p1, jl_value_t *p2, jl_value_t *p3); -JL_DLLEXPORT jl_datatype_t *jl_apply_modify_type(jl_value_t *dt); -JL_DLLEXPORT jl_datatype_t *jl_apply_cmpswap_type(jl_value_t *dt); -JL_DLLEXPORT jl_value_t *jl_apply_tuple_type(jl_svec_t *params, int check); // if uncertain, set check=1 -JL_DLLEXPORT jl_value_t *jl_apply_tuple_type_v(jl_value_t **p, size_t np); +JL_DLLEXPORT jl_typename_t *jl_new_typename_in(jl_sym_t *name, jl_module_t *inmodule, int abstract, int mutabl) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_tvar_t *jl_new_typevar(jl_sym_t *name, jl_value_t *lb, jl_value_t *ub) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_instantiate_unionall(jl_unionall_t *u, jl_value_t *p) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_apply_type(jl_value_t *tc, jl_value_t **params, size_t n) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_apply_type1(jl_value_t *tc, jl_value_t *p1) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_apply_type2(jl_value_t *tc, jl_value_t *p1, jl_value_t *p2) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_apply_type3(jl_value_t *tc, jl_value_t *p1, jl_value_t *p2, jl_value_t *p3) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_datatype_t *jl_apply_modify_type(jl_value_t *dt) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_datatype_t *jl_apply_cmpswap_type(jl_value_t *dt) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_apply_tuple_type(jl_svec_t *params, int check) JL_CANSAFEPOINT; // if uncertain, set check=1 +JL_DLLEXPORT jl_value_t *jl_apply_tuple_type_v(jl_value_t **p, size_t np) JL_CANSAFEPOINT; JL_DLLEXPORT jl_datatype_t *jl_new_datatype(jl_sym_t *name, jl_module_t *module, jl_datatype_t *super, @@ -1972,73 +2034,73 @@ JL_DLLEXPORT jl_datatype_t *jl_new_datatype(jl_sym_t *name, jl_svec_t *ftypes, jl_svec_t *fattrs, int abstract, int mutabl, - int ninitialized); + int ninitialized) JL_CANSAFEPOINT; JL_DLLEXPORT jl_datatype_t *jl_new_primitivetype(jl_value_t *name, jl_module_t *module, jl_datatype_t *super, - jl_svec_t *parameters, size_t nbits); + jl_svec_t *parameters, size_t nbits) JL_CANSAFEPOINT; // constructors -JL_DLLEXPORT jl_value_t *jl_new_bits(jl_value_t *bt, const void *src); -JL_DLLEXPORT jl_value_t *jl_atomic_new_bits(jl_value_t *dt, const char *src); +JL_DLLEXPORT jl_value_t *jl_new_bits(jl_value_t *bt, const void *src) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_atomic_new_bits(jl_value_t *dt, const char *src) JL_CANSAFEPOINT; JL_DLLEXPORT void jl_atomic_store_bits(char *dst, const jl_value_t *src, int nb) JL_NOTSAFEPOINT; -JL_DLLEXPORT jl_value_t *jl_atomic_swap_bits(jl_value_t *dt, char *dst, const jl_value_t *src, int nb); +JL_DLLEXPORT jl_value_t *jl_atomic_swap_bits(jl_value_t *dt, char *dst, const jl_value_t *src, int nb) JL_CANSAFEPOINT; JL_DLLEXPORT int jl_atomic_bool_cmpswap_bits(char *dst, const jl_value_t *expected, const jl_value_t *src, int nb) JL_NOTSAFEPOINT; JL_DLLEXPORT int jl_atomic_cmpswap_bits(jl_datatype_t *dt, jl_value_t *y, char *dst, const jl_value_t *expected, const jl_value_t *src, int nb) JL_NOTSAFEPOINT; JL_DLLEXPORT int jl_atomic_storeonce_bits(jl_datatype_t *dt, char *dst, const jl_value_t *src, int nb) JL_NOTSAFEPOINT; -JL_DLLEXPORT jl_value_t *jl_new_struct(jl_datatype_t *type, ...) JL_ROOTED_VARARGS; -JL_DLLEXPORT jl_value_t *jl_new_structv(jl_datatype_t *type, jl_value_t **args, uint32_t na); -JL_DLLEXPORT jl_value_t *jl_new_structt(jl_datatype_t *type, jl_value_t *tup); -JL_DLLEXPORT jl_value_t *jl_new_struct_uninit(jl_datatype_t *type); -JL_DLLEXPORT jl_method_instance_t *jl_new_method_instance_uninit(void); -JL_DLLEXPORT jl_svec_t *jl_svec(size_t n, ...) JL_MAYBE_UNROOTED JL_ROOTED_VARARGS; +JL_DLLEXPORT jl_value_t *jl_new_struct(jl_datatype_t *type, ...) JL_CANSAFEPOINT JL_ROOTED_VARARGS; +JL_DLLEXPORT jl_value_t *jl_new_structv(jl_datatype_t *type, jl_value_t **args, uint32_t na) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_new_structt(jl_datatype_t *type, jl_value_t *tup) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_new_struct_uninit(jl_datatype_t *type) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_method_instance_t *jl_new_method_instance_uninit(void) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_svec_t *jl_svec(size_t n, ...) JL_CANSAFEPOINT JL_MAYBE_UNROOTED JL_ROOTED_VARARGS; JL_DLLEXPORT jl_svec_t *jl_svec1( - void *a JL_ROOTED_BY_RETURN); + void *a JL_ROOTED_BY_RETURN) JL_CANSAFEPOINT; JL_DLLEXPORT jl_svec_t *jl_svec2( void *a JL_ROOTED_BY_RETURN, - void *b JL_ROOTED_BY_RETURN); + void *b JL_ROOTED_BY_RETURN) JL_CANSAFEPOINT; JL_DLLEXPORT jl_svec_t *jl_svec3( void *a JL_ROOTED_BY_RETURN, void *b JL_ROOTED_BY_RETURN, - void *c JL_ROOTED_BY_RETURN); -JL_DLLEXPORT jl_svec_t *jl_alloc_svec(size_t n); -JL_DLLEXPORT jl_svec_t *jl_alloc_svec_uninit(size_t n); -JL_DLLEXPORT jl_svec_t *jl_svec_copy(jl_svec_t *a); -JL_DLLEXPORT jl_svec_t *jl_svec_fill(size_t n, jl_value_t *x); + void *c JL_ROOTED_BY_RETURN) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_svec_t *jl_alloc_svec(size_t n) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_svec_t *jl_alloc_svec_uninit(size_t n) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_svec_t *jl_svec_copy(jl_svec_t *a) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_svec_t *jl_svec_fill(size_t n, jl_value_t *x) JL_CANSAFEPOINT; JL_DLLEXPORT jl_sym_t *jl_symbol(const char *str) JL_NOTSAFEPOINT; JL_DLLEXPORT jl_sym_t *jl_symbol_lookup(const char *str) JL_NOTSAFEPOINT; JL_DLLEXPORT jl_sym_t *jl_symbol_n(const char *str, size_t len) JL_NOTSAFEPOINT; JL_DLLEXPORT jl_sym_t *jl_gensym(void); JL_DLLEXPORT jl_sym_t *jl_tagged_gensym(const char *str, size_t len); JL_DLLEXPORT jl_sym_t *jl_get_root_symbol(void); -JL_DLLEXPORT jl_value_t *jl_get_binding_value(jl_binding_t *b JL_PROPAGATES_ROOT); -JL_DLLEXPORT jl_value_t *jl_get_binding_value_in_world(jl_binding_t *b JL_PROPAGATES_ROOT, size_t world); -JL_DLLEXPORT jl_value_t *jl_get_latest_binding_value_if_const(jl_binding_t *b JL_PROPAGATES_ROOT); +JL_DLLEXPORT jl_value_t *jl_get_binding_value(jl_binding_t *b JL_PROPAGATES_ROOT) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_get_binding_value_in_world(jl_binding_t *b JL_PROPAGATES_ROOT, size_t world) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_get_latest_binding_value_if_const(jl_binding_t *b JL_PROPAGATES_ROOT) JL_CANSAFEPOINT; JL_DLLEXPORT jl_value_t *jl_get_latest_binding_value_if_resolved_debug_only(jl_binding_t *b JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT; JL_DLLEXPORT jl_value_t *jl_get_latest_binding_value_if_resolved_and_const_debug_only(jl_binding_t *b JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT; -JL_DLLEXPORT jl_value_t *jl_declare_const_gf(jl_module_t *mod, jl_sym_t *name); -JL_DLLEXPORT jl_method_t *jl_method_def(jl_svec_t *argdata, jl_methtable_t *mt, jl_code_info_t *f, jl_module_t *module); -JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *linfo JL_PROPAGATES_ROOT, size_t world, jl_code_instance_t **cache JL_OUT_ROOTED_BY_ARG(0)); -JL_DLLEXPORT jl_code_info_t *jl_copy_code_info(jl_code_info_t *src); +JL_DLLEXPORT jl_value_t *jl_declare_const_gf(jl_module_t *mod, jl_sym_t *name) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_method_t *jl_method_def(jl_svec_t *argdata, jl_methtable_t *mt, jl_code_info_t *f, jl_module_t *module) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *linfo JL_PROPAGATES_ROOT, size_t world, jl_code_instance_t **cache JL_OUT_ROOTED_BY_ARG(0)) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_code_info_t *jl_copy_code_info(jl_code_info_t *src) JL_CANSAFEPOINT; JL_DLLEXPORT size_t jl_get_world_counter(void) JL_NOTSAFEPOINT; JL_DLLEXPORT size_t jl_get_tls_world_age(void) JL_NOTSAFEPOINT; -JL_DLLEXPORT void jl_drop_all_caches(void); +JL_DLLEXPORT void jl_drop_all_caches(void) JL_CANSAFEPOINT; JL_DLLEXPORT jl_value_t *jl_box_bool(int8_t x) JL_NOTSAFEPOINT; JL_DLLEXPORT jl_value_t *jl_box_int8(int8_t x) JL_NOTSAFEPOINT; JL_DLLEXPORT jl_value_t *jl_box_uint8(uint8_t x) JL_NOTSAFEPOINT; -JL_DLLEXPORT jl_value_t *jl_box_int16(int16_t x); -JL_DLLEXPORT jl_value_t *jl_box_uint16(uint16_t x); -JL_DLLEXPORT jl_value_t *jl_box_int32(int32_t x); -JL_DLLEXPORT jl_value_t *jl_box_uint32(uint32_t x); -JL_DLLEXPORT jl_value_t *jl_box_char(uint32_t x); -JL_DLLEXPORT jl_value_t *jl_box_int64(int64_t x); -JL_DLLEXPORT jl_value_t *jl_box_uint64(uint64_t x); -JL_DLLEXPORT jl_value_t *jl_box_float32(float x); -JL_DLLEXPORT jl_value_t *jl_box_float64(double x); -JL_DLLEXPORT jl_value_t *jl_box_voidpointer(void *x); -JL_DLLEXPORT jl_value_t *jl_box_uint8pointer(uint8_t *x); -JL_DLLEXPORT jl_value_t *jl_box_ssavalue(size_t x); -JL_DLLEXPORT jl_value_t *jl_box_slotnumber(size_t x); +JL_DLLEXPORT jl_value_t *jl_box_int16(int16_t x) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_box_uint16(uint16_t x) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_box_int32(int32_t x) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_box_uint32(uint32_t x) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_box_char(uint32_t x) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_box_int64(int64_t x) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_box_uint64(uint64_t x) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_box_float32(float x) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_box_float64(double x) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_box_voidpointer(void *x) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_box_uint8pointer(uint8_t *x) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_box_ssavalue(size_t x) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_box_slotnumber(size_t x) JL_CANSAFEPOINT; JL_DLLEXPORT int8_t jl_unbox_bool(jl_value_t *v) JL_NOTSAFEPOINT; JL_DLLEXPORT int8_t jl_unbox_int8(jl_value_t *v) JL_NOTSAFEPOINT; JL_DLLEXPORT uint8_t jl_unbox_uint8(jl_value_t *v) JL_NOTSAFEPOINT; @@ -2076,73 +2138,73 @@ JL_DLLEXPORT int jl_get_size(jl_value_t *val, size_t *pnt); #endif // structs -JL_DLLEXPORT int jl_field_index(jl_datatype_t *t, jl_sym_t *fld, int err); -JL_DLLEXPORT jl_value_t *jl_get_nth_field(jl_value_t *v, size_t i); +JL_DLLEXPORT int jl_field_index(jl_datatype_t *t, jl_sym_t *fld, int err) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_get_nth_field(jl_value_t *v, size_t i) JL_CANSAFEPOINT; // Like jl_get_nth_field above, but asserts if it needs to allocate JL_DLLEXPORT jl_value_t *jl_get_nth_field_noalloc(jl_value_t *v JL_PROPAGATES_ROOT, size_t i) JL_NOTSAFEPOINT; -JL_DLLEXPORT jl_value_t *jl_get_nth_field_checked(jl_value_t *v, size_t i); +JL_DLLEXPORT jl_value_t *jl_get_nth_field_checked(jl_value_t *v, size_t i) JL_CANSAFEPOINT; JL_DLLEXPORT void jl_set_nth_field(jl_value_t *v, size_t i, jl_value_t *rhs); JL_DLLEXPORT int jl_field_isdefined(jl_value_t *v, size_t i) JL_NOTSAFEPOINT; -JL_DLLEXPORT int jl_field_isdefined_checked(jl_value_t *v, size_t i); -JL_DLLEXPORT jl_value_t *jl_get_field(jl_value_t *o, const char *fld); +JL_DLLEXPORT int jl_field_isdefined_checked(jl_value_t *v, size_t i) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_get_field(jl_value_t *o, const char *fld) JL_CANSAFEPOINT; JL_DLLEXPORT jl_value_t *jl_value_ptr(jl_value_t *a); -int jl_uniontype_size(jl_value_t *ty, size_t *sz); -JL_DLLEXPORT int jl_islayout_inline(jl_value_t *eltype, size_t *fsz, size_t *al); +int jl_uniontype_size(jl_value_t *ty, size_t *sz) JL_CANSAFEPOINT; +JL_DLLEXPORT int jl_islayout_inline(jl_value_t *eltype, size_t *fsz, size_t *al) JL_CANSAFEPOINT; // arrays JL_DLLEXPORT jl_array_t *jl_ptr_to_array_1d(jl_value_t *atype, void *data, - size_t nel, int own_buffer); + size_t nel, int own_buffer) JL_CANSAFEPOINT; JL_DLLEXPORT jl_array_t *jl_ptr_to_array(jl_value_t *atype, void *data, - jl_value_t *dims, int own_buffer); - -JL_DLLEXPORT jl_array_t *jl_alloc_array_1d(jl_value_t *atype, size_t nr); -JL_DLLEXPORT jl_array_t *jl_alloc_array_2d(jl_value_t *atype, size_t nr, size_t nc); -JL_DLLEXPORT jl_array_t *jl_alloc_array_3d(jl_value_t *atype, size_t nr, size_t nc, size_t z); -JL_DLLEXPORT jl_array_t *jl_alloc_array_nd(jl_value_t *atype, size_t *dims, size_t ndims); -JL_DLLEXPORT jl_array_t *jl_pchar_to_array(const char *str, size_t len); -JL_DLLEXPORT jl_value_t *jl_pchar_to_string(const char *str, size_t len); -JL_DLLEXPORT jl_value_t *jl_cstr_to_string(const char *str); -JL_DLLEXPORT jl_value_t *jl_alloc_string(size_t len); -JL_DLLEXPORT jl_value_t *jl_array_to_string(jl_array_t *a); -JL_DLLEXPORT jl_array_t *jl_alloc_vec_any(size_t n); -JL_DLLEXPORT void jl_array_grow_end(jl_array_t *a, size_t inc); + jl_value_t *dims, int own_buffer) JL_CANSAFEPOINT; + +JL_DLLEXPORT jl_array_t *jl_alloc_array_1d(jl_value_t *atype, size_t nr) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_array_t *jl_alloc_array_2d(jl_value_t *atype, size_t nr, size_t nc) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_array_t *jl_alloc_array_3d(jl_value_t *atype, size_t nr, size_t nc, size_t z) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_array_t *jl_alloc_array_nd(jl_value_t *atype, size_t *dims, size_t ndims) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_array_t *jl_pchar_to_array(const char *str, size_t len) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_pchar_to_string(const char *str, size_t len) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_cstr_to_string(const char *str) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_alloc_string(size_t len) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_array_to_string(jl_array_t *a) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_array_t *jl_alloc_vec_any(size_t n) JL_CANSAFEPOINT; +JL_DLLEXPORT void jl_array_grow_end(jl_array_t *a, size_t inc) JL_CANSAFEPOINT; JL_DLLEXPORT void jl_array_del_end(jl_array_t *a, size_t dec); -JL_DLLEXPORT void jl_array_ptr_1d_push(jl_array_t *a, jl_value_t *item); -JL_DLLEXPORT void jl_array_ptr_1d_append(jl_array_t *a, jl_array_t *a2); -JL_DLLEXPORT jl_value_t *jl_apply_array_type(jl_value_t *type, size_t dim); +JL_DLLEXPORT void jl_array_ptr_1d_push(jl_array_t *a, jl_value_t *item) JL_CANSAFEPOINT; +JL_DLLEXPORT void jl_array_ptr_1d_append(jl_array_t *a, jl_array_t *a2) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_apply_array_type(jl_value_t *type, size_t dim) JL_CANSAFEPOINT; // property access JL_DLLEXPORT void *jl_array_ptr(jl_array_t *a); JL_DLLEXPORT void *jl_array_eltype(jl_value_t *a); JL_DLLEXPORT int jl_array_rank(jl_value_t *a); // genericmemory -JL_DLLEXPORT jl_genericmemory_t *jl_new_genericmemory(jl_value_t *mtype, jl_value_t *dim); +JL_DLLEXPORT jl_genericmemory_t *jl_new_genericmemory(jl_value_t *mtype, jl_value_t *dim) JL_CANSAFEPOINT; JL_DLLEXPORT jl_genericmemory_t *jl_ptr_to_genericmemory(jl_value_t *mtype, void *data, - size_t nel, int own_buffer); -JL_DLLEXPORT jl_genericmemory_t *jl_alloc_genericmemory(jl_value_t *mtype, size_t nel); + size_t nel, int own_buffer) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_genericmemory_t *jl_alloc_genericmemory(jl_value_t *mtype, size_t nel) JL_CANSAFEPOINT; JL_DLLEXPORT jl_genericmemory_t *jl_pchar_to_memory(const char *str, size_t len); -JL_DLLEXPORT jl_genericmemory_t *jl_alloc_genericmemory_unchecked(jl_ptls_t ptls, size_t nbytes, jl_datatype_t *mtype); -JL_DLLEXPORT jl_value_t *jl_genericmemory_to_string(jl_genericmemory_t *m, size_t len); -JL_DLLEXPORT jl_genericmemory_t *jl_alloc_memory_any(size_t n); -JL_DLLEXPORT jl_value_t *jl_genericmemoryref(jl_genericmemory_t *m, size_t i); // 0-indexed +JL_DLLEXPORT jl_genericmemory_t *jl_alloc_genericmemory_unchecked(jl_ptls_t ptls, size_t nbytes, jl_datatype_t *mtype) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_genericmemory_to_string(jl_genericmemory_t *m, size_t len) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_genericmemory_t *jl_alloc_memory_any(size_t n) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_genericmemoryref(jl_genericmemory_t *m, size_t i) JL_CANSAFEPOINT; // 0-indexed -JL_DLLEXPORT jl_genericmemoryref_t *jl_new_memoryref(jl_value_t *typ, jl_genericmemory_t *mem, void *data); -JL_DLLEXPORT jl_value_t *jl_memoryrefget(jl_genericmemoryref_t m JL_PROPAGATES_ROOT, int isatomic); +JL_DLLEXPORT jl_genericmemoryref_t *jl_new_memoryref(jl_value_t *typ, jl_genericmemory_t *mem, void *data) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_memoryrefget(jl_genericmemoryref_t m JL_PROPAGATES_ROOT, int isatomic) JL_CANSAFEPOINT; JL_DLLEXPORT jl_value_t *jl_ptrmemoryrefget(jl_genericmemoryref_t m JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT; JL_DLLEXPORT jl_value_t *jl_memoryref_isassigned(jl_genericmemoryref_t m, int isatomic) JL_GLOBALLY_ROOTED; JL_DLLEXPORT jl_genericmemoryref_t jl_memoryrefindex(jl_genericmemoryref_t m JL_PROPAGATES_ROOT, size_t idx) JL_NOTSAFEPOINT; -JL_DLLEXPORT void jl_memoryrefset(jl_genericmemoryref_t m, jl_value_t *v JL_ROOTED_BY_ARG(0) JL_MAYBE_UNROOTED, int isatomic); +JL_DLLEXPORT void jl_memoryrefset(jl_genericmemoryref_t m, jl_value_t *v JL_ROOTED_BY_ARG(0) JL_MAYBE_UNROOTED, int isatomic) JL_CANSAFEPOINT; JL_DLLEXPORT void jl_memoryrefunset(jl_genericmemoryref_t m, int isatomic); -JL_DLLEXPORT jl_value_t *jl_memoryrefswap(jl_genericmemoryref_t m, jl_value_t *v, int isatomic); -JL_DLLEXPORT jl_value_t *jl_memoryrefmodify(jl_genericmemoryref_t m, jl_value_t *op, jl_value_t *v, int isatomic); -JL_DLLEXPORT jl_value_t *jl_memoryrefreplace(jl_genericmemoryref_t m, jl_value_t *expected, jl_value_t *v, int isatomic); -JL_DLLEXPORT jl_value_t *jl_memoryrefsetonce(jl_genericmemoryref_t m, jl_value_t *v, int isatomic); +JL_DLLEXPORT jl_value_t *jl_memoryrefswap(jl_genericmemoryref_t m, jl_value_t *v, int isatomic) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_memoryrefmodify(jl_genericmemoryref_t m, jl_value_t *op, jl_value_t *v, int isatomic) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_memoryrefreplace(jl_genericmemoryref_t m, jl_value_t *expected, jl_value_t *v, int isatomic) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_memoryrefsetonce(jl_genericmemoryref_t m, jl_value_t *v, int isatomic) JL_CANSAFEPOINT; // strings JL_DLLEXPORT const char *jl_string_ptr(jl_value_t *s); // modules and global variables -JL_DLLEXPORT jl_module_t *jl_new_module(jl_sym_t *name, jl_module_t *parent); +JL_DLLEXPORT jl_module_t *jl_new_module(jl_sym_t *name, jl_module_t *parent) JL_CANSAFEPOINT; JL_DLLEXPORT void jl_set_module_nospecialize(jl_module_t *self, int on); JL_DLLEXPORT void jl_set_module_optlevel(jl_module_t *self, int lvl); JL_DLLEXPORT int jl_get_module_optlevel(jl_module_t *m); @@ -2154,40 +2216,45 @@ JL_DLLEXPORT void jl_set_module_max_methods(jl_module_t *self, int value); JL_DLLEXPORT int jl_get_module_max_methods(jl_module_t *m); JL_DLLEXPORT jl_value_t *jl_get_module_usings_backedges(jl_module_t *m); JL_DLLEXPORT jl_value_t *jl_get_module_scanned_methods(jl_module_t *m); -JL_DLLEXPORT jl_value_t *jl_get_module_binding_or_nothing(jl_module_t *m, jl_sym_t *s); +JL_DLLEXPORT jl_value_t *jl_get_module_binding_or_nothing(jl_module_t *m, jl_sym_t *s) JL_CANSAFEPOINT; // get binding for reading -JL_DLLEXPORT jl_binding_t *jl_get_binding(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var); -JL_DLLEXPORT jl_value_t *jl_module_globalref(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var); -JL_DLLEXPORT jl_value_t *jl_get_binding_type(jl_module_t *m, jl_sym_t *var); +JL_DLLEXPORT jl_binding_t *jl_get_binding(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_module_globalref(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_get_binding_type(jl_module_t *m, jl_sym_t *var) JL_CANSAFEPOINT; // get binding for assignment -JL_DLLEXPORT void jl_check_binding_currently_writable(jl_binding_t *b, jl_module_t *m, jl_sym_t *s); -JL_DLLEXPORT jl_binding_t *jl_get_binding_wr(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var); -JL_DLLEXPORT jl_value_t *jl_get_existing_strong_gf(jl_binding_t *b JL_PROPAGATES_ROOT, size_t new_world); -JL_DLLEXPORT int jl_boundp(jl_module_t *m, jl_sym_t *var, int allow_import); -JL_DLLEXPORT int jl_is_const(jl_module_t *m, jl_sym_t *var); -JL_DLLEXPORT int jl_globalref_is_const(jl_globalref_t *gr); -JL_DLLEXPORT jl_value_t *jl_get_global(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var); -JL_DLLEXPORT void jl_set_global(jl_module_t *m, jl_sym_t *var, jl_value_t *val JL_ROOTED_BY_ARG(0)); -JL_DLLEXPORT void jl_set_const(jl_module_t *m, jl_sym_t *var, jl_value_t *val JL_ROOTED_BY_ARG(0)); -void jl_set_initial_const(jl_module_t *m, jl_sym_t *var, jl_value_t *val JL_ROOTED_BY_ARG(0), int exported); -JL_DLLEXPORT void jl_checked_assignment(jl_binding_t *b, jl_module_t *mod, jl_sym_t *var, jl_value_t *rhs JL_MAYBE_UNROOTED); -JL_DLLEXPORT jl_value_t *jl_checked_swap(jl_binding_t *b, jl_module_t *mod, jl_sym_t *var, jl_value_t *rhs JL_MAYBE_UNROOTED); -JL_DLLEXPORT jl_value_t *jl_checked_replace(jl_binding_t *b, jl_module_t *mod, jl_sym_t *var, jl_value_t *expected, jl_value_t *rhs); -JL_DLLEXPORT jl_value_t *jl_checked_modify(jl_binding_t *b, jl_module_t *mod, jl_sym_t *var, jl_value_t *op, jl_value_t *rhs); -JL_DLLEXPORT jl_value_t *jl_checked_assignonce(jl_binding_t *b, jl_module_t *mod, jl_sym_t *var, jl_value_t *rhs JL_MAYBE_UNROOTED); -JL_DLLEXPORT jl_binding_partition_t *jl_declare_constant_val(jl_binding_t *b, jl_module_t *mod, jl_sym_t *var, jl_value_t *val JL_ROOTED_BY_ARG(1) JL_MAYBE_UNROOTED); -JL_DLLEXPORT jl_binding_partition_t *jl_declare_constant_val2(jl_binding_t *b, jl_module_t *mod, jl_sym_t *var, jl_value_t *val JL_ROOTED_BY_ARG(1) JL_MAYBE_UNROOTED, enum jl_partition_kind); -JL_DLLEXPORT void jl_module_import(jl_task_t *ct, jl_module_t *to, jl_module_t *from, jl_sym_t *asname, jl_sym_t *s, int explici); -JL_DLLEXPORT void jl_import_module(jl_task_t *ct, jl_module_t *m, jl_module_t *import, jl_sym_t *asname); -JL_DLLEXPORT void jl_module_using(jl_module_t *to, jl_module_t *from, size_t flags); -JL_DLLEXPORT void jl_module_public(jl_module_t *from, jl_value_t **symbols, size_t nsymbols, int exported); -JL_DLLEXPORT void jl_module_set_visibility(jl_module_t *m, jl_sym_t *var, int state); -JL_DLLEXPORT int jl_is_imported(jl_module_t *m, jl_sym_t *s); -JL_DLLEXPORT int jl_module_exports_p(jl_module_t *m, jl_sym_t *var); +JL_DLLEXPORT void jl_check_binding_currently_writable(jl_binding_t *b, jl_module_t *m, jl_sym_t *s) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_binding_t *jl_get_binding_wr(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_get_existing_strong_gf(jl_binding_t *b JL_PROPAGATES_ROOT, size_t new_world) JL_CANSAFEPOINT; +JL_DLLEXPORT int jl_boundp(jl_module_t *m, jl_sym_t *var, int allow_import) JL_CANSAFEPOINT; +JL_DLLEXPORT int jl_is_const(jl_module_t *m, jl_sym_t *var) JL_CANSAFEPOINT; +JL_DLLEXPORT int jl_globalref_is_const(jl_globalref_t *gr) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_get_global(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var) JL_CANSAFEPOINT; +JL_DLLEXPORT void jl_set_global(jl_module_t *m, jl_sym_t *var, jl_value_t *val JL_ROOTED_BY_ARG(0)) JL_CANSAFEPOINT; +JL_DLLEXPORT void jl_set_const(jl_module_t *m, jl_sym_t *var, jl_value_t *val JL_ROOTED_BY_ARG(0)) JL_CANSAFEPOINT; +void jl_set_initial_const(jl_module_t *m, jl_sym_t *var, jl_value_t *val JL_ROOTED_BY_ARG(0), int exported) JL_CANSAFEPOINT; +JL_DLLEXPORT void jl_checked_assignment(jl_binding_t *b, jl_module_t *mod, jl_sym_t *var, jl_value_t *rhs) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_checked_swap(jl_binding_t *b, jl_module_t *mod, jl_sym_t *var, jl_value_t *rhs) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_checked_replace(jl_binding_t *b, jl_module_t *mod, jl_sym_t *var, jl_value_t *expected, jl_value_t *rhs) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_checked_modify(jl_binding_t *b, jl_module_t *mod, jl_sym_t *var, jl_value_t *op, jl_value_t *rhs) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_checked_assignonce(jl_binding_t *b, jl_module_t *mod, jl_sym_t *var, jl_value_t *rhs) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_binding_partition_t *jl_declare_constant_val(jl_binding_t *b, jl_module_t *mod, jl_sym_t *var, jl_value_t *val JL_ROOTED_BY_ARG(1) JL_MAYBE_UNROOTED) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_binding_partition_t *jl_declare_constant_val2(jl_binding_t *b, jl_module_t *mod, jl_sym_t *var, jl_value_t *val JL_ROOTED_BY_ARG(1) JL_MAYBE_UNROOTED, enum jl_partition_kind) JL_CANSAFEPOINT; +JL_DLLEXPORT void jl_module_import(jl_task_t *ct, jl_module_t *to, jl_module_t *from, jl_sym_t *asname, jl_sym_t *s, int explici) JL_CANSAFEPOINT; +JL_DLLEXPORT void jl_import_module(jl_task_t *ct, jl_module_t *m, jl_module_t *import, jl_sym_t *asname) JL_CANSAFEPOINT; +JL_DLLEXPORT void jl_module_using(jl_module_t *to, jl_module_t *from, size_t flags) JL_CANSAFEPOINT; +JL_DLLEXPORT void jl_module_public(jl_module_t *from, jl_value_t **symbols, size_t nsymbols, int exported) JL_CANSAFEPOINT; +JL_DLLEXPORT void jl_module_set_visibility(jl_module_t *m, jl_sym_t *var, int state) JL_CANSAFEPOINT; +JL_DLLEXPORT int jl_is_imported(jl_module_t *m, jl_sym_t *s) JL_CANSAFEPOINT; +JL_DLLEXPORT int jl_module_exports_p(jl_module_t *m, jl_sym_t *var) +#ifdef __clang_safetyanalysis__ + JL_NOTSAFEPOINT; +#else + ; +#endif // eq hash tables -JL_DLLEXPORT jl_genericmemory_t *jl_eqtable_put(jl_genericmemory_t *h, jl_value_t *key, jl_value_t *val JL_ROOTED_BY_ARG(0), int *inserted); +JL_DLLEXPORT jl_genericmemory_t *jl_eqtable_put(jl_genericmemory_t *h, jl_value_t *key, jl_value_t *val JL_ROOTED_BY_ARG(0), int *inserted) JL_CANSAFEPOINT; JL_DLLEXPORT jl_value_t *jl_eqtable_get(jl_genericmemory_t *h JL_PROPAGATES_ROOT, jl_value_t *key, jl_value_t *deflt) JL_NOTSAFEPOINT; JL_DLLEXPORT jl_value_t *jl_eqtable_pop(jl_genericmemory_t *h, jl_value_t *key, jl_value_t *deflt, int *found); jl_value_t *jl_eqtable_getkey(jl_genericmemory_t *h JL_PROPAGATES_ROOT, jl_value_t *key, jl_value_t *deflt) JL_NOTSAFEPOINT; @@ -2218,7 +2285,7 @@ extern int jl_n_sweepthreads; // throwing common exceptions JL_DLLEXPORT jl_value_t *jl_vexceptionf(jl_datatype_t *exception_type, - const char *fmt, va_list args); + const char *fmt, va_list args) JL_CANSAFEPOINT; JL_DLLEXPORT void JL_NORETURN jl_error(const char *str); JL_DLLEXPORT void JL_NORETURN jl_errorf(const char *fmt, ...); JL_DLLEXPORT void JL_NORETURN jl_exceptionf(jl_datatype_t *ty, @@ -2295,49 +2362,49 @@ struct _jl_image_t; typedef struct _jl_image_t jl_image_t; JL_DLLIMPORT const char *jl_get_libdir(void) JL_NOTSAFEPOINT; -JL_DLLEXPORT void jl_init(void); +JL_DLLEXPORT void jl_init(void) JL_CANSAFEPOINT_ENTER; JL_DLLEXPORT void jl_init_with_image_file(const char *julia_bindir, - const char *image_path); -JL_DLLEXPORT void jl_init_with_image_handle(void *handle); + const char *image_path) JL_CANSAFEPOINT_ENTER; +JL_DLLEXPORT void jl_init_with_image_handle(void *handle) JL_CANSAFEPOINT_ENTER; JL_DLLEXPORT const char *jl_get_default_sysimg_path(void) JL_NOTSAFEPOINT; JL_DLLEXPORT int jl_is_initialized(void) JL_NOTSAFEPOINT; -JL_DLLEXPORT void jl_atexit_hook(int status) JL_NOTSAFEPOINT_ENTER; -JL_DLLEXPORT void jl_task_wait_empty(void); -JL_DLLEXPORT void jl_postoutput_hook(void); -JL_DLLEXPORT void JL_NORETURN jl_exit(int status); +JL_DLLEXPORT void jl_atexit_hook(int status) JL_CANSAFEPOINT_LEAVE; // also should be JL_NOTSAFEPOINT_ENTER +JL_DLLEXPORT void jl_task_wait_empty(void) JL_CANSAFEPOINT; +JL_DLLEXPORT void jl_postoutput_hook(void) JL_CANSAFEPOINT; +JL_DLLEXPORT void JL_NORETURN jl_exit(int status) JL_CANSAFEPOINT; JL_DLLEXPORT void JL_NORETURN jl_raise(int signo); JL_DLLEXPORT const char *jl_pathname_for_handle(void *handle) JL_NOTSAFEPOINT; JL_DLLEXPORT const char *jl_pathname_for_symbol(void *symbol) JL_NOTSAFEPOINT; -JL_DLLEXPORT jl_gcframe_t **jl_adopt_thread(void); +JL_DLLEXPORT jl_gcframe_t **jl_adopt_thread(void) JL_CANSAFEPOINT_ENTER; JL_DLLEXPORT int jl_deserialize_verify_header(ios_t *s); -JL_DLLEXPORT jl_image_buf_t jl_preload_sysimg(const char *fname); +JL_DLLEXPORT jl_image_buf_t jl_preload_sysimg(const char *fname) JL_NOTSAFEPOINT; JL_DLLEXPORT jl_image_buf_t jl_set_sysimg_so(void *handle) JL_NOTSAFEPOINT; -JL_DLLEXPORT void jl_create_system_image(void **, jl_array_t *worklist, bool_t emit_split, ios_t **s, ios_t **z, jl_array_t **udeps JL_REQUIRE_ROOTED_SLOT, int64_t *srctextpos, jl_array_t *module_init_order); -JL_DLLEXPORT void jl_restore_system_image(jl_image_t *image, jl_image_buf_t buf); -JL_DLLEXPORT jl_value_t *jl_restore_incremental(const char *fname, jl_array_t *depmods, int complete, const char *pkgimage); +JL_DLLEXPORT void jl_create_system_image(void **, jl_array_t *worklist, bool_t emit_split, ios_t **s, ios_t **z, jl_array_t **udeps JL_REQUIRE_ROOTED_SLOT, int64_t *srctextpos, jl_array_t *module_init_order) JL_CANSAFEPOINT; +JL_DLLEXPORT void jl_restore_system_image(jl_image_t *image, jl_image_buf_t buf) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_restore_incremental(const char *fname, jl_array_t *depmods, int complete, const char *pkgimage) JL_CANSAFEPOINT; JL_DLLEXPORT jl_value_t *jl_object_top_module(jl_value_t* v) JL_NOTSAFEPOINT; JL_DLLEXPORT void jl_set_newly_inferred(jl_value_t *newly_inferred); JL_DLLEXPORT void jl_finalize_precompile_inferred(int8_t cleanup_keep_ir); -JL_DLLEXPORT jl_array_t* jl_compute_new_ext(void); -JL_DLLEXPORT void jl_push_newly_inferred(jl_value_t *ci); -JL_DLLEXPORT void jl_set_inference_entrance_backtraces(jl_value_t *inference_entrance_backtraces); -JL_DLLEXPORT void jl_push_inference_entrance_backtraces(jl_value_t *ci); -JL_DLLEXPORT void jl_write_compiler_output(void); +JL_DLLEXPORT jl_array_t* jl_compute_new_ext(void) JL_CANSAFEPOINT; +JL_DLLEXPORT void jl_push_newly_inferred(jl_value_t *ci) JL_CANSAFEPOINT; +JL_DLLEXPORT void jl_set_inference_entrance_backtraces(jl_value_t *inference_entrance_backtraces) JL_CANSAFEPOINT; +JL_DLLEXPORT void jl_push_inference_entrance_backtraces(jl_value_t *ci) JL_CANSAFEPOINT; +JL_DLLEXPORT void jl_write_compiler_output(void) JL_CANSAFEPOINT; // parsing JL_DLLEXPORT jl_value_t *jl_parse_all(const char *text, size_t text_len, - const char *filename, size_t filename_len, size_t lineno); + const char *filename, size_t filename_len, size_t lineno) JL_CANSAFEPOINT; JL_DLLEXPORT jl_value_t *jl_parse_string(const char *text, size_t text_len, - int offset, int greedy); + int offset, int greedy) JL_CANSAFEPOINT; // lowering JL_DLLEXPORT jl_value_t *jl_lower(jl_value_t *expr, jl_module_t *inmodule, const char *file, int line, size_t world, - bool_t warn); + bool_t warn) JL_CANSAFEPOINT; // deprecated; use jl_parse_all JL_DLLEXPORT jl_value_t *jl_parse_input_line(const char *text, size_t text_len, - const char *filename, size_t filename_len); + const char *filename, size_t filename_len) JL_CANSAFEPOINT; // external libraries enum JL_RTLD_CONSTANT { @@ -2356,19 +2423,20 @@ enum JL_RTLD_CONSTANT { #define JL_RTLD_DEFAULT (JL_RTLD_LAZY | JL_RTLD_DEEPBIND) typedef void *jl_libhandle; // compatible with dlopen (void*) / LoadLibrary (HMODULE) -JL_DLLEXPORT jl_libhandle jl_load_dynamic_library(const char *fname, unsigned flags, int throw_err); -JL_DLLEXPORT jl_libhandle jl_dlopen(const char *filename, unsigned flags) JL_NOTSAFEPOINT; +JL_DLLEXPORT jl_libhandle jl_load_dynamic_library(const char *fname, unsigned flags, int throw_err) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_libhandle jl_dlopen(const char *filename, unsigned flags) JL_CANCALLBACK; +JL_DLLEXPORT jl_libhandle jl_dlopen_e(const char *filename, unsigned flags) JL_NOTSAFEPOINT; JL_DLLEXPORT int jl_dlclose(jl_libhandle handle) JL_NOTSAFEPOINT; JL_DLLEXPORT int jl_dlsym(jl_libhandle handle, const char *symbol, void ** value, int throw_err, int search_deps) JL_NOTSAFEPOINT; // evaluation -JL_DLLEXPORT jl_value_t *jl_toplevel_eval(jl_module_t *m, jl_value_t *v); -JL_DLLEXPORT jl_value_t *jl_toplevel_eval_in(jl_module_t *m, jl_value_t *ex); +JL_DLLEXPORT jl_value_t *jl_toplevel_eval(jl_module_t *m, jl_value_t *v) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_toplevel_eval_in(jl_module_t *m, jl_value_t *ex) JL_CANSAFEPOINT; // code loading (parsing + evaluation) -JL_DLLEXPORT jl_value_t *jl_eval_string(const char *str); // embedding interface +JL_DLLEXPORT jl_value_t *jl_eval_string(const char *str) JL_CANSAFEPOINT; // embedding interface JL_DLLEXPORT jl_value_t *jl_load_file_string(const char *text, size_t len, - char *filename, jl_module_t *module); -JL_DLLEXPORT jl_value_t *jl_load(jl_module_t *module, const char *fname); + char *filename, jl_module_t *module) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_load(jl_module_t *module, const char *fname) JL_CANSAFEPOINT; JL_DLLEXPORT jl_module_t *jl_base_relative_to(jl_module_t *m JL_PROPAGATES_ROOT); @@ -2376,23 +2444,23 @@ JL_DLLEXPORT jl_module_t *jl_base_relative_to(jl_module_t *m JL_PROPAGATES_ROOT) JL_DLLEXPORT void jl_register_newmeth_tracer(void (*callback)(jl_method_t *tracee)); // AST access -JL_DLLEXPORT jl_value_t *jl_copy_ast(jl_value_t *expr JL_MAYBE_UNROOTED); +JL_DLLEXPORT jl_value_t *jl_copy_ast(jl_value_t *expr JL_MAYBE_UNROOTED) JL_CANSAFEPOINT; // IR representation -JL_DLLEXPORT jl_value_t *jl_compress_ir(jl_method_t *m, jl_code_info_t *code); -JL_DLLEXPORT jl_code_info_t *jl_uncompress_ir(jl_method_t *m, jl_code_instance_t *metadata, jl_value_t *data); +JL_DLLEXPORT jl_value_t *jl_compress_ir(jl_method_t *m, jl_code_info_t *code) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_code_info_t *jl_uncompress_ir(jl_method_t *m, jl_code_instance_t *metadata, jl_value_t *data) JL_CANSAFEPOINT; JL_DLLEXPORT uint8_t jl_ir_flag_inlining(jl_value_t *data) JL_NOTSAFEPOINT; JL_DLLEXPORT uint8_t jl_ir_flag_has_fcall(jl_value_t *data) JL_NOTSAFEPOINT; JL_DLLEXPORT uint8_t jl_ir_flag_has_image_globalref(jl_value_t *data) JL_NOTSAFEPOINT; JL_DLLEXPORT uint16_t jl_ir_inlining_cost(jl_value_t *data) JL_NOTSAFEPOINT; JL_DLLEXPORT ssize_t jl_ir_nslots(jl_value_t *data) JL_NOTSAFEPOINT; JL_DLLEXPORT uint8_t jl_ir_slotflag(jl_value_t *data, size_t i) JL_NOTSAFEPOINT; -JL_DLLEXPORT jl_value_t *jl_compress_argnames(jl_array_t *syms); -JL_DLLEXPORT jl_array_t *jl_uncompress_argnames(jl_value_t *syms); +JL_DLLEXPORT jl_value_t *jl_compress_argnames(jl_array_t *syms) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_array_t *jl_uncompress_argnames(jl_value_t *syms) JL_CANSAFEPOINT; JL_DLLEXPORT jl_value_t *jl_uncompress_argname_n(jl_value_t *syms, size_t i); JL_DLLEXPORT struct jl_codeloc_t jl_uncompress1_codeloc(jl_debuginfo_t *di, size_t pc) JL_NOTSAFEPOINT; -JL_DLLEXPORT jl_value_t *jl_compress_codelocs(int32_t firstloc, jl_value_t *codelocs, size_t nstmts); -JL_DLLEXPORT jl_value_t *jl_uncompress_codelocs(jl_debuginfo_t *di, size_t nstmts); +JL_DLLEXPORT jl_value_t *jl_compress_codelocs(int32_t firstloc, jl_value_t *codelocs, size_t nstmts) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_uncompress_codelocs(jl_debuginfo_t *di, size_t nstmts) JL_CANSAFEPOINT; JL_DLLEXPORT jl_locspan_t jl_cdi_bytespan(jl_debuginfo_t *di, int32_t pc) JL_NOTSAFEPOINT; JL_DLLEXPORT jl_locspan_t jl_cdi_byte_to_xy(jl_debuginfo_t *di, int32_t b) JL_NOTSAFEPOINT; JL_DLLEXPORT jl_locspan_t jl_cdi_firstxy(jl_debuginfo_t *di, int32_t pc) JL_NOTSAFEPOINT; @@ -2402,11 +2470,11 @@ JL_DLLEXPORT const char *jl_cdi_file(jl_debuginfo_t *di) JL_NOTSAFEPOINT; JL_DLLEXPORT uint8_t jl_encode_inlining_cost(uint16_t inlining_cost) JL_NOTSAFEPOINT; JL_DLLEXPORT uint16_t jl_decode_inlining_cost(uint8_t inlining_cost) JL_NOTSAFEPOINT; -JL_DLLEXPORT int jl_is_operator(const char *sym); -JL_DLLEXPORT int jl_is_unary_operator(const char *sym); -JL_DLLEXPORT int jl_is_unary_and_binary_operator(const char *sym); -JL_DLLEXPORT int jl_is_syntactic_operator(const char *sym); -JL_DLLEXPORT int jl_operator_precedence(const char *sym); +JL_DLLEXPORT int jl_is_operator(const char *sym) JL_CANSAFEPOINT; +JL_DLLEXPORT int jl_is_unary_operator(const char *sym) JL_CANSAFEPOINT; +JL_DLLEXPORT int jl_is_unary_and_binary_operator(const char *sym) JL_CANSAFEPOINT; +JL_DLLEXPORT int jl_is_syntactic_operator(const char *sym) JL_CANSAFEPOINT; +JL_DLLEXPORT int jl_operator_precedence(const char *sym) JL_CANSAFEPOINT; STATIC_INLINE int jl_vinfo_sa(uint8_t vi) { @@ -2420,25 +2488,25 @@ STATIC_INLINE int jl_vinfo_usedundef(uint8_t vi) // calling into julia --------------------------------------------------------- -JL_DLLEXPORT jl_value_t *jl_apply_generic(jl_value_t *F, jl_value_t **args, uint32_t nargs); -JL_DLLEXPORT jl_value_t *jl_invoke(jl_value_t *F, jl_value_t **args, uint32_t nargs, jl_method_instance_t *meth); -JL_DLLEXPORT jl_value_t *jl_invoke_oc(jl_value_t *F, jl_value_t **args, uint32_t nargs, jl_method_instance_t *meth); +JL_DLLEXPORT jl_value_t *jl_apply_generic(jl_value_t *F, jl_value_t **args, uint32_t nargs) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_invoke(jl_value_t *F, jl_value_t **args, uint32_t nargs, jl_method_instance_t *meth) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_invoke_oc(jl_value_t *F, jl_value_t **args, uint32_t nargs, jl_method_instance_t *meth) JL_CANSAFEPOINT; JL_DLLEXPORT int32_t jl_invoke_api(jl_code_instance_t *linfo); -STATIC_INLINE jl_value_t *jl_apply(jl_value_t **args, uint32_t nargs) +STATIC_INLINE jl_value_t *jl_apply(jl_value_t **args, uint32_t nargs) JL_CANSAFEPOINT { return jl_apply_generic(args[0], &args[1], nargs - 1); } -JL_DLLEXPORT jl_value_t *jl_call(jl_value_t *f JL_MAYBE_UNROOTED, jl_value_t **args, uint32_t nargs); -JL_DLLEXPORT jl_value_t *jl_call0(jl_value_t *f JL_MAYBE_UNROOTED); -JL_DLLEXPORT jl_value_t *jl_call1(jl_value_t *f JL_MAYBE_UNROOTED, jl_value_t *a JL_MAYBE_UNROOTED); -JL_DLLEXPORT jl_value_t *jl_call2(jl_value_t *f JL_MAYBE_UNROOTED, jl_value_t *a JL_MAYBE_UNROOTED, jl_value_t *b JL_MAYBE_UNROOTED); +JL_DLLEXPORT jl_value_t *jl_call(jl_value_t *f JL_MAYBE_UNROOTED, jl_value_t **args, uint32_t nargs) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_call0(jl_value_t *f JL_MAYBE_UNROOTED) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_call1(jl_value_t *f JL_MAYBE_UNROOTED, jl_value_t *a JL_MAYBE_UNROOTED) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_call2(jl_value_t *f JL_MAYBE_UNROOTED, jl_value_t *a JL_MAYBE_UNROOTED, jl_value_t *b JL_MAYBE_UNROOTED) JL_CANSAFEPOINT; JL_DLLEXPORT jl_value_t *jl_call3(jl_value_t *f JL_MAYBE_UNROOTED, jl_value_t *a JL_MAYBE_UNROOTED, - jl_value_t *b JL_MAYBE_UNROOTED, jl_value_t *c JL_MAYBE_UNROOTED); + jl_value_t *b JL_MAYBE_UNROOTED, jl_value_t *c JL_MAYBE_UNROOTED) JL_CANSAFEPOINT; JL_DLLEXPORT jl_value_t *jl_call4(jl_value_t *f JL_MAYBE_UNROOTED, jl_value_t *a JL_MAYBE_UNROOTED, jl_value_t *b JL_MAYBE_UNROOTED, jl_value_t *c JL_MAYBE_UNROOTED, - jl_value_t *d JL_MAYBE_UNROOTED); + jl_value_t *d JL_MAYBE_UNROOTED) JL_CANSAFEPOINT; // async signal handling ------------------------------------------------------ @@ -2465,8 +2533,8 @@ struct _jl_handler_t { #define JL_TASK_STATE_DONE 1 #define JL_TASK_STATE_FAILED 2 -JL_DLLEXPORT jl_task_t *jl_new_task(jl_value_t*, jl_value_t*, size_t); -JL_DLLEXPORT void jl_switchto(jl_task_t **pt) JL_NOTSAFEPOINT_ENTER; +JL_DLLEXPORT jl_task_t *jl_new_task(jl_value_t*, jl_value_t*, size_t) JL_CANSAFEPOINT; +JL_DLLEXPORT void jl_switchto(jl_task_t **pt) JL_CANSAFEPOINT_ENTER_LEAVE; JL_DLLEXPORT int jl_set_task_tid(jl_task_t *task, int16_t tid) JL_NOTSAFEPOINT; JL_DLLEXPORT int jl_set_task_threadpoolid(jl_task_t *task, int8_t tpid) JL_NOTSAFEPOINT; JL_DLLEXPORT void JL_NORETURN jl_throw(jl_value_t *e JL_MAYBE_UNROOTED); @@ -2494,10 +2562,10 @@ JL_DLLEXPORT jl_value_t *jl_current_exception(jl_task_t *ct) JL_GLOBALLY_ROOTED JL_DLLEXPORT jl_value_t *jl_exception_occurred(void); JL_DLLEXPORT void jl_exception_clear(void) JL_NOTSAFEPOINT; -JL_DLLEXPORT void jl_enter_handler(jl_task_t *ct, jl_handler_t *eh) JL_NOTSAFEPOINT ; -JL_DLLEXPORT void jl_eh_restore_state(jl_task_t *ct, jl_handler_t *eh); +JL_DLLEXPORT void jl_enter_handler(jl_task_t *ct, jl_handler_t *eh) JL_NOTSAFEPOINT; +JL_DLLEXPORT void jl_eh_restore_state(jl_task_t *ct, jl_handler_t *eh) JL_CANSAFEPOINT; JL_DLLEXPORT void jl_eh_restore_state_noexcept(jl_task_t *ct, jl_handler_t *eh) JL_NOTSAFEPOINT; -JL_DLLEXPORT void jl_pop_handler(jl_task_t *ct, int n) JL_NOTSAFEPOINT; +JL_DLLEXPORT void jl_pop_handler(jl_task_t *ct, int n) JL_CANSAFEPOINT; JL_DLLEXPORT void jl_pop_handler_noexcept(jl_task_t *ct, int n) JL_NOTSAFEPOINT; JL_DLLEXPORT size_t jl_excstack_state(jl_task_t *ct) JL_NOTSAFEPOINT; JL_DLLEXPORT void jl_restore_excstack(jl_task_t *ct, size_t state) JL_NOTSAFEPOINT; @@ -2590,9 +2658,6 @@ extern int had_exception; // I/O system ----------------------------------------------------------------- -struct uv_loop_s; -struct uv_handle_s; -struct uv_stream_s; #ifdef _OS_WINDOWS_ typedef HANDLE jl_uv_os_fd_t; #else @@ -2603,13 +2668,13 @@ typedef int jl_uv_os_fd_t; #define JL_STDERR jl_uv_stderr #define JL_STDIN jl_uv_stdin -JL_DLLEXPORT int jl_process_events(void); +JL_DLLEXPORT int jl_process_events(void) JL_CANSAFEPOINT; JL_DLLEXPORT struct uv_loop_s *jl_global_event_loop(void) JL_NOTSAFEPOINT; -JL_DLLEXPORT void jl_close_uv(struct uv_handle_s *handle); +JL_DLLEXPORT void jl_close_uv(struct uv_handle_s *handle) JL_CANSAFEPOINT; -JL_DLLEXPORT jl_array_t *jl_take_buffer(ios_t *s); +JL_DLLEXPORT jl_array_t *jl_take_buffer(ios_t *s) JL_CANSAFEPOINT; typedef struct { void *data; @@ -2630,10 +2695,10 @@ typedef struct { #define _JL_FORMAT_ATTR(str, arg) #endif -JL_DLLEXPORT void jl_uv_puts(struct uv_stream_s *stream, const char *str, size_t n); -JL_DLLEXPORT int jl_printf(struct uv_stream_s *s, const char *format, ...) +JL_DLLEXPORT void jl_uv_puts(struct uv_stream_s *stream, const char *str, size_t n) JL_CANSAFEPOINT; +JL_DLLEXPORT int jl_printf(struct uv_stream_s *s, const char *format, ...) JL_CANSAFEPOINT _JL_FORMAT_ATTR(2, 3); -JL_DLLEXPORT int jl_vprintf(struct uv_stream_s *s, const char *format, va_list args) +JL_DLLEXPORT int jl_vprintf(struct uv_stream_s *s, const char *format, va_list args) JL_CANSAFEPOINT _JL_FORMAT_ATTR(2, 0); JL_DLLEXPORT void jl_safe_printf(const char *str, ...) JL_NOTSAFEPOINT _JL_FORMAT_ATTR(1, 2); @@ -2651,7 +2716,7 @@ JL_DLLEXPORT int jl_termios_size(void); // showing and std streams JL_DLLEXPORT void jl_flush_cstdio(void) JL_NOTSAFEPOINT; -JL_DLLEXPORT jl_value_t *jl_stderr_obj(void) JL_NOTSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_stderr_obj(void) JL_CANSAFEPOINT; JL_DLLEXPORT size_t jl_static_show(JL_STREAM *out, jl_value_t *v) JL_NOTSAFEPOINT; JL_DLLEXPORT size_t jl_safe_static_show(JL_STREAM *out, jl_value_t *v) JL_NOTSAFEPOINT; JL_DLLEXPORT size_t jl_static_show_func_sig(JL_STREAM *s, jl_value_t *type) JL_NOTSAFEPOINT; @@ -2676,7 +2741,7 @@ uint64_t parse_heap_size_option(const char *optarg, const char *option_name, int // Set julia-level ARGS array according to the arguments provided in // argc/argv -JL_DLLEXPORT jl_value_t *jl_set_ARGS(int argc, char **argv); +JL_DLLEXPORT jl_value_t *jl_set_ARGS(int argc, char **argv) JL_CANSAFEPOINT; JL_DLLEXPORT int jl_generating_output(void) JL_NOTSAFEPOINT; @@ -2780,7 +2845,7 @@ typedef struct { #define jl_root_task (jl_current_task->ptls->root_task) JL_DLLEXPORT jl_task_t *jl_get_current_task(void) JL_GLOBALLY_ROOTED JL_NOTSAFEPOINT; -STATIC_INLINE jl_value_t *jl_get_function(jl_module_t *m, const char *name) +STATIC_INLINE jl_value_t *jl_get_function(jl_module_t *m, const char *name) JL_CANSAFEPOINT { return (jl_value_t*)jl_get_global(m, jl_symbol(name)); } diff --git a/src/julia_gcext.h b/src/julia_gcext.h index 28e90b5bdb73f..5fe3765bb0c0f 100644 --- a/src/julia_gcext.h +++ b/src/julia_gcext.h @@ -51,7 +51,7 @@ JL_DLLEXPORT jl_datatype_t *jl_new_foreign_type( jl_markfunc_t markfunc, jl_sweepfunc_t sweepfunc, int haspointers, - int large); + int large) JL_CANSAFEPOINT; #define HAVE_JL_REINIT_FOREIGN_TYPE 1 @@ -74,7 +74,7 @@ typedef struct { } jl_fielddescdyn_t; // Allocate an object of a foreign type. -JL_DLLEXPORT void *jl_gc_alloc_typed(jl_ptls_t ptls, size_t sz, void *ty); +JL_DLLEXPORT void *jl_gc_alloc_typed(jl_ptls_t ptls, size_t sz, void *ty) JL_CANSAFEPOINT; // Queue an object or array of objects for scanning by the garbage collector. // These functions must only be called from within a root scanner callback @@ -113,7 +113,7 @@ JL_DLLEXPORT void jl_gc_schedule_foreign_sweepfunc(jl_ptls_t ptls, jl_value_t *b // whether support was already enabled. The function may implicitly // trigger a full garbage collection to properly update all internal // data structures. -JL_DLLEXPORT int jl_gc_enable_conservative_gc_support(void); +JL_DLLEXPORT int jl_gc_enable_conservative_gc_support(void) JL_CANSAFEPOINT; // This function returns whether support for conservative scanning has // been enabled. The return values are the same as for diff --git a/src/julia_internal.h b/src/julia_internal.h index 71210662016e0..7c2881a2398f3 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -227,14 +227,14 @@ extern JL_HIDDEN struct jl_internal_global internal_global; #endif // Generated macros to access globals -void JL_UV_LOCK(void); +void JL_UV_LOCK(void) JL_CANSAFEPOINT; #define JL_UV_UNLOCK() JL_UNLOCK(&jl_uv_mutex) extern _Atomic(unsigned) _threadedregion; extern _Atomic(uint16_t) io_loop_tid; -JL_DLLEXPORT void jl_init_(jl_image_buf_t sysimage); +JL_DLLEXPORT void jl_init_(jl_image_buf_t sysimage) JL_CANSAFEPOINT_ENTER; JL_DLLEXPORT void jl_enter_threaded_region(void); -JL_DLLEXPORT void jl_exit_threaded_region(void); +JL_DLLEXPORT void jl_exit_threaded_region(void) JL_CANSAFEPOINT; JL_DLLEXPORT int jl_running_under_rr(int recheck) JL_NOTSAFEPOINT; int jl_running_under_sanitizer(int recheck) JL_NOTSAFEPOINT; @@ -246,10 +246,11 @@ JL_DLLEXPORT uint64_t jl_hrtime(void) JL_NOTSAFEPOINT; JL_DLLEXPORT double jl_get_profile_peek_duration(void); JL_DLLEXPORT void jl_set_profile_peek_duration(double); -JL_DLLEXPORT void jl_init_profile_lock(void); -JL_DLLEXPORT int jl_lock_profile(void) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_ENTER; +JL_DLLEXPORT void jl_init_profile_lock(void) JL_NOTSAFEPOINT; +JL_DLLEXPORT void jl_lock_profile(void) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_ENTER; +JL_DLLEXPORT int jl_trylock_profile(void) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_ENTER_CONDITIONAL(1); JL_DLLEXPORT void jl_unlock_profile(void) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_LEAVE; -JL_DLLEXPORT int jl_lock_profile_wr(void) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_ENTER; +JL_DLLEXPORT int jl_lock_profile_wr(void) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_ENTER_CONDITIONAL(1); JL_DLLEXPORT void jl_unlock_profile_wr(void) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_LEAVE; arraylist_t *jl_get_all_tasks_arraylist(void) JL_NOTSAFEPOINT; @@ -281,7 +282,7 @@ extern uv_mutex_t bt_data_prof_lock; #define PROFILE_STATE_THREAD_NOT_SLEEPING (1) #define PROFILE_STATE_THREAD_SLEEPING (2) #define PROFILE_STATE_WALL_TIME_PROFILING (3) -void jl_profile_task(void); +void jl_profile_task(void) JL_NOTSAFEPOINT; #if defined(_OS_WINDOWS_) && defined(_CPU_X86_64_) JL_DLLEXPORT void jl_set_profile_abort_ptr(_Atomic(int) *abort_ptr) JL_NOTSAFEPOINT; #endif @@ -517,8 +518,8 @@ extern JL_DLLEXPORT _Atomic(size_t) jl_world_counter; typedef void (*tracer_cb)(jl_value_t *tracee); extern tracer_cb jl_newmeth_tracer; -void jl_call_tracer(tracer_cb callback, jl_value_t *tracee); -void print_func_loc(JL_STREAM *s, jl_method_t *m); +void jl_call_tracer(tracer_cb callback, jl_value_t *tracee) JL_CANSAFEPOINT; +void print_func_loc(JL_STREAM *s, jl_method_t *m) JL_CANSAFEPOINT; extern jl_array_t *_jl_debug_method_invalidation JL_GLOBALLY_ROOTED; extern JL_DLLEXPORT size_t jl_page_size; @@ -536,8 +537,8 @@ JL_DLLEXPORT extern _Atomic(int) jl_lineno; JL_DLLEXPORT extern _Atomic(const char *) jl_filename; jl_value_t *jl_gc_small_alloc_noinline(jl_ptls_t ptls, int offset, - int osize); -jl_value_t *jl_gc_big_alloc_noinline(jl_ptls_t ptls, size_t allocsz); + int osize) JL_CANSAFEPOINT; +jl_value_t *jl_gc_big_alloc_noinline(jl_ptls_t ptls, size_t allocsz) JL_CANSAFEPOINT; JL_DLLEXPORT int jl_gc_classify_pools(size_t sz, int *osize) JL_NOTSAFEPOINT; extern arraylist_t image_remset; extern jl_mutex_t image_remset_lock; @@ -684,7 +685,7 @@ static_assert(ARRAY_CACHE_ALIGN_THRESHOLD > GC_MAX_SZCLASS, ""); * the JL_GC_PUSH macro until the value has been initialized, any accidental * safepoints will be caught by the GC analyzer. */ -JL_DLLEXPORT jl_value_t *jl_gc_alloc(jl_ptls_t ptls, size_t sz, void *ty); +JL_DLLEXPORT jl_value_t *jl_gc_alloc(jl_ptls_t ptls, size_t sz, void *ty) JL_CANSAFEPOINT; // On GCC, only inline when sz is constant #ifdef __GNUC__ # define jl_gc_alloc(ptls, sz, ty) \ @@ -702,7 +703,7 @@ const extern uint64_t _jl_buff_tag[3]; JL_DLLEXPORT uintptr_t jl_get_buff_tag(void) JL_NOTSAFEPOINT; typedef void jl_gc_tracked_buffer_t; // For the benefit of the static analyzer -STATIC_INLINE jl_gc_tracked_buffer_t *jl_gc_alloc_buf(jl_ptls_t ptls, size_t sz) +STATIC_INLINE jl_gc_tracked_buffer_t *jl_gc_alloc_buf(jl_ptls_t ptls, size_t sz) JL_CANSAFEPOINT { return jl_gc_alloc(ptls, sz, (void*)jl_buff_tag); } @@ -746,7 +747,7 @@ void jl_gc_track_malloced_genericmemory(jl_ptls_t ptls, jl_genericmemory_t *m, i size_t jl_genericmemory_nbytes(jl_genericmemory_t *a) JL_NOTSAFEPOINT; size_t memory_block_usable_size(void *mem, int isaligned) JL_NOTSAFEPOINT; void jl_gc_count_allocd(size_t sz) JL_NOTSAFEPOINT; -void jl_gc_run_all_finalizers(jl_task_t *ct); +void jl_gc_run_all_finalizers(jl_task_t *ct) JL_CANSAFEPOINT; void jl_release_task_stack(jl_ptls_t ptls, jl_task_t *task); void jl_gc_add_finalizer_(jl_ptls_t ptls, void *v, void *f) JL_NOTSAFEPOINT; @@ -805,36 +806,36 @@ typedef union { #define METHOD_SIG_LATEST_ONLY 0b0010 #define METHOD_SIG_PRECOMPILE_MANY 0b0100 -void jl_init_engine(void); +void jl_init_engine(void) JL_NOTSAFEPOINT; void jl_engine_sweep(jl_ptls_t *gc_all_tls_states) JL_NOTSAFEPOINT; int jl_engine_hasreserved(jl_method_instance_t *m, jl_value_t *owner) JL_NOTSAFEPOINT; -JL_DLLEXPORT jl_code_instance_t *jl_engine_reserve(jl_method_instance_t *m, jl_value_t *owner); -JL_DLLEXPORT void jl_engine_fulfill(jl_code_instance_t *ci, jl_code_info_t *src); +JL_DLLEXPORT jl_code_instance_t *jl_engine_reserve(jl_method_instance_t *m, jl_value_t *owner) JL_CANSAFEPOINT; +JL_DLLEXPORT void jl_engine_fulfill(jl_code_instance_t *ci, jl_code_info_t *src) JL_CANSAFEPOINT; -JL_DLLEXPORT jl_code_instance_t *jl_type_infer(jl_method_instance_t *li JL_PROPAGATES_ROOT, size_t world, uint8_t source_mode, uint8_t trim_mode); +JL_DLLEXPORT jl_code_instance_t *jl_type_infer(jl_method_instance_t *li JL_PROPAGATES_ROOT, size_t world, uint8_t source_mode, uint8_t trim_mode) JL_CANSAFEPOINT; JL_DLLEXPORT int8_t jl_get_type_infer_preserve_ir(void); JL_DLLEXPORT void jl_set_type_infer_preserve_ir(int8_t v); JL_DLLEXPORT int8_t jl_get_precompile_keep_ir(void); JL_DLLEXPORT void jl_set_precompile_keep_ir(int8_t v); -JL_DLLEXPORT jl_code_info_t *jl_gdbcodetyped1(jl_method_instance_t *mi, size_t world); -JL_DLLEXPORT jl_code_instance_t *jl_compile_method_internal(jl_method_instance_t *meth JL_PROPAGATES_ROOT, size_t world); +JL_DLLEXPORT jl_code_info_t *jl_gdbcodetyped1(jl_method_instance_t *mi, size_t world) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_code_instance_t *jl_compile_method_internal(jl_method_instance_t *meth JL_PROPAGATES_ROOT, size_t world) JL_CANSAFEPOINT; JL_DLLEXPORT jl_code_instance_t *jl_get_method_uninferred( jl_method_instance_t *mi JL_PROPAGATES_ROOT, jl_value_t *rettype, - size_t min_world, size_t max_world, jl_debuginfo_t *di, jl_svec_t *edges); + size_t min_world, size_t max_world, jl_debuginfo_t *di, jl_svec_t *edges) JL_CANSAFEPOINT; JL_DLLEXPORT int jl_mi_cache_has_ci(jl_method_instance_t *mi, jl_code_instance_t *ci) JL_NOTSAFEPOINT; -JL_DLLEXPORT void jl_read_codeinst_invoke(jl_code_instance_t *ci, uint8_t *specsigflags, jl_callptr_t *invoke, void **specptr, int waitcompile); -JL_DLLEXPORT void jl_add_codeinsts_to_jit(jl_array_t *codeinsts, jl_array_t *srcs); +JL_DLLEXPORT void jl_read_codeinst_invoke(jl_code_instance_t *ci, uint8_t *specsigflags, jl_callptr_t *invoke, void **specptr, int waitcompile) JL_CANSAFEPOINT; +JL_DLLEXPORT void jl_add_codeinsts_to_jit(jl_array_t *codeinsts, jl_array_t *srcs) JL_CANSAFEPOINT; -JL_DLLEXPORT jl_value_t *jl_invoke_oneshot(jl_value_t *F, jl_value_t **args, uint32_t nargs, jl_method_instance_t *meth); +JL_DLLEXPORT jl_value_t *jl_invoke_oneshot(jl_value_t *F, jl_value_t **args, uint32_t nargs, jl_method_instance_t *meth) JL_CANSAFEPOINT; -JL_DLLEXPORT jl_code_instance_t *jl_new_codeinst_uninit(jl_method_instance_t *mi, jl_value_t *owner); +JL_DLLEXPORT jl_code_instance_t *jl_new_codeinst_uninit(jl_method_instance_t *mi, jl_value_t *owner) JL_CANSAFEPOINT; JL_DLLEXPORT jl_code_instance_t *jl_new_codeinst( jl_method_instance_t *mi, jl_value_t *owner, jl_value_t *rettype, jl_value_t *exctype, jl_value_t *inferred_const, jl_value_t *inferred, int32_t const_flags, size_t min_world, size_t max_world, uint32_t effects, jl_value_t *analysis_results, - jl_debuginfo_t *di, jl_svec_t *edges /* , int absolute_max*/); + jl_debuginfo_t *di, jl_svec_t *edges /* , int absolute_max*/) JL_CANSAFEPOINT; JL_DLLEXPORT jl_code_instance_t *jl_get_ci_equiv(jl_code_instance_t *ci JL_PROPAGATES_ROOT, size_t target_world) JL_NOTSAFEPOINT; STATIC_INLINE jl_method_instance_t *jl_get_ci_mi(jl_code_instance_t *ci JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT @@ -874,18 +875,18 @@ JL_DLLEXPORT jl_module_t *jl_debuginfo_module1(jl_value_t *debuginfo_def) JL_NOT JL_DLLEXPORT const char *jl_debuginfo_name(jl_value_t *func) JL_NOTSAFEPOINT; JL_DLLEXPORT int jl_is_compiled_codeinst(jl_code_instance_t *codeinst) JL_NOTSAFEPOINT; -JL_DLLEXPORT void jl_compile_method_instance(jl_method_instance_t *mi, jl_tupletype_t *types, size_t world); -JL_DLLEXPORT void jl_compile_method_sig(jl_method_t *m, jl_value_t *types, jl_svec_t *sparams, size_t world); -JL_DLLEXPORT int jl_compile_hint(jl_tupletype_t *types); -jl_code_info_t *jl_code_for_interpreter(jl_method_instance_t *lam JL_PROPAGATES_ROOT, size_t world); -jl_value_t *jl_code_or_ci_for_interpreter(jl_method_instance_t *lam JL_PROPAGATES_ROOT, size_t world); -int jl_code_requires_compiler(jl_code_info_t *src, int include_force_compile); -jl_code_info_t *jl_new_code_info_from_ir(jl_expr_t *ast); -JL_DLLEXPORT jl_code_info_t *jl_new_code_info_uninit(void); +JL_DLLEXPORT void jl_compile_method_instance(jl_method_instance_t *mi, jl_tupletype_t *types, size_t world) JL_CANSAFEPOINT; +JL_DLLEXPORT void jl_compile_method_sig(jl_method_t *m, jl_value_t *types, jl_svec_t *sparams, size_t world) JL_CANSAFEPOINT; +JL_DLLEXPORT int jl_compile_hint(jl_tupletype_t *types) JL_CANSAFEPOINT; +jl_code_info_t *jl_code_for_interpreter(jl_method_instance_t *lam JL_PROPAGATES_ROOT, size_t world) JL_CANSAFEPOINT; +jl_value_t *jl_code_or_ci_for_interpreter(jl_method_instance_t *lam JL_PROPAGATES_ROOT, size_t world) JL_CANSAFEPOINT; +int jl_code_requires_compiler(jl_code_info_t *src, int include_force_compile) JL_CANSAFEPOINT; +jl_code_info_t *jl_new_code_info_from_ir(jl_expr_t *ast) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_code_info_t *jl_new_code_info_uninit(void) JL_CANSAFEPOINT; JL_DLLEXPORT void jl_resolve_definition_effects_in_ir(jl_array_t *stmts, jl_module_t *m, jl_svec_t *sparam_vals, jl_value_t *binding_edge, - int binding_effects); -JL_DLLEXPORT int jl_maybe_add_binding_backedge(jl_binding_t *b, jl_value_t *edge, jl_method_t *in_method); -JL_DLLEXPORT void jl_add_binding_backedge(jl_binding_t *b, jl_value_t *edge); + int binding_effects) JL_CANSAFEPOINT; +JL_DLLEXPORT int jl_maybe_add_binding_backedge(jl_binding_t *b, jl_value_t *edge, jl_method_t *in_method) JL_CANSAFEPOINT; +JL_DLLEXPORT void jl_add_binding_backedge(jl_binding_t *b, jl_value_t *edge) JL_CANSAFEPOINT; static const uint8_t MI_FLAG_BACKEDGES_INUSE = 0b0100; static const uint8_t MI_FLAG_BACKEDGES_DIRTY = 0b1000; @@ -913,11 +914,11 @@ int set_next_edge(jl_array_t *list JL_PROPAGATES_ROOT, int i, jl_code_instance_t *caller JL_ROOTED_BY_ARG(0)) JL_NOTSAFEPOINT; int clear_next_edge(jl_array_t *list JL_PROPAGATES_ROOT, int i, jl_value_t *invokesig, jl_code_instance_t *caller) JL_NOTSAFEPOINT; -void push_edge(jl_array_t *list, jl_value_t *invokesig, jl_code_instance_t *caller); +void push_edge(jl_array_t *list, jl_value_t *invokesig, jl_code_instance_t *caller) JL_CANSAFEPOINT; void jl_mi_done_backedges(jl_method_instance_t *mi JL_PROPAGATES_ROOT, uint8_t old_flags); -JL_DLLEXPORT void jl_add_method_root(jl_method_t *m, jl_module_t *mod, jl_value_t* root); -void jl_append_method_roots(jl_method_t *m, uint64_t modid, jl_array_t* roots); +JL_DLLEXPORT void jl_add_method_root(jl_method_t *m, jl_module_t *mod, jl_value_t* root) JL_CANSAFEPOINT; +void jl_append_method_roots(jl_method_t *m, uint64_t modid, jl_array_t* roots) JL_CANSAFEPOINT; int get_root_reference(rle_reference *rr, jl_method_t *m, size_t i) JL_NOTSAFEPOINT; jl_value_t *lookup_root(jl_method_t *m, uint64_t key, int index) JL_NOTSAFEPOINT; int nroots_with_key(jl_method_t *m, uint64_t key) JL_NOTSAFEPOINT; @@ -926,21 +927,21 @@ int jl_valid_type_param(jl_value_t *v); JL_DLLEXPORT jl_value_t *jl_apply_2va(jl_value_t *f, jl_value_t **args, uint32_t nargs); -void JL_NORETURN jl_method_error(jl_value_t *F, jl_value_t **args, size_t na, size_t world); -JL_DLLEXPORT jl_value_t *jl_get_exceptionf(jl_datatype_t *exception_type, const char *fmt, ...); +void JL_NORETURN jl_method_error(jl_value_t *F, jl_value_t **args, size_t na, size_t world) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_get_exceptionf(jl_datatype_t *exception_type, const char *fmt, ...) JL_CANSAFEPOINT; -JL_DLLEXPORT void jl_typeassert(jl_value_t *x, jl_value_t *t); +JL_DLLEXPORT void jl_typeassert(jl_value_t *x, jl_value_t *t) JL_CANSAFEPOINT; #define JL_CALLABLE(name) \ JL_DLLEXPORT jl_value_t *name(jl_value_t *F, jl_value_t **args, uint32_t nargs) -JL_CALLABLE(jl_f_tuple); -void jl_install_default_signal_handlers(void); -void restore_signals(void); -void jl_install_thread_signal_handler(jl_ptls_t ptls); +JL_CALLABLE(jl_f_tuple) JL_CANSAFEPOINT; +void jl_install_default_signal_handlers(void) JL_NOTSAFEPOINT; +void restore_signals(void) JL_NOTSAFEPOINT; +void jl_install_thread_signal_handler(jl_ptls_t ptls) JL_NOTSAFEPOINT; extern uv_loop_t *jl_io_loop; -JL_DLLEXPORT void jl_uv_flush(uv_stream_t *stream); +JL_DLLEXPORT void jl_uv_flush(uv_stream_t *stream) JL_CANSAFEPOINT; typedef struct jl_typeenv_t { jl_tvar_t *var; @@ -948,8 +949,8 @@ typedef struct jl_typeenv_t { struct jl_typeenv_t *prev; } jl_typeenv_t; -int jl_tuple_isa(jl_value_t **child, size_t cl, jl_datatype_t *pdt); -int jl_tuple1_isa(jl_value_t *child1, jl_value_t **child, size_t cl, jl_datatype_t *pdt); +int jl_tuple_isa(jl_value_t **child, size_t cl, jl_datatype_t *pdt) JL_CANSAFEPOINT; +int jl_tuple1_isa(jl_value_t *child1, jl_value_t **child, size_t cl, jl_datatype_t *pdt) JL_CANSAFEPOINT; enum atomic_kind { isatomic_none = 0, @@ -961,80 +962,80 @@ JL_DLLEXPORT int jl_has_intersect_type_not_kind(jl_value_t *t); int jl_has_intersect_kind_not_type(jl_value_t *t); int jl_subtype_invariant(jl_value_t *a, jl_value_t *b, int ta); JL_DLLEXPORT int jl_has_concrete_subtype(jl_value_t *typ); -jl_tupletype_t *jl_inst_arg_tuple_type(jl_value_t *arg1, jl_value_t **args, size_t nargs, int leaf); -jl_tupletype_t *jl_lookup_arg_tuple_type(jl_value_t *arg1 JL_PROPAGATES_ROOT, jl_value_t **args, size_t nargs, int leaf); -JL_DLLEXPORT void jl_method_table_insert(jl_methtable_t *mt, jl_method_t *method, jl_tupletype_t *simpletype); -void jl_method_table_activate(jl_typemap_entry_t *newentry); -jl_typemap_entry_t *jl_method_table_add(jl_methtable_t *mt, jl_method_t *method, jl_tupletype_t *simpletype); -jl_method_t *jl_mk_builtin_func(jl_datatype_t *dt, jl_sym_t *name, jl_fptr_args_t fptr) JL_GC_DISABLED; +jl_tupletype_t *jl_inst_arg_tuple_type(jl_value_t *arg1, jl_value_t **args, size_t nargs, int leaf) JL_CANSAFEPOINT; +jl_tupletype_t *jl_lookup_arg_tuple_type(jl_value_t *arg1 JL_PROPAGATES_ROOT, jl_value_t **args, size_t nargs, int leaf) JL_CANSAFEPOINT; +JL_DLLEXPORT void jl_method_table_insert(jl_methtable_t *mt, jl_method_t *method, jl_tupletype_t *simpletype) JL_CANSAFEPOINT; +void jl_method_table_activate(jl_typemap_entry_t *newentry) JL_CANSAFEPOINT; +jl_typemap_entry_t *jl_method_table_add(jl_methtable_t *mt, jl_method_t *method, jl_tupletype_t *simpletype) JL_CANSAFEPOINT; +jl_method_t *jl_mk_builtin_func(jl_datatype_t *dt, jl_sym_t *name, jl_fptr_args_t fptr) JL_CANSAFEPOINT JL_GC_DISABLED; int jl_obviously_unequal(jl_value_t *a, jl_value_t *b); int jl_has_bound_typevars(jl_value_t *v, jl_typeenv_t *env) JL_NOTSAFEPOINT; -JL_DLLEXPORT jl_array_t *jl_find_free_typevars(jl_value_t *v); +JL_DLLEXPORT jl_array_t *jl_find_free_typevars(jl_value_t *v) JL_CANSAFEPOINT; JL_DLLEXPORT jl_value_t *jl_rewrap_free_typevars(jl_value_t *t, jl_array_t *pre); -int jl_has_fixed_layout(jl_datatype_t *t); -JL_DLLEXPORT int jl_struct_try_layout(jl_datatype_t *dt); -JL_DLLEXPORT int jl_type_mappable_to_c(jl_value_t *ty); -jl_svec_t *jl_outer_unionall_vars(jl_value_t *u); -jl_value_t *jl_type_intersection_env_s(jl_value_t *a, jl_value_t *b, jl_svec_t **penv, int *issubty); -jl_value_t *jl_type_intersection_env(jl_value_t *a, jl_value_t *b, jl_svec_t **penv); -int jl_subtype_matching(jl_value_t *a, jl_value_t *b, jl_svec_t **penv); +int jl_has_fixed_layout(jl_datatype_t *t) JL_CANSAFEPOINT; +JL_DLLEXPORT int jl_struct_try_layout(jl_datatype_t *dt) JL_CANSAFEPOINT; +JL_DLLEXPORT int jl_type_mappable_to_c(jl_value_t *ty) JL_CANSAFEPOINT; +jl_svec_t *jl_outer_unionall_vars(jl_value_t *u) JL_CANSAFEPOINT; +jl_value_t *jl_type_intersection_env_s(jl_value_t *a, jl_value_t *b, jl_svec_t **penv, int *issubty) JL_CANSAFEPOINT; +jl_value_t *jl_type_intersection_env(jl_value_t *a, jl_value_t *b, jl_svec_t **penv) JL_CANSAFEPOINT; +int jl_subtype_matching(jl_value_t *a, jl_value_t *b, jl_svec_t **penv) JL_CANSAFEPOINT; JL_DLLEXPORT int jl_types_struct_equiv(jl_value_t *a, jl_value_t *b) JL_NOTSAFEPOINT; // specificity comparison assuming !(a <: b) and !(b <: a) -JL_DLLEXPORT int jl_type_morespecific_no_subtype(jl_value_t *a, jl_value_t *b); -JL_DLLEXPORT jl_value_t *jl_instantiate_type_with(jl_value_t *t, jl_value_t **env, size_t n); -JL_DLLEXPORT jl_value_t *jl_instantiate_type_in_env(jl_value_t *ty, jl_unionall_t *env, jl_value_t **vals); -jl_value_t *jl_substitute_var(jl_value_t *t, jl_tvar_t *var, jl_value_t *val); -jl_value_t *jl_substitute_var_nothrow(jl_value_t *t, jl_tvar_t *var, jl_value_t *val, int nothrow); -jl_unionall_t *jl_rename_unionall(jl_unionall_t *u); +JL_DLLEXPORT int jl_type_morespecific_no_subtype(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_instantiate_type_with(jl_value_t *t, jl_value_t **env, size_t n) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_instantiate_type_in_env(jl_value_t *ty, jl_unionall_t *env, jl_value_t **vals) JL_CANSAFEPOINT; +jl_value_t *jl_substitute_var(jl_value_t *t, jl_tvar_t *var, jl_value_t *val) JL_CANSAFEPOINT; +jl_value_t *jl_substitute_var_nothrow(jl_value_t *t, jl_tvar_t *var, jl_value_t *val, int nothrow) JL_CANSAFEPOINT; +jl_unionall_t *jl_rename_unionall(jl_unionall_t *u) JL_CANSAFEPOINT; JL_DLLEXPORT jl_value_t *jl_unwrap_unionall(jl_value_t *v JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT; -JL_DLLEXPORT jl_value_t *jl_rewrap_unionall(jl_value_t *t, jl_value_t *u); -JL_DLLEXPORT jl_value_t *jl_rewrap_unionall_(jl_value_t *t, jl_value_t *u); -jl_value_t* jl_substitute_datatype(jl_value_t *t, jl_datatype_t * x, jl_datatype_t * y); +JL_DLLEXPORT jl_value_t *jl_rewrap_unionall(jl_value_t *t, jl_value_t *u) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_rewrap_unionall_(jl_value_t *t, jl_value_t *u) JL_CANSAFEPOINT; +jl_value_t* jl_substitute_datatype(jl_value_t *t, jl_datatype_t * x, jl_datatype_t * y) JL_CANSAFEPOINT; int jl_count_union_components(jl_value_t *v); JL_DLLEXPORT jl_value_t *jl_nth_union_component(jl_value_t *v JL_PROPAGATES_ROOT, int i) JL_NOTSAFEPOINT; int jl_find_union_component(jl_value_t *haystack, jl_value_t *needle, unsigned *nth) JL_NOTSAFEPOINT; jl_datatype_t *jl_new_abstracttype(jl_value_t *name, jl_module_t *module, - jl_datatype_t *super, jl_svec_t *parameters); -jl_datatype_t *jl_new_uninitialized_datatype(void); + jl_datatype_t *super, jl_svec_t *parameters) JL_CANSAFEPOINT; +jl_datatype_t *jl_new_uninitialized_datatype(void) JL_CANSAFEPOINT; void jl_precompute_memoized_dt(jl_datatype_t *dt, int cacheable); -JL_DLLEXPORT jl_typeeq_t *jl_wrap_Type(jl_value_t *t); // x -> Type{x} -JL_DLLEXPORT jl_value_t *jl_wrap_TypeEgal(jl_value_t *t); // x -> TypeEgal{x} (egality, no free typevars) -jl_vararg_t *jl_wrap_vararg(jl_value_t *t, jl_value_t *n, int check, int nothrow); -void jl_reinstantiate_inner_types(jl_datatype_t *t); -jl_datatype_t *jl_lookup_cache_type_(jl_datatype_t *type); -jl_value_t *jl_lookup_foreignsymbol(jl_value_t *v); -void jl_cache_type_(jl_datatype_t *type); -jl_svec_t *cache_rehash_set(jl_svec_t *a, size_t newsz); +JL_DLLEXPORT jl_typeeq_t *jl_wrap_Type(jl_value_t *t) JL_CANSAFEPOINT; // x -> Type{x} +JL_DLLEXPORT jl_value_t *jl_wrap_TypeEgal(jl_value_t *t) JL_CANSAFEPOINT; // x -> TypeEgal{x} (egality, no free typevars) +jl_vararg_t *jl_wrap_vararg(jl_value_t *t, jl_value_t *n, int check, int nothrow) JL_CANSAFEPOINT; +void jl_reinstantiate_inner_types(jl_datatype_t *t) JL_CANSAFEPOINT; +jl_datatype_t *jl_lookup_cache_type_(jl_datatype_t *type) JL_CANSAFEPOINT; +jl_value_t *jl_lookup_foreignsymbol(jl_value_t *v) JL_CANSAFEPOINT; +void jl_cache_type_(jl_datatype_t *type) JL_CANSAFEPOINT; +jl_svec_t *cache_rehash_set(jl_svec_t *a, size_t newsz) JL_CANSAFEPOINT; void set_nth_field(jl_datatype_t *st, jl_value_t *v, size_t i, jl_value_t *rhs, int isatomic) JL_NOTSAFEPOINT; -jl_value_t *swap_nth_field(jl_datatype_t *st, jl_value_t *v, size_t i, jl_value_t *rhs, int isatomic); -jl_value_t *modify_nth_field(jl_datatype_t *st, jl_value_t *v, size_t i, jl_value_t *op, jl_value_t *rhs, int isatomic); -jl_value_t *replace_nth_field(jl_datatype_t *st, jl_value_t *v, size_t i, jl_value_t *expected, jl_value_t *rhs, int isatomic); -int set_nth_fieldonce(jl_datatype_t *st, jl_value_t *v, size_t i, jl_value_t *rhs, int isatomic); -jl_value_t *swap_bits(jl_value_t *ty, char *v, uint8_t *psel, jl_value_t *parent, jl_value_t *rhs, enum atomic_kind isatomic); -jl_value_t *replace_value(jl_value_t *ty, _Atomic(jl_value_t*) *p, jl_value_t *parent, jl_value_t *expected, jl_value_t *rhs, int isatomic, jl_module_t *mod, jl_sym_t *name); -jl_value_t *replace_bits(jl_value_t *ty, char *p, uint8_t *psel, jl_value_t *parent, jl_value_t *expected, jl_value_t *rhs, enum atomic_kind isatomic); -jl_value_t *modify_value(jl_value_t *ty, _Atomic(jl_value_t*) *p, jl_value_t *parent, jl_value_t *op, jl_value_t *rhs, int isatomic, jl_binding_t *b, jl_module_t *mod, jl_sym_t *name); -jl_value_t *modify_bits(jl_value_t *ty, char *p, uint8_t *psel, jl_value_t *parent, jl_value_t *op, jl_value_t *rhs, enum atomic_kind isatomic); +jl_value_t *swap_nth_field(jl_datatype_t *st, jl_value_t *v, size_t i, jl_value_t *rhs, int isatomic) JL_CANSAFEPOINT; +jl_value_t *modify_nth_field(jl_datatype_t *st, jl_value_t *v, size_t i, jl_value_t *op, jl_value_t *rhs, int isatomic) JL_CANSAFEPOINT; +jl_value_t *replace_nth_field(jl_datatype_t *st, jl_value_t *v, size_t i, jl_value_t *expected, jl_value_t *rhs, int isatomic) JL_CANSAFEPOINT; +int set_nth_fieldonce(jl_datatype_t *st, jl_value_t *v, size_t i, jl_value_t *rhs, int isatomic) JL_CANSAFEPOINT; +jl_value_t *swap_bits(jl_value_t *ty, char *v, uint8_t *psel, jl_value_t *parent, jl_value_t *rhs, enum atomic_kind isatomic) JL_CANSAFEPOINT; +jl_value_t *replace_value(jl_value_t *ty, _Atomic(jl_value_t*) *p, jl_value_t *parent, jl_value_t *expected, jl_value_t *rhs, int isatomic, jl_module_t *mod, jl_sym_t *name) JL_CANSAFEPOINT; +jl_value_t *replace_bits(jl_value_t *ty, char *p, uint8_t *psel, jl_value_t *parent, jl_value_t *expected, jl_value_t *rhs, enum atomic_kind isatomic) JL_CANSAFEPOINT; +jl_value_t *modify_value(jl_value_t *ty, _Atomic(jl_value_t*) *p, jl_value_t *parent, jl_value_t *op, jl_value_t *rhs, int isatomic, jl_binding_t *b, jl_module_t *mod, jl_sym_t *name) JL_CANSAFEPOINT; +jl_value_t *modify_bits(jl_value_t *ty, char *p, uint8_t *psel, jl_value_t *parent, jl_value_t *op, jl_value_t *rhs, enum atomic_kind isatomic) JL_CANSAFEPOINT; int setonce_bits(jl_datatype_t *rty, char *p, jl_value_t *owner, jl_value_t *rhs, enum atomic_kind isatomic); -jl_expr_t *jl_exprn(jl_sym_t *head, size_t n); -jl_value_t *jl_new_generic_function(jl_sym_t *name, jl_module_t *module, size_t new_world); -jl_value_t *jl_new_generic_function_with_supertype(jl_sym_t *name, jl_module_t *module, jl_datatype_t *st, size_t new_world); -int jl_foreach_reachable_mtable(int (*visit)(jl_methtable_t *mt, void *env), jl_array_t *mod_array, void *env); -void jl_init_main_module(void); +jl_expr_t *jl_exprn(jl_sym_t *head, size_t n) JL_CANSAFEPOINT; +jl_value_t *jl_new_generic_function(jl_sym_t *name, jl_module_t *module, size_t new_world) JL_CANSAFEPOINT; +jl_value_t *jl_new_generic_function_with_supertype(jl_sym_t *name, jl_module_t *module, jl_datatype_t *st, size_t new_world) JL_CANSAFEPOINT; +int jl_foreach_reachable_mtable(int (*visit)(jl_methtable_t *mt, void *env) JL_CANSAFEPOINT, jl_array_t *mod_array, void *env) JL_CANSAFEPOINT; +void jl_init_main_module(void) JL_CANSAFEPOINT; JL_DLLEXPORT int jl_is_submodule(jl_module_t *child, jl_module_t *parent) JL_NOTSAFEPOINT; -jl_array_t *jl_get_loaded_modules(void); -JL_DLLEXPORT int jl_datatype_isinlinealloc(jl_datatype_t *ty, int pointerfree); +jl_array_t *jl_get_loaded_modules(void) JL_CANSAFEPOINT; +JL_DLLEXPORT int jl_datatype_isinlinealloc(jl_datatype_t *ty, int pointerfree) JL_CANSAFEPOINT; int jl_type_equality_is_identity(jl_value_t *t1, jl_value_t *t2) JL_NOTSAFEPOINT; -jl_value_t *jl_check_binding_assign_value(jl_binding_t *b JL_PROPAGATES_ROOT, jl_module_t *mod, jl_sym_t *var, jl_value_t *rhs JL_ROOTS_TEMPORARILY JL_MAYBE_UNROOTED, const char *msg); +jl_value_t *jl_check_binding_assign_value(jl_binding_t *b JL_PROPAGATES_ROOT, jl_module_t *mod, jl_sym_t *var, jl_value_t *rhs, const char *msg) JL_CANSAFEPOINT; void jl_binding_set_type(jl_binding_t *b, jl_module_t *mod, jl_sym_t *sym, jl_value_t *ty); -JL_DLLEXPORT void jl_declare_global(jl_module_t *m, jl_value_t *arg, jl_value_t *set_type, int strong); -JL_DLLEXPORT jl_binding_partition_t *jl_declare_constant_val3(jl_binding_t *b, jl_module_t *mod, jl_sym_t *var, jl_value_t *val JL_ROOTED_BY_ARG(1) JL_MAYBE_UNROOTED, enum jl_partition_kind, size_t new_world) JL_GLOBALLY_ROOTED; -JL_DLLEXPORT jl_value_t *jl_toplevel_eval_flex(jl_module_t *m, jl_value_t *e, int fast, int expanded, const char **toplevel_filename, int *toplevel_lineno); -JL_DLLEXPORT jl_value_t *jl_eval_thunk(jl_module_t *JL_NONNULL m, jl_code_info_t *thk, int fast); -int jl_module_public_(jl_module_t *from, jl_sym_t *s, int exported, size_t new_world); -void jl_module_initial_using(jl_module_t *to, jl_module_t *from); -void jl_add_usings_backedge(jl_module_t *from, jl_module_t *to); +JL_DLLEXPORT void jl_declare_global(jl_module_t *m, jl_value_t *arg, jl_value_t *set_type, int strong) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_binding_partition_t *jl_declare_constant_val3(jl_binding_t *b, jl_module_t *mod, jl_sym_t *var, jl_value_t *val JL_ROOTED_BY_ARG(1) JL_MAYBE_UNROOTED, enum jl_partition_kind, size_t new_world) JL_CANSAFEPOINT JL_GLOBALLY_ROOTED; +JL_DLLEXPORT jl_value_t *jl_toplevel_eval_flex(jl_module_t *m, jl_value_t *e, int fast, int expanded, const char **toplevel_filename, int *toplevel_lineno) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_eval_thunk(jl_module_t *JL_NONNULL m, jl_code_info_t *thk, int fast) JL_CANSAFEPOINT; +int jl_module_public_(jl_module_t *from, jl_sym_t *s, int exported, size_t new_world) JL_CANSAFEPOINT; +void jl_module_initial_using(jl_module_t *to, jl_module_t *from) JL_CANSAFEPOINT; +void jl_add_usings_backedge(jl_module_t *from, jl_module_t *to) JL_CANSAFEPOINT; typedef struct _modstack_t { jl_binding_t *b; struct _modstack_t *prev; @@ -1063,30 +1064,30 @@ STATIC_INLINE size_t module_usings_max(jl_module_t *m) JL_NOTSAFEPOINT { JL_DLLEXPORT jl_sym_t *jl_module_name(jl_module_t *m) JL_NOTSAFEPOINT; jl_module_t *jl_module_root(jl_module_t *m); -void jl_add_scanned_method(jl_module_t *m, jl_method_t *meth); -jl_value_t *jl_eval_global_var(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *e, size_t world); -JL_DLLEXPORT jl_value_t *jl_eval_globalref(jl_globalref_t *g, size_t world); -jl_value_t *jl_get_globalref_value(jl_globalref_t *gr, size_t world); -jl_value_t *jl_get_global_value(jl_module_t *m, jl_sym_t *var, size_t world); -jl_value_t *jl_interpret_opaque_closure(jl_opaque_closure_t *clos, jl_value_t **args, size_t nargs); -jl_value_t *jl_interpret_toplevel_thunk(jl_module_t *m, jl_code_info_t *src); +void jl_add_scanned_method(jl_module_t *m, jl_method_t *meth) JL_CANSAFEPOINT; +jl_value_t *jl_eval_global_var(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *e, size_t world) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_eval_globalref(jl_globalref_t *g, size_t world) JL_CANSAFEPOINT; +jl_value_t *jl_get_globalref_value(jl_globalref_t *gr, size_t world) JL_CANSAFEPOINT; +jl_value_t *jl_get_global_value(jl_module_t *m, jl_sym_t *var, size_t world) JL_CANSAFEPOINT; +jl_value_t *jl_interpret_opaque_closure(jl_opaque_closure_t *clos, jl_value_t **args, size_t nargs) JL_CANSAFEPOINT; +jl_value_t *jl_interpret_toplevel_thunk(jl_module_t *m, jl_code_info_t *src) JL_CANSAFEPOINT; jl_value_t *jl_interpret_toplevel_expr_in(jl_module_t *m, jl_value_t *e, jl_code_info_t *src, - jl_svec_t *sparam_vals); + jl_svec_t *sparam_vals) JL_CANSAFEPOINT; JL_DLLEXPORT int jl_is_toplevel_only_expr(jl_value_t *e) JL_NOTSAFEPOINT; jl_value_t *jl_call_scm_on_ast_and_loc(const char *funcname, jl_value_t *expr, - jl_module_t *inmodule, const char *file, int line); + jl_module_t *inmodule, const char *file, int line) JL_CANSAFEPOINT; int jl_isa_ast_node(jl_value_t *e) JL_NOTSAFEPOINT; -jl_method_instance_t *jl_builtin_method_lookup(jl_value_t *builtin); -JL_DLLEXPORT jl_method_instance_t *jl_method_lookup(jl_value_t **args, size_t nargs, size_t world); -jl_method_instance_t *jl_apply_lookup(jl_value_t **args, size_t nargs, size_t world); +jl_method_instance_t *jl_builtin_method_lookup(jl_value_t *builtin) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_method_instance_t *jl_method_lookup(jl_value_t **args, size_t nargs, size_t world) JL_CANSAFEPOINT; +jl_method_instance_t *jl_apply_lookup(jl_value_t **args, size_t nargs, size_t world) JL_CANSAFEPOINT; -jl_value_t *jl_gf_invoke_by_method(jl_method_t *method, jl_value_t *gf, jl_value_t **args, size_t nargs); -jl_value_t *jl_gf_invoke(jl_value_t *types, jl_value_t *f, jl_value_t **args, size_t nargs); -JL_DLLEXPORT jl_value_t *jl_gf_invoke_lookup_worlds(jl_value_t *types, jl_value_t *mt, size_t world, size_t *min_world, size_t *max_world); +jl_value_t *jl_gf_invoke_by_method(jl_method_t *method, jl_value_t *gf, jl_value_t **args, size_t nargs) JL_CANSAFEPOINT; +jl_value_t *jl_gf_invoke(jl_value_t *types, jl_value_t *f, jl_value_t **args, size_t nargs) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_gf_invoke_lookup_worlds(jl_value_t *types, jl_value_t *mt, size_t world, size_t *min_world, size_t *max_world) JL_CANSAFEPOINT; JL_DLLEXPORT jl_value_t *jl_matching_methods(jl_tupletype_t *types, jl_value_t *mt, int lim, int include_ambiguous, - size_t world, size_t *min_valid, size_t *max_valid, int *ambig); + size_t world, size_t *min_valid, size_t *max_valid, int *ambig) JL_CANSAFEPOINT; JL_DLLEXPORT jl_value_t *jl_gf_invoke_lookup_worlds(jl_value_t *types, jl_value_t *mt, size_t world, size_t *min_world, size_t *max_world); @@ -1109,17 +1110,17 @@ JL_DLLEXPORT jl_methcache_t *jl_method_get_cache( JL_DLLEXPORT int jl_pointer_egal(jl_value_t *t); JL_DLLEXPORT jl_value_t *jl_nth_slot_type(jl_value_t *sig JL_PROPAGATES_ROOT, size_t i) JL_NOTSAFEPOINT; -void jl_compute_field_offsets(jl_datatype_t *st); -void jl_check_valid_supertype(jl_value_t *super, const char *type_name); +void jl_compute_field_offsets(jl_datatype_t *st) JL_CANSAFEPOINT; +void jl_check_valid_supertype(jl_value_t *super, const char *type_name) JL_CANSAFEPOINT; void jl_check_field_types(jl_svec_t *ftypes, jl_sym_t *type_name); -void jl_module_run_initializer(jl_module_t *m); -JL_DLLEXPORT jl_binding_t *jl_get_module_binding(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var, int alloc); -JL_DLLEXPORT void jl_binding_deprecation_warning(jl_binding_t *b); +void jl_module_run_initializer(jl_module_t *m) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_binding_t *jl_get_module_binding(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var, int alloc) JL_CANSAFEPOINT; +JL_DLLEXPORT void jl_binding_deprecation_warning(jl_binding_t *b) JL_CANSAFEPOINT; JL_DLLEXPORT jl_binding_partition_t *jl_replace_binding_locked(jl_binding_t *b JL_PROPAGATES_ROOT, - jl_binding_partition_t *old_bpart, jl_value_t *restriction_val, enum jl_partition_kind kind, size_t new_world) JL_GLOBALLY_ROOTED; + jl_binding_partition_t *old_bpart, jl_value_t *restriction_val, enum jl_partition_kind kind, size_t new_world) JL_CANSAFEPOINT JL_GLOBALLY_ROOTED; JL_DLLEXPORT jl_binding_partition_t *jl_replace_binding_locked2(jl_binding_t *b JL_PROPAGATES_ROOT, - jl_binding_partition_t *old_bpart, jl_value_t *restriction_val, size_t kind, size_t new_world) JL_GLOBALLY_ROOTED; -JL_DLLEXPORT void jl_update_loaded_bpart(jl_binding_t *b, jl_binding_partition_t *bpart); + jl_binding_partition_t *old_bpart, jl_value_t *restriction_val, size_t kind, size_t new_world) JL_CANSAFEPOINT JL_GLOBALLY_ROOTED; +JL_DLLEXPORT void jl_update_loaded_bpart(jl_binding_t *b, jl_binding_partition_t *bpart) JL_CANSAFEPOINT; extern jl_array_t *jl_module_init_order JL_GLOBALLY_ROOTED; extern htable_t jl_current_modules JL_GLOBALLY_ROOTED; extern jl_module_t *jl_precompile_toplevel_module JL_GLOBALLY_ROOTED; @@ -1127,14 +1128,14 @@ extern jl_genericmemory_t *jl_global_roots_list JL_GLOBALLY_ROOTED; extern jl_genericmemory_t *jl_global_roots_keyset JL_GLOBALLY_ROOTED; JL_DLLEXPORT extern size_t jl_require_world; JL_DLLEXPORT int jl_is_globally_rooted(jl_value_t *val JL_MAYBE_UNROOTED) JL_NOTSAFEPOINT; -JL_DLLEXPORT jl_value_t *jl_as_global_root(jl_value_t *val, int insert) JL_GLOBALLY_ROOTED; +JL_DLLEXPORT jl_value_t *jl_as_global_root(jl_value_t *val, int insert) JL_CANSAFEPOINT JL_GLOBALLY_ROOTED; extern jl_svec_t *precompile_field_replace JL_GLOBALLY_ROOTED; -JL_DLLEXPORT void jl_set_precompile_field_replace(jl_value_t *val, jl_value_t *field, jl_value_t *newval) JL_GLOBALLY_ROOTED; +JL_DLLEXPORT void jl_set_precompile_field_replace(jl_value_t *val, jl_value_t *field, jl_value_t *newval) JL_CANSAFEPOINT JL_GLOBALLY_ROOTED; jl_opaque_closure_t *jl_new_opaque_closure(jl_tupletype_t *argt, jl_value_t *rt_lb, jl_value_t *rt_ub, - jl_value_t *source, jl_value_t **env, size_t nenv, int do_compile); + jl_value_t *source, jl_value_t **env, size_t nenv, int do_compile) JL_CANSAFEPOINT; jl_method_t *jl_make_opaque_closure_method(jl_module_t *module, jl_value_t *name, - int nargs, jl_value_t *functionloc, jl_code_info_t *ci, int isva, int isinferred); + int nargs, jl_value_t *functionloc, jl_code_info_t *ci, int isva, int isinferred) JL_CANSAFEPOINT; JL_DLLEXPORT int jl_is_valid_oc_argtype(jl_tupletype_t *argt, jl_method_t *source); STATIC_INLINE int jl_bkind_is_some_import(enum jl_partition_kind kind) JL_NOTSAFEPOINT { @@ -1169,9 +1170,9 @@ STATIC_INLINE int jl_bpart_is_exported(uint8_t flags) JL_NOTSAFEPOINT { return flags & (PARTITION_FLAG_EXPORTED | PARTITION_FLAG_IMPLICITLY_EXPORTED); } -JL_DLLEXPORT jl_binding_partition_t *jl_get_binding_partition(jl_binding_t *b JL_PROPAGATES_ROOT, size_t world) JL_GLOBALLY_ROOTED; -JL_DLLEXPORT jl_binding_partition_t *jl_get_binding_partition_with_hint(jl_binding_t *b JL_PROPAGATES_ROOT, jl_binding_partition_t *previous_part, size_t world) JL_GLOBALLY_ROOTED; -JL_DLLEXPORT jl_binding_partition_t *jl_get_binding_partition_all(jl_binding_t *b JL_PROPAGATES_ROOT, size_t min_world, size_t max_world) JL_GLOBALLY_ROOTED; +JL_DLLEXPORT jl_binding_partition_t *jl_get_binding_partition(jl_binding_t *b JL_PROPAGATES_ROOT, size_t world) JL_CANSAFEPOINT JL_GLOBALLY_ROOTED; +JL_DLLEXPORT jl_binding_partition_t *jl_get_binding_partition_with_hint(jl_binding_t *b JL_PROPAGATES_ROOT, jl_binding_partition_t *previous_part, size_t world) JL_CANSAFEPOINT JL_GLOBALLY_ROOTED; +JL_DLLEXPORT jl_binding_partition_t *jl_get_binding_partition_all(jl_binding_t *b JL_PROPAGATES_ROOT, size_t min_world, size_t max_world) JL_CANSAFEPOINT JL_GLOBALLY_ROOTED; struct restriction_kind_pair { jl_binding_t *binding_if_global; @@ -1179,9 +1180,9 @@ struct restriction_kind_pair { enum jl_partition_kind kind; int maybe_depwarn; }; -JL_DLLEXPORT int jl_get_binding_leaf_partitions_restriction_kind(jl_binding_t *b JL_PROPAGATES_ROOT, struct restriction_kind_pair *rkp, size_t min_world, size_t max_world) JL_GLOBALLY_ROOTED; -JL_DLLEXPORT jl_value_t *jl_get_binding_leaf_partitions_value_if_const(jl_binding_t *b JL_PROPAGATES_ROOT, int *maybe_depwarn, size_t min_world, size_t max_world); -void check_safe_newbinding(jl_module_t *m, jl_sym_t *var); +JL_DLLEXPORT int jl_get_binding_leaf_partitions_restriction_kind(jl_binding_t *b JL_PROPAGATES_ROOT, struct restriction_kind_pair *rkp, size_t min_world, size_t max_world) JL_CANSAFEPOINT JL_GLOBALLY_ROOTED; +JL_DLLEXPORT jl_value_t *jl_get_binding_leaf_partitions_value_if_const(jl_binding_t *b JL_PROPAGATES_ROOT, int *maybe_depwarn, size_t min_world, size_t max_world) JL_CANSAFEPOINT; +void check_safe_newbinding(jl_module_t *m, jl_sym_t *var) JL_CANSAFEPOINT; STATIC_INLINE int is10digit(char c) JL_NOTSAFEPOINT { @@ -1286,15 +1287,15 @@ STATIC_INLINE jl_vararg_kind_t jl_va_tuple_kind(jl_datatype_t *t) JL_NOTSAFEPOIN // -- init.c -- // -void jl_init_types(void) JL_GC_DISABLED; -void jl_init_flisp(void); +void jl_init_types(void) JL_CANSAFEPOINT JL_GC_DISABLED; +void jl_init_flisp(void) JL_NOTSAFEPOINT; void jl_init_common_symbols(void) JL_NOTSAFEPOINT; -void jl_init_primitives(void) JL_GC_DISABLED; -void jl_init_llvm(void); -void jl_init_runtime_ccall(void); -void jl_init_intrinsic_functions(void) JL_GC_DISABLED; -void jl_init_intrinsic_properties(void) JL_GC_DISABLED; -void jl_init_staticdata(void); +void jl_init_primitives(void) JL_CANSAFEPOINT JL_GC_DISABLED; +void jl_init_llvm(void) JL_CANSAFEPOINT; +void jl_init_runtime_ccall(void) JL_NOTSAFEPOINT; +void jl_init_intrinsic_functions(void) JL_CANSAFEPOINT JL_GC_DISABLED; +void jl_init_intrinsic_properties(void) JL_GC_DISABLED JL_NOTSAFEPOINT; +void jl_init_staticdata(void) JL_NOTSAFEPOINT; // TypeApp: immutable struct with head::Any, param::Any // Represents a single lazy type application step (like UnionAll for where bindings). typedef struct { @@ -1304,17 +1305,17 @@ typedef struct { } jl_typeapp_t; extern jl_datatype_t *jl_typeapp_type; -JL_DLLEXPORT jl_value_t *jl_resolve_typegroup(jl_module_t *module, jl_svec_t *typevars, jl_svec_t *struct_infos); +JL_DLLEXPORT jl_value_t *jl_resolve_typegroup(jl_module_t *module, jl_svec_t *typevars, jl_svec_t *struct_infos) JL_CANSAFEPOINT; // Type predicate for TypeApp (inline: called per type node on hot type-query paths) STATIC_INLINE int jl_is_typeapp(jl_value_t *v) JL_NOTSAFEPOINT { return jl_typeapp_type != NULL && jl_typeis(v, jl_typeapp_type); } -void jl_init_tasks(void) JL_GC_DISABLED; +void jl_init_tasks(void) JL_GC_DISABLED JL_NOTSAFEPOINT; void jl_init_stack_limits(int ismaster, void **stack_hi, void **stack_lo) JL_NOTSAFEPOINT; -jl_task_t *jl_init_root_task(jl_ptls_t ptls, void *stack_lo, void *stack_hi); -void jl_init_serializer(void); -void jl_init_uv(void); +jl_task_t *jl_init_root_task(jl_ptls_t ptls, void *stack_lo, void *stack_hi) JL_CANSAFEPOINT; +void jl_init_serializer(void) JL_CANSAFEPOINT; +void jl_init_uv(void) JL_NOTSAFEPOINT; void jl_init_box_caches(void) JL_NOTSAFEPOINT; JL_DLLEXPORT void jl_init_options(void); @@ -1322,8 +1323,8 @@ void jl_set_base_ctx(char *__stk); extern JL_DLLEXPORT ssize_t jl_tls_offset; extern JL_DLLEXPORT const int jl_tls_elf_support; -void jl_init_threading(void); -void jl_start_threads(void); +void jl_init_threading(void) JL_NOTSAFEPOINT; +void jl_start_threads(void) JL_CANSAFEPOINT; // Whether the GC is running extern uv_mutex_t safepoint_lock; @@ -1339,7 +1340,7 @@ extern _Atomic(uint32_t) jl_gc_disable_counter; // provided that the thread will not be interrupted by another asynchronous // signal. // Initialize the safepoint -void jl_safepoint_init(void); +void jl_safepoint_init(void) JL_NOTSAFEPOINT; // Start the GC, return `1` if the thread should be running the GC. // Otherwise, the thread will wait in this function until the GC finishes on // another thread and return `0`. @@ -1347,29 +1348,29 @@ void jl_safepoint_init(void); // before calling this function. If the calling thread is to run the GC, // it should also wait for the mutator threads to hit a safepoint **AFTER** // this function returns -int jl_safepoint_start_gc(jl_task_t *ct); +int jl_safepoint_start_gc(jl_task_t *ct) JL_CANSAFEPOINT; // Can only be called by the thread that have got a `1` return value from // `jl_safepoint_start_gc()`. This disables the safepoint (for GC, // the `mprotect` may not be removed if there's pending SIGINT) and wake // up waiting threads if there's any. // The caller should restore `gc_state` **AFTER** calling this function. -void jl_safepoint_end_gc(void); +void jl_safepoint_end_gc(void) JL_CANSAFEPOINT; // Wait for the GC to finish // This function does **NOT** modify the `gc_state` to inform the GC thread // The caller should set it **BEFORE** calling this function. void jl_safepoint_wait_gc(jl_task_t *ct) JL_NOTSAFEPOINT; void jl_safepoint_wait_thread_resume(jl_task_t *ct) JL_NOTSAFEPOINT; -int8_t jl_safepoint_take_sleep_lock(jl_ptls_t ptls) JL_NOTSAFEPOINT_ENTER; +void jl_safepoint_take_sleep_lock(jl_ptls_t ptls) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_ENTER; // Set pending sigint and enable the mechanisms to deliver the sigint. -void jl_safepoint_enable_sigint(void); +void jl_safepoint_enable_sigint(void) JL_NOTSAFEPOINT; // If the safepoint is enabled to deliver sigint, disable it // so that the thread won't repeatedly trigger it in a sigatomic region // while not being able to actually throw the exception. -void jl_safepoint_defer_sigint(void); +void jl_safepoint_defer_sigint(void) JL_NOTSAFEPOINT; // Clear the sigint pending flag and disable the mechanism to deliver sigint. // Return `1` if the sigint should be delivered and `0` if there's no sigint // to be delivered. -int jl_safepoint_consume_sigint(void); +int jl_safepoint_consume_sigint(void) JL_CANSAFEPOINT; void jl_wake_libuv(void) JL_NOTSAFEPOINT; void jl_set_pgcstack(jl_gcframe_t **) JL_NOTSAFEPOINT; @@ -1384,45 +1385,45 @@ JL_DLLEXPORT void jl_pgcstack_getkey(jl_get_pgcstack_func_t *f, jl_pgcstack_key_ extern pthread_mutex_t in_signal_lock; #endif -void jl_set_gc_and_wait(jl_task_t *ct); +void jl_set_gc_and_wait(jl_task_t *ct) JL_CANSAFEPOINT; // Query if this object is perm-allocated in an image. JL_DLLEXPORT uint8_t jl_object_in_image(jl_value_t* v) JL_NOTSAFEPOINT; // 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_genericmemory_t *jl_idtable_rehash(jl_genericmemory_t *a, size_t newsz); +JL_DLLEXPORT jl_genericmemory_t *jl_idtable_rehash(jl_genericmemory_t *a, size_t newsz) JL_CANSAFEPOINT; _Atomic(jl_value_t*) *jl_table_peek_bp(jl_genericmemory_t *a, jl_value_t *key) JL_NOTSAFEPOINT; -JL_DLLEXPORT jl_method_t *jl_new_method_uninit(jl_module_t*); +JL_DLLEXPORT jl_method_t *jl_new_method_uninit(jl_module_t*) JL_CANSAFEPOINT; -jl_module_t *jl_new_module_(jl_sym_t *name, jl_module_t *parent, uint8_t default_using_core, uint8_t self_name); -jl_module_t *jl_add_standard_imports(jl_module_t *m); -JL_DLLEXPORT jl_methtable_t *jl_new_method_table(jl_sym_t *name, jl_module_t *module); -JL_DLLEXPORT jl_methcache_t *jl_new_method_cache(void); -JL_DLLEXPORT jl_value_t *jl_get_specialization1(jl_tupletype_t *types JL_PROPAGATES_ROOT, size_t world); -jl_method_instance_t *jl_get_specialized(jl_method_t *m, jl_value_t *types, jl_svec_t *sp) JL_PROPAGATES_ROOT; +jl_module_t *jl_new_module_(jl_sym_t *name, jl_module_t *parent, uint8_t default_using_core, uint8_t self_name) JL_CANSAFEPOINT; +jl_module_t *jl_add_standard_imports(jl_module_t *m) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_methtable_t *jl_new_method_table(jl_sym_t *name, jl_module_t *module) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_methcache_t *jl_new_method_cache(void) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_get_specialization1(jl_tupletype_t *types JL_PROPAGATES_ROOT, size_t world) JL_CANSAFEPOINT; +jl_method_instance_t *jl_get_specialized(jl_method_t *m, jl_value_t *types, jl_svec_t *sp) JL_CANSAFEPOINT JL_PROPAGATES_ROOT; JL_DLLEXPORT jl_value_t *jl_rettype_inferred(jl_value_t *owner, jl_method_instance_t *li JL_PROPAGATES_ROOT, size_t min_world, size_t max_world) JL_NOTSAFEPOINT; JL_DLLEXPORT jl_value_t *jl_rettype_inferred_native(jl_method_instance_t *mi, size_t min_world, size_t max_world) JL_NOTSAFEPOINT; JL_DLLEXPORT jl_code_instance_t *jl_method_compiled(jl_method_instance_t *mi JL_PROPAGATES_ROOT, size_t world) JL_NOTSAFEPOINT; -JL_DLLEXPORT jl_value_t *jl_methtable_lookup(jl_value_t *type, size_t world) JL_GLOBALLY_ROOTED; +JL_DLLEXPORT jl_value_t *jl_methtable_lookup(jl_value_t *type, size_t world) JL_CANSAFEPOINT JL_GLOBALLY_ROOTED; JL_DLLEXPORT jl_method_instance_t *jl_specializations_get_linfo( - jl_method_t *m JL_PROPAGATES_ROOT, jl_value_t *type, jl_svec_t *sparams); -jl_method_instance_t *jl_specializations_get_or_insert(jl_method_instance_t *mi_ins JL_PROPAGATES_ROOT); -JL_DLLEXPORT void jl_method_instance_add_backedge(jl_method_instance_t *callee, jl_value_t *invokesig, jl_code_instance_t *caller); -JL_DLLEXPORT void jl_method_table_add_backedge(jl_value_t *typ, jl_code_instance_t *caller); + jl_method_t *m JL_PROPAGATES_ROOT, jl_value_t *type, jl_svec_t *sparams) JL_CANSAFEPOINT; +jl_method_instance_t *jl_specializations_get_or_insert(jl_method_instance_t *mi_ins JL_PROPAGATES_ROOT) JL_CANSAFEPOINT; +JL_DLLEXPORT void jl_method_instance_add_backedge(jl_method_instance_t *callee, jl_value_t *invokesig, jl_code_instance_t *caller) JL_CANSAFEPOINT; +JL_DLLEXPORT void jl_method_table_add_backedge(jl_value_t *typ, jl_code_instance_t *caller) JL_CANSAFEPOINT; JL_DLLEXPORT void jl_mi_cache_insert(jl_method_instance_t *mi, - jl_code_instance_t *ci JL_ROOTED_BY_ARG(0) JL_MAYBE_UNROOTED); + jl_code_instance_t *ci JL_ROOTED_BY_ARG(0) JL_MAYBE_UNROOTED) JL_CANSAFEPOINT; JL_DLLEXPORT int jl_mi_try_insert(jl_method_instance_t *mi, jl_code_instance_t *expected_ci, - jl_code_instance_t *ci JL_ROOTED_BY_ARG(0) JL_MAYBE_UNROOTED); -JL_DLLEXPORT jl_code_instance_t *jl_cached_uninferred(jl_code_instance_t *codeinst, size_t world); -JL_DLLEXPORT jl_code_instance_t *jl_cache_uninferred(jl_method_instance_t *mi JL_PROPAGATES_ROOT, jl_code_instance_t *checked, size_t world, jl_code_instance_t *newci JL_MAYBE_UNROOTED); -JL_DLLEXPORT jl_code_instance_t *jl_new_codeinst_for_uninferred(jl_method_instance_t *mi, jl_code_info_t *src); + jl_code_instance_t *ci JL_ROOTED_BY_ARG(0) JL_MAYBE_UNROOTED) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_code_instance_t *jl_cached_uninferred(jl_code_instance_t *codeinst JL_PROPAGATES_ROOT, size_t world); +JL_DLLEXPORT jl_code_instance_t *jl_cache_uninferred(jl_method_instance_t *mi JL_PROPAGATES_ROOT, jl_code_instance_t *checked, size_t world, jl_code_instance_t *newci JL_MAYBE_UNROOTED) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_code_instance_t *jl_new_codeinst_for_uninferred(jl_method_instance_t *mi, jl_code_info_t *src) JL_CANSAFEPOINT; JL_DLLEXPORT extern jl_value_t *(*const jl_rettype_inferred_addr)(jl_method_instance_t *mi JL_PROPAGATES_ROOT, size_t min_world, size_t max_world) JL_NOTSAFEPOINT; -JL_DLLEXPORT void jl_force_trace_compile_timing_enable(void); -JL_DLLEXPORT void jl_force_trace_compile_timing_disable(void); +JL_DLLEXPORT void jl_force_trace_compile_timing_enable(void) JL_NOTSAFEPOINT; +JL_DLLEXPORT void jl_force_trace_compile_timing_disable(void) JL_NOTSAFEPOINT; JL_DLLEXPORT void jl_force_trace_dispatch_enable(void); JL_DLLEXPORT void jl_force_trace_dispatch_disable(void); @@ -1431,12 +1432,12 @@ JL_DLLEXPORT void jl_tag_newly_inferred_enable(void); JL_DLLEXPORT void jl_tag_newly_inferred_disable(void); uint32_t jl_module_next_counter(jl_module_t *m) JL_NOTSAFEPOINT; -jl_tupletype_t *arg_type_tuple(jl_value_t *arg1, jl_value_t **args, size_t nargs); +jl_tupletype_t *arg_type_tuple(jl_value_t *arg1, jl_value_t **args, size_t nargs) JL_CANSAFEPOINT; JL_DLLEXPORT int jl_has_meta(jl_array_t *body, jl_sym_t *sym) JL_NOTSAFEPOINT; JL_DLLEXPORT jl_value_t *jl_parse(const char *text, size_t text_len, jl_value_t *filename, - size_t lineno, size_t offset, jl_value_t *options, jl_module_t *inmodule); + size_t lineno, size_t offset, jl_value_t *options, jl_module_t *inmodule) JL_CANSAFEPOINT; //-------------------------------------------------- // Backtraces @@ -1600,15 +1601,15 @@ size_t rec_backtrace_ctx(jl_bt_element_t *bt_data, size_t maxsize, bt_context_t #ifdef LLVMLIBUNWIND size_t rec_backtrace_ctx_dwarf(jl_bt_element_t *bt_data, size_t maxsize, bt_context_t *ctx, jl_gcframe_t *pgcstack) JL_NOTSAFEPOINT; #endif -JL_DLLEXPORT jl_value_t *jl_get_backtrace(void); -JL_DLLEXPORT jl_value_t *jl_backtrace_from_here(int returnsp, int skip); -void jl_fprint_critical_error(ios_t *t, int sig, int si_code, bt_context_t *context, jl_task_t *ct); +JL_DLLEXPORT jl_value_t *jl_get_backtrace(void) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_backtrace_from_here(int returnsp, int skip) JL_CANSAFEPOINT; +void jl_fprint_critical_error(ios_t *t, int sig, int si_code, bt_context_t *context, jl_task_t *ct) JL_CANSAFEPOINT; JL_DLLEXPORT void jl_raise_debugger(void) JL_NOTSAFEPOINT; JL_DLLEXPORT void jl_print_task_backtraces(int show_done) JL_NOTSAFEPOINT; void jl_fprint_native_codeloc(ios_t *s, uintptr_t ip) JL_NOTSAFEPOINT; void jl_fprint_bt_entry_codeloc(ios_t *s, jl_bt_element_t *bt_data) JL_NOTSAFEPOINT; -void jl_thread_resume(int tid) JL_NOTSAFEPOINT; -int jl_thread_suspend(int16_t tid, bt_context_t *ctx) JL_NOTSAFEPOINT; +void jl_thread_resume(int tid) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_LEAVE; +int jl_thread_suspend(int16_t tid, bt_context_t *ctx) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_ENTER_CONDITIONAL(1); // *to is NULL or malloc'd pointer, from is allowed to be NULL STATIC_INLINE char *jl_copy_str(char **to, const char *from) JL_NOTSAFEPOINT @@ -1668,7 +1669,7 @@ STATIC_INLINE size_t jl_excstack_next(jl_excstack_t *stack, size_t itr) JL_NOTSA // Exception stack manipulation void jl_push_excstack(jl_task_t *ct, jl_excstack_t **stack JL_REQUIRE_ROOTED_SLOT, jl_value_t *exception JL_ROOTED_BY_ARG(1), - jl_bt_element_t *bt_data, size_t bt_size); + jl_bt_element_t *bt_data, size_t bt_size) JL_CANSAFEPOINT; // System util to get maximum RSS JL_DLLEXPORT size_t jl_maxrss(void) JL_NOTSAFEPOINT; @@ -1725,17 +1726,17 @@ extern void *jl_winsock_handle; void win32_formatmessage(DWORD code, char *reason, int len) JL_NOTSAFEPOINT; #endif -JL_DLLEXPORT void *jl_get_library_(const char *f_lib, int throw_err); +JL_DLLEXPORT void *jl_get_library_(const char *f_lib, int throw_err) JL_CANSAFEPOINT; void *jl_find_dynamic_library_by_addr(void *symbol, int throw_err, int close) JL_NOTSAFEPOINT; #define jl_get_library(f_lib) jl_get_library_(f_lib, 1) -JL_DLLEXPORT void *jl_load_and_lookup(const char *f_lib, const char *f_name, _Atomic(void*) *hnd); -JL_DLLEXPORT void *jl_lazy_load_and_lookup(jl_value_t *lib_val, jl_value_t *f_name); +JL_DLLEXPORT void *jl_load_and_lookup(const char *f_lib, const char *f_name, _Atomic(void*) *hnd) JL_CANSAFEPOINT; +JL_DLLEXPORT void *jl_lazy_load_and_lookup(jl_value_t *lib_val, jl_value_t *f_name) JL_CANSAFEPOINT; JL_DLLEXPORT jl_value_t *jl_get_cfunction_trampoline( jl_value_t *fobj, jl_datatype_t *result, htable_t *cache, jl_svec_t *fill, void *(*init_trampoline)(void *tramp, void **nval), - jl_unionall_t *env, jl_value_t **vals); -JL_DLLEXPORT void *jl_get_abi_converter(jl_task_t *ct, void *data); -JL_DLLIMPORT void *jl_jit_abi_converter(jl_task_t *ct, jl_abi_t from_abi, jl_code_instance_t *codeinst); + jl_unionall_t *env, jl_value_t **vals) JL_CANSAFEPOINT; +JL_DLLEXPORT void *jl_get_abi_converter(jl_task_t *ct, void *data) JL_CANSAFEPOINT; +JL_DLLIMPORT void *jl_jit_abi_converter(jl_task_t *ct, jl_abi_t from_abi, jl_code_instance_t *codeinst) JL_CANSAFEPOINT; // Special filenames used to refer to internal julia libraries @@ -1752,102 +1753,102 @@ STATIC_INLINE int is_valid_intrinsic_elptr(jl_value_t *ety) { return ety == (jl_value_t*)jl_any_type || (jl_is_concrete_type(ety) && !jl_is_layout_opaque(((jl_datatype_t*)ety)->layout) && !jl_is_array_type(ety)); } -JL_DLLEXPORT jl_value_t *jl_bitcast(jl_value_t *ty, jl_value_t *v); -JL_DLLEXPORT jl_value_t *jl_pointerref(jl_value_t *p, jl_value_t *i, jl_value_t *align); +JL_DLLEXPORT jl_value_t *jl_bitcast(jl_value_t *ty, jl_value_t *v) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_pointerref(jl_value_t *p, jl_value_t *i, jl_value_t *align) JL_CANSAFEPOINT; JL_DLLEXPORT jl_value_t *jl_pointerset(jl_value_t *p, jl_value_t *x, jl_value_t *align, jl_value_t *i); JL_DLLEXPORT jl_value_t *jl_atomic_fence(jl_value_t *order, jl_value_t *syncscope); -JL_DLLEXPORT jl_value_t *jl_atomic_pointerref(jl_value_t *p, jl_value_t *order); +JL_DLLEXPORT jl_value_t *jl_atomic_pointerref(jl_value_t *p, jl_value_t *order) JL_CANSAFEPOINT; JL_DLLEXPORT jl_value_t *jl_atomic_pointerset(jl_value_t *p, jl_value_t *x, jl_value_t *order); -JL_DLLEXPORT jl_value_t *jl_atomic_pointerswap(jl_value_t *p, jl_value_t *x, jl_value_t *order); -JL_DLLEXPORT jl_value_t *jl_atomic_pointermodify(jl_value_t *p, jl_value_t *f, jl_value_t *x, jl_value_t *order); -JL_DLLEXPORT jl_value_t *jl_atomic_pointerreplace(jl_value_t *p, jl_value_t *x, jl_value_t *expected, jl_value_t *success_order, jl_value_t *failure_order); -JL_DLLEXPORT jl_value_t *jl_cglobal(jl_value_t *v, jl_value_t *ty); // deprecated -JL_DLLEXPORT jl_value_t *jl_cglobal_auto(jl_value_t *v); // deprecated - -JL_DLLEXPORT jl_value_t *jl_neg_int(jl_value_t *a); -JL_DLLEXPORT jl_value_t *jl_add_int(jl_value_t *a, jl_value_t *b); -JL_DLLEXPORT jl_value_t *jl_sub_int(jl_value_t *a, jl_value_t *b); -JL_DLLEXPORT jl_value_t *jl_mul_int(jl_value_t *a, jl_value_t *b); -JL_DLLEXPORT jl_value_t *jl_sdiv_int(jl_value_t *a, jl_value_t *b); -JL_DLLEXPORT jl_value_t *jl_udiv_int(jl_value_t *a, jl_value_t *b); -JL_DLLEXPORT jl_value_t *jl_srem_int(jl_value_t *a, jl_value_t *b); -JL_DLLEXPORT jl_value_t *jl_urem_int(jl_value_t *a, jl_value_t *b); - -JL_DLLEXPORT jl_value_t *jl_add_ptr(jl_value_t *a, jl_value_t *b); -JL_DLLEXPORT jl_value_t *jl_sub_ptr(jl_value_t *a, jl_value_t *b); - -JL_DLLEXPORT jl_value_t *jl_neg_float(jl_value_t *a); -JL_DLLEXPORT jl_value_t *jl_add_float(jl_value_t *a, jl_value_t *b); -JL_DLLEXPORT jl_value_t *jl_sub_float(jl_value_t *a, jl_value_t *b); -JL_DLLEXPORT jl_value_t *jl_mul_float(jl_value_t *a, jl_value_t *b); -JL_DLLEXPORT jl_value_t *jl_div_float(jl_value_t *a, jl_value_t *b); -JL_DLLEXPORT jl_value_t *jl_min_float(jl_value_t *a, jl_value_t *b); -JL_DLLEXPORT jl_value_t *jl_max_float(jl_value_t *a, jl_value_t *b); -JL_DLLEXPORT jl_value_t *jl_fma_float(jl_value_t *a, jl_value_t *b, jl_value_t *c); -JL_DLLEXPORT jl_value_t *jl_muladd_float(jl_value_t *a, jl_value_t *b, jl_value_t *c); - -JL_DLLEXPORT jl_value_t *jl_eq_int(jl_value_t *a, jl_value_t *b); -JL_DLLEXPORT jl_value_t *jl_ne_int(jl_value_t *a, jl_value_t *b); -JL_DLLEXPORT jl_value_t *jl_slt_int(jl_value_t *a, jl_value_t *b); -JL_DLLEXPORT jl_value_t *jl_ult_int(jl_value_t *a, jl_value_t *b); -JL_DLLEXPORT jl_value_t *jl_sle_int(jl_value_t *a, jl_value_t *b); -JL_DLLEXPORT jl_value_t *jl_ule_int(jl_value_t *a, jl_value_t *b); - -JL_DLLEXPORT jl_value_t *jl_eq_float(jl_value_t *a, jl_value_t *b); -JL_DLLEXPORT jl_value_t *jl_ne_float(jl_value_t *a, jl_value_t *b); -JL_DLLEXPORT jl_value_t *jl_lt_float(jl_value_t *a, jl_value_t *b); -JL_DLLEXPORT jl_value_t *jl_le_float(jl_value_t *a, jl_value_t *b); -JL_DLLEXPORT jl_value_t *jl_fpiseq(jl_value_t *a, jl_value_t *b); - -JL_DLLEXPORT jl_value_t *jl_not_int(jl_value_t *a); -JL_DLLEXPORT jl_value_t *jl_and_int(jl_value_t *a, jl_value_t *b); -JL_DLLEXPORT jl_value_t *jl_or_int(jl_value_t *a, jl_value_t *b); -JL_DLLEXPORT jl_value_t *jl_xor_int(jl_value_t *a, jl_value_t *b); -JL_DLLEXPORT jl_value_t *jl_shl_int(jl_value_t *a, jl_value_t *b); -JL_DLLEXPORT jl_value_t *jl_lshr_int(jl_value_t *a, jl_value_t *b); -JL_DLLEXPORT jl_value_t *jl_ashr_int(jl_value_t *a, jl_value_t *b); -JL_DLLEXPORT jl_value_t *jl_bswap_int(jl_value_t *a); -JL_DLLEXPORT jl_value_t *jl_ctpop_int(jl_value_t *a); -JL_DLLEXPORT jl_value_t *jl_ctlz_int(jl_value_t *a); -JL_DLLEXPORT jl_value_t *jl_cttz_int(jl_value_t *a); - -JL_DLLEXPORT jl_value_t *jl_sext_int(jl_value_t *ty, jl_value_t *a); -JL_DLLEXPORT jl_value_t *jl_zext_int(jl_value_t *ty, jl_value_t *a); -JL_DLLEXPORT jl_value_t *jl_trunc_int(jl_value_t *ty, jl_value_t *a); -JL_DLLEXPORT jl_value_t *jl_sitofp(jl_value_t *ty, jl_value_t *a); -JL_DLLEXPORT jl_value_t *jl_uitofp(jl_value_t *ty, jl_value_t *a); - -JL_DLLEXPORT jl_value_t *jl_fptoui(jl_value_t *ty, jl_value_t *a); -JL_DLLEXPORT jl_value_t *jl_fptosi(jl_value_t *ty, jl_value_t *a); -JL_DLLEXPORT jl_value_t *jl_fptrunc(jl_value_t *ty, jl_value_t *a); -JL_DLLEXPORT jl_value_t *jl_fpext(jl_value_t *ty, jl_value_t *a); - -JL_DLLEXPORT jl_value_t *jl_checked_sadd_int(jl_value_t *a, jl_value_t *b); -JL_DLLEXPORT jl_value_t *jl_checked_uadd_int(jl_value_t *a, jl_value_t *b); -JL_DLLEXPORT jl_value_t *jl_checked_ssub_int(jl_value_t *a, jl_value_t *b); -JL_DLLEXPORT jl_value_t *jl_checked_usub_int(jl_value_t *a, jl_value_t *b); -JL_DLLEXPORT jl_value_t *jl_checked_smul_int(jl_value_t *a, jl_value_t *b); -JL_DLLEXPORT jl_value_t *jl_checked_umul_int(jl_value_t *a, jl_value_t *b); -JL_DLLEXPORT jl_value_t *jl_checked_sdiv_int(jl_value_t *a, jl_value_t *b); -JL_DLLEXPORT jl_value_t *jl_checked_udiv_int(jl_value_t *a, jl_value_t *b); -JL_DLLEXPORT jl_value_t *jl_checked_srem_int(jl_value_t *a, jl_value_t *b); -JL_DLLEXPORT jl_value_t *jl_checked_urem_int(jl_value_t *a, jl_value_t *b); - -JL_DLLEXPORT jl_value_t *jl_ceil_llvm(jl_value_t *a); -JL_DLLEXPORT jl_value_t *jl_floor_llvm(jl_value_t *a); -JL_DLLEXPORT jl_value_t *jl_trunc_llvm(jl_value_t *a); -JL_DLLEXPORT jl_value_t *jl_rint_llvm(jl_value_t *a); -JL_DLLEXPORT jl_value_t *jl_sqrt_llvm(jl_value_t *a); -JL_DLLEXPORT jl_value_t *jl_sqrt_llvm_fast(jl_value_t *a); -JL_DLLEXPORT jl_value_t *jl_abs_float(jl_value_t *a); -JL_DLLEXPORT jl_value_t *jl_copysign_float(jl_value_t *a, jl_value_t *b); -JL_DLLEXPORT jl_value_t *jl_flipsign_int(jl_value_t *a, jl_value_t *b); +JL_DLLEXPORT jl_value_t *jl_atomic_pointerswap(jl_value_t *p, jl_value_t *x, jl_value_t *order) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_atomic_pointermodify(jl_value_t *p, jl_value_t *f, jl_value_t *x, jl_value_t *order) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_atomic_pointerreplace(jl_value_t *p, jl_value_t *x, jl_value_t *expected, jl_value_t *success_order, jl_value_t *failure_order) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_cglobal(jl_value_t *v, jl_value_t *ty) JL_CANSAFEPOINT; // deprecated +JL_DLLEXPORT jl_value_t *jl_cglobal_auto(jl_value_t *v) JL_CANSAFEPOINT; // deprecated + +JL_DLLEXPORT jl_value_t *jl_neg_int(jl_value_t *a) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_add_int(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_sub_int(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_mul_int(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_sdiv_int(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_udiv_int(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_srem_int(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_urem_int(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; + +JL_DLLEXPORT jl_value_t *jl_add_ptr(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_sub_ptr(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; + +JL_DLLEXPORT jl_value_t *jl_neg_float(jl_value_t *a) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_add_float(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_sub_float(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_mul_float(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_div_float(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_min_float(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_max_float(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_fma_float(jl_value_t *a, jl_value_t *b, jl_value_t *c) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_muladd_float(jl_value_t *a, jl_value_t *b, jl_value_t *c) JL_CANSAFEPOINT; + +JL_DLLEXPORT jl_value_t *jl_eq_int(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_ne_int(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_slt_int(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_ult_int(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_sle_int(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_ule_int(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; + +JL_DLLEXPORT jl_value_t *jl_eq_float(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_ne_float(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_lt_float(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_le_float(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_fpiseq(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; + +JL_DLLEXPORT jl_value_t *jl_not_int(jl_value_t *a) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_and_int(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_or_int(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_xor_int(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_shl_int(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_lshr_int(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_ashr_int(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_bswap_int(jl_value_t *a) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_ctpop_int(jl_value_t *a) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_ctlz_int(jl_value_t *a) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_cttz_int(jl_value_t *a) JL_CANSAFEPOINT; + +JL_DLLEXPORT jl_value_t *jl_sext_int(jl_value_t *ty, jl_value_t *a) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_zext_int(jl_value_t *ty, jl_value_t *a) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_trunc_int(jl_value_t *ty, jl_value_t *a) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_sitofp(jl_value_t *ty, jl_value_t *a) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_uitofp(jl_value_t *ty, jl_value_t *a) JL_CANSAFEPOINT; + +JL_DLLEXPORT jl_value_t *jl_fptoui(jl_value_t *ty, jl_value_t *a) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_fptosi(jl_value_t *ty, jl_value_t *a) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_fptrunc(jl_value_t *ty, jl_value_t *a) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_fpext(jl_value_t *ty, jl_value_t *a) JL_CANSAFEPOINT; + +JL_DLLEXPORT jl_value_t *jl_checked_sadd_int(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_checked_uadd_int(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_checked_ssub_int(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_checked_usub_int(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_checked_smul_int(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_checked_umul_int(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_checked_sdiv_int(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_checked_udiv_int(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_checked_srem_int(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_checked_urem_int(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; + +JL_DLLEXPORT jl_value_t *jl_ceil_llvm(jl_value_t *a) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_floor_llvm(jl_value_t *a) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_trunc_llvm(jl_value_t *a) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_rint_llvm(jl_value_t *a) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_sqrt_llvm(jl_value_t *a) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_sqrt_llvm_fast(jl_value_t *a) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_abs_float(jl_value_t *a) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_copysign_float(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_flipsign_int(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; JL_DLLEXPORT jl_value_t *jl_have_fma(jl_value_t *a); -JL_DLLEXPORT int jl_stored_inline(jl_value_t *el_type); +JL_DLLEXPORT int jl_stored_inline(jl_value_t *el_type) JL_CANSAFEPOINT; JL_DLLEXPORT jl_value_t *(jl_array_data_owner)(jl_array_t *a); -JL_DLLEXPORT jl_array_t *jl_array_copy(jl_array_t *ary); -JL_DLLEXPORT jl_genericmemory_t *jl_genericmemory_copy(jl_genericmemory_t *mem); +JL_DLLEXPORT jl_array_t *jl_array_copy(jl_array_t *ary) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_genericmemory_t *jl_genericmemory_copy(jl_genericmemory_t *mem) JL_CANSAFEPOINT; JL_DLLEXPORT uintptr_t jl_object_id_(uintptr_t tv, jl_value_t *v) JL_NOTSAFEPOINT; JL_DLLEXPORT void jl_set_next_task(jl_task_t *task) JL_NOTSAFEPOINT; @@ -1869,24 +1870,24 @@ extern jl_mutex_t world_counter_lock; typedef uint_t (*smallintset_hash)(size_t val, jl_value_t *data); typedef int (*smallintset_eq)(size_t val, const void *key, jl_value_t *data, uint_t hv); ssize_t jl_smallintset_lookup(jl_genericmemory_t *cache, smallintset_eq eq, const void *key, jl_value_t *data, uint_t hv, int pop); -void jl_smallintset_insert(_Atomic(jl_genericmemory_t*) *pcache, jl_value_t *parent, smallintset_hash hash, size_t val, jl_value_t *data); -jl_genericmemory_t* smallintset_rehash(jl_genericmemory_t* a, smallintset_hash hash, jl_value_t *data, size_t newsz, size_t np); +void jl_smallintset_insert(_Atomic(jl_genericmemory_t*) *pcache, jl_value_t *parent, smallintset_hash hash, size_t val, jl_value_t *data) JL_CANSAFEPOINT; +jl_genericmemory_t* smallintset_rehash(jl_genericmemory_t* a, smallintset_hash hash, jl_value_t *data, size_t newsz, size_t np) JL_CANSAFEPOINT; void smallintset_empty(const jl_genericmemory_t *a) JL_NOTSAFEPOINT; -JL_DLLEXPORT jl_genericmemory_t *jl_idset_rehash(jl_genericmemory_t *keys, jl_genericmemory_t *idxs, size_t newsz); +JL_DLLEXPORT jl_genericmemory_t *jl_idset_rehash(jl_genericmemory_t *keys, jl_genericmemory_t *idxs, size_t newsz) JL_CANSAFEPOINT; JL_DLLEXPORT ssize_t jl_idset_peek_bp(jl_genericmemory_t *keys, jl_genericmemory_t *idxs, jl_value_t *key) JL_NOTSAFEPOINT; JL_DLLEXPORT jl_value_t *jl_idset_get(jl_genericmemory_t *keys JL_PROPAGATES_ROOT, jl_genericmemory_t *idxs, jl_value_t *key) JL_NOTSAFEPOINT; -JL_DLLEXPORT jl_genericmemory_t *jl_idset_put_key(jl_genericmemory_t *keys, jl_value_t *key, ssize_t *newidx); -JL_DLLEXPORT jl_genericmemory_t *jl_idset_put_idx(jl_genericmemory_t *keys, jl_genericmemory_t *idxs, ssize_t idx); +JL_DLLEXPORT jl_genericmemory_t *jl_idset_put_key(jl_genericmemory_t *keys, jl_value_t *key, ssize_t *newidx) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_genericmemory_t *jl_idset_put_idx(jl_genericmemory_t *keys, jl_genericmemory_t *idxs, ssize_t idx) JL_CANSAFEPOINT; JL_DLLEXPORT ssize_t jl_idset_pop(jl_genericmemory_t *keys, jl_genericmemory_t *idxs, jl_value_t *key) JL_NOTSAFEPOINT; // -- typemap.c -- // 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 *newrec, int8_t offs) JL_CANSAFEPOINT; jl_typemap_entry_t *jl_typemap_alloc( jl_tupletype_t *type, jl_tupletype_t *simpletype, jl_svec_t *guardsigs, - jl_value_t *newvalue, size_t min_world, size_t max_world); + jl_value_t *newvalue, size_t min_world, size_t max_world) JL_CANSAFEPOINT; struct jl_typemap_assoc { // inputs @@ -1899,13 +1900,13 @@ struct jl_typemap_assoc { jl_typemap_entry_t *jl_typemap_assoc_by_type( jl_typemap_t *ml_or_cache JL_PROPAGATES_ROOT, struct jl_typemap_assoc *search, - int8_t offs, uint8_t subtype); + int8_t offs, uint8_t subtype) JL_CANSAFEPOINT; -jl_typemap_entry_t *jl_typemap_level_assoc_exact(jl_typemap_level_t *cache, jl_value_t *arg1, jl_value_t **args, size_t n, int8_t offs, size_t world); -jl_typemap_entry_t *jl_typemap_entry_assoc_exact(jl_typemap_entry_t *mn, jl_value_t *arg1, jl_value_t **args, size_t n, size_t world); +jl_typemap_entry_t *jl_typemap_level_assoc_exact(jl_typemap_level_t *cache, jl_value_t *arg1, jl_value_t **args, size_t n, int8_t offs, size_t world) JL_CANSAFEPOINT; +jl_typemap_entry_t *jl_typemap_entry_assoc_exact(jl_typemap_entry_t *mn, jl_value_t *arg1, jl_value_t **args, size_t n, size_t world) JL_CANSAFEPOINT; STATIC_INLINE jl_typemap_entry_t *jl_typemap_assoc_exact( jl_typemap_t *ml_or_cache JL_PROPAGATES_ROOT, - jl_value_t *arg1, jl_value_t **args, size_t n, int8_t offs, size_t world) + jl_value_t *arg1, jl_value_t **args, size_t n, int8_t offs, size_t world) JL_CANSAFEPOINT { // NOTE: This function is a huge performance hot spot!! if (jl_typeof(ml_or_cache) == (jl_value_t *)jl_typemap_entry_type) { @@ -1918,11 +1919,11 @@ STATIC_INLINE jl_typemap_entry_t *jl_typemap_assoc_exact( } return NULL; } -typedef int (*jl_typemap_visitor_fptr)(jl_typemap_entry_t *l, void *closure); -int jl_typemap_visitor(jl_typemap_t *a, jl_typemap_visitor_fptr fptr, void *closure); +typedef int (*jl_typemap_visitor_fptr)(jl_typemap_entry_t *l, void *closure) JL_CANSAFEPOINT; +int jl_typemap_visitor(jl_typemap_t *a, jl_typemap_visitor_fptr fptr, void *closure) JL_CANSAFEPOINT; struct typemap_intersection_env; -typedef int (*jl_typemap_intersection_visitor_fptr)(jl_typemap_entry_t *l, struct typemap_intersection_env *closure); +typedef int (*jl_typemap_intersection_visitor_fptr)(jl_typemap_entry_t *l, struct typemap_intersection_env *closure) JL_CANSAFEPOINT; struct typemap_intersection_env { // input values jl_typemap_intersection_visitor_fptr const fptr; // fptr to call on a match @@ -1939,7 +1940,7 @@ struct typemap_intersection_env { // nonempty/bottom placeholder); the callback may consume just // the match verdict and `issubty` }; -int jl_typemap_intersection_visitor(jl_typemap_t *a, int offs, struct typemap_intersection_env *closure); +int jl_typemap_intersection_visitor(jl_typemap_t *a, int offs, struct typemap_intersection_env *closure) JL_CANSAFEPOINT; void typemap_slurp_search(jl_typemap_entry_t *ml, struct typemap_intersection_env *closure); // -- simplevector.c -- // @@ -1948,11 +1949,11 @@ void typemap_slurp_search(jl_typemap_entry_t *ml, struct typemap_intersection_en // specified number of parameters of the tuple type JL_DLLEXPORT int jl_tupletype_length_compat(jl_value_t *v, size_t nargs) JL_NOTSAFEPOINT; -JL_DLLEXPORT jl_value_t *jl_argtype_with_function(jl_value_t *f, jl_value_t *types0); -JL_DLLEXPORT jl_value_t *jl_argtype_with_function_type(jl_value_t *ft JL_MAYBE_UNROOTED, jl_value_t *types0); -JL_DLLEXPORT jl_value_t *jl_argtype_without_function(jl_value_t *ftypes); +JL_DLLEXPORT jl_value_t *jl_argtype_with_function(jl_value_t *f, jl_value_t *types0) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_argtype_with_function_type(jl_value_t *ft JL_MAYBE_UNROOTED, jl_value_t *types0) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_argtype_without_function(jl_value_t *ftypes) JL_CANSAFEPOINT; -JL_DLLEXPORT unsigned jl_special_vector_alignment(size_t nfields, jl_value_t *field_type); +JL_DLLEXPORT unsigned jl_special_vector_alignment(size_t nfields, jl_value_t *field_type) JL_CANSAFEPOINT; void register_eh_frames(uint8_t *Addr, size_t Size) JL_NOTSAFEPOINT; void deregister_eh_frames(uint8_t *Addr, size_t Size) JL_NOTSAFEPOINT; @@ -1975,7 +1976,7 @@ STATIC_INLINE void *jl_get_frame_addr(void) JL_NOTSAFEPOINT // of keyword arguments will be passed. void jl_log(int level, jl_value_t *module, jl_value_t *group, jl_value_t *id, jl_value_t *file, jl_value_t *line, jl_value_t *kwargs, - jl_value_t *msg); + jl_value_t *msg) JL_CANSAFEPOINT; JL_DLLEXPORT int jl_isabspath(const char *in) JL_NOTSAFEPOINT; @@ -2101,28 +2102,28 @@ jl_sym_t *_jl_symbol(const char *str, size_t len) JL_NOTSAFEPOINT; // This prevents `ct` from returning via error handlers or other unintentional // means by destroying some old state before we start destroying that state in atexit hooks. -void post_boot_hooks(void); -JL_DLLEXPORT jl_genericmemory_t *jl_genericmemory_copy_slice(jl_genericmemory_t *mem, void *data, size_t len); +void post_boot_hooks(void) JL_CANSAFEPOINT; +JL_DLLEXPORT jl_genericmemory_t *jl_genericmemory_copy_slice(jl_genericmemory_t *mem, void *data, size_t len) JL_CANSAFEPOINT; int obviously_disjoint(jl_value_t *a, jl_value_t *b, int specificity) JL_NOTSAFEPOINT; -JL_CALLABLE(jl_f_opaque_closure_call); +JL_CALLABLE(jl_f_opaque_closure_call) JL_CANSAFEPOINT; uint_t bindingkey_hash(size_t idx, jl_value_t *data); uint_t speccache_hash(size_t idx, jl_value_t *data); -void JL_NORETURN jl_finish_task(jl_task_t *ct); -void jl_wait_empty_begin(void); +void JL_NORETURN jl_finish_task(jl_task_t *ct) JL_CANSAFEPOINT; +void jl_wait_empty_begin(void) JL_CANSAFEPOINT; void jl_wait_empty_end(void); // concurrent reads are permitted, using the same pattern as mtsmall_arraylist // it is implemented separately because the API of direct jl_all_tls_states use is already widely prevalent void jl_init_thread_scheduler(jl_ptls_t ptls) JL_NOTSAFEPOINT; -void jl_lisp_prompt(void); -void jl_task_frame_noreturn(jl_task_t *ct) JL_NOTSAFEPOINT; +void jl_lisp_prompt(void) JL_CANSAFEPOINT; +void jl_task_frame_noreturn(jl_task_t *ct) JL_CANSAFEPOINT; void scheduler_delete_thread(jl_ptls_t ptls) JL_NOTSAFEPOINT; void surprise_wakeup(jl_ptls_t ptls) JL_NOTSAFEPOINT; void _jl_free_stack(jl_ptls_t ptls, void *stkbuf, size_t bufsz) JL_NOTSAFEPOINT; JL_DLLEXPORT int jl_id_start_char(uint32_t wc) JL_NOTSAFEPOINT; // declared also in flisp.h JL_DLLEXPORT int jl_id_char(uint32_t wc) JL_NOTSAFEPOINT; // declared also in flisp.h -jl_value_t *simple_union(jl_value_t *a, jl_value_t *b); -jl_value_t *simple_intersect(jl_value_t *a, jl_value_t *b, int overesi); -int simple_subtype(jl_value_t *a, jl_value_t *b, int hasfree, int isUnion); +jl_value_t *simple_union(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT; +jl_value_t *simple_intersect(jl_value_t *a, jl_value_t *b, int overesi) JL_CANSAFEPOINT; +int simple_subtype(jl_value_t *a, jl_value_t *b, int hasfree, int isUnion) JL_CANSAFEPOINT; void jl_rng_split(uint64_t dst[JL_RNG_SIZE], uint64_t src[JL_RNG_SIZE]) JL_NOTSAFEPOINT; JL_DLLEXPORT void jl_coverage_alloc_line(const char *filename, int line) JL_NOTSAFEPOINT; JL_DLLEXPORT uint64_t *jl_coverage_data_pointer(const char *filename, int line) JL_NOTSAFEPOINT; @@ -2189,9 +2190,9 @@ JL_DLLEXPORT uint32_t jl_crc32c(uint32_t crc, const char *buf, size_t len); #define IR_FLAG_INBOUNDS 0x01 -JL_DLLIMPORT void jl_generate_fptr_for_unspecialized(jl_code_instance_t *unspec); -JL_DLLIMPORT int jl_compile_codeinst(jl_code_instance_t *unspec); -JL_DLLIMPORT void jl_emit_codeinsts_to_jit(jl_code_instance_t **codeinsts, jl_code_info_t **srcs, int len); +JL_DLLIMPORT void jl_generate_fptr_for_unspecialized(jl_code_instance_t *unspec) JL_CANSAFEPOINT; +JL_DLLIMPORT int jl_compile_codeinst(jl_code_instance_t *unspec) JL_CANSAFEPOINT; +JL_DLLIMPORT void jl_emit_codeinsts_to_jit(jl_code_instance_t **codeinsts, jl_code_info_t **srcs, int len) JL_CANSAFEPOINT; typedef struct { LLVMOrcThreadSafeModuleRef TSM; @@ -2200,15 +2201,15 @@ typedef struct { } jl_llvmf_dump_t; JL_DLLIMPORT jl_value_t *jl_dump_method_asm(jl_method_instance_t *linfo, size_t world, - char emit_mc, char getwrapper, const char* asm_variant, const char *debuginfo, char binary); -JL_DLLIMPORT void jl_get_llvmf_defn(jl_llvmf_dump_t* dump, jl_method_instance_t *linfo, jl_code_info_t *src, char getwrapper, char optimize, const char *llvm_options, const jl_cgparams_t params); -JL_DLLIMPORT jl_value_t *jl_dump_fptr_asm(uint64_t fptr, char emit_mc, const char* asm_variant, const char *debuginfo, char binary); -JL_DLLIMPORT jl_value_t *jl_dump_function_ir(jl_llvmf_dump_t *dump, char strip_ir_metadata, char dump_module, const char *debuginfo); -JL_DLLIMPORT jl_value_t *jl_dump_function_asm(jl_llvmf_dump_t *dump, char emit_mc, const char* asm_variant, const char *debuginfo, char binary, char raw); + char emit_mc, char getwrapper, const char* asm_variant, const char *debuginfo, char binary) JL_CANSAFEPOINT; +JL_DLLIMPORT void jl_get_llvmf_defn(jl_llvmf_dump_t* dump, jl_method_instance_t *linfo, jl_code_info_t *src, char getwrapper, char optimize, const char *llvm_options, const jl_cgparams_t params) JL_CANSAFEPOINT; +JL_DLLIMPORT jl_value_t *jl_dump_fptr_asm(uint64_t fptr, char emit_mc, const char* asm_variant, const char *debuginfo, char binary) JL_CANSAFEPOINT; +JL_DLLIMPORT jl_value_t *jl_dump_function_ir(jl_llvmf_dump_t *dump, char strip_ir_metadata, char dump_module, const char *debuginfo) JL_CANSAFEPOINT; +JL_DLLIMPORT jl_value_t *jl_dump_function_asm(jl_llvmf_dump_t *dump, char emit_mc, const char* asm_variant, const char *debuginfo, char binary, char raw) JL_CANSAFEPOINT; typedef jl_value_t *(*jl_codeinstance_lookup_t)(jl_method_instance_t *mi JL_PROPAGATES_ROOT, size_t min_world, size_t max_world); -JL_DLLIMPORT void *jl_create_native(LLVMOrcThreadSafeModuleRef llvmmod, int trim, int cache, size_t world, jl_array_t *mod_array, jl_array_t *worklist, int all, jl_array_t *module_init_order, jl_array_t *ext_foreign_cis); -JL_DLLIMPORT void *jl_emit_native(jl_array_t *codeinfos, jl_array_t *ci_order, LLVMOrcThreadSafeModuleRef llvmmod, const jl_cgparams_t *cgparams, int _external_linkage); +JL_DLLIMPORT void *jl_create_native(LLVMOrcThreadSafeModuleRef llvmmod, int trim, int cache, size_t world, jl_array_t *mod_array, jl_array_t *worklist, int all, jl_array_t *module_init_order, jl_array_t *ext_foreign_cis) JL_CANSAFEPOINT; +JL_DLLIMPORT void *jl_emit_native(jl_array_t *codeinfos, jl_array_t *ci_order, LLVMOrcThreadSafeModuleRef llvmmod, const jl_cgparams_t *cgparams, int _external_linkage) JL_CANSAFEPOINT; JL_DLLIMPORT void jl_dump_native(void *native_code, const char *bc_fname, const char *unopt_bc_fname, const char *obj_fname, const char *asm_fname, ios_t *z, ios_t *s, jl_emission_params_t *params); @@ -2224,7 +2225,7 @@ JL_DLLIMPORT void jl_get_llvm_cis(void *native_code, size_t *num_els, jl_code_instance_t **CIs); JL_DLLIMPORT void jl_get_llvm_mi_cache_order(void *native_code, size_t *num_els, jl_code_instance_t **CIs); -JL_DLLIMPORT void jl_init_codegen(void); +JL_DLLIMPORT void jl_init_codegen(void) JL_CANSAFEPOINT; JL_DLLIMPORT void jl_teardown_codegen(void) JL_NOTSAFEPOINT; JL_DLLIMPORT void jl_decorate_llvm_module(LLVMModuleRef m) JL_NOTSAFEPOINT; JL_DLLIMPORT int jl_getFunctionInfo(jl_frame_t **frames, uintptr_t pointer, int skipC, int noInline) JL_NOTSAFEPOINT; diff --git a/src/julia_locks.h b/src/julia_locks.h index 35d14cd084dea..98086a1fc14d6 100644 --- a/src/julia_locks.h +++ b/src/julia_locks.h @@ -20,19 +20,19 @@ extern "C" { // while the jl_mutex_* functions are always locking and unlocking the locks. JL_DLLEXPORT void _jl_mutex_init(jl_mutex_t *lock, const char *name) JL_NOTSAFEPOINT; -JL_DLLEXPORT void _jl_mutex_wait(jl_task_t *self, jl_mutex_t *lock, int safepoint); -JL_DLLEXPORT void _jl_mutex_lock(jl_task_t *self, jl_mutex_t *lock); -JL_DLLEXPORT int _jl_mutex_trylock_nogc(jl_task_t *self, jl_mutex_t *lock) JL_NOTSAFEPOINT; -JL_DLLEXPORT int _jl_mutex_trylock(jl_task_t *self, jl_mutex_t *lock); -JL_DLLEXPORT void _jl_mutex_unlock(jl_task_t *self, jl_mutex_t *lock); -JL_DLLEXPORT void _jl_mutex_unlock_nogc(jl_mutex_t *lock) JL_NOTSAFEPOINT; - -static inline void jl_mutex_wait(jl_mutex_t *lock, int safepoint) +JL_DLLEXPORT void _jl_mutex_wait(jl_task_t *self, jl_mutex_t *lock, int safepoint) JL_CANSAFEPOINT; +JL_DLLEXPORT void _jl_mutex_lock(jl_task_t *self, jl_mutex_t *lock) JL_CANSAFEPOINT; +JL_DLLEXPORT int _jl_mutex_trylock_nogc(jl_task_t *self, jl_mutex_t *lock) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_ENTER_CONDITIONAL(1); +JL_DLLEXPORT int _jl_mutex_trylock(jl_task_t *self, jl_mutex_t *lock) JL_NOTSAFEPOINT; +JL_DLLEXPORT void _jl_mutex_unlock(jl_task_t *self, jl_mutex_t *lock) JL_CANSAFEPOINT; +JL_DLLEXPORT void _jl_mutex_unlock_nogc(jl_mutex_t *lock) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_LEAVE; + +static inline void jl_mutex_wait(jl_mutex_t *lock, int safepoint) JL_CANSAFEPOINT { _jl_mutex_wait(jl_current_task, lock, safepoint); } -static inline void jl_mutex_lock_nogc(jl_mutex_t *lock) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_ENTER +static inline void jl_mutex_lock_nogc(jl_mutex_t *lock) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_ENTER JL_NO_SAFEPOINT_ANALYSIS { #ifndef __clang_gcanalyzer__ // Hide this body from the analyzer, otherwise it complains that we're calling @@ -70,22 +70,22 @@ static inline void jl_mutex_lock_nogc(jl_mutex_t *lock) JL_NOTSAFEPOINT JL_NOTSA } \ } while (0) -static inline void jl_mutex_lock(jl_mutex_t *lock) +static inline void jl_mutex_lock(jl_mutex_t *lock) JL_CANSAFEPOINT { _jl_mutex_lock(jl_current_task, lock); } -static inline int jl_mutex_trylock_nogc(jl_mutex_t *lock) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_ENTER +static inline int jl_mutex_trylock_nogc(jl_mutex_t *lock) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_ENTER_CONDITIONAL(1) { return _jl_mutex_trylock_nogc(jl_current_task, lock); } -static inline int jl_mutex_trylock(jl_mutex_t *lock) +static inline int jl_mutex_trylock(jl_mutex_t *lock) JL_NOTSAFEPOINT { return _jl_mutex_trylock(jl_current_task, lock); } -static inline void jl_mutex_unlock(jl_mutex_t *lock) +static inline void jl_mutex_unlock(jl_mutex_t *lock) JL_CANSAFEPOINT { _jl_mutex_unlock(jl_current_task, lock); } @@ -106,24 +106,67 @@ static inline void jl_mutex_init(jl_mutex_t *lock, const char *name) JL_NOTSAFEP #define JL_LOCK_NOGC(m) jl_mutex_lock_nogc(m) #define JL_UNLOCK_NOGC(m) jl_mutex_unlock_nogc(m) -JL_DLLEXPORT void jl_lock_value(jl_mutex_t *v) JL_NOTSAFEPOINT; -JL_DLLEXPORT void jl_unlock_value(jl_mutex_t *v) JL_NOTSAFEPOINT; -JL_DLLEXPORT void jl_lock_field(jl_mutex_t *v) JL_NOTSAFEPOINT; -JL_DLLEXPORT void jl_unlock_field(jl_mutex_t *v) JL_NOTSAFEPOINT; +JL_DLLEXPORT void jl_lock_value(jl_mutex_t *v) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_ENTER; +JL_DLLEXPORT void jl_unlock_value(jl_mutex_t *v) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_LEAVE; +JL_DLLEXPORT void jl_lock_field(jl_mutex_t *v) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_ENTER; +JL_DLLEXPORT void jl_unlock_field(jl_mutex_t *v) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_LEAVE; + +// Redeclare platform locks with NOTSAFEPOINT enter/leave annotations +// n.b. we should add mutex_lock_safe aliases, which assert !jl_gcunsaferegion instead of enter/leave +#ifdef JL_LIBRARY_EXPORTS +UV_EXTERN void uv_mutex_lock(uv_mutex_t *lock) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_ENTER; +UV_EXTERN void uv_mutex_unlock(uv_mutex_t *lock) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_LEAVE; +#ifndef _OS_WINDOWS_ +int pthread_mutex_lock(pthread_mutex_t *lock) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_ENTER; +int pthread_mutex_trylock(pthread_mutex_t *lock) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_ENTER_CONDITIONAL(0); +int pthread_mutex_unlock(pthread_mutex_t *lock) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_LEAVE; +int pthread_rwlock_rdlock(pthread_rwlock_t *lock) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_ENTER; +int pthread_rwlock_tryrdlock(pthread_rwlock_t *lock) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_ENTER_CONDITIONAL(0); +int pthread_rwlock_wrlock(pthread_rwlock_t *lock) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_ENTER; +int pthread_rwlock_trywrlock(pthread_rwlock_t *lock) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_ENTER_CONDITIONAL(0); +int pthread_rwlock_unlock(pthread_rwlock_t *lock) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_LEAVE; +#endif +#endif #ifdef __cplusplus } #include +#include #include +// n.b. we should add mutex_lock_safe aliases, which assert !jl_gcunsaferegion instead of enter/leave +#ifdef __clang_safetyanalysis__ +#define JL_TSA_ANNOTATE_SCOPED_LOCK(Template, Name, Mutex) \ + template JL_NOTSAFEPOINT_ENTER Template::Name(Mutex&); \ + template JL_NOTSAFEPOINT_LEAVE Template::~Name() +#define JL_TSA_ANNOTATE_LOCK(Template, Name, Mutex) \ + JL_TSA_ANNOTATE_SCOPED_LOCK(Template, Name, Mutex); \ + template JL_NOTSAFEPOINT_ENTER void Template::lock(); \ + template JL_NOTSAFEPOINT_LEAVE void Template::unlock() + +// The qualified destructor name (e.g. std::lock_guard::~lock_guard) +// draws a pedantic -Wdtor-name because the name after `::~` is not visible at +// this scope; that is expected for these explicit instantiations, so silence it. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdtor-name" +JL_TSA_ANNOTATE_SCOPED_LOCK(std::lock_guard, lock_guard, std::mutex); +JL_TSA_ANNOTATE_LOCK(std::unique_lock, unique_lock, std::mutex); +JL_TSA_ANNOTATE_LOCK(std::unique_lock, unique_lock, std::shared_mutex); +JL_TSA_ANNOTATE_LOCK(std::shared_lock, shared_lock, std::shared_mutex); +#pragma clang diagnostic pop + +#undef JL_TSA_ANNOTATE_SCOPED_LOCK +#undef JL_TSA_ANNOTATE_LOCK +#endif + // simple C++ shim around a std::unique_lock + gc-safe + disabled finalizers region // since we nearly always want that combination together class jl_unique_gcsafe_lock { public: int8_t gc_state; std::unique_lock native; - explicit jl_unique_gcsafe_lock(std::mutex &native) JL_NOTSAFEPOINT_ENTER + explicit jl_unique_gcsafe_lock(std::mutex &native) JL_CANSAFEPOINT_LEAVE { jl_task_t *ct = jl_current_task; gc_state = jl_gc_safe_enter(ct->ptls); // contains jl_gc_safepoint after enter @@ -132,7 +175,8 @@ class jl_unique_gcsafe_lock { } jl_unique_gcsafe_lock(jl_unique_gcsafe_lock &&native) = delete; jl_unique_gcsafe_lock(jl_unique_gcsafe_lock &native) = delete; - ~jl_unique_gcsafe_lock() JL_NOTSAFEPOINT_LEAVE { + ~jl_unique_gcsafe_lock() JL_CANSAFEPOINT_ENTER + { jl_task_t *ct = jl_current_task; native.unlock(); jl_gc_safe_leave(ct->ptls, gc_state); // contains jl_gc_safepoint after leave @@ -142,6 +186,7 @@ class jl_unique_gcsafe_lock { cond.wait(native); } }; + #endif #endif diff --git a/src/julia_threads.h b/src/julia_threads.h index a4e45b7047779..e8d7b92e56de8 100644 --- a/src/julia_threads.h +++ b/src/julia_threads.h @@ -355,13 +355,16 @@ STATIC_INLINE int8_t jl_gc_state_save_and_set(jl_ptls_t ptls, { return jl_gc_state_set(ptls, state, jl_atomic_load_relaxed(&ptls->gc_state)); } -#ifdef __clang_gcanalyzer__ + // these might not be a safepoint (if they are no-op safe=>safe transitions), but we have to assume it could be (statically) -// however mark a delineated region in which safepoints would be not permissible -int8_t jl_gc_unsafe_enter(jl_ptls_t ptls) JL_NOTSAFEPOINT_LEAVE; -void jl_gc_unsafe_leave(jl_ptls_t ptls, int8_t state) JL_NOTSAFEPOINT_ENTER; -int8_t jl_gc_safe_enter(jl_ptls_t ptls) JL_NOTSAFEPOINT_ENTER; -void jl_gc_safe_leave(jl_ptls_t ptls, int8_t state) JL_NOTSAFEPOINT_LEAVE; +// however mark a delineated region in which safepoints would be permissible: a +// gc-unsafe region is entered (jl_gc_unsafe_enter / jl_gc_safe_leave) and left +// (jl_gc_unsafe_leave / jl_gc_safe_enter) as the thread toggles gc-unsafe state. +#if defined(__clang_gcanalyzer__) || defined(__clang_safetyanalysis__) +int8_t jl_gc_unsafe_enter(jl_ptls_t ptls) JL_CANSAFEPOINT_ENTER; +void jl_gc_unsafe_leave(jl_ptls_t ptls, int8_t state) JL_CANSAFEPOINT_LEAVE; +int8_t jl_gc_safe_enter(jl_ptls_t ptls) JL_CANSAFEPOINT_LEAVE; +void jl_gc_safe_leave(jl_ptls_t ptls, int8_t state) JL_CANSAFEPOINT_ENTER; #else #define jl_gc_unsafe_enter(ptls) jl_gc_state_save_and_set(ptls, JL_GC_STATE_UNSAFE) #define jl_gc_unsafe_leave(ptls, state) ((void)jl_gc_state_set(ptls, (state), JL_GC_STATE_UNSAFE)) @@ -369,10 +372,10 @@ void jl_gc_safe_leave(jl_ptls_t ptls, int8_t state) JL_NOTSAFEPOINT_LEAVE; #define jl_gc_safe_leave(ptls, state) ((void)jl_gc_state_set(ptls, (state), JL_GC_STATE_SAFE)) #endif -JL_DLLEXPORT void jl_gc_enable_finalizers(struct _jl_task_t *ct, int on); +JL_DLLEXPORT void jl_gc_enable_finalizers(struct _jl_task_t *ct, int on) JL_CANSAFEPOINT; JL_DLLEXPORT void jl_gc_disable_finalizers_internal(void) JL_NOTSAFEPOINT; -JL_DLLEXPORT void jl_gc_enable_finalizers_internal(void); -JL_DLLEXPORT void jl_gc_run_pending_finalizers(struct _jl_task_t *ct); +JL_DLLEXPORT void jl_gc_enable_finalizers_internal(void) JL_CANSAFEPOINT; +JL_DLLEXPORT void jl_gc_run_pending_finalizers(struct _jl_task_t *ct) JL_CANSAFEPOINT; extern JL_DLLEXPORT _Atomic(int) jl_gc_have_pending_finalizers; JL_DLLEXPORT int8_t jl_gc_is_in_finalizer(void) JL_NOTSAFEPOINT; diff --git a/src/llvm_api.cpp b/src/llvm_api.cpp index 918314027392b..bdee8959e6a1e 100644 --- a/src/llvm_api.cpp +++ b/src/llvm_api.cpp @@ -91,7 +91,7 @@ JL_DLLEXPORT_CODEGEN LLVMErrorRef JLJITAddLLVMIRModule_impl( } JL_DLLEXPORT_CODEGEN LLVMErrorRef -JLJITJDLookup_impl(JuliaOJITRef JIT, LLVMOrcJITDylibRef JD, LLVMOrcExecutorAddress *Result, const char *Name, int ExternalJDOnly) +JLJITJDLookup_impl(JuliaOJITRef JIT, LLVMOrcJITDylibRef JD, LLVMOrcExecutorAddress *Result, const char *Name, int ExternalJDOnly) JL_CANSAFEPOINT { auto Sym = unwrap(JIT)->findJDSymbol(*unwrap(JD), Name, ExternalJDOnly); if (Sym) { diff --git a/src/method.c b/src/method.c index 19f3743782ca0..f23edf6074363 100644 --- a/src/method.c +++ b/src/method.c @@ -16,7 +16,7 @@ extern "C" { #endif -static void check_c_types(const char *where, jl_value_t *rt, jl_value_t *at) +static void check_c_types(const char *where, jl_value_t *rt, jl_value_t *at) JL_CANSAFEPOINT { if (jl_is_svec(rt)) jl_errorf("%s: missing return type", where); @@ -45,7 +45,7 @@ void jl_add_scanned_method(jl_module_t *m, jl_method_t *meth) JL_UNLOCK(&m->lock); } -JL_DLLEXPORT void jl_scan_method_source_now(jl_method_t *m, jl_value_t *src) +JL_DLLEXPORT void jl_scan_method_source_now(jl_method_t *m, jl_value_t *src) JL_CANSAFEPOINT { if (!jl_atomic_fetch_or(&m->did_scan_source, 1)) { jl_code_info_t *code = NULL; @@ -73,7 +73,7 @@ JL_DLLEXPORT void jl_scan_method_source_now(jl_method_t *m, jl_value_t *src) } } -static void normalize_foreignsymbol(jl_expr_t *e, jl_module_t *module, const char *kind) +static void normalize_foreignsymbol(jl_expr_t *e, jl_module_t *module, const char *kind) JL_CANSAFEPOINT { jl_task_t *ct = jl_current_task; jl_value_t *fptr = jl_exprarg(e, 0); @@ -157,7 +157,7 @@ static void normalize_foreignsymbol(jl_expr_t *e, jl_module_t *module, const cha // Resolve references to non-locally-defined variables to become references to global // variables in `module` (unless the rvalue is one of the type parameters in `sparam_vals`). static jl_value_t *resolve_definition_effects(jl_value_t *expr, jl_module_t *module, jl_svec_t *sparam_vals, jl_value_t *binding_edge, - int binding_effects) + int binding_effects) JL_CANSAFEPOINT { if (jl_is_symbol(expr)) { jl_errorf("Found raw symbol %s in code returned from lowering. Expected all symbols to have been resolved to GlobalRef or slots.", @@ -331,7 +331,7 @@ static jl_value_t *expr_arg1(jl_value_t *expr) { return jl_array_ptr_ref(args, 0); } -static jl_value_t *alloc_edges(arraylist_t *edges_list) +static jl_value_t *alloc_edges(arraylist_t *edges_list) JL_CANSAFEPOINT { jl_value_t *jledges = (jl_value_t*)jl_alloc_svec(edges_list->len); jl_value_t *jledges2 = NULL; @@ -362,7 +362,7 @@ static jl_value_t *alloc_edges(arraylist_t *edges_list) return jledges; } -static void add_edge(arraylist_t *edges_list, arraylist_t *inlinestack, int32_t *p_to, int32_t *p_pc) +static void add_edge(arraylist_t *edges_list, arraylist_t *inlinestack, int32_t *p_to, int32_t *p_pc) JL_CANSAFEPOINT { jl_value_t *locinfo = (jl_value_t*)arraylist_pop(inlinestack); jl_sym_t *filesym = (jl_sym_t*)jl_fieldref_noalloc(locinfo, 0); @@ -404,7 +404,7 @@ static void add_edge(arraylist_t *edges_list, arraylist_t *inlinestack, int32_t *p_pc = (i - 2) / 3 + 1; } -static jl_debuginfo_t *jl_linetable_to_debuginfo(jl_array_t *codelocs_any, jl_array_t *linetable) +static jl_debuginfo_t *jl_linetable_to_debuginfo(jl_array_t *codelocs_any, jl_array_t *linetable) JL_CANSAFEPOINT { size_t nlocs = jl_array_nrows(codelocs_any); jl_value_t *toplocinfo = jl_array_ptr_ref(linetable, 0); @@ -715,7 +715,7 @@ JL_DLLEXPORT jl_code_info_t *jl_new_code_info_uninit(void) // invoke (compiling if necessary) the jlcall function pointer for a method template static jl_value_t *jl_call_staged(jl_method_t *def, jl_value_t *generator, - size_t world, jl_svec_t *sparam_vals, jl_value_t **args, uint32_t nargs) + size_t world, jl_svec_t *sparam_vals, jl_value_t **args, uint32_t nargs) JL_CANSAFEPOINT { size_t n_sparams = jl_svec_len(sparam_vals); jl_value_t **gargs; @@ -929,7 +929,7 @@ jl_method_instance_t *jl_get_specialized(jl_method_t *m, jl_value_t *types, jl_s return new_linfo; } -JL_DLLEXPORT void jl_method_set_source(jl_method_t *m, jl_code_info_t *src) +JL_DLLEXPORT void jl_method_set_source(jl_method_t *m, jl_code_info_t *src) JL_CANSAFEPOINT { uint8_t j; uint8_t called = 0; @@ -1438,7 +1438,7 @@ static uint64_t current_root_id(jl_array_t *root_blocks) } // Add a new block of `len` roots with key `modid` (module id) -static void add_root_block(jl_array_t *root_blocks, uint64_t modid, size_t len) +static void add_root_block(jl_array_t *root_blocks, uint64_t modid, size_t len) JL_CANSAFEPOINT { assert(jl_is_array(root_blocks)); jl_array_grow_end(root_blocks, 2); @@ -1449,7 +1449,7 @@ static void add_root_block(jl_array_t *root_blocks, uint64_t modid, size_t len) } // Allocate storage for roots -static void prepare_method_for_roots(jl_method_t *m, uint64_t modid) +static void prepare_method_for_roots(jl_method_t *m, uint64_t modid) JL_CANSAFEPOINT { if (!m->roots) { jl_gc_write(m, m->roots, jl_array_t, jl_alloc_vec_any(0)); diff --git a/src/module.c b/src/module.c index 94017cd2ca900..55e4585ef9f88 100644 --- a/src/module.c +++ b/src/module.c @@ -12,7 +12,7 @@ extern "C" { #endif -static jl_binding_partition_t *new_binding_partition(void) +static jl_binding_partition_t *new_binding_partition(void) JL_CANSAFEPOINT { jl_binding_partition_t *bpart = (jl_binding_partition_t*)jl_gc_alloc(jl_current_task->ptls, sizeof(jl_binding_partition_t), jl_binding_partition_type); bpart->restriction = NULL; @@ -125,7 +125,7 @@ static void update_implicit_resolution(struct implicit_search_resolution *to_upd to_update->debug_only_ultimate_binding = NULL; } -static jl_binding_partition_t *jl_implicit_import_resolved(jl_binding_t *b, struct implicit_search_gap gap, struct implicit_search_resolution resolution) +static jl_binding_partition_t *jl_implicit_import_resolved(jl_binding_t *b, struct implicit_search_gap gap, struct implicit_search_resolution resolution) JL_CANSAFEPOINT { size_t new_kind = resolution.ultimate_kind | gap.inherited_flags; // If the resolution indicates this should be reexported, add the implicit export flag @@ -206,7 +206,7 @@ static jl_binding_partition_t *jl_implicit_import_resolved(jl_binding_t *b, stru } // find a binding from a module's `usings` list -static struct implicit_search_resolution jl_resolve_implicit_import(jl_binding_t *b, modstack_t *st, size_t world, int trust_cache) +static struct implicit_search_resolution jl_resolve_implicit_import(jl_binding_t *b, modstack_t *st, size_t world, int trust_cache) JL_CANSAFEPOINT { // First check if we've hit a cycle in this resolution { @@ -356,7 +356,7 @@ static struct implicit_search_resolution jl_resolve_implicit_import(jl_binding_t return impstate; } -JL_DLLEXPORT jl_binding_partition_t *jl_maybe_reresolve_implicit(jl_binding_t *b, size_t new_max_world) +JL_DLLEXPORT jl_binding_partition_t *jl_maybe_reresolve_implicit(jl_binding_t *b, size_t new_max_world) JL_CANSAFEPOINT { struct implicit_search_gap gap; while (1) { @@ -397,7 +397,7 @@ JL_DLLEXPORT void jl_update_loaded_bpart(jl_binding_t *b, jl_binding_partition_t bpart->kind = resolution.ultimate_kind; } -static void jl_walk_binding_inplace(jl_binding_t **bnd, jl_binding_partition_t **pbpart, size_t world) +static void jl_walk_binding_inplace(jl_binding_t **bnd, jl_binding_partition_t **pbpart, size_t world) JL_CANSAFEPOINT { jl_binding_partition_t *bpart = *pbpart; while (1) { @@ -411,7 +411,7 @@ static void jl_walk_binding_inplace(jl_binding_t **bnd, jl_binding_partition_t * *pbpart = bpart; } -static void jl_walk_binding_inplace_depwarn(jl_binding_t **bnd, jl_binding_partition_t **pbpart, size_t world, int *depwarn) +static void jl_walk_binding_inplace_depwarn(jl_binding_t **bnd, jl_binding_partition_t **pbpart, size_t world, int *depwarn) JL_CANSAFEPOINT { int passed_explicit = 0; jl_binding_partition_t *bpart = *pbpart; @@ -432,7 +432,7 @@ static void jl_walk_binding_inplace_depwarn(jl_binding_t **bnd, jl_binding_parti *pbpart = bpart; } -static void jl_walk_binding_inplace_worlds(jl_binding_t **bnd, jl_binding_partition_t **pbpart, size_t *min_world, size_t *max_world, int *depwarn, size_t world) +static void jl_walk_binding_inplace_worlds(jl_binding_t **bnd, jl_binding_partition_t **pbpart, size_t *min_world, size_t *max_world, int *depwarn, size_t world) JL_CANSAFEPOINT { int passed_explicit = 0; jl_binding_partition_t *bpart = *pbpart; @@ -459,7 +459,7 @@ static void jl_walk_binding_inplace_worlds(jl_binding_t **bnd, jl_binding_partit *pbpart = bpart; } -STATIC_INLINE jl_binding_partition_t *jl_get_binding_partition_(jl_binding_t *b JL_PROPAGATES_ROOT, jl_value_t *parent, _Atomic(jl_binding_partition_t *)*insert, size_t world, size_t max_world, modstack_t *st) JL_GLOBALLY_ROOTED +STATIC_INLINE jl_binding_partition_t *jl_get_binding_partition_(jl_binding_t *b JL_PROPAGATES_ROOT, jl_value_t *parent, _Atomic(jl_binding_partition_t *)*insert, size_t world, size_t max_world, modstack_t *st) JL_CANSAFEPOINT JL_GLOBALLY_ROOTED { assert(jl_is_binding(b)); struct implicit_search_gap gap; @@ -556,7 +556,7 @@ JL_DLLEXPORT jl_value_t *jl_get_binding_leaf_partitions_value_if_const(jl_bindin return NULL; } -JL_DLLEXPORT size_t jl_binding_backedges_length(jl_binding_t *b) +JL_DLLEXPORT size_t jl_binding_backedges_length(jl_binding_t *b) JL_CANSAFEPOINT { JL_LOCK(&b->globalref->mod->lock); size_t len = 0; @@ -566,7 +566,7 @@ JL_DLLEXPORT size_t jl_binding_backedges_length(jl_binding_t *b) return len; } -JL_DLLEXPORT jl_value_t *jl_binding_backedges_getindex(jl_binding_t *b, size_t i) +JL_DLLEXPORT jl_value_t *jl_binding_backedges_getindex(jl_binding_t *b, size_t i) JL_CANSAFEPOINT { JL_LOCK(&b->globalref->mod->lock); assert(b->backedges); @@ -575,7 +575,7 @@ JL_DLLEXPORT jl_value_t *jl_binding_backedges_getindex(jl_binding_t *b, size_t i return ret; } -static jl_module_t *jl_new_module__(jl_sym_t *name, jl_module_t *parent) +static jl_module_t *jl_new_module__(jl_sym_t *name, jl_module_t *parent) JL_CANSAFEPOINT { jl_task_t *ct = jl_current_task; const jl_uuid_t uuid_zero = {0, 0}; @@ -615,7 +615,7 @@ static jl_module_t *jl_new_module__(jl_sym_t *name, jl_module_t *parent) return m; } -static void jl_add_default_names(jl_module_t *m, uint8_t default_using_core, uint8_t self_name) +static void jl_add_default_names(jl_module_t *m, uint8_t default_using_core, uint8_t self_name) JL_CANSAFEPOINT { if (jl_core_module) { // Bootstrap: Before jl_core_module is defined, we don't have enough infrastructure @@ -739,7 +739,7 @@ uint32_t jl_module_next_counter(jl_module_t *m) return jl_atomic_fetch_add_relaxed(&m->counter, 1); } -JL_DLLEXPORT jl_value_t *jl_f_new_module(jl_sym_t *name, uint8_t std_imports, uint8_t default_names) +JL_DLLEXPORT jl_value_t *jl_f_new_module(jl_sym_t *name, uint8_t std_imports, uint8_t default_names) JL_CANSAFEPOINT { // TODO: should we prohibit this during incremental compilation? // TODO: the parent module is a lie @@ -833,7 +833,7 @@ JL_DLLEXPORT uint8_t jl_istopmod(jl_module_t *mod) return mod->istopmod; } -static jl_globalref_t *jl_new_globalref(jl_module_t *mod, jl_sym_t *name, jl_binding_t *b) +static jl_globalref_t *jl_new_globalref(jl_module_t *mod, jl_sym_t *name, jl_binding_t *b) JL_CANSAFEPOINT { jl_task_t *ct = jl_current_task; jl_globalref_t *g = (jl_globalref_t*)jl_gc_alloc(ct->ptls, sizeof(jl_globalref_t), jl_globalref_type); @@ -847,7 +847,7 @@ static jl_globalref_t *jl_new_globalref(jl_module_t *mod, jl_sym_t *name, jl_bin return g; } -static jl_binding_t *new_binding(jl_module_t *mod, jl_sym_t *name) +static jl_binding_t *new_binding(jl_module_t *mod, jl_sym_t *name) JL_CANSAFEPOINT { jl_task_t *ct = jl_current_task; assert(jl_is_module(mod) && jl_is_symbol(name)); @@ -865,7 +865,7 @@ static jl_binding_t *new_binding(jl_module_t *mod, jl_sym_t *name) extern jl_mutex_t jl_modules_mutex; -static int is_module_open(jl_module_t *m) +static int is_module_open(jl_module_t *m) JL_CANSAFEPOINT { JL_LOCK(&jl_modules_mutex); int open = ptrhash_has(&jl_current_modules, (void*)m); @@ -893,7 +893,7 @@ void check_safe_newbinding(jl_module_t *m, jl_sym_t *var) } } -static jl_module_t *jl_binding_dbgmodule(jl_binding_t *b) JL_GLOBALLY_ROOTED; +static jl_module_t *jl_binding_dbgmodule(jl_binding_t *b) JL_CANSAFEPOINT JL_GLOBALLY_ROOTED; // Checks that the binding in general is currently writable, but does not perform any checks on the // value to be written into the binding. @@ -936,7 +936,7 @@ JL_DLLEXPORT jl_binding_t *jl_get_binding_wr(jl_module_t *m JL_PROPAGATES_ROOT, } // return module of binding -JL_DLLEXPORT jl_module_t *jl_get_module_of_binding(jl_module_t *m, jl_sym_t *var) +JL_DLLEXPORT jl_module_t *jl_get_module_of_binding(jl_module_t *m, jl_sym_t *var) JL_CANSAFEPOINT { size_t world = jl_current_task->world_age; jl_binding_t *b = jl_get_module_binding(m, var, 1); @@ -995,7 +995,7 @@ JL_DLLEXPORT jl_value_t *jl_get_binding_value_in_world(jl_binding_t *b, size_t w return jl_atomic_load_relaxed(&b->value); } -static jl_value_t *jl_get_binding_value_depwarn(jl_binding_t *b, size_t world) +static jl_value_t *jl_get_binding_value_depwarn(jl_binding_t *b, size_t world) JL_CANSAFEPOINT { assert(b); // alloc=1 parameter ensured that jl_get_module_binding returns a valid binding jl_binding_partition_t *bpart = jl_get_binding_partition(b, world); @@ -1019,7 +1019,7 @@ static jl_value_t *jl_get_binding_value_depwarn(jl_binding_t *b, size_t world) return jl_atomic_load_relaxed(&b->value); } -JL_DLLEXPORT jl_value_t *jl_get_binding_value_seqcst(jl_binding_t *b) +JL_DLLEXPORT jl_value_t *jl_get_binding_value_seqcst(jl_binding_t *b) JL_CANSAFEPOINT { size_t world = jl_current_task->world_age; jl_binding_partition_t *bpart = jl_get_binding_partition(b, world); @@ -1187,7 +1187,7 @@ JL_DLLEXPORT jl_value_t *jl_get_existing_strong_gf(jl_binding_t *b, size_t new_w return f; } -static void jl_binding_dep_message(jl_binding_t *b); +static void jl_binding_dep_message(jl_binding_t *b) JL_CANSAFEPOINT; // get type of binding m.var, without resolving the binding JL_DLLEXPORT jl_value_t *jl_get_binding_type(jl_module_t *m, jl_sym_t *var) @@ -1293,7 +1293,7 @@ JL_DLLEXPORT void check_safe_import_from(jl_module_t *m) } } -static int eq_bindings(jl_binding_partition_t *owner, jl_binding_t *alias, size_t world) +static int eq_bindings(jl_binding_partition_t *owner, jl_binding_t *alias, size_t world) JL_CANSAFEPOINT { jl_binding_t *ownerb = NULL; jl_binding_partition_t *alias_bpart = jl_get_binding_partition(alias, world); @@ -1521,7 +1521,7 @@ JL_DLLEXPORT jl_value_t *jl_get_module_usings_backedges(jl_module_t *m) return m->usings_backedges; } -JL_DLLEXPORT size_t jl_module_scanned_methods_length(jl_module_t *m) +JL_DLLEXPORT size_t jl_module_scanned_methods_length(jl_module_t *m) JL_CANSAFEPOINT { JL_LOCK(&m->lock); size_t len = 0; @@ -1531,7 +1531,7 @@ JL_DLLEXPORT size_t jl_module_scanned_methods_length(jl_module_t *m) return len; } -JL_DLLEXPORT jl_value_t *jl_module_scanned_methods_getindex(jl_module_t *m, size_t i) +JL_DLLEXPORT jl_value_t *jl_module_scanned_methods_getindex(jl_module_t *m, size_t i) JL_CANSAFEPOINT { JL_LOCK(&m->lock); assert(m->scanned_methods != jl_nothing); @@ -1623,14 +1623,16 @@ JL_DLLEXPORT int jl_boundp(jl_module_t *m, jl_sym_t *var, int allow_import) // u return jl_atomic_load(&b->value) != NULL; } -JL_DLLEXPORT int jl_module_exports_p(jl_module_t *m, jl_sym_t *var) +#ifndef __clang_gcanalyzer__ // this method is unsound due to mutating behavior of jl_get_binding_partition +JL_DLLEXPORT int jl_module_exports_p(jl_module_t *m, jl_sym_t *var) JL_NO_SAFEPOINT_ANALYSIS { jl_binding_t *b = jl_get_module_binding(m, var, 0); jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); return b && jl_bpart_is_exported(bpart->kind); } +#endif -JL_DLLEXPORT int jl_module_public_p(jl_module_t *m, jl_sym_t *var) +JL_DLLEXPORT int jl_module_public_p(jl_module_t *m, jl_sym_t *var) JL_CANSAFEPOINT { jl_binding_t *b = jl_get_module_binding(m, var, 0); return b && (jl_atomic_load_relaxed(&b->flags) & BINDING_FLAG_PUBLICP); @@ -1755,7 +1757,7 @@ JL_DLLEXPORT void jl_set_const(jl_module_t *m, jl_sym_t *var, jl_value_t *val JL jl_gc_write(bpart, bpart->restriction, jl_value_t, val); } -static void jl_invalidate_binding_refs(jl_globalref_t *ref, jl_binding_partition_t *invalidated_bpart, jl_binding_partition_t *new_bpart, size_t new_world) +static void jl_invalidate_binding_refs(jl_globalref_t *ref, jl_binding_partition_t *invalidated_bpart, jl_binding_partition_t *new_bpart, size_t new_world) JL_CANSAFEPOINT { jl_value_t *invalidate_code_for_globalref = NULL; if (jl_base_module != NULL) @@ -1884,7 +1886,7 @@ JL_DLLEXPORT jl_binding_partition_t *jl_replace_binding_locked2(jl_binding_t *b, } JL_DLLEXPORT jl_binding_partition_t *jl_replace_binding(jl_binding_t *b, - jl_binding_partition_t *old_bpart, jl_value_t *restriction_val, enum jl_partition_kind kind) { + jl_binding_partition_t *old_bpart, jl_value_t *restriction_val, enum jl_partition_kind kind) JL_CANSAFEPOINT { JL_LOCK(&world_counter_lock); @@ -1912,7 +1914,7 @@ JL_DLLEXPORT int jl_globalref_is_const(jl_globalref_t *gr) return jl_bkind_is_real_constant(jl_binding_kind(bpart)); } -JL_DLLEXPORT void jl_disable_binding(jl_globalref_t *gr) +JL_DLLEXPORT void jl_disable_binding(jl_globalref_t *gr) JL_CANSAFEPOINT { jl_binding_t *b = gr->binding; if (!b) @@ -1944,7 +1946,7 @@ JL_DLLEXPORT int jl_is_const(jl_module_t *m, jl_sym_t *var) // set the deprecated flag for a binding: // 0=not deprecated, 1=renamed, 2=moved to another package static const size_t DEPWARN_FLAGS = PARTITION_FLAG_DEPRECATED | PARTITION_FLAG_DEPWARN; -JL_DLLEXPORT void jl_deprecate_binding(jl_module_t *m, jl_sym_t *var, int flag) +JL_DLLEXPORT void jl_deprecate_binding(jl_module_t *m, jl_sym_t *var, int flag) JL_CANSAFEPOINT { jl_binding_t *b = jl_get_binding(m, var); size_t new_flags = flag == 1 ? PARTITION_FLAG_DEPRECATED | PARTITION_FLAG_DEPWARN : @@ -1993,7 +1995,7 @@ JL_DLLEXPORT void jl_module_set_visibility(jl_module_t *m, jl_sym_t *var, int st jl_atomic_fetch_and_relaxed(&b->flags, (uint8_t)~BINDING_FLAG_PUBLICP); } -static int should_depwarn(jl_binding_t *b, uint8_t flag) +static int should_depwarn(jl_binding_t *b, uint8_t flag) JL_CANSAFEPOINT { // We consider bindings deprecated, if: // @@ -2010,13 +2012,13 @@ static int should_depwarn(jl_binding_t *b, uint8_t flag) return 0; } -JL_DLLEXPORT void jl_binding_deprecation_check(jl_binding_t *b) +JL_DLLEXPORT void jl_binding_deprecation_check(jl_binding_t *b) JL_CANSAFEPOINT { if (jl_options.depwarn && should_depwarn(b, PARTITION_FLAG_DEPWARN)) jl_binding_deprecation_warning(b); } -JL_DLLEXPORT int jl_is_binding_deprecated(jl_module_t *m, jl_sym_t *var) +JL_DLLEXPORT int jl_is_binding_deprecated(jl_module_t *m, jl_sym_t *var) JL_CANSAFEPOINT { jl_binding_t *b = jl_get_module_binding(m, var, 0); if (!b) @@ -2051,7 +2053,6 @@ void jl_binding_deprecation_warning(jl_binding_t *b) // we can actually write the value `rhs` to it. jl_value_t *jl_check_binding_assign_value(jl_binding_t *b JL_PROPAGATES_ROOT, jl_module_t *mod, jl_sym_t *var, jl_value_t *rhs, const char *msg) { - JL_GC_PUSH1(&rhs); // callee-rooted jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); enum jl_partition_kind kind = jl_binding_kind(bpart); assert(kind == PARTITION_KIND_DECLARED || kind == PARTITION_KIND_GLOBAL); @@ -2060,7 +2061,6 @@ jl_value_t *jl_check_binding_assign_value(jl_binding_t *b JL_PROPAGATES_ROOT, jl if (old_ty != (jl_value_t*)jl_any_type && jl_typeof(rhs) != old_ty && !jl_isa(rhs, old_ty)) { jl_type_error_global(msg, mod, var, old_ty, rhs); } - JL_GC_POP(); return old_ty; } @@ -2100,7 +2100,7 @@ JL_DLLEXPORT jl_value_t *jl_checked_modify(jl_binding_t *b, jl_module_t *mod, jl return modify_value(ty, &b->value, (jl_value_t*)b, op, rhs, 1, b, mod, var); } -JL_DLLEXPORT jl_value_t *jl_checked_assignonce(jl_binding_t *b, jl_module_t *mod, jl_sym_t *var, jl_value_t *rhs ) +JL_DLLEXPORT jl_value_t *jl_checked_assignonce(jl_binding_t *b, jl_module_t *mod, jl_sym_t *var, jl_value_t *rhs) { jl_check_binding_assign_value(b, mod, var, rhs, "setglobalonce!"); jl_value_t *old = NULL; @@ -2109,7 +2109,7 @@ JL_DLLEXPORT jl_value_t *jl_checked_assignonce(jl_binding_t *b, jl_module_t *mod return old; } -JL_DLLEXPORT jl_value_t *jl_module_usings(jl_module_t *m) +JL_DLLEXPORT jl_value_t *jl_module_usings(jl_module_t *m) JL_CANSAFEPOINT { JL_LOCK(&m->lock); int j = module_usings_length(m); @@ -2125,13 +2125,13 @@ JL_DLLEXPORT jl_value_t *jl_module_usings(jl_module_t *m) return (jl_value_t*)a; } -static void _append_symbol_to_bindings_array(jl_array_t* a, jl_sym_t *name) { +static void _append_symbol_to_bindings_array(jl_array_t* a, jl_sym_t *name) JL_CANSAFEPOINT { jl_array_grow_end(a, 1); //XXX: change to jl_arrayset if array storage allocation for Array{Symbols,1} changes: jl_array_ptr_set(a, jl_array_dim0(a)-1, (jl_value_t*)name); } -static void _materialize_reexported_bindings(jl_module_t *m, size_t world, jl_array_t *visited_modules) +static void _materialize_reexported_bindings(jl_module_t *m, size_t world, jl_array_t *visited_modules) JL_CANSAFEPOINT { size_t len = jl_array_len(visited_modules); for (size_t i = 0; i < len; i++) { @@ -2176,7 +2176,7 @@ static void _materialize_reexported_bindings(jl_module_t *m, size_t world, jl_ar } } -static void append_module_names(jl_array_t* a, jl_module_t *m, int all, int imported, int usings, size_t world) +static void append_module_names(jl_array_t* a, jl_module_t *m, int all, int imported, int usings, size_t world) JL_CANSAFEPOINT { // Materialize reexported bindings first jl_array_t *visited_modules = jl_alloc_vec_any(0); @@ -2224,7 +2224,7 @@ static void append_module_names(jl_array_t* a, jl_module_t *m, int all, int impo } } -static void append_exported_names(jl_array_t* a, jl_module_t *m, int all, size_t world) +static void append_exported_names(jl_array_t* a, jl_module_t *m, int all, size_t world) JL_CANSAFEPOINT { // First, materialize all reexported bindings jl_array_t *visited_modules = jl_alloc_vec_any(0); @@ -2250,7 +2250,7 @@ static void append_exported_names(jl_array_t* a, jl_module_t *m, int all, size_t } } -JL_DLLEXPORT jl_value_t *jl_module_names(jl_module_t *m, int all, int imported, int usings, size_t world) +JL_DLLEXPORT jl_value_t *jl_module_names(jl_module_t *m, int all, int imported, int usings, size_t world) JL_CANSAFEPOINT { jl_array_t *a = jl_alloc_array_1d(jl_array_symbol_type, 0); JL_GC_PUSH1(&a); @@ -2306,7 +2306,7 @@ int jl_is_submodule(jl_module_t *child, jl_module_t *parent) JL_NOTSAFEPOINT // resolution decisions for a module. This is dangerous, and should only be // done for modules that are essentially empty anyway. The only use case for this // is to leave `Main` as empty as possible in the default system image. -JL_DLLEXPORT void jl_clear_implicit_imports(jl_module_t *m) +JL_DLLEXPORT void jl_clear_implicit_imports(jl_module_t *m) JL_CANSAFEPOINT { JL_LOCK(&m->lock); jl_svec_t *table = jl_atomic_load_relaxed(&m->bindings); @@ -2322,7 +2322,7 @@ JL_DLLEXPORT void jl_clear_implicit_imports(jl_module_t *m) JL_UNLOCK(&m->lock); } -JL_DLLEXPORT void jl_add_to_module_init_list(jl_value_t *mod) +JL_DLLEXPORT void jl_add_to_module_init_list(jl_value_t *mod) JL_CANSAFEPOINT { if (jl_module_init_order == NULL) jl_module_init_order = jl_alloc_vec_any(0); @@ -2334,7 +2334,7 @@ JL_DLLEXPORT jl_svec_t *jl_module_get_bindings(jl_module_t *m) return jl_atomic_load_relaxed(&m->bindings); } -JL_DLLEXPORT void jl_init_restored_module(jl_value_t *mod) +JL_DLLEXPORT void jl_init_restored_module(jl_value_t *mod) JL_CANSAFEPOINT { if (!jl_generating_output() || jl_options.incremental) { jl_module_run_initializer((jl_module_t*)mod); diff --git a/src/opaque_closure.c b/src/opaque_closure.c index 8dfe576d2d37f..e5bf6962f7e16 100644 --- a/src/opaque_closure.c +++ b/src/opaque_closure.c @@ -28,7 +28,7 @@ JL_DLLEXPORT int jl_is_valid_oc_argtype(jl_tupletype_t *argt, jl_method_t *sourc } static jl_opaque_closure_t *new_opaque_closure(jl_tupletype_t *argt, jl_value_t *rt_lb, jl_value_t *rt_ub, - jl_value_t *source_, jl_value_t *captures, int do_compile, size_t world) + jl_value_t *source_, jl_value_t *captures, int do_compile, size_t world) JL_CANSAFEPOINT { if (!jl_is_tuple_type((jl_value_t*)argt)) { jl_error("OpaqueClosure argument tuple must be a tuple type"); @@ -146,7 +146,7 @@ jl_opaque_closure_t *jl_new_opaque_closure(jl_tupletype_t *argt, jl_value_t *rt_ } JL_DLLEXPORT jl_opaque_closure_t *jl_new_opaque_closure_from_code_info_in_world(jl_tupletype_t *argt, jl_value_t *rt_lb, jl_value_t *rt_ub, - jl_module_t *mod, jl_code_info_t *ci, int lineno, jl_value_t *file, int nargs, int isva, jl_value_t *env, int do_compile, int isinferred, size_t world) + jl_module_t *mod, jl_code_info_t *ci, int lineno, jl_value_t *file, int nargs, int isva, jl_value_t *env, int do_compile, int isinferred, size_t world) JL_CANSAFEPOINT { jl_value_t *root = NULL, *sigtype = NULL; jl_code_instance_t *inst = NULL; @@ -177,12 +177,12 @@ JL_DLLEXPORT jl_opaque_closure_t *jl_new_opaque_closure_from_code_info_in_world( } JL_DLLEXPORT jl_opaque_closure_t *jl_new_opaque_closure_from_code_info(jl_tupletype_t *argt, jl_value_t *rt_lb, jl_value_t *rt_ub, - jl_module_t *mod, jl_code_info_t *ci, int lineno, jl_value_t *file, int nargs, int isva, jl_value_t *env, int do_compile, int isinferred) + jl_module_t *mod, jl_code_info_t *ci, int lineno, jl_value_t *file, int nargs, int isva, jl_value_t *env, int do_compile, int isinferred) JL_CANSAFEPOINT { return jl_new_opaque_closure_from_code_info_in_world(argt, rt_lb, rt_ub, mod, ci, lineno, file, nargs, isva, env, do_compile, isinferred, jl_current_task->world_age); } -JL_CALLABLE(jl_new_opaque_closure_jlcall) +JL_CALLABLE(jl_new_opaque_closure_jlcall) JL_CANSAFEPOINT { if (nargs < 5) jl_error("new_opaque_closure: Not enough arguments"); @@ -209,7 +209,7 @@ int jl_tupletype_length_compat(jl_value_t *v, size_t nargs) return nparams == nargs; } -JL_CALLABLE(jl_f_opaque_closure_call) +JL_CALLABLE(jl_f_opaque_closure_call) JL_CANSAFEPOINT { jl_opaque_closure_t *oc = (jl_opaque_closure_t*)F; jl_value_t *argt = jl_tparam0(jl_typeof(oc)); diff --git a/src/precompile.c b/src/precompile.c index 802e90d6d6bba..e87178b6337f6 100644 --- a/src/precompile.c +++ b/src/precompile.c @@ -21,7 +21,7 @@ JL_DLLEXPORT int jl_generating_output(void) return jl_options.outputo || jl_options.outputbc || jl_options.outputunoptbc || jl_options.outputji || jl_options.outputasm; } -static void write_srctext(ios_t *f, jl_array_t *udeps, int64_t srctextpos) { +static void write_srctext(ios_t *f, jl_array_t *udeps, int64_t srctextpos) JL_CANSAFEPOINT { // Write the source-text for the dependent files if (udeps) { // Go back and update the source-text position to point to the current position diff --git a/src/precompile_utils.c b/src/precompile_utils.c index d75f8e5dd88e7..1ec0dadaa806f 100644 --- a/src/precompile_utils.c +++ b/src/precompile_utils.c @@ -7,7 +7,7 @@ JL_DLLEXPORT void jl_suppress_precompile(int suppress) } -static void jl_rebuild_methtables(arraylist_t *MIs, htable_t *mtables) JL_GC_DISABLED +static void jl_rebuild_methtables(arraylist_t *MIs, htable_t *mtables) JL_CANSAFEPOINT JL_GC_DISABLED { // Rebuild MethodTable to contain only those methods for which we compiled code. // This can have significant soundness problems if there previously existed diff --git a/src/processor.cpp b/src/processor.cpp index 9dda3908e3ee8..ca69ec552d082 100644 --- a/src/processor.cpp +++ b/src/processor.cpp @@ -359,7 +359,7 @@ static void init_jit_targets(const char *cpu_target, bool imaging) JL_NOTSAFEPOI // Shared: deserialize image targets, match against a resolved target. // Returns {target_index, vreg_size} or {UINT32_MAX, 0} on failure. static std::pair match_image_targets( - const void *id, const tp::LLVMTargetSpec &target, jl_value_t **rejection_reason) + const void *id, const tp::LLVMTargetSpec &target, jl_value_t **rejection_reason) JL_CANSAFEPOINT { auto image_targets = tp::deserialize_targets((const uint8_t *)id); CF_DEBUG("[cpufeatures] image has %zu target(s)\n", image_targets.size()); @@ -379,7 +379,7 @@ static std::pair match_image_targets( return {(uint32_t)match.best_idx, match.vreg_size}; } -static uint32_t match_sysimg_target(void *ctx, const void *id, jl_value_t **rejection_reason) +static uint32_t match_sysimg_target(void *ctx, const void *id, jl_value_t **rejection_reason) JL_CANSAFEPOINT { const char *cpu_target = (const char *)ctx; CF_DEBUG("[cpufeatures] match_sysimg_target: cpu_target='%s'\n", @@ -465,7 +465,7 @@ static uint32_t match_sysimg_target(void *ctx, const void *id, jl_value_t **reje return match_result.first; } -static uint32_t match_pkgimg_target(void *ctx, const void *id, jl_value_t **rejection_reason) +static uint32_t match_pkgimg_target(void *ctx, const void *id, jl_value_t **rejection_reason) JL_CANSAFEPOINT { auto &target = jit_targets.front(); auto result = match_image_targets(id, target, rejection_reason); diff --git a/src/processor.h b/src/processor.h index db82649e7f35c..e0cf0835de644 100644 --- a/src/processor.h +++ b/src/processor.h @@ -180,22 +180,22 @@ jl_image_t jl_load_pkgimg(jl_image_buf_t image); void jl_set_sysimage_cpu_target(const char *cpu_target) JL_NOTSAFEPOINT; // Return the name of the host CPU as a julia string. -JL_DLLEXPORT jl_value_t *jl_get_cpu_name(void); +JL_DLLEXPORT jl_value_t *jl_get_cpu_name(void) JL_CANSAFEPOINT; // Return the features of the host CPU as a julia string. -JL_DLLEXPORT jl_value_t *jl_get_cpu_features(void); +JL_DLLEXPORT jl_value_t *jl_get_cpu_features(void) JL_CANSAFEPOINT; // Return the CPU target string used to build the current sysimage -JL_DLLEXPORT jl_value_t *jl_get_sysimage_cpu_target(void); +JL_DLLEXPORT jl_value_t *jl_get_sysimage_cpu_target(void) JL_CANSAFEPOINT; // Check if the CPU has native FMA instructions; // For debugging only JL_DLLEXPORT jl_value_t *jl_cpu_has_fma(int bits); // Dump the name and feature set of the host CPU JL_DLLEXPORT void jl_dump_host_cpu(void); -JL_DLLEXPORT jl_value_t* jl_check_pkgimage_clones(char* data); +JL_DLLEXPORT jl_value_t* jl_check_pkgimage_clones(char* data) JL_CANSAFEPOINT; -JL_DLLEXPORT int32_t jl_set_zero_subnormals(int8_t isZero); -JL_DLLEXPORT int32_t jl_get_zero_subnormals(void); -JL_DLLEXPORT int32_t jl_set_default_nans(int8_t isDefault); -JL_DLLEXPORT int32_t jl_get_default_nans(void); +JL_DLLEXPORT int32_t jl_set_zero_subnormals(int8_t isZero) JL_NOTSAFEPOINT; +JL_DLLEXPORT int32_t jl_get_zero_subnormals(void) JL_NOTSAFEPOINT; +JL_DLLEXPORT int32_t jl_set_default_nans(int8_t isDefault) JL_NOTSAFEPOINT; +JL_DLLEXPORT int32_t jl_get_default_nans(void) JL_NOTSAFEPOINT; /** * System image contents. @@ -286,8 +286,8 @@ extern "C" JL_DLLEXPORT jl_llvm_target_t jl_get_llvm_target(const char *cpu_targ */ extern "C" JL_DLLEXPORT jl_llvm_target_t jl_get_llvm_disasm_target(void) JL_NOTSAFEPOINT; -extern "C" JL_DLLEXPORT jl_value_t* jl_reflect_clone_targets(); -extern "C" JL_DLLEXPORT jl_value_t *jl_feature_bits_to_string(const uint8_t *bits, int32_t nwords); +extern "C" JL_DLLEXPORT jl_value_t* jl_reflect_clone_targets() JL_CANSAFEPOINT; +extern "C" JL_DLLEXPORT jl_value_t *jl_feature_bits_to_string(const uint8_t *bits, int32_t nwords) JL_CANSAFEPOINT; #endif #endif diff --git a/src/rtutils.c b/src/rtutils.c index 363f0ad755fc7..9cd16c25e9796 100644 --- a/src/rtutils.c +++ b/src/rtutils.c @@ -32,7 +32,7 @@ extern "C" { // exceptions ----------------------------------------------------------------- -JL_DLLEXPORT void JL_NORETURN jl_error(const char *str) +JL_DLLEXPORT void JL_NORETURN JL_NO_SAFEPOINT_ANALYSIS jl_error(const char *str) { if (jl_errorexception_type == NULL) { jl_printf(JL_STDERR, "ERROR: %s\n", str); @@ -70,7 +70,7 @@ jl_value_t *jl_vexceptionf(jl_datatype_t *exception_type, return e; } -JL_DLLEXPORT void JL_NORETURN jl_errorf(const char *fmt, ...) +JL_DLLEXPORT void JL_NORETURN JL_NO_SAFEPOINT_ANALYSIS jl_errorf(const char *fmt, ...) { va_list args; va_start(args, fmt); @@ -79,7 +79,7 @@ JL_DLLEXPORT void JL_NORETURN jl_errorf(const char *fmt, ...) jl_throw(e); } -JL_DLLEXPORT void JL_NORETURN jl_exceptionf(jl_datatype_t *exception_type, +JL_DLLEXPORT void JL_NORETURN JL_NO_SAFEPOINT_ANALYSIS jl_exceptionf(jl_datatype_t *exception_type, const char *fmt, ...) { va_list args; @@ -99,18 +99,18 @@ jl_value_t *jl_get_exceptionf(jl_datatype_t *exception_type, return e; } -JL_DLLEXPORT void JL_NORETURN jl_too_few_args(const char *fname, int min) +JL_DLLEXPORT void JL_NORETURN JL_NO_SAFEPOINT_ANALYSIS jl_too_few_args(const char *fname, int min) { jl_exceptionf(jl_argumenterror_type, "%s: too few arguments (expected %d)", fname, min); } -JL_DLLEXPORT void JL_NORETURN jl_too_many_args(const char *fname, int max) +JL_DLLEXPORT void JL_NORETURN JL_NO_SAFEPOINT_ANALYSIS jl_too_many_args(const char *fname, int max) { jl_exceptionf(jl_argumenterror_type, "%s: too many arguments (expected %d)", fname, max); } // with function name / location description, plus extra context -JL_DLLEXPORT void JL_NORETURN jl_type_error_rt(const char *fname, const char *context, +JL_DLLEXPORT void JL_NORETURN JL_NO_SAFEPOINT_ANALYSIS jl_type_error_rt(const char *fname, const char *context, jl_value_t *expected JL_MAYBE_UNROOTED, jl_value_t *got JL_MAYBE_UNROOTED) { @@ -121,7 +121,7 @@ JL_DLLEXPORT void JL_NORETURN jl_type_error_rt(const char *fname, const char *co jl_throw(ex); } -JL_DLLEXPORT void JL_NORETURN jl_type_error_global(const char *fname, jl_module_t *mod, jl_sym_t *sym, +JL_DLLEXPORT void JL_NORETURN JL_NO_SAFEPOINT_ANALYSIS jl_type_error_global(const char *fname, jl_module_t *mod, jl_sym_t *sym, jl_value_t *expected JL_MAYBE_UNROOTED, jl_value_t *got JL_MAYBE_UNROOTED) { @@ -133,14 +133,14 @@ JL_DLLEXPORT void JL_NORETURN jl_type_error_global(const char *fname, jl_module_ // with function name or description only -JL_DLLEXPORT void JL_NORETURN jl_type_error(const char *fname, +JL_DLLEXPORT void JL_NORETURN JL_NO_SAFEPOINT_ANALYSIS jl_type_error(const char *fname, jl_value_t *expected JL_MAYBE_UNROOTED, jl_value_t *got JL_MAYBE_UNROOTED) { jl_type_error_rt(fname, "", expected, got); } -JL_DLLEXPORT void JL_NORETURN jl_undefined_var_error(jl_sym_t *var, jl_value_t *scope) +JL_DLLEXPORT void JL_NORETURN JL_NO_SAFEPOINT_ANALYSIS jl_undefined_var_error(jl_sym_t *var, jl_value_t *scope) { if (!jl_undefvarerror_type) { const char *s1 = ""; @@ -167,19 +167,19 @@ JL_DLLEXPORT void JL_NORETURN jl_undefined_var_error(jl_sym_t *var, jl_value_t * jl_throw(jl_new_struct(jl_undefvarerror_type, var, active_age, scope)); } -JL_DLLEXPORT void JL_NORETURN jl_has_no_field_error(jl_datatype_t *t, jl_sym_t *var) +JL_DLLEXPORT void JL_NORETURN JL_NO_SAFEPOINT_ANALYSIS jl_has_no_field_error(jl_datatype_t *t, jl_sym_t *var) { jl_throw(jl_new_struct(jl_fielderror_type, t, var)); } -JL_DLLEXPORT void JL_NORETURN jl_argument_error(char *str) // == jl_exceptionf(jl_argumenterror_type, "%s", str) +JL_DLLEXPORT void JL_NORETURN JL_NO_SAFEPOINT_ANALYSIS jl_argument_error(char *str) // == jl_exceptionf(jl_argumenterror_type, "%s", str) { jl_value_t *msg = jl_pchar_to_string((char*)str, strlen(str)); JL_GC_PUSH1(&msg); jl_throw(jl_new_struct(jl_argumenterror_type, msg)); } -JL_DLLEXPORT void JL_NORETURN jl_atomic_error(char *str) // == jl_exceptionf(jl_atomicerror_type, "%s", str) +JL_DLLEXPORT void JL_NORETURN JL_NO_SAFEPOINT_ANALYSIS jl_atomic_error(char *str) // == jl_exceptionf(jl_atomicerror_type, "%s", str) { jl_value_t *msg = jl_pchar_to_string((char*)str, strlen(str)); JL_GC_PUSH1(&msg); @@ -187,13 +187,13 @@ JL_DLLEXPORT void JL_NORETURN jl_atomic_error(char *str) // == jl_exceptionf(jl_ } -JL_DLLEXPORT void JL_NORETURN jl_bounds_error(jl_value_t *v, jl_value_t *t) +JL_DLLEXPORT void JL_NORETURN JL_NO_SAFEPOINT_ANALYSIS jl_bounds_error(jl_value_t *v, jl_value_t *t) { JL_GC_PUSH2(&v, &t); // root arguments so the caller doesn't need to jl_throw(jl_new_struct((jl_datatype_t*)jl_boundserror_type, v, t)); } -JL_DLLEXPORT void JL_NORETURN jl_bounds_error_v(jl_value_t *v, jl_value_t **idxs, size_t nidxs) +JL_DLLEXPORT void JL_NORETURN JL_NO_SAFEPOINT_ANALYSIS jl_bounds_error_v(jl_value_t *v, jl_value_t **idxs, size_t nidxs) { jl_value_t *t = NULL; // items in idxs are assumed to already be rooted @@ -202,13 +202,13 @@ JL_DLLEXPORT void JL_NORETURN jl_bounds_error_v(jl_value_t *v, jl_value_t **idxs jl_throw(jl_new_struct((jl_datatype_t*)jl_boundserror_type, v, t)); } -JL_DLLEXPORT void JL_NORETURN jl_bounds_error_tuple_int(jl_value_t **v, size_t nv, size_t i) +JL_DLLEXPORT void JL_NORETURN JL_NO_SAFEPOINT_ANALYSIS jl_bounds_error_tuple_int(jl_value_t **v, size_t nv, size_t i) { // values in v are expected to already be gc-rooted jl_bounds_error_int(jl_f_tuple(NULL, v, nv), i); } -JL_DLLEXPORT void JL_NORETURN jl_bounds_error_unboxed_int(void *data, jl_value_t *vt, size_t i) +JL_DLLEXPORT void JL_NORETURN JL_NO_SAFEPOINT_ANALYSIS jl_bounds_error_unboxed_int(void *data, jl_value_t *vt, size_t i) { jl_value_t *t = NULL, *v = NULL; // data is expected to be gc-safe (either gc-rooted, or alloca) @@ -219,7 +219,7 @@ JL_DLLEXPORT void JL_NORETURN jl_bounds_error_unboxed_int(void *data, jl_value_t jl_throw(jl_new_struct((jl_datatype_t*)jl_boundserror_type, v, t)); } -JL_DLLEXPORT void JL_NORETURN jl_bounds_error_int(jl_value_t *v JL_MAYBE_UNROOTED, size_t i) +JL_DLLEXPORT void JL_NORETURN JL_NO_SAFEPOINT_ANALYSIS jl_bounds_error_int(jl_value_t *v JL_MAYBE_UNROOTED, size_t i) { jl_value_t *t = NULL; JL_GC_PUSH2(&v, &t); // root arguments so the caller doesn't need to @@ -227,7 +227,7 @@ JL_DLLEXPORT void JL_NORETURN jl_bounds_error_int(jl_value_t *v JL_MAYBE_UNROOTE jl_throw(jl_new_struct((jl_datatype_t*)jl_boundserror_type, v, t)); } -JL_DLLEXPORT void JL_NORETURN jl_bounds_error_ints(jl_value_t *v JL_MAYBE_UNROOTED, +JL_DLLEXPORT void JL_NORETURN JL_NO_SAFEPOINT_ANALYSIS jl_bounds_error_ints(jl_value_t *v JL_MAYBE_UNROOTED, size_t *idxs, size_t nidxs) { size_t i; @@ -281,7 +281,8 @@ JL_DLLEXPORT void jl_enter_handler(jl_task_t *ct, jl_handler_t *eh) // * We leave a try block through normal control flow // * An exception causes a nonlocal jump to the catch block. In this case // there's additional cleanup required, eg pushing the exception stack. -JL_DLLEXPORT void jl_eh_restore_state(jl_task_t *ct, jl_handler_t *eh) +// Safepoint analysis will be confused by the jl_mutex_unlock_nogc here, so disable it +JL_DLLEXPORT void jl_eh_restore_state(jl_task_t *ct, jl_handler_t *eh) JL_NO_SAFEPOINT_ANALYSIS { #ifdef _OS_WINDOWS_ if (ct->ptls->needs_resetstkoflw) { @@ -385,7 +386,7 @@ static void jl_copy_excstack(jl_excstack_t *dest, jl_excstack_t *src) JL_NOTSAFE } static void jl_reserve_excstack(jl_task_t *ct, jl_excstack_t **stack JL_REQUIRE_ROOTED_SLOT, - size_t reserved_size) + size_t reserved_size) JL_CANSAFEPOINT { jl_excstack_t *s = *stack; if (s && s->reserved_size >= reserved_size) @@ -588,7 +589,7 @@ JL_DLLEXPORT void jl_flush_cstdio(void) JL_NOTSAFEPOINT fflush(stderr); } -JL_DLLEXPORT jl_value_t *jl_stderr_obj(void) JL_NOTSAFEPOINT +JL_DLLEXPORT jl_value_t *jl_stderr_obj(void) { if (jl_base_module == NULL) return NULL; @@ -603,6 +604,19 @@ struct recur_list { jl_value_t *v; }; +// redeclare jl_printf as NOTSAFEPOINT so that analysis ignores it +// this is safe if the user doesn't pass libuv objects here +#ifdef __clang_safetyanalysis__ +#undef jl_printf +#undef jl_is_operator +#define jl_printf jl_printf_nosafepoint +JL_DLLEXPORT int jl_printf(struct uv_stream_s *s, const char *format, ...) JL_NOTSAFEPOINT; +#define jl_uv_puts jl_uv_puts_nosafepoint +JL_DLLEXPORT void jl_uv_puts(struct uv_stream_s *stream, const char *str, size_t n) JL_NOTSAFEPOINT; +#define jl_is_operator jl_is_operator_unsound +JL_DLLEXPORT int jl_is_operator(const char *sym) JL_NOTSAFEPOINT; +#endif + static size_t jl_static_show_x(JL_STREAM *out, jl_value_t *v, struct recur_list *depth, jl_static_show_config_t ctx) JL_NOTSAFEPOINT; static size_t jl_static_show_x_(JL_STREAM *out, jl_value_t *v, jl_datatype_t *vt, struct recur_list *depth, jl_static_show_config_t ctx) JL_NOTSAFEPOINT; static size_t jl_static_show_next_(JL_STREAM *out, jl_value_t *v, jl_value_t *prev, struct recur_list *depth, jl_static_show_config_t ctx) JL_NOTSAFEPOINT; @@ -741,7 +755,14 @@ static int is_globname_binding(jl_value_t *v, jl_datatype_t *dv) JL_NOTSAFEPOINT { jl_sym_t *globname = dv->name->singletonname; if (globname && dv->name->module) { +#ifdef __clang_safetyanalysis__ +#define jl_get_module_binding jl_get_module_binding_nosafepoint +JL_DLLEXPORT jl_binding_t *jl_get_module_binding(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var, int alloc) JL_NOTSAFEPOINT; +#endif jl_binding_t *b = jl_get_module_binding(dv->name->module, globname, 0); +#ifdef __clang_safetyanalysis__ +#undef jl_get_module_binding +#endif jl_value_t *bv = jl_get_latest_binding_value_if_resolved_and_const_debug_only(b); if (bv && ((jl_value_t*)dv == v ? jl_typeof(bv) == v : bv == v)) return 1; @@ -1714,6 +1735,14 @@ JL_DLLEXPORT void jl__(void *jl_value) JL_NOTSAFEPOINT jl_safe_static_show_((JL_STREAM*)STDERR_FILENO, (jl_value_t*)jl_value, ctx); } +#ifdef __clang_safetyanalysis__ +#undef jl_printf +#undef jl_uv_puts +#undef jl_is_operator +#define jl_printf ijl_printf +#define jl_is_operator ijl_is_operator +#endif + JL_DLLEXPORT void jl_breakpoint(jl_value_t *v) { // put a breakpoint in your debugger here diff --git a/src/runtime_ccall.c b/src/runtime_ccall.c index f106fba8d7f9c..0972f21bec036 100644 --- a/src/runtime_ccall.c +++ b/src/runtime_ccall.c @@ -25,7 +25,7 @@ jl_value_t *jl_libdl_dlopen_func JL_GLOBALLY_ROOTED; static htable_t libMap; static jl_mutex_t libmap_lock; -void *jl_get_library_(const char *f_lib, int throw_err) +void *jl_get_library_(const char *f_lib, int throw_err) JL_CANSAFEPOINT { if (f_lib == NULL) return jl_RTLD_DEFAULT_handle; @@ -97,7 +97,7 @@ void *jl_lazy_load_and_lookup(jl_value_t *lib_val, jl_value_t *f_name) // miscellany JL_DLLEXPORT -jl_value_t *jl_get_JIT(void) +jl_value_t *jl_get_JIT(void) JL_CANSAFEPOINT { const char *JITName = "ORCJIT"; return jl_pchar_to_string(JITName, strlen(JITName)); diff --git a/src/runtime_intrinsics.c b/src/runtime_intrinsics.c index 9a5815ed9ac1a..11b2512e665d2 100644 --- a/src/runtime_intrinsics.c +++ b/src/runtime_intrinsics.c @@ -984,7 +984,8 @@ uu_iintrinsic(name, u) static inline jl_value_t *jl_iintrinsic_1(jl_value_t *a, const char *name, char (*getsign)(void*, unsigned), - jl_value_t *(*lambda1)(jl_value_t*, void*, unsigned, unsigned, const void*), const void *list) + jl_value_t *(*lambda1)(jl_value_t*, void*, unsigned, unsigned, const void*) JL_CANSAFEPOINT, + const void *list) JL_CANSAFEPOINT { jl_value_t *ty = jl_typeof(a); if (!jl_is_primitivetype(ty)) @@ -1012,7 +1013,7 @@ jl_value_t *jl_iintrinsic_1(jl_value_t *a, const char *name, return newv; } -static inline jl_value_t *jl_intrinsiclambda_ty1(jl_value_t *ty, void *pa, unsigned osize, unsigned osize2, const void *voidlist) +static inline jl_value_t *jl_intrinsiclambda_ty1(jl_value_t *ty, void *pa, unsigned osize, unsigned osize2, const void *voidlist) JL_CANSAFEPOINT { intrinsic_1_t op = select_intrinsic_1(osize2, (const intrinsic_1_t*)voidlist); void *pr = alloca(osize2); @@ -1020,7 +1021,7 @@ static inline jl_value_t *jl_intrinsiclambda_ty1(jl_value_t *ty, void *pa, unsig return jl_new_bits(ty, pr); } -static inline jl_value_t *jl_intrinsiclambda_u1(jl_value_t *ty, void *pa, unsigned osize, unsigned osize2, const void *voidlist) +static inline jl_value_t *jl_intrinsiclambda_u1(jl_value_t *ty, void *pa, unsigned osize, unsigned osize2, const void *voidlist) JL_CANSAFEPOINT { jl_task_t *ct = jl_current_task; intrinsic_u1_t op = select_intrinsic_u1(osize2, (const intrinsic_u1_t*)voidlist); @@ -1047,7 +1048,7 @@ JL_DLLEXPORT jl_value_t *jl_##name(jl_value_t *ty, jl_value_t *a) \ return jl_intrinsic_cvt(ty, a, #name, LLVMOP); \ } -static inline jl_value_t *jl_intrinsic_cvt(jl_value_t *ty, jl_value_t *a, const char *name, intrinsic_cvt_t op) +static inline jl_value_t *jl_intrinsic_cvt(jl_value_t *ty, jl_value_t *a, const char *name, intrinsic_cvt_t op) JL_CANSAFEPOINT { JL_TYPECHKS(name, datatype, ty); if (!jl_is_concrete_type(ty) || !jl_is_primitivetype(ty)) @@ -1069,7 +1070,7 @@ un_fintrinsic_bfloat(OP, jl_##name##bf16) \ un_fintrinsic_half(OP, jl_##name##16) \ un_fintrinsic_ctype(OP, jl_##name##32, float) \ un_fintrinsic_ctype(OP, jl_##name##64, double) \ -JL_DLLEXPORT jl_value_t *jl_##name(jl_value_t *ty, jl_value_t *a) \ +JL_DLLEXPORT jl_value_t *jl_##name(jl_value_t *ty, jl_value_t *a) JL_CANSAFEPOINT \ { \ return jl_fintrinsic_1(ty, a, #name, jl_##name##bf16, jl_##name##16, jl_##name##32, jl_##name##64); \ } @@ -1083,7 +1084,7 @@ JL_DLLEXPORT jl_value_t *jl_##name(jl_value_t *a) \ typedef void (*fintrinsic_op1)(unsigned, jl_value_t*, void*, void*) JL_NOTSAFEPOINT; -static inline jl_value_t *jl_fintrinsic_1(jl_value_t *ty, jl_value_t *a, const char *name, fintrinsic_op1 bfloatop, fintrinsic_op1 halfop, fintrinsic_op1 floatop, fintrinsic_op1 doubleop) +static inline jl_value_t *jl_fintrinsic_1(jl_value_t *ty, jl_value_t *a, const char *name, fintrinsic_op1 bfloatop, fintrinsic_op1 halfop, fintrinsic_op1 floatop, fintrinsic_op1 doubleop) JL_CANSAFEPOINT { jl_task_t *ct = jl_current_task; jl_datatype_t *aty = (jl_datatype_t *)jl_typeof(a); @@ -1191,8 +1192,9 @@ checked_iintrinsic(name, u, jl_intrinsiclambda_checkeddiv) static inline jl_value_t *jl_iintrinsic_2(jl_value_t *a, jl_value_t *b, const char *name, char (*getsign)(void*, unsigned), - jl_value_t *(*lambda2)(jl_value_t*, void*, void*, unsigned, unsigned, const void*), - const void *list, int cvtb) + jl_value_t *(*lambda2)(jl_value_t*, void*, void*, unsigned, unsigned, const void*) JL_CANSAFEPOINT, + const void *list, + int cvtb) JL_CANSAFEPOINT { jl_value_t *ty = jl_typeof(a); jl_value_t *tyb = jl_typeof(b); @@ -1228,7 +1230,7 @@ jl_value_t *jl_iintrinsic_2(jl_value_t *a, jl_value_t *b, const char *name, return newv; } -static inline jl_value_t *jl_intrinsiclambda_2(jl_value_t *ty, void *pa, void *pb, unsigned sz, unsigned sz2, const void *voidlist) +static inline jl_value_t *jl_intrinsiclambda_2(jl_value_t *ty, void *pa, void *pb, unsigned sz, unsigned sz2, const void *voidlist) JL_CANSAFEPOINT { void *pr = alloca(sz2); intrinsic_2_t op = select_intrinsic_2(sz2, (const intrinsic_2_t*)voidlist); @@ -1243,7 +1245,7 @@ static inline jl_value_t *jl_intrinsiclambda_cmp(jl_value_t *ty, void *pa, void return cmp ? jl_true : jl_false; } -static inline jl_value_t *jl_intrinsiclambda_checked(jl_value_t *ty, void *pa, void *pb, unsigned sz, unsigned sz2, const void *voidlist) +static inline jl_value_t *jl_intrinsiclambda_checked(jl_value_t *ty, void *pa, void *pb, unsigned sz, unsigned sz2, const void *voidlist) JL_CANSAFEPOINT { jl_value_t *params[2]; params[0] = ty; @@ -1260,7 +1262,7 @@ static inline jl_value_t *jl_intrinsiclambda_checked(jl_value_t *ty, void *pa, v *ao = (char)ovflw; return newv; } -static inline jl_value_t *jl_intrinsiclambda_checkeddiv(jl_value_t *ty, void *pa, void *pb, unsigned sz, unsigned sz2, const void *voidlist) +static inline jl_value_t *jl_intrinsiclambda_checkeddiv(jl_value_t *ty, void *pa, void *pb, unsigned sz, unsigned sz2, const void *voidlist) JL_CANSAFEPOINT { void *pr = alloca(sz2); intrinsic_checked_t op = select_intrinsic_checked(sz2, (const intrinsic_checked_t*)voidlist); diff --git a/src/safepoint.c b/src/safepoint.c index c9a85c849204e..d37f45889091d 100644 --- a/src/safepoint.c +++ b/src/safepoint.c @@ -105,7 +105,7 @@ void jl_safepoint_init(void) addr = NULL; #endif if (addr == NULL) { - jl_printf(JL_STDERR, "could not allocate GC synchronization page\n"); + ios_printf(ios_safe_stderr, "could not allocate GC synchronization page\n"); jl_gc_debug_fprint_critical_error(ios_safe_stderr); abort(); } @@ -126,7 +126,7 @@ void jl_safepoint_init(void) jl_safepoint_pages = addr; } -extern void jl_gc_wait_for_the_world(jl_ptls_t* gc_all_tls_states, int gc_n_threads) +extern void jl_gc_wait_for_the_world(jl_ptls_t* gc_all_tls_states, int gc_n_threads) JL_CANSAFEPOINT { JL_TIMING(GC, GC_Stop); #ifdef USE_TRACY @@ -294,9 +294,8 @@ void jl_safepoint_wait_thread_resume(jl_task_t *ct) uv_mutex_unlock(&ct->ptls->sleep_lock); } // This takes the sleep lock and puts the thread in GC_SAFE -int8_t jl_safepoint_take_sleep_lock(jl_ptls_t ptls) +void jl_safepoint_take_sleep_lock(jl_ptls_t ptls) { - int8_t gc_state = jl_gc_safe_enter(ptls); uv_mutex_lock(&ptls->sleep_lock); if (jl_atomic_load_relaxed(&ptls->suspend_count)) { // This dance with the locks is because we are not allowed to hold both these locks at the same time @@ -310,7 +309,6 @@ int8_t jl_safepoint_take_sleep_lock(jl_ptls_t ptls) uv_mutex_unlock(&safepoint_lock); uv_mutex_lock(&ptls->sleep_lock); } - return gc_state; } // n.b. suspended threads may still run in the GC or GC safe regions diff --git a/src/scheduler.c b/src/scheduler.c index 7867e549a717b..ceae3ef01ff50 100644 --- a/src/scheduler.c +++ b/src/scheduler.c @@ -109,7 +109,11 @@ void jl_threadfun(void *arg) JL_GC_PROMISE_ROOTED(ct); // wait for all threads +#ifdef __clang_safetyanalysis__ + jl_gc_safe_enter(ptls); +#else jl_gc_state_set(ptls, JL_GC_STATE_SAFE, JL_GC_STATE_UNSAFE); +#endif uv_barrier_wait(targ->barrier); // free the thread argument here @@ -121,7 +125,7 @@ void jl_threadfun(void *arg) -void jl_init_thread_scheduler(jl_ptls_t ptls) JL_NOTSAFEPOINT +void jl_init_thread_scheduler(jl_ptls_t ptls) { uv_mutex_init(&ptls->sleep_lock); uv_cond_init(&ptls->wake_signal); @@ -376,7 +380,7 @@ JL_DLLEXPORT void jl_wakeup_threadpool(int8_t tpid) } // get the next runnable task -static jl_task_t *get_next_task(jl_value_t *trypoptask, jl_value_t *q) +static jl_task_t *get_next_task(jl_value_t *trypoptask, jl_value_t *q) JL_CANSAFEPOINT { jl_gc_safepoint(); jl_task_t *task = (jl_task_t*)jl_apply_generic(trypoptask, &q, 1); @@ -388,7 +392,7 @@ static jl_task_t *get_next_task(jl_value_t *trypoptask, jl_value_t *q) return NULL; } -static int check_empty(jl_value_t *checkempty) +static int check_empty(jl_value_t *checkempty) JL_CANSAFEPOINT { return jl_apply_generic(checkempty, NULL, 0) == jl_true; } @@ -433,7 +437,7 @@ static int may_sleep(jl_ptls_t ptls) JL_NOTSAFEPOINT } -JL_DLLEXPORT jl_task_t *jl_task_get_next(jl_value_t *trypoptask, jl_value_t *q, jl_value_t *checkempty) +JL_DLLEXPORT jl_task_t *jl_task_get_next(jl_value_t *trypoptask, jl_value_t *q, jl_value_t *checkempty) JL_CANSAFEPOINT { jl_task_t *ct = jl_current_task; uint64_t start_cycles = 0; @@ -574,7 +578,8 @@ JL_DLLEXPORT jl_task_t *jl_task_get_next(jl_value_t *trypoptask, jl_value_t *q, // the other threads will just wait for an individual wake signal to resume JULIA_DEBUG_SLEEPWAKE( ptls->sleep_enter = cycleclock() ); - int8_t gc_state = jl_safepoint_take_sleep_lock(ptls); // This puts the thread in GC_SAFE and takes the sleep lock + int8_t gc_state = jl_gc_safe_enter(ptls); + jl_safepoint_take_sleep_lock(ptls); // This puts the thread in GC_SAFE and takes the sleep lock while (may_sleep(ptls)) { if (ptls->tid == 0) { task = wait_empty; diff --git a/src/signal-handling.c b/src/signal-handling.c index 8ad371959e808..02b64144b2c91 100644 --- a/src/signal-handling.c +++ b/src/signal-handling.c @@ -28,8 +28,8 @@ volatile int profile_running = 0; volatile int profile_all_tasks = 0; static const uint64_t GIGA = 1000000000ULL; // Timers to take samples at intervals -JL_DLLEXPORT void jl_profile_stop_timer(void); -JL_DLLEXPORT int jl_profile_start_timer(uint8_t); +JL_DLLEXPORT void jl_profile_stop_timer(void) JL_NOTSAFEPOINT; +JL_DLLEXPORT int jl_profile_start_timer(uint8_t) JL_NOTSAFEPOINT; /////////////////////// // Utility functions // @@ -111,7 +111,13 @@ static uintptr_t jl_lock_profile_rd_held(void) JL_NOTSAFEPOINT #endif } -int jl_lock_profile(void) +void jl_lock_profile(void) +{ + int got = jl_trylock_profile(); + assert(got); (void)got; +} + +int jl_trylock_profile(void) { uintptr_t held = jl_lock_profile_rd_held(); if (held == -1) @@ -135,7 +141,7 @@ int jl_lock_profile(void) return 1; } -JL_DLLEXPORT void jl_unlock_profile(void) +JL_DLLEXPORT void jl_unlock_profile(void) JL_NO_SAFEPOINT_ANALYSIS { uintptr_t held = jl_lock_profile_rd_held(); assert(held && held != -1); @@ -164,7 +170,7 @@ int jl_lock_profile_wr(void) return 1; } -void jl_unlock_profile_wr(void) +void jl_unlock_profile_wr(void) JL_NO_SAFEPOINT_ANALYSIS { uintptr_t held = jl_lock_profile_rd_held(); assert(held == -1); @@ -210,7 +216,7 @@ static int *profile_get_randperm(int size) } -JL_DLLEXPORT int jl_profile_is_buffer_full(void) +JL_DLLEXPORT int jl_profile_is_buffer_full(void) JL_NOTSAFEPOINT { // Declare buffer full if there isn't enough room to sample even just the // thread metadata and one max-sized frame. The `+ 6` is for the two block @@ -221,7 +227,7 @@ JL_DLLEXPORT int jl_profile_is_buffer_full(void) #define PROFILE_TASK_DEBUG_FORCE_SAMPLING_FAILURE (0) #define PROFILE_TASK_DEBUG_FORCE_STOP_THREAD_FAILURE (0) -void jl_profile_task(void) +void jl_profile_task(void) JL_NOTSAFEPOINT JL_NO_SAFEPOINT_ANALYSIS { if (jl_profile_is_buffer_full()) { // Buffer full: Delete the timer @@ -420,7 +426,7 @@ JL_DLLEXPORT void jl_set_peek_cond(uv_async_t *cond) JL_UNLOCK_NOGC(&profile_show_peek_cond_lock); } -static void jl_check_profile_autostop(void) +static void jl_check_profile_autostop(void) JL_NOTSAFEPOINT { if (profile_show_peek_cond_loc != NULL && profile_autostop_time != -1.0 && jl_hrtime() > profile_autostop_time) { profile_autostop_time = -1.0; @@ -683,7 +689,7 @@ static void jl_fprint_sigill(ios_t *s, void *_ctx) // this is generally quite a foolish operation, but does free you up to do // arbitrary things on this stack now without worrying about corrupt state that // existed already on it -void jl_task_frame_noreturn(jl_task_t *ct) JL_NOTSAFEPOINT +void jl_task_frame_noreturn(jl_task_t *ct) { jl_set_safe_restore(NULL); if (ct) { @@ -693,8 +699,10 @@ void jl_task_frame_noreturn(jl_task_t *ct) JL_NOTSAFEPOINT // Force all locks to drop. Is this a good idea? Of course not. But the alternative would probably deadlock instead of crashing. jl_ptls_t ptls = ct->ptls; small_arraylist_t *locks = &ptls->locks; +#ifndef __clang_safetyanalysis__ for (size_t i = locks->len; i > 0; i--) jl_mutex_unlock_nogc((jl_mutex_t*)locks->items[i - 1]); +#endif locks->len = 0; ptls->in_pure_callback = 0; ptls->in_finalizer = 0; diff --git a/src/signals-unix.c b/src/signals-unix.c index 5066c1d3350e1..9a1ed37242d55 100644 --- a/src/signals-unix.c +++ b/src/signals-unix.c @@ -198,7 +198,7 @@ static int is_addr_on_sigstack(jl_ptls_t ptls, void *ptr) JL_NOTSAFEPOINT // Modify signal context `_ctx` so that `fptr` will execute when the signal returns // The function `fptr` itself must not return. -JL_NO_ASAN static void jl_call_in_ctx(jl_ptls_t ptls, void (*fptr)(void), int sig, void *_ctx) +JL_NO_ASAN static void jl_call_in_ctx(jl_ptls_t ptls, void (*fptr)(void) JL_CANSAFEPOINT, int sig, void *_ctx) { // Modifying the ucontext should work but there is concern that // sigreturn oriented programming mitigation can work against us @@ -350,7 +350,7 @@ static int is_addr_on_stack(jl_task_t *ct, void *addr) JL_NOTSAFEPOINT (char*)addr < (char*)ct->ctx.stkbuf + ct->ctx.bufsz); } -static void sigdie_handler(int sig, siginfo_t *info, void *context) +static void sigdie_handler(int sig, siginfo_t *info, void *context) JL_CANSAFEPOINT { signal(sig, SIG_DFL); uv_tty_reset_mode(); @@ -422,7 +422,7 @@ int exc_reg_is_write_fault(uintptr_t esr) { } #endif -static int jl_thread_suspend_and_get_state(int tid, int timeout, bt_context_t *ctx); +static int jl_thread_suspend_and_get_state(int tid, int timeout, bt_context_t *ctx) JL_NOTSAFEPOINT_ENTER_CONDITIONAL(1); #if defined(HAVE_MACH) #include "signals-mach.c" @@ -508,7 +508,7 @@ static int jl_is_on_sigstack(jl_ptls_t ptls, void *ptr, void *context) JL_NOTSAF is_addr_on_sigstack(ptls, (void*)jl_get_rsp_from_ctx(context))); } -JL_NO_ASAN static void segv_handler(int sig, siginfo_t *info, void *context) +JL_NO_ASAN static void segv_handler(int sig, siginfo_t *info, void *context) JL_CANSAFEPOINT { assert(sig == SIGSEGV || sig == SIGBUS); jl_jmp_buf *saferestore = jl_get_safe_restore(); @@ -570,7 +570,7 @@ static int exit_signal_cond = -1; static int signal_caught_cond = -1; static int signals_inflight = 0; -static int jl_thread_suspend_and_get_state(int tid, int timeout, bt_context_t *ctx) +static int jl_thread_suspend_and_get_state(int tid, int timeout, bt_context_t *ctx) JL_NOTSAFEPOINT_ENTER_CONDITIONAL(1) { int err; pthread_mutex_lock(&in_signal_lock); @@ -652,7 +652,7 @@ void jl_thread_resume(int tid) // Throw jl_interrupt_exception if the master thread is in a signal async region // or if SIGINT happens too often. -static void jl_try_deliver_sigint(void) +static void jl_try_deliver_sigint(void) JL_NOTSAFEPOINT { jl_ptls_t ptls2 = jl_atomic_load_relaxed(&jl_all_tls_states)[0]; jl_safepoint_enable_sigint(); @@ -668,7 +668,7 @@ static void jl_try_deliver_sigint(void) // Write only by signal handling thread, read only by main thread // no sync necessary. static int thread0_exit_signo = 0; -static void jl_exit_thread0_cb(void) +static void jl_exit_thread0_cb(void) JL_CANSAFEPOINT { jl_atomic_fetch_add(&jl_gc_disable_counter, -1); jl_fprint_critical_error(ios_safe_stderr, thread0_exit_signo, 0, NULL, jl_current_task); @@ -702,7 +702,7 @@ static void jl_exit_thread0(int signo, jl_bt_element_t *bt_data, size_t bt_size) // is reached // 3: raise `thread0_exit_signo` and try to exit // 4: no-op -void usr2_handler(int sig, siginfo_t *info, void *ctx) +void usr2_handler(int sig, siginfo_t *info, void *ctx) JL_CANSAFEPOINT { jl_task_t *ct = jl_get_current_task(); if (ct == NULL) @@ -845,7 +845,7 @@ static void allocate_segv_handler(void) struct sigaction act; memset(&act, 0, sizeof(struct sigaction)); sigemptyset(&act.sa_mask); - act.sa_sigaction = segv_handler; + act.sa_sigaction = segv_handler; // NOLINT(julia-first-decl-annotations) act.sa_flags = SA_ONSTACK | SA_SIGINFO; if (sigaction(SIGSEGV, &act, NULL) < 0) { jl_errorf("fatal error: sigaction: %s", strerror(errno)); @@ -977,7 +977,7 @@ static void do_critical_profile(void) } } -static void do_profile(void) +static void do_profile(void) JL_NOTSAFEPOINT { bt_context_t signal_context; int nthreads = jl_atomic_load_acquire(&jl_n_threads); @@ -1037,7 +1037,7 @@ static void do_profile(void) } #endif -static void *signal_listener(void *arg) +static void *signal_listener(void *arg) JL_NOTSAFEPOINT { sigset_t sset; int sig, critical, profile; @@ -1257,7 +1257,7 @@ void restore_signals(void) } } -static void fpe_handler(int sig, siginfo_t *info, void *context) +static void fpe_handler(int sig, siginfo_t *info, void *context) JL_CANSAFEPOINT { (void)info; jl_jmp_buf *saferestore = jl_get_safe_restore(); @@ -1293,7 +1293,7 @@ static void sigint_handler(int sig) } #if defined(_OS_DARWIN_) && defined(_CPU_AARCH64_) -static void sigtrap_handler(int sig, siginfo_t *info, void *context) +static void sigtrap_handler(int sig, siginfo_t *info, void *context) JL_CANSAFEPOINT { uintptr_t pc = ((ucontext_t*)context)->uc_mcontext->__ss.__pc; // TODO: Do this in linux as well uint32_t* code = (uint32_t*)(pc); // https://gcc.gnu.org/legacy-ml/gcc-patches/2013-11/msg02228.html @@ -1310,7 +1310,7 @@ void jl_install_default_signal_handlers(void) struct sigaction actf; memset(&actf, 0, sizeof(struct sigaction)); sigemptyset(&actf.sa_mask); - actf.sa_sigaction = fpe_handler; + actf.sa_sigaction = fpe_handler; // NOLINT(julia-first-decl-annotations) actf.sa_flags = SA_SIGINFO; if (sigaction(SIGFPE, &actf, NULL) < 0) { jl_errorf("fatal error: sigaction: %s", strerror(errno)); @@ -1319,7 +1319,7 @@ void jl_install_default_signal_handlers(void) struct sigaction acttrap; memset(&acttrap, 0, sizeof(struct sigaction)); sigemptyset(&acttrap.sa_mask); - acttrap.sa_sigaction = sigtrap_handler; + acttrap.sa_sigaction = sigtrap_handler; // NOLINT(julia-first-decl-annotations) acttrap.sa_flags = SA_SIGINFO; if (sigaction(SIGTRAP, &acttrap, NULL) < 0) { jl_errorf("fatal error: sigaction: %s", strerror(errno)); @@ -1347,7 +1347,7 @@ void jl_install_default_signal_handlers(void) struct sigaction act; memset(&act, 0, sizeof(struct sigaction)); sigemptyset(&act.sa_mask); - act.sa_sigaction = usr2_handler; + act.sa_sigaction = usr2_handler; // NOLINT(julia-first-decl-annotations) act.sa_flags = SA_SIGINFO | SA_RESTART; if (sigaction(SIGUSR2, &act, NULL) < 0) { jl_errorf("fatal error: sigaction: %s", strerror(errno)); @@ -1359,7 +1359,7 @@ void jl_install_default_signal_handlers(void) struct sigaction act_die; memset(&act_die, 0, sizeof(struct sigaction)); sigemptyset(&act_die.sa_mask); - act_die.sa_sigaction = sigdie_handler; + act_die.sa_sigaction = sigdie_handler; // NOLINT(julia-first-decl-annotations) act_die.sa_flags = SA_SIGINFO | SA_RESETHAND; if (sigaction(SIGILL, &act_die, NULL) < 0) { jl_errorf("fatal error: sigaction: %s", strerror(errno)); diff --git a/src/smallintset.c b/src/smallintset.c index 6b6e5ef355324..75b44f29641f0 100644 --- a/src/smallintset.c +++ b/src/smallintset.c @@ -103,7 +103,7 @@ void smallintset_empty(const jl_genericmemory_t *a) JL_NOTSAFEPOINT memset(a->ptr, 0, a->length * elsize); } -static jl_genericmemory_t *jl_alloc_int_1d(size_t np, size_t len) +static jl_genericmemory_t *jl_alloc_int_1d(size_t np, size_t len) JL_CANSAFEPOINT { jl_value_t *ty; if (np < 0xFF) diff --git a/src/stackwalk.c b/src/stackwalk.c index 6356ddc4a893d..aaa8e46a6ede2 100644 --- a/src/stackwalk.c +++ b/src/stackwalk.c @@ -85,7 +85,8 @@ static int jl_unw_stepn(bt_cursor_t *cursor, jl_bt_element_t *bt_data, size_t *b skip--; } #endif - jl_lock_profile(); + if (!jl_trylock_profile()) + return 0; #endif #if !defined(_OS_WINDOWS_) // no point on windows, since RtlVirtualUnwind won't give us a second chance if the segfault happens in ntdll jl_jmp_buf *old_buf = jl_get_safe_restore(); @@ -320,7 +321,7 @@ JL_DLLEXPORT jl_value_t *jl_backtrace_from_here(int returnsp, int skip) static void decode_backtrace(jl_bt_element_t *bt_data, size_t bt_size, jl_array_t **btout JL_REQUIRE_ROOTED_SLOT, - jl_array_t **bt2out JL_REQUIRE_ROOTED_SLOT) + jl_array_t **bt2out JL_REQUIRE_ROOTED_SLOT) JL_CANSAFEPOINT { jl_array_t *bt, *bt2; if (array_ptr_void_type == NULL) { @@ -371,7 +372,7 @@ JL_DLLEXPORT jl_value_t *jl_get_backtrace(void) // with the top of the stack and returning up to `max_entries`. If requested by // setting the `include_bt` flag, backtrace data in bt,bt2 format is // interleaved. -JL_DLLEXPORT jl_value_t *jl_get_excstack(jl_task_t* task, int include_bt, int max_entries) +JL_DLLEXPORT jl_value_t *jl_get_excstack(jl_task_t* task, int include_bt, int max_entries) JL_CANSAFEPOINT { JL_TYPECHK(current_exceptions, task, (jl_value_t*)task); JL_TIMING(STACKWALK, STACKWALK_Excstack); @@ -790,7 +791,7 @@ static int jl_unw_step(bt_cursor_t *cursor, int from_signal_handler, uintptr_t * } #endif -JL_DLLEXPORT jl_value_t *jl_lookup_code_address(void *ip, int skipC) +JL_DLLEXPORT jl_value_t *jl_lookup_code_address(void *ip, int skipC) JL_CANSAFEPOINT { jl_task_t *ct = jl_current_task; jl_frame_t *frames = NULL; @@ -1427,23 +1428,47 @@ return 0; #endif } -JL_DLLEXPORT size_t jl_try_record_thread_backtrace(jl_ptls_t ptls2, jl_bt_element_t *bt_data, size_t max_bt_size) JL_NOTSAFEPOINT +JL_DLLEXPORT size_t jl_try_record_thread_backtrace(jl_ptls_t ptls2, jl_bt_element_t *bt_data, size_t max_bt_size) { int16_t tid = ptls2->tid; jl_task_t *t = NULL; bt_context_t *context = NULL; bt_context_t c; - if (!jl_thread_suspend(tid, &c)) { - return 0; + size_t bt_size = 0; + if (jl_thread_suspend(tid, &c)) { + // thread is stopped, safe to read the task it was running before we stopped it + t = jl_atomic_load_relaxed(&ptls2->current_task); + context = &c; + bt_size = rec_backtrace_ctx(bt_data, max_bt_size, context, ptls2->previous_task ? NULL : t->gcstack); + jl_thread_resume(tid); } - // thread is stopped, safe to read the task it was running before we stopped it - t = jl_atomic_load_relaxed(&ptls2->current_task); - context = &c; - size_t bt_size = rec_backtrace_ctx(bt_data, max_bt_size, context, ptls2->previous_task ? NULL : t->gcstack); - jl_thread_resume(tid); return bt_size; } +static size_t rec_backtrace_task(jl_task_t *t, bt_context_t *c, int use_ctx, jl_bt_element_t *bt_data, size_t max_bt_size, int all_tasks_profiler) JL_NOTSAFEPOINT +{ + if (!use_ctx && !t->ctx.copy_stack && t->ctx.started && t->ctx.ctx != NULL) { + // need to read the context from the task stored state + jl_jmp_buf *mctx = &t->ctx.ctx->uc_mcontext; +#if defined(JL_TASK_SWITCH_WINDOWS) + memset(c, 0, sizeof(*c)); + if (jl_simulate_longjmp(*mctx, c)) + use_ctx = 1; +#elif defined(JL_TASK_SWITCH_LIBUNWIND) + context = t->ctx.ctx; +#elif defined(JL_TASK_SWITCH_ASM) + memset(c, 0, sizeof(*c)); + if (jl_simulate_longjmp(*mctx, c)) + use_ctx = 1; +#else + #pragma message("jl_record_backtrace not defined for unknown task system") +#endif + } + if (use_ctx) + return rec_backtrace_ctx(bt_data, max_bt_size, c, all_tasks_profiler ? NULL : t->gcstack); + return 0; +} + JL_DLLEXPORT jl_record_backtrace_result_t jl_record_backtrace(jl_task_t *t, jl_bt_element_t *bt_data, size_t max_bt_size, int all_tasks_profiler) JL_NOTSAFEPOINT { int16_t tid = INT16_MAX; @@ -1461,11 +1486,14 @@ JL_DLLEXPORT jl_record_backtrace_result_t jl_record_backtrace(jl_task_t *t, jl_b result.tid = tid; return result; } - bt_context_t *context = NULL; bt_context_t c; int16_t old; - for (old = -1; !jl_atomic_cmpswap(&t->tid, &old, tid) && old != tid; old = -1) { - // if this task is already running somewhere, we need to stop the thread it is running on and query its state + while (1) { + old = INT16_MAX; + // Try to lock this task, if free, otherwise get the id of the thread running it + if (jl_atomic_cmpswap(&t->tid, &old, tid) || old == tid) + break; + // Try to stop that thread if (!jl_thread_suspend(old, &c)) { if (jl_atomic_load_relaxed(&t->tid) != old) continue; @@ -1473,43 +1501,25 @@ JL_DLLEXPORT jl_record_backtrace_result_t jl_record_backtrace(jl_task_t *t, jl_b } if (jl_atomic_load_relaxed(&t->tid) == old) { jl_ptls_t ptls2 = jl_atomic_load_relaxed(&jl_all_tls_states)[old]; + int use_ctx = 0; if (ptls2->previous_task == t || // we might print the wrong stack here, since we can't know whether we executed the swapcontext yet or not, but it at least avoids trying to access the state inside uc_mcontext which might not be set yet (ptls2->previous_task == NULL && jl_atomic_load_relaxed(&ptls2->current_task) == t)) { // this case should be always accurate // use the thread context for the unwind state - context = &c; + use_ctx = 1; } - break; + result.bt_size = rec_backtrace_task(t, &c, use_ctx, bt_data, max_bt_size, all_tasks_profiler); + result.tid = old; + jl_thread_resume(old); + return result; } // got the wrong thread stopped, try again jl_thread_resume(old); } - if (context == NULL && (!t->ctx.copy_stack && t->ctx.started && t->ctx.ctx != NULL)) { - // need to read the context from the task stored state - jl_jmp_buf *mctx = &t->ctx.ctx->uc_mcontext; -#if defined(JL_TASK_SWITCH_WINDOWS) - memset(&c, 0, sizeof(c)); - if (jl_simulate_longjmp(*mctx, &c)) - context = &c; -#elif defined(JL_TASK_SWITCH_LIBUNWIND) - context = t->ctx.ctx; -#elif defined(JL_TASK_SWITCH_ASM) - memset(&c, 0, sizeof(c)); - if (jl_simulate_longjmp(*mctx, &c)) - context = &c; -#else - #pragma message("jl_record_backtrace not defined for unknown task system") -#endif - } - size_t bt_size = 0; - if (context) { - bt_size = rec_backtrace_ctx(bt_data, max_bt_size, context, all_tasks_profiler ? NULL : t->gcstack); - } - if (old == -1) - jl_atomic_store_relaxed(&t->tid, old); - else if (old != tid) - jl_thread_resume(old); - result.bt_size = bt_size; + // This task is locked to our thread + result.bt_size = rec_backtrace_task(t, &c, 0, bt_data, max_bt_size, all_tasks_profiler); result.tid = old; + if (old == INT16_MAX) + jl_atomic_store_relaxed(&t->tid, old); return result; } diff --git a/src/staticdata.c b/src/staticdata.c index 12fcc3070e6c3..e2a72cc0dfdef 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -435,7 +435,7 @@ static void record_field_change(jl_value_t **addr, jl_value_t *newval) JL_NOTSAF ptrhash_put(&field_replace, (void*)addr, newval); } -static jl_value_t *get_replaceable_field(jl_value_t **addr, int mutabl) JL_GC_DISABLED +static jl_value_t *get_replaceable_field(jl_value_t **addr, int mutabl) JL_CANSAFEPOINT JL_GC_DISABLED { jl_value_t *fld = (jl_value_t*)ptrhash_get(&field_replace, addr); if (fld == HT_NOTFOUND) { @@ -524,9 +524,9 @@ static int effects_foldable(uint32_t effects) // `jl_queue_for_serialization` adds items to `serialization_order` #define jl_queue_for_serialization(s, v) jl_queue_for_serialization_((s), (jl_value_t*)(v), 1, 0) -static void jl_queue_for_serialization_(jl_serializer_state *s, jl_value_t *v, int recursive, int immediate) JL_GC_DISABLED; +static void jl_queue_for_serialization_(jl_serializer_state *s, jl_value_t *v, int recursive, int immediate) JL_CANSAFEPOINT JL_GC_DISABLED; -static void jl_queue_module_for_serialization(jl_serializer_state *s, jl_module_t *m) JL_GC_DISABLED +static void jl_queue_module_for_serialization(jl_serializer_state *s, jl_module_t *m) JL_CANSAFEPOINT JL_GC_DISABLED { jl_queue_for_serialization(s, m->name); jl_queue_for_serialization(s, m->parent); @@ -590,7 +590,7 @@ static int codeinst_may_be_runnable(jl_code_instance_t *ci, int incremental) { // you want to handle uniquing of `Dict{String,Float64}` before you tackle `Vector{Dict{String,Float64}}`. // Uniquing is done in `serialization_order`, so the very first mention of such an object must // be the "source" rather than merely a cross-reference. -static void jl_insert_into_serialization_queue(jl_serializer_state *s, jl_value_t *v, int recursive, int immediate) JL_GC_DISABLED +static void jl_insert_into_serialization_queue(jl_serializer_state *s, jl_value_t *v, int recursive, int immediate) JL_CANSAFEPOINT JL_GC_DISABLED { jl_datatype_t *t = (jl_datatype_t*)jl_typeof(v); jl_queue_for_serialization_(s, (jl_value_t*)t, 1, immediate); @@ -1013,7 +1013,7 @@ static void jl_queue_for_serialization_(jl_serializer_state *s, jl_value_t *v, i // Do a pre-order traversal of the to-serialize worklist, in the identical order // to the calls to jl_queue_for_serialization would occur in a purely recursive // implementation, but without potentially running out of stack. -static void jl_serialize_reachable(jl_serializer_state *s) JL_GC_DISABLED +static void jl_serialize_reachable(jl_serializer_state *s) JL_CANSAFEPOINT JL_GC_DISABLED { size_t i, prevlen = 0; while (1) { @@ -1076,7 +1076,7 @@ static void write_pointer(ios_t *s) JL_NOTSAFEPOINT } // Records the buildid holding `v` and returns the tagged offset within the corresponding image -static uintptr_t add_external_linkage(jl_serializer_state *s, jl_value_t *v, jl_array_t *link_ids) JL_GC_DISABLED +static uintptr_t add_external_linkage(jl_serializer_state *s, jl_value_t *v, jl_array_t *link_ids) JL_CANSAFEPOINT JL_GC_DISABLED { image_metadata_t *meta = external_blob_metadata(v); if (meta) { @@ -1107,7 +1107,7 @@ static uintptr_t add_external_linkage(jl_serializer_state *s, jl_value_t *v, jl_ // but symbols, small integers, and a couple of special items (`nothing` and the root Task) // have special handling. #define backref_id(s, v, link_ids) _backref_id(s, (jl_value_t*)(v), link_ids) -static uintptr_t _backref_id(jl_serializer_state *s, jl_value_t *v, jl_array_t *link_ids) JL_GC_DISABLED JL_NOTSAFEPOINT +static uintptr_t _backref_id(jl_serializer_state *s, jl_value_t *v, jl_array_t *link_ids) JL_GC_DISABLED JL_CANSAFEPOINT { assert(v != NULL && "cannot get backref to NULL object"); if (jl_is_symbol(v)) { @@ -1176,7 +1176,7 @@ static void record_uniquing(jl_serializer_state *s, jl_value_t *fld, uintptr_t o // Save blank space in stream `s` for a pointer `fld`, storing both location and target // in `relocs_list`. -static void write_pointerfield(jl_serializer_state *s, jl_value_t *fld) JL_NOTSAFEPOINT +static void write_pointerfield(jl_serializer_state *s, jl_value_t *fld) JL_CANSAFEPOINT JL_GC_DISABLED { if (fld != NULL) { arraylist_push(&s->relocs_list, (void*)(uintptr_t)ios_pos(s->s)); @@ -1188,7 +1188,7 @@ static void write_pointerfield(jl_serializer_state *s, jl_value_t *fld) JL_NOTSA // Save blank space in stream `s` for a pointer `fld`, storing both location and target // in `gctags_list`. -static void write_gctaggedfield(jl_serializer_state *s, jl_datatype_t *ref) JL_NOTSAFEPOINT +static void write_gctaggedfield(jl_serializer_state *s, jl_datatype_t *ref) JL_CANSAFEPOINT JL_GC_DISABLED { // jl_printf(JL_STDOUT, "gctaggedfield: position %p, value 0x%lx\n", (void*)(uintptr_t)ios_pos(s->s), ref); arraylist_push(&s->gctags_list, (void*)(uintptr_t)ios_pos(s->s)); @@ -1198,7 +1198,7 @@ static void write_gctaggedfield(jl_serializer_state *s, jl_datatype_t *ref) JL_N // Special handling from `jl_write_values` for modules -static void jl_write_module(jl_serializer_state *s, uintptr_t item, jl_module_t *m) JL_GC_DISABLED +static void jl_write_module(jl_serializer_state *s, uintptr_t item, jl_module_t *m) JL_CANSAFEPOINT JL_GC_DISABLED { size_t reloc_offset = ios_pos(s->s); size_t tot = sizeof(jl_module_t); @@ -1326,7 +1326,7 @@ static void record_memoryrefs_inside(jl_serializer_state *s, jl_datatype_t *t, s } } -static void record_gvars(jl_serializer_state *s, arraylist_t *globals) JL_GC_DISABLED +static void record_gvars(jl_serializer_state *s, arraylist_t *globals) JL_CANSAFEPOINT JL_GC_DISABLED { for (size_t i = 0; i < globals->len; i++) jl_queue_for_serialization(s, globals->items[i]); @@ -1354,7 +1354,7 @@ jl_value_t *jl_find_ptr = NULL; // The main function for serializing all the items queued in `serialization_order` // (They are also stored in `serialization_queue` which is order-preserving, unlike the hash table used // for `serialization_order`). -static void jl_write_values(jl_serializer_state *s) JL_GC_DISABLED +static void jl_write_values(jl_serializer_state *s) JL_CANSAFEPOINT JL_GC_DISABLED { size_t l = serialization_queue.len; @@ -1976,7 +1976,7 @@ static uintptr_t get_reloc_for_item(uintptr_t reloc_item, size_t reloc_offset) } // Compute target location at deserialization -static inline uintptr_t get_item_for_reloc(jl_serializer_state *s, uintptr_t base, uintptr_t reloc_id, jl_array_t *link_ids, int *link_index) JL_NOTSAFEPOINT +static inline uintptr_t get_item_for_reloc(jl_serializer_state *s, uintptr_t base, uintptr_t reloc_id, jl_array_t *link_ids, int *link_index) JL_CANSAFEPOINT { enum RefTags tag = (enum RefTags)(reloc_id >> RELOC_TAG_OFFSET); size_t offset = (reloc_id & (((uintptr_t)1 << RELOC_TAG_OFFSET) - 1)); @@ -2104,7 +2104,7 @@ static void jl_write_arraylist(ios_t *s, arraylist_t *list) ios_write(s, (const char*)list->items, list->len * sizeof(void*)); } -static void jl_read_reloclist(jl_serializer_state *s, jl_array_t *link_ids, uint8_t bits) +static void jl_read_reloclist(jl_serializer_state *s, jl_array_t *link_ids, uint8_t bits) JL_CANSAFEPOINT { uintptr_t base = (uintptr_t)s->s->buf; uintptr_t last_pos = 0; @@ -2188,7 +2188,7 @@ jl_mutex_t image_remset_lock; // the image proper. For example, new methods added to external callables require // insertion into the appropriate method table. #define jl_write_value(s, v) _jl_write_value((s), (jl_value_t*)(v)) -static void _jl_write_value(jl_serializer_state *s, jl_value_t *v) JL_GC_DISABLED +static void _jl_write_value(jl_serializer_state *s, jl_value_t *v) JL_CANSAFEPOINT JL_GC_DISABLED { if (v == NULL) { write_reloc_t(s->s, 0); @@ -2199,7 +2199,7 @@ static void _jl_write_value(jl_serializer_state *s, jl_value_t *v) JL_GC_DISABLE write_reloc_t(s->s, reloc); } -static jl_value_t *jl_read_value(jl_serializer_state *s) +static jl_value_t *jl_read_value(jl_serializer_state *s) JL_CANSAFEPOINT { uintptr_t base = (uintptr_t)s->s->buf; uintptr_t offset = *(reloc_t*)(base + (uintptr_t)s->s->bpos); @@ -2225,7 +2225,7 @@ static uintptr_t jl_read_offset(jl_serializer_state *s) return offset; } -static jl_value_t *jl_delayed_reloc(jl_serializer_state *s, uintptr_t offset) JL_GC_DISABLED +static jl_value_t *jl_delayed_reloc(jl_serializer_state *s, uintptr_t offset) JL_GC_DISABLED JL_CANSAFEPOINT { if (!offset) return NULL; @@ -2295,7 +2295,7 @@ static void jl_update_all_fptrs(jl_serializer_state *s, jl_image_t *image) jl_register_fptrs(image->base, &fvars, linfos, img_fvars_max); } -static uint32_t write_gvars(jl_serializer_state *s, arraylist_t *globals, arraylist_t *external_fns) JL_GC_DISABLED +static uint32_t write_gvars(jl_serializer_state *s, arraylist_t *globals, arraylist_t *external_fns) JL_CANSAFEPOINT JL_GC_DISABLED { size_t len = globals->len + external_fns->len; ios_ensureroom(s->gvar_record, len * sizeof(reloc_t)); @@ -2317,7 +2317,7 @@ static uint32_t write_gvars(jl_serializer_state *s, arraylist_t *globals, arrayl } // Pointer relocation for native-code referenced global variables -static void jl_update_all_gvars(jl_serializer_state *s, jl_image_t *image, uint32_t external_fns_begin) +static void jl_update_all_gvars(jl_serializer_state *s, jl_image_t *image, uint32_t external_fns_begin) JL_CANSAFEPOINT { if (image->gvars_base == NULL) return; @@ -2344,7 +2344,7 @@ static void jl_update_all_gvars(jl_serializer_state *s, jl_image_t *image, uint3 assert(!s->link_ids_external_fnvars || external_fns_link_index == jl_array_len(s->link_ids_external_fnvars)); } -static void jl_root_new_gvars(jl_serializer_state *s, jl_image_t *image, uint32_t external_fns_begin) +static void jl_root_new_gvars(jl_serializer_state *s, jl_image_t *image, uint32_t external_fns_begin) JL_CANSAFEPOINT { if (image->gvars_base == NULL) return; @@ -2368,7 +2368,7 @@ static void jl_root_new_gvars(jl_serializer_state *s, jl_image_t *image, uint32_ // Code below helps slim down the images by // removing cached types not referenced in the stream -static jl_svec_t *jl_prune_type_cache_hash(jl_svec_t *cache) JL_GC_DISABLED +static jl_svec_t *jl_prune_type_cache_hash(jl_svec_t *cache) JL_CANSAFEPOINT JL_GC_DISABLED { size_t l = jl_svec_len(cache), i; size_t sz = 0; @@ -2463,7 +2463,7 @@ static void jl_prune_binding_backedges(jl_array_t *backedges) jl_array_del_end(backedges, n - ins); } -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 +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_CANSAFEPOINT JL_GC_DISABLED { jl_svec_t *keys = jl_atomic_load_relaxed(pkeys); size_t l = jl_svec_len(keys), i; @@ -2502,7 +2502,7 @@ static void jl_prune_idset(_Atomic(jl_svec_t*) *pkeys, _Atomic(jl_genericmemory_ jl_gc_write_atomic(parent, *pkeyset, jl_genericmemory_t, jl_atomic_load_relaxed(&keyset2), relaxed); } -static void jl_prune_method_specializations(jl_method_t *m) JL_GC_DISABLED +static void jl_prune_method_specializations(jl_method_t *m) JL_CANSAFEPOINT JL_GC_DISABLED { jl_value_t *specializations_ = jl_atomic_load_relaxed(&m->specializations); if (!jl_is_svec(specializations_)) { @@ -2513,7 +2513,7 @@ static void jl_prune_method_specializations(jl_method_t *m) JL_GC_DISABLED 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 +static void jl_prune_module_bindings(jl_module_t *m) JL_CANSAFEPOINT JL_GC_DISABLED { jl_prune_idset(&m->bindings, &m->bindingkeyset, bindingkey_hash, (jl_value_t*)m); } @@ -2530,7 +2530,7 @@ static void strip_slotnames(jl_array_t *slotnames, int n) } } -static jl_value_t *strip_codeinfo_meta(jl_method_t *m, jl_value_t *ci_, jl_code_instance_t *codeinst) +static jl_value_t *strip_codeinfo_meta(jl_method_t *m, jl_value_t *ci_, jl_code_instance_t *codeinst) JL_CANSAFEPOINT { jl_code_info_t *ci = NULL; JL_GC_PUSH1(&ci); @@ -2551,7 +2551,7 @@ static jl_value_t *strip_codeinfo_meta(jl_method_t *m, jl_value_t *ci_, jl_code_ return ret; } -static void strip_specializations_(jl_method_instance_t *mi) +static void strip_specializations_(jl_method_instance_t *mi) JL_CANSAFEPOINT { assert(jl_is_method_instance(mi)); jl_code_instance_t *codeinst = jl_atomic_load_relaxed(&mi->cache); @@ -2576,7 +2576,7 @@ static void strip_specializations_(jl_method_instance_t *mi) } } -static int strip_all_codeinfos__(jl_typemap_entry_t *def, void *_env) +static int strip_all_codeinfos__(jl_typemap_entry_t *def, void *_env) JL_CANSAFEPOINT { jl_method_t *m = def->func.method; if (m->source) { @@ -2644,17 +2644,17 @@ static int strip_all_codeinfos__(jl_typemap_entry_t *def, void *_env) return 1; } -static int strip_all_codeinfos_mt(jl_methtable_t *mt, void *_env) +static int strip_all_codeinfos_mt(jl_methtable_t *mt, void *_env) JL_CANSAFEPOINT { return jl_typemap_visitor(jl_atomic_load_relaxed(&mt->defs), strip_all_codeinfos__, NULL); } -static void jl_strip_all_codeinfos(jl_array_t *mod_array) +static void jl_strip_all_codeinfos(jl_array_t *mod_array) JL_CANSAFEPOINT { jl_foreach_reachable_mtable(strip_all_codeinfos_mt, mod_array, NULL); } -static int strip_module(jl_module_t *m, jl_sym_t *docmeta_sym) +static int strip_module(jl_module_t *m, jl_sym_t *docmeta_sym) JL_CANSAFEPOINT { size_t world = jl_atomic_load_relaxed(&jl_world_counter); jl_svec_t *table = jl_atomic_load_relaxed(&m->bindings); @@ -2692,7 +2692,7 @@ static int strip_module(jl_module_t *m, jl_sym_t *docmeta_sym) } -static void jl_strip_all_docmeta(jl_array_t *mod_array) +static void jl_strip_all_docmeta(jl_array_t *mod_array) JL_CANSAFEPOINT { jl_sym_t *docmeta_sym = NULL; if (jl_base_module) { @@ -2720,7 +2720,7 @@ jl_mutex_t global_roots_lock; jl_mutex_t precompile_field_replace_lock; jl_svec_t *precompile_field_replace JL_GLOBALLY_ROOTED; -static inline jl_value_t *get_checked_fieldindex(const char *name, jl_datatype_t *st, jl_value_t *v, jl_value_t *arg, int mutabl) +static inline jl_value_t *get_checked_fieldindex(const char *name, jl_datatype_t *st, jl_value_t *v, jl_value_t *arg, int mutabl) JL_CANSAFEPOINT { if (mutabl) { if (st == jl_module_type) @@ -2860,7 +2860,7 @@ static int jl_prune_internal_mtable(jl_methtable_t *mt, void *env) // In addition to the system image (where `worklist = NULL`), this can also save incremental images with external linkage static void jl_save_system_image_to_stream(ios_t *f, jl_array_t *mod_array, jl_array_t *module_init_order, jl_array_t *worklist, jl_array_t *extext_methods, - jl_array_t *new_ext, jl_query_cache *query_cache) + jl_array_t *new_ext, jl_query_cache *query_cache) JL_CANSAFEPOINT { htable_new(&field_replace, 0); htable_new(&bits_replace, 0); @@ -3306,7 +3306,7 @@ static int ci_not_internal_cache(jl_code_instance_t *ci) return !(jl_atomic_load_relaxed(&ci->flags) & JL_CI_FLAGS_NATIVE_CACHE_VALID) || jl_object_in_image(mi->def.value); } -static uint8_t jl_get_toplevel_syntax_version(void) +static uint8_t jl_get_toplevel_syntax_version(void) JL_CANSAFEPOINT { jl_task_t *ct = jl_current_task; jl_module_t *toplevel = (jl_module_t*)jl_get_global_value(jl_base_module, jl_symbol("__toplevel__"), ct->world_age); @@ -3315,7 +3315,7 @@ static uint8_t jl_get_toplevel_syntax_version(void) return jl_unbox_uint8(syntax_version); } -static void jl_write_header_for_incremental(ios_t *f, jl_array_t *worklist, jl_array_t *mod_array, jl_array_t **udeps, int64_t *srctextpos, int64_t *checksumpos) +static void jl_write_header_for_incremental(ios_t *f, jl_array_t *worklist, jl_array_t *mod_array, jl_array_t **udeps, int64_t *srctextpos, int64_t *checksumpos) JL_CANSAFEPOINT { *checksumpos = write_header(f, 0); write_uint8(f, jl_cache_flags()); @@ -3516,9 +3516,10 @@ JL_DLLEXPORT jl_image_buf_t jl_preload_sysimg(const char *fname) .base = 0, }; return jl_sysimage_buf; - } else { + } + else { // Get handle to sys.so - return jl_set_sysimg_so(jl_load_dynamic_library(fname, JL_RTLD_LOCAL | JL_RTLD_NOW, 1)); + return jl_set_sysimg_so(jl_dlopen_e(fname, JL_RTLD_LOCAL | JL_RTLD_NOW)); } } @@ -3549,7 +3550,7 @@ JL_DLLEXPORT void jl_image_unpack_uncomp(void *handle, jl_image_buf_t *image) jl_prefetch_system_image(image->data, image->size); } -JL_DLLEXPORT void jl_image_unpack_zstd(void *handle, jl_image_buf_t *image) +JL_DLLEXPORT void jl_image_unpack_zstd(void *handle, jl_image_buf_t *image) JL_CANSAFEPOINT { size_t *plen; uint32_t *pchecksum; @@ -3679,7 +3680,7 @@ JL_DLLEXPORT jl_image_buf_t jl_set_sysimg_so(void *handle) int IMAGE_NATIVE_CODE_TAINTED = 0; // TODO: This should possibly be in Julia -static int jl_validate_binding_partition(jl_binding_t *b, jl_binding_partition_t *bpart, size_t mod_idx, int unchanged_implicit, int no_replacement) +static int jl_validate_binding_partition(jl_binding_t *b, jl_binding_partition_t *bpart, size_t mod_idx, int unchanged_implicit, int no_replacement) JL_CANSAFEPOINT { if (jl_atomic_load_relaxed(&bpart->max_world) != ~(size_t)0) return 1; @@ -3778,7 +3779,7 @@ static void jl_restore_system_image_from_stream_(ios_t *f, jl_image_t *image, jl_array_t **extext_methods JL_REQUIRE_ROOTED_SLOT, jl_array_t **internal_methods JL_REQUIRE_ROOTED_SLOT, jl_array_t **method_roots_list JL_REQUIRE_ROOTED_SLOT, - pkgcachesizes *cachesizes) JL_GC_DISABLED + pkgcachesizes *cachesizes) JL_CANSAFEPOINT JL_GC_DISABLED { jl_task_t *ct = jl_current_task; int en = jl_gc_enable(0); @@ -4326,7 +4327,7 @@ static void jl_restore_system_image_from_stream_(ios_t *f, jl_image_t *image, } -static jl_value_t *jl_validate_cache_file(ios_t *f, jl_array_t *depmods, uint64_t *checksum, int64_t *dataendpos, int64_t *datastartpos) +static jl_value_t *jl_validate_cache_file(ios_t *f, jl_array_t *depmods, uint64_t *checksum, int64_t *dataendpos, int64_t *datastartpos) JL_CANSAFEPOINT { uint8_t pkgimage = 0; if (ios_eof(f) || 0 == (*checksum = jl_read_verify_header(f, &pkgimage, dataendpos, datastartpos)) || (*checksum >> 32 != 0xfafbfcfd)) { @@ -4355,7 +4356,7 @@ static jl_value_t *jl_validate_cache_file(ios_t *f, jl_array_t *depmods, uint64_ } // TODO?: refactor to make it easier to create the "package inspector" -static jl_value_t *jl_restore_package_image_from_stream(ios_t *f, jl_image_t *image, jl_array_t *depmods, int completeinfo, const char *pkgname, int needs_permalloc) +static jl_value_t *jl_restore_package_image_from_stream(ios_t *f, jl_image_t *image, jl_array_t *depmods, int completeinfo, const char *pkgname, int needs_permalloc) JL_CANSAFEPOINT { JL_TIMING(LOAD_IMAGE, LOAD_Pkgimg); jl_timing_printf(JL_TIMING_DEFAULT_BLOCK, pkgname); @@ -4458,13 +4459,13 @@ static jl_value_t *jl_restore_package_image_from_stream(ios_t *f, jl_image_t *im return restored; } -static void jl_restore_system_image_from_stream(ios_t *f, jl_image_t *image, uint32_t checksum) +static void jl_restore_system_image_from_stream(ios_t *f, jl_image_t *image, uint32_t checksum) JL_CANSAFEPOINT { JL_TIMING(LOAD_IMAGE, LOAD_Sysimg); jl_restore_system_image_from_stream_(f, image, NULL, checksum | ((uint64_t)0xfdfcfbfa << 32), NULL, NULL, NULL, NULL, NULL, NULL); } -JL_DLLEXPORT jl_value_t *jl_restore_incremental_from_buf(jl_image_buf_t buf, jl_image_t *image, jl_array_t *depmods, int completeinfo, const char *pkgname, int needs_permalloc) +JL_DLLEXPORT jl_value_t *jl_restore_incremental_from_buf(jl_image_buf_t buf, jl_image_t *image, jl_array_t *depmods, int completeinfo, const char *pkgname, int needs_permalloc) JL_CANSAFEPOINT { ios_t f; ios_static_buffer(&f, (char*)buf.data, buf.size); @@ -4505,21 +4506,9 @@ JL_DLLEXPORT void jl_restore_system_image(jl_image_t *image, jl_image_buf_t buf) JL_SIGATOMIC_END(); } -JL_DLLEXPORT jl_value_t *jl_restore_package_image_from_file(const char *fname, jl_array_t *depmods, int completeinfo, const char *pkgname, int ignore_native) +JL_DLLEXPORT jl_value_t *jl_restore_package_image_from_file(const char *fname, jl_array_t *depmods, int completeinfo, const char *pkgname, int ignore_native) JL_CANSAFEPOINT { - void *pkgimg_handle = jl_dlopen(fname, JL_RTLD_LAZY); - if (!pkgimg_handle) { -#ifdef _OS_WINDOWS_ - int err; - char reason[256]; - err = GetLastError(); - win32_formatmessage(err, reason, sizeof(reason)); -#else - const char *reason = dlerror(); -#endif - jl_errorf("Error opening package file %s: %s\n", fname, reason); - } - + void *pkgimg_handle = jl_dlopen_e(fname, JL_RTLD_LAZY); jl_image_buf_t buf = get_image_buf(pkgimg_handle, /* is_pkgimage */ 1); jl_gc_notify_image_load(buf.data, buf.size); diff --git a/src/staticdata_utils.c b/src/staticdata_utils.c index acac95f778079..63dd2f434cf4e 100644 --- a/src/staticdata_utils.c +++ b/src/staticdata_utils.c @@ -154,7 +154,7 @@ JL_DLLEXPORT void jl_finalize_precompile_inferred(int8_t cleanup_keep_ir) } } -static jl_array_t *queue_used(jl_array_t *list, jl_query_cache *query_cache); +static jl_array_t *queue_used(jl_array_t *list, jl_query_cache *query_cache) JL_CANSAFEPOINT; JL_DLLEXPORT jl_array_t* jl_compute_new_used_ci(void) { @@ -578,7 +578,7 @@ static jl_array_t *queue_used(jl_array_t *list, jl_query_cache *query_cache) // - if the method is owned by a worklist module, add it to the list of things to be // verified on reloading // - if the method is extext, record that it needs to be reinserted later in the method table -static int jl_collect_methcache_from_mod(jl_typemap_entry_t *ml, void *closure) +static int jl_collect_methcache_from_mod(jl_typemap_entry_t *ml, void *closure) JL_CANSAFEPOINT { jl_array_t *s = (jl_array_t*)closure; jl_method_t *m = ml->func.method; @@ -597,7 +597,7 @@ static int jl_collect_methcache_internal(jl_typemap_entry_t *ml, void *closure) return 1; } -static int jl_collect_methtable_from_mod(jl_methtable_t *mt, void *env) +static int jl_collect_methtable_from_mod(jl_methtable_t *mt, void *env) JL_CANSAFEPOINT { // Custom method tables owned by the worklist are serialized without their // contents (jl_prune_internal_mtable), so all of their methods are treated @@ -612,7 +612,7 @@ static int jl_collect_methtable_from_mod(jl_methtable_t *mt, void *env) // Collect methods of external functions defined by modules in the worklist // "extext" = "extending external" // Also collect relevant backedges -static void jl_collect_extext_methods(jl_array_t *s, jl_array_t *mod_array) +static void jl_collect_extext_methods(jl_array_t *s, jl_array_t *mod_array) JL_CANSAFEPOINT { jl_foreach_reachable_mtable(jl_collect_methtable_from_mod, mod_array, s); } @@ -687,7 +687,7 @@ JL_DLLEXPORT uint8_t jl_match_cache_flags_current(uint8_t flags) } // return char* from String field in Base.GIT_VERSION_INFO -static const char *git_info_string(const char *fld) +static const char *git_info_string(const char *fld) JL_CANSAFEPOINT { static jl_value_t *GIT_VERSION_INFO = NULL; if (!GIT_VERSION_INFO) @@ -697,14 +697,14 @@ static const char *git_info_string(const char *fld) return jl_string_data(f); } -static const char *jl_git_branch(void) +static const char *jl_git_branch(void) JL_CANSAFEPOINT { static const char *branch = NULL; if (!branch) branch = git_info_string("branch"); return branch; } -static const char *jl_git_commit(void) +static const char *jl_git_commit(void) JL_CANSAFEPOINT { static const char *commit = NULL; if (!commit) commit = git_info_string("commit"); @@ -716,7 +716,7 @@ static const char *jl_git_commit(void) static const int JI_FORMAT_VERSION = 13; static const char JI_MAGIC[] = "\373jli\r\n\032\n"; // based on PNG signature static const uint16_t BOM = 0xFEFF; // byte-order marker -static int64_t write_header(ios_t *s, uint8_t pkgimage) +static int64_t write_header(ios_t *s, uint8_t pkgimage) JL_CANSAFEPOINT { ios_write(s, JI_MAGIC, strlen(JI_MAGIC)); write_uint16(s, JI_FORMAT_VERSION); @@ -774,7 +774,7 @@ static void write_module_path(ios_t *s, jl_module_t *depmod) JL_NOTSAFEPOINT // Serialize the global Base._require_dependencies array of pathnames that // are include dependencies. Also write Preferences and return // the location of the srctext "pointer" in the header index. -static int64_t write_dependency_list(ios_t *s, jl_array_t* worklist, jl_array_t **udepsp) +static int64_t write_dependency_list(ios_t *s, jl_array_t* worklist, jl_array_t **udepsp) JL_CANSAFEPOINT { int64_t initial_pos = 0; int64_t pos = 0; @@ -888,7 +888,7 @@ static int64_t write_dependency_list(ios_t *s, jl_array_t* worklist, jl_array_t // Add methods to external (non-worklist-owned) functions // mutating external to point at the new methodtable entry instead of the new method -static void jl_add_methods(jl_array_t *external) +static void jl_add_methods(jl_array_t *external) JL_CANSAFEPOINT { size_t i, l = jl_array_nrows(external); for (i = 0; i < l; i++) { @@ -903,7 +903,7 @@ static void jl_add_methods(jl_array_t *external) } extern _Atomic(int) allow_new_worlds; -static void jl_activate_methods(jl_array_t *external, jl_array_t *internal, size_t world, const char *pkgname) +static void jl_activate_methods(jl_array_t *external, jl_array_t *internal, size_t world, const char *pkgname) JL_CANSAFEPOINT { size_t i, l = jl_array_nrows(internal); for (i = 0; i < l; i++) { @@ -949,7 +949,7 @@ static void jl_activate_methods(jl_array_t *external, jl_array_t *internal, size } } -static int jl_copy_roots(jl_array_t *method_roots_list, uint64_t key) +static int jl_copy_roots(jl_array_t *method_roots_list, uint64_t key) JL_CANSAFEPOINT { size_t i, l = jl_array_nrows(method_roots_list); int failed = 0; @@ -976,7 +976,7 @@ static int jl_copy_roots(jl_array_t *method_roots_list, uint64_t key) return failed; } -static jl_value_t *read_verify_mod_list(ios_t *s, jl_array_t *depmods) +static jl_value_t *read_verify_mod_list(ios_t *s, jl_array_t *depmods) JL_CANSAFEPOINT { if (!jl_main_module->build_id.lo) { return jl_get_exceptionf(jl_errorexception_type, @@ -1017,7 +1017,7 @@ static int readstr_verify(ios_t *s, const char *str, int include_null) return 1; } -JL_DLLEXPORT uint64_t jl_read_verify_header(ios_t *s, uint8_t *pkgimage, int64_t *dataendpos, int64_t *datastartpos) +JL_DLLEXPORT uint64_t jl_read_verify_header(ios_t *s, uint8_t *pkgimage, int64_t *dataendpos, int64_t *datastartpos) JL_CANSAFEPOINT { uint16_t bom; uint64_t checksum = 0; @@ -1040,7 +1040,7 @@ JL_DLLEXPORT uint64_t jl_read_verify_header(ios_t *s, uint8_t *pkgimage, int64_t } // Returns `depmodidxs` where `j = depmodidxs[i]` corresponds to the blob `depmods[j]` in `write_mod_list` -static jl_array_t *image_to_depmodidx(jl_array_t *depmods) +static jl_array_t *image_to_depmodidx(jl_array_t *depmods) JL_CANSAFEPOINT { if (!depmods) return NULL; @@ -1064,7 +1064,7 @@ static jl_array_t *image_to_depmodidx(jl_array_t *depmods) } // Returns `imageidxs` where `j = imageidxs[i]` is the blob corresponding to `depmods[j]` -static jl_array_t *depmod_to_imageidx(jl_array_t *depmods) +static jl_array_t *depmod_to_imageidx(jl_array_t *depmods) JL_CANSAFEPOINT { if (!depmods) return NULL; diff --git a/src/subtype.c b/src/subtype.c index 60121037576f6..f916821da55ed 100644 --- a/src/subtype.c +++ b/src/subtype.c @@ -214,7 +214,7 @@ static int binding_has_innervar(jl_varbinding_t *b, jl_tvar_t *v) JL_NOTSAFEPOIN return 0; } -static void push_innervar(jl_varbinding_t *b, jl_value_t *v) +static void push_innervar(jl_varbinding_t *b, jl_value_t *v) JL_CANSAFEPOINT { assert(jl_is_typevar(v)); if (binding_has_innervar(b, (jl_tvar_t*)v)) @@ -447,7 +447,7 @@ static void re_save_env(jl_stenv_t *e, jl_savedenv_t *se, int root) se->rdepth = e->Runions.depth; } -static void alloc_env(jl_stenv_t *e, jl_savedenv_t *se, int root) +static void alloc_env(jl_stenv_t *e, jl_savedenv_t *se, int root) JL_CANSAFEPOINT { jl_task_t *ct = jl_current_task; int len = current_env_length(e); @@ -478,7 +478,7 @@ static void alloc_env(jl_stenv_t *e, jl_savedenv_t *se, int root) #endif } -static void save_env(jl_stenv_t *e, jl_savedenv_t *se, int root) +static void save_env(jl_stenv_t *e, jl_savedenv_t *se, int root) JL_CANSAFEPOINT { alloc_env(e, se, root); re_save_env(e, se, root); @@ -815,7 +815,7 @@ int obviously_disjoint(jl_value_t *a, jl_value_t *b, int specificity) JL_NOTSAFE } // compute a least upper bound of `a` and `b` -static jl_value_t *simple_join(jl_value_t *a, jl_value_t *b) +static jl_value_t *simple_join(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT { if (a == jl_bottom_type || b == (jl_value_t*)jl_any_type || obviously_egal(a, b)) return b; @@ -844,7 +844,7 @@ static jl_value_t *simple_join(jl_value_t *a, jl_value_t *b) // Compute a greatest lower bound of `a` and `b` // For the subtype path, we need to over-estimate this by returning `b` in many cases. // But for `merge_env`, we'd better under-estimate and return a `Union{}` -static jl_value_t *simple_meet(jl_value_t *a, jl_value_t *b, int overesi) +static jl_value_t *simple_meet(jl_value_t *a, jl_value_t *b, int overesi) JL_CANSAFEPOINT { if (a == (jl_value_t*)jl_any_type || b == jl_bottom_type || obviously_egal(a,b)) return b; @@ -880,7 +880,7 @@ static jl_value_t *simple_meet(jl_value_t *a, jl_value_t *b, int overesi) // constructor), so it suffices to peel that spine here. `Intersect{a, b}` // denotes `a ∩ b`, which `simple_meet` with `overesi==2` over-approximates by a // real supertype. `typeintersect` may over-approximate, so this is sound. -static jl_value_t *widen_intersect(jl_value_t *t) +static jl_value_t *widen_intersect(jl_value_t *t) JL_CANSAFEPOINT { if (t == NULL || !jl_is_intersecttype(t)) return t; @@ -895,9 +895,9 @@ static jl_value_t *widen_intersect(jl_value_t *t) // main subtyping algorithm -static int subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, jl_param_pos_t param); +static int subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, jl_param_pos_t param) JL_CANSAFEPOINT; -static int local_forall_exists_subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, jl_param_pos_t param, int limit_slow); +static int local_forall_exists_subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, jl_param_pos_t param, int limit_slow) JL_CANSAFEPOINT; static int is_leaf_typevar(jl_tvar_t *v) JL_NOTSAFEPOINT; @@ -939,7 +939,7 @@ static int push_consistency_scope(jl_stenv_t *e, int8_t *saved) JL_NOTSAFEPOINT; static void pop_consistency_scope(jl_stenv_t *e, const int8_t *saved, int nsaved) JL_NOTSAFEPOINT; // subtype for variable bounds consistency check. needs its own forall/exists environment. -static int subtype_ccheck(jl_value_t *x, jl_value_t *y, jl_stenv_t *e) +static int subtype_ccheck(jl_value_t *x, jl_value_t *y, jl_stenv_t *e) JL_CANSAFEPOINT { if (jl_is_long(x) && jl_is_long(y)) return jl_unbox_long(x) == jl_unbox_long(y) + e->Loffset; @@ -992,7 +992,7 @@ static int subtype_ccheck(jl_value_t *x, jl_value_t *y, jl_stenv_t *e) return sub; } -static int subtype_left_var(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, jl_param_pos_t param) +static int subtype_left_var(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, jl_param_pos_t param) JL_CANSAFEPOINT { if (jl_is_long(x) && jl_is_long(y)) return jl_unbox_long(x) == jl_unbox_long(y) + e->Loffset; @@ -1114,7 +1114,7 @@ static int var_outside(jl_stenv_t *e, jl_tvar_t *x, jl_tvar_t *y) return 0; } -static jl_value_t *intersect_aside(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, int depth); +static jl_value_t *intersect_aside(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, int depth) JL_CANSAFEPOINT; static int reachable_var(jl_value_t *x, jl_tvar_t *y, jl_stenv_t *e); @@ -1139,7 +1139,7 @@ static int subtype_singleton_typevar(jl_value_t *a, jl_tvar_t *v) JL_NOTSAFEPOIN } // check that type var `b` is <: `a`, and update b's upper bound. -static int var_lt(jl_tvar_t *b, jl_value_t *a, jl_stenv_t *e, jl_param_pos_t param, jl_varbinding_t *bb, int innervar) +static int var_lt(jl_tvar_t *b, jl_value_t *a, jl_stenv_t *e, jl_param_pos_t param, jl_varbinding_t *bb, int innervar) JL_CANSAFEPOINT { if (bb == NULL) { if (innervar && e->intersection) @@ -1190,7 +1190,7 @@ static int var_lt(jl_tvar_t *b, jl_value_t *a, jl_stenv_t *e, jl_param_pos_t par } // check that type var `b` is >: `a`, and update b's lower bound. -static int var_gt(jl_tvar_t *b, jl_value_t *a, jl_stenv_t *e, jl_param_pos_t param, jl_varbinding_t *bb, int innervar) +static int var_gt(jl_tvar_t *b, jl_value_t *a, jl_stenv_t *e, jl_param_pos_t param, jl_varbinding_t *bb, int innervar) JL_CANSAFEPOINT { if (bb == NULL) { if (innervar && e->intersection) @@ -1249,7 +1249,7 @@ static int var_gt(jl_tvar_t *b, jl_value_t *a, jl_stenv_t *e, jl_param_pos_t par return 1; } -static int subtype_var(jl_tvar_t *b, jl_value_t *a, jl_stenv_t *e, int R, jl_param_pos_t param, jl_varbinding_t *bb, int innervar) +static int subtype_var(jl_tvar_t *b, jl_value_t *a, jl_stenv_t *e, int R, jl_param_pos_t param, jl_varbinding_t *bb, int innervar) JL_CANSAFEPOINT { if (e->intersection) { jl_value_t *bub = bb ? bb->ub : innervar ? ((jl_tvar_t*)b)->ub : (jl_value_t*)b; @@ -1372,11 +1372,11 @@ static jl_value_t *widen_Type_if_concrete(jl_value_t *t JL_PROPAGATES_ROOT, jl_s return t; } -static int try_subtype_in_env(jl_value_t *a, jl_value_t *b, jl_stenv_t *e); +static int try_subtype_in_env(jl_value_t *a, jl_value_t *b, jl_stenv_t *e) JL_CANSAFEPOINT; // Map Type{X} to kind type (DataType, UnionAll, Union, TypeofBottom) over union // only if the widened kind satisfies `bound` , otherwise leave unchanged -static jl_value_t *widen_Type_to_union(jl_value_t *t, jl_value_t *bound, jl_stenv_t *e) +static jl_value_t *widen_Type_to_union(jl_value_t *t, jl_value_t *bound, jl_stenv_t *e) JL_CANSAFEPOINT { if (jl_is_some_Type(t) && !jl_is_typevar(jl_some_Type_T(t))) { // This runs in the existential (intersection) direction only, where @@ -1422,7 +1422,7 @@ static int var_occurs_inside(jl_value_t *v, jl_tvar_t *var, int inside, int want // identity while carrying the "constrained by any concrete subtype" bit. // `tvar` is the uncertain value (typically a TypeVar); `constrained` is 1 // iff any concrete subtype of the LHS will pin this var to a definite value. -static jl_value_t *wrap_tvar_env(jl_value_t *tvar, int constrained) +static jl_value_t *wrap_tvar_env(jl_value_t *tvar, int constrained) JL_CANSAFEPOINT { return (jl_value_t*)jl_svec2(tvar, constrained ? jl_true : jl_false); } @@ -1516,7 +1516,7 @@ static int var_occurs_invariant(jl_value_t *v, jl_tvar_t *var) JL_NOTSAFEPOINT return var_occurs_inside(v, var, 0, 1); } -static jl_unionall_t *unalias_unionall(jl_unionall_t *u, jl_stenv_t *e) +static jl_unionall_t *unalias_unionall(jl_unionall_t *u, jl_stenv_t *e) JL_CANSAFEPOINT { jl_varbinding_t *btemp = e->vars; // if the var for this unionall (based on identity) already appears somewhere @@ -1635,7 +1635,7 @@ static int var_occurs_covariant_only(jl_value_t *t, jl_tvar_t *var, int covarian // legacy plain binding (#61242), egality-certain values stay unwrapped. static jl_value_t *eq_pinned_envout_marker(jl_unionall_t *u, jl_varbinding_t *vb, jl_value_t *lb, jl_value_t **new_tvar JL_REQUIRE_ROOTED_SLOT, - int constrained) + int constrained) JL_CANSAFEPOINT { if (jl_is_type(lb) && lb != jl_bottom_type && vb->lb_certainty < BOUND_EGAL && !jl_has_free_typevars(lb)) { @@ -1648,7 +1648,7 @@ static jl_value_t *eq_pinned_envout_marker(jl_unionall_t *u, jl_varbinding_t *vb static jl_value_t *subtype_unionall_envout_value(jl_value_t *t, jl_unionall_t *u, jl_stenv_t *e, jl_varbinding_t *vb, jl_value_t *lb, jl_value_t **new_tvar JL_REQUIRE_ROOTED_SLOT, - int constrained) + int constrained) JL_CANSAFEPOINT { if (vb->intvalued && lb == (jl_value_t*)jl_any_type) return (jl_value_t*)jl_wrap_vararg(NULL, NULL, 0, 0); // special token result that represents N::Int in the envout @@ -1700,7 +1700,7 @@ static jl_value_t *subtype_unionall_envout_value(jl_value_t *t, jl_unionall_t *u return wrap_tvar_env(*new_tvar, constrained); } -static int subtype_unionall(jl_value_t *t, jl_unionall_t *u, jl_stenv_t *e, int8_t R, jl_param_pos_t param) +static int subtype_unionall(jl_value_t *t, jl_unionall_t *u, jl_stenv_t *e, int8_t R, jl_param_pos_t param) JL_CANSAFEPOINT { u = unalias_unionall(u, e); jl_value_t *new_tvar = NULL; @@ -1921,7 +1921,7 @@ static int subtype_unionall(jl_value_t *t, jl_unionall_t *u, jl_stenv_t *e, int8 } // check n <: (length of vararg type v) -static int check_vararg_length(jl_value_t *v, ssize_t n, jl_stenv_t *e) +static int check_vararg_length(jl_value_t *v, ssize_t n, jl_stenv_t *e) JL_CANSAFEPOINT { jl_value_t *N = jl_unwrap_vararg_num(v); // only do the check if N is free in the tuple type's last parameter @@ -1938,13 +1938,13 @@ static int check_vararg_length(jl_value_t *v, ssize_t n, jl_stenv_t *e) return 1; } -static int forall_exists_equal(jl_value_t *x, jl_value_t *y, jl_stenv_t *e); +static int forall_exists_equal(jl_value_t *x, jl_value_t *y, jl_stenv_t *e) JL_CANSAFEPOINT; static int subtype_tuple_varargs( jl_vararg_t *vtx, jl_vararg_t *vty, jl_value_t *lastx, jl_value_t *lasty, size_t vx, size_t vy, size_t x_reps, - jl_stenv_t *e, jl_param_pos_t param) + jl_stenv_t *e, jl_param_pos_t param) JL_CANSAFEPOINT { jl_value_t *xp0 = jl_unwrap_vararg(vtx); jl_value_t *xp1 = jl_unwrap_vararg_num(vtx); jl_value_t *yp0 = jl_unwrap_vararg(vty); jl_value_t *yp1 = jl_unwrap_vararg_num(vty); @@ -2093,7 +2093,7 @@ static int subtype_tuple_varargs( return ans; } -static int subtype_tuple_tail(jl_datatype_t *xd, jl_datatype_t *yd, int8_t R, jl_stenv_t *e, jl_param_pos_t param) +static int subtype_tuple_tail(jl_datatype_t *xd, jl_datatype_t *yd, int8_t R, jl_stenv_t *e, jl_param_pos_t param) JL_CANSAFEPOINT { size_t lx = jl_nparams(xd); size_t ly = jl_nparams(yd); @@ -2193,7 +2193,7 @@ static int subtype_tuple_tail(jl_datatype_t *xd, jl_datatype_t *yd, int8_t R, jl return 1; } -static int subtype_tuple(jl_datatype_t *xd, jl_datatype_t *yd, jl_stenv_t *e, jl_param_pos_t param) +static int subtype_tuple(jl_datatype_t *xd, jl_datatype_t *yd, jl_stenv_t *e, jl_param_pos_t param) JL_CANSAFEPOINT { // Check tuple compatibility based on tuple length only (fastpath) size_t lx = jl_nparams(xd); @@ -2579,7 +2579,7 @@ static jl_datatype_t *typeeq_kind_datatype(int bit) JL_NOTSAFEPOINT // `===`) pin just the same. A genuinely non-collapsing range instead admits // `Union` values strictly between the bounds, so nothing sharper than the // conservative all-kinds answer is sound for it. -static jl_value_t *typeeq_unpin_tvar(jl_value_t *tp0 JL_PROPAGATES_ROOT) +static jl_value_t *typeeq_unpin_tvar(jl_value_t *tp0 JL_PROPAGATES_ROOT) JL_CANSAFEPOINT { while (jl_is_typevar(tp0)) { jl_value_t *lb = ((jl_tvar_t*)tp0)->lb; @@ -2638,7 +2638,7 @@ static void typeeq_collect_closed_components(jl_value_t *y, jl_value_t **out, si // left out: the cover holding over the closed components alone proves the // subtyping without constraining any variable, just as the per-branch // decomposition proves it by choosing a var-free branch. -static int typeeq_subtype_kind_cover(jl_value_t *tp0, jl_value_t *y) +static int typeeq_subtype_kind_cover(jl_value_t *tp0, jl_value_t *y) JL_CANSAFEPOINT { int mask = typeeq_kind_mask(tp0); jl_value_t *kinds[6]; @@ -3088,7 +3088,7 @@ static int is_existential_typevar(jl_value_t *x, jl_stenv_t *e) return vb && vb->existential; } -static int forall_exists_subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, jl_param_pos_t param); +static int forall_exists_subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, jl_param_pos_t param) JL_CANSAFEPOINT; static int local_forall_exists_subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, jl_param_pos_t param, int limit_slow) { @@ -3171,7 +3171,7 @@ static int local_forall_exists_subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t return sub; } -static int equal_var(jl_tvar_t *v, jl_value_t *x, jl_stenv_t *e) +static int equal_var(jl_tvar_t *v, jl_value_t *x, jl_stenv_t *e) JL_CANSAFEPOINT { assert(e->Loffset == 0); // Theoretically bounds change would be merged for union inputs. @@ -3281,7 +3281,7 @@ static int forall_exists_equal(jl_value_t *x, jl_value_t *y, jl_stenv_t *e) return sub; } -static int exists_subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, jl_savedenv_t *se, jl_param_pos_t param) +static int exists_subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, jl_savedenv_t *se, jl_param_pos_t param) JL_CANSAFEPOINT { e->Runions.used = 0; while (1) { @@ -3850,7 +3850,7 @@ JL_DLLEXPORT int jl_subtype_env(jl_value_t *x, jl_value_t *y, jl_value_t **env, return subtype; } -static int subtype_in_env(jl_value_t *x, jl_value_t *y, jl_stenv_t *e) +static int subtype_in_env(jl_value_t *x, jl_value_t *y, jl_stenv_t *e) JL_CANSAFEPOINT { jl_stenv_t e2; init_stenv(&e2, NULL, 0); @@ -4096,9 +4096,9 @@ JL_DLLEXPORT int jl_isa(jl_value_t *x, jl_value_t *t) // type intersection -static jl_value_t *intersect(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, jl_param_pos_t param); +static jl_value_t *intersect(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, jl_param_pos_t param) JL_CANSAFEPOINT; -static jl_value_t *intersect_all(jl_value_t *x, jl_value_t *y, jl_stenv_t *e); +static jl_value_t *intersect_all(jl_value_t *x, jl_value_t *y, jl_stenv_t *e) JL_CANSAFEPOINT; // intersect in nested union environment, similar to subtype_ccheck static jl_value_t *intersect_aside(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, int depth) @@ -4149,7 +4149,7 @@ static jl_value_t *intersect_aside(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, return res; } -static jl_value_t *intersect_union(jl_value_t *x, jl_uniontype_t *u, jl_stenv_t *e, int8_t R, jl_param_pos_t param) +static jl_value_t *intersect_union(jl_value_t *x, jl_uniontype_t *u, jl_stenv_t *e, int8_t R, jl_param_pos_t param) JL_CANSAFEPOINT { int no_free = !jl_has_free_typevars(x) && !jl_has_free_typevars((jl_value_t*)u); if (param == PARAM_INVARIANT || no_free) { @@ -4175,7 +4175,7 @@ static jl_value_t *intersect_union(jl_value_t *x, jl_uniontype_t *u, jl_stenv_t } // set a variable to a non-type constant -static jl_value_t *set_var_to_const(jl_varbinding_t *bb, jl_value_t *v JL_MAYBE_UNROOTED, jl_stenv_t *e, int R) +static jl_value_t *set_var_to_const(jl_varbinding_t *bb, jl_value_t *v JL_MAYBE_UNROOTED, jl_stenv_t *e, int R) JL_CANSAFEPOINT { int offset = R ? -e->Loffset : e->Loffset; if (bb->lb == jl_bottom_type && bb->ub == (jl_value_t*)jl_any_type) { @@ -4204,7 +4204,7 @@ static jl_value_t *set_var_to_const(jl_varbinding_t *bb, jl_value_t *v JL_MAYBE_ return v; } -static jl_value_t *bound_var_below(jl_tvar_t *tv, jl_varbinding_t *bb, jl_stenv_t *e, int R) { +static jl_value_t *bound_var_below(jl_tvar_t *tv, jl_varbinding_t *bb, jl_stenv_t *e, int R) JL_CANSAFEPOINT { if (!bb) return (jl_value_t*)tv; if (bb->depth0 != e->invdepth) @@ -4288,7 +4288,7 @@ static void set_bound(jl_value_t **bound, jl_value_t *val, jl_tvar_t *v, jl_sten } // subtype, treating all vars as existential -static int subtype_in_env_existential(jl_value_t *x, jl_value_t *y, jl_stenv_t *e) +static int subtype_in_env_existential(jl_value_t *x, jl_value_t *y, jl_stenv_t *e) JL_CANSAFEPOINT { if (x == jl_bottom_type || y == (jl_value_t*)jl_any_type || obviously_in_union(y, x)) return 1; @@ -4356,9 +4356,9 @@ static int check_unsat_bound(jl_value_t *t, jl_tvar_t *v, jl_stenv_t *e) JL_NOTS } -static int intersect_var_ccheck_in_env(jl_value_t *xlb, jl_value_t *xub, jl_value_t *ylb, jl_value_t *yub, jl_stenv_t *e, int flip); +static int intersect_var_ccheck_in_env(jl_value_t *xlb, jl_value_t *xub, jl_value_t *ylb, jl_value_t *yub, jl_stenv_t *e, int flip) JL_CANSAFEPOINT; -static jl_value_t *intersect_var(jl_tvar_t *b, jl_value_t *a, jl_stenv_t *e, int8_t R, jl_param_pos_t param) +static jl_value_t *intersect_var(jl_tvar_t *b, jl_value_t *a, jl_stenv_t *e, int8_t R, jl_param_pos_t param) JL_CANSAFEPOINT { int innervar = 0; jl_varbinding_t *bb = lookup_binding(e, b, &innervar); @@ -4532,7 +4532,7 @@ static int var_occurs_inside(jl_value_t *v, jl_tvar_t *var, int inside, int want return 0; } -static jl_value_t *omit_bad_union(jl_value_t *u, jl_tvar_t *t) +static jl_value_t *omit_bad_union(jl_value_t *u, jl_tvar_t *t) JL_CANSAFEPOINT { if (!jl_has_typevar(u, t)) return u; // return u if possible as many checks use `==`. @@ -4631,7 +4631,7 @@ static int has_typevar_via_flatten_env(jl_value_t *x, jl_tvar_t *t, jl_ivarbindi } // Caller might not have rooted `res` -static jl_value_t *finish_unionall(jl_value_t *res JL_MAYBE_UNROOTED, jl_varbinding_t *vb, jl_unionall_t *u, jl_stenv_t *e) +static jl_value_t *finish_unionall(jl_value_t *res JL_MAYBE_UNROOTED, jl_varbinding_t *vb, jl_unionall_t *u, jl_stenv_t *e) JL_CANSAFEPOINT { jl_value_t *varval = NULL, *ilb = NULL, *iub = NULL, *nivar = NULL; jl_tvar_t *newvar = vb->var, *ivar = NULL; @@ -4977,7 +4977,7 @@ static jl_value_t *finish_unionall(jl_value_t *res JL_MAYBE_UNROOTED, jl_varbind return res; } -static jl_value_t *intersect_unionall_(jl_value_t *t, jl_unionall_t *u, jl_stenv_t *e, int8_t R, jl_param_pos_t param, jl_varbinding_t *vb) +static jl_value_t *intersect_unionall_(jl_value_t *t, jl_unionall_t *u, jl_stenv_t *e, int8_t R, jl_param_pos_t param, jl_varbinding_t *vb) JL_CANSAFEPOINT { jl_varbinding_t *btemp = e->vars; int envsize = 0; @@ -5095,7 +5095,7 @@ static int always_occurs_cov(jl_value_t *v, jl_tvar_t *var, jl_param_pos_t param return 0; } -static jl_value_t *intersect_unionall(jl_value_t *t, jl_unionall_t *u, jl_stenv_t *e, int8_t R, jl_param_pos_t param) +static jl_value_t *intersect_unionall(jl_value_t *t, jl_unionall_t *u, jl_stenv_t *e, int8_t R, jl_param_pos_t param) JL_CANSAFEPOINT { jl_value_t *res = NULL; jl_savedenv_t se; @@ -5168,10 +5168,10 @@ static jl_value_t *intersect_unionall(jl_value_t *t, jl_unionall_t *u, jl_stenv_ return res; } -static jl_value_t *intersect_invariant(jl_value_t *x, jl_value_t *y, jl_stenv_t *e); +static jl_value_t *intersect_invariant(jl_value_t *x, jl_value_t *y, jl_stenv_t *e) JL_CANSAFEPOINT; // check n = (length of vararg type v) -static int intersect_vararg_length(jl_value_t *v, ssize_t n, jl_stenv_t *e, int8_t R) +static int intersect_vararg_length(jl_value_t *v, ssize_t n, jl_stenv_t *e, int8_t R) JL_CANSAFEPOINT { jl_value_t *N = jl_unwrap_vararg_num(v); // only do the check if N is free in the tuple type's last parameter @@ -5186,7 +5186,7 @@ static int intersect_vararg_length(jl_value_t *v, ssize_t n, jl_stenv_t *e, int8 return 1; } -static jl_value_t *intersect_varargs(jl_vararg_t *vmx, jl_vararg_t *vmy, ssize_t offset, jl_stenv_t *e, jl_param_pos_t param) +static jl_value_t *intersect_varargs(jl_vararg_t *vmx, jl_vararg_t *vmy, ssize_t offset, jl_stenv_t *e, jl_param_pos_t param) JL_CANSAFEPOINT { // Vararg: covariant in first parameter, invariant in second jl_value_t *xp1=jl_unwrap_vararg(vmx), *xp2=jl_unwrap_vararg_num(vmx), @@ -5269,7 +5269,7 @@ static jl_value_t *intersect_varargs(jl_vararg_t *vmx, jl_vararg_t *vmy, ssize_t } -static jl_value_t *intersect_tuple(jl_datatype_t *xd, jl_datatype_t *yd, jl_stenv_t *e, jl_param_pos_t param) +static jl_value_t *intersect_tuple(jl_datatype_t *xd, jl_datatype_t *yd, jl_stenv_t *e, jl_param_pos_t param) JL_CANSAFEPOINT { size_t lx = jl_nparams(xd), ly = jl_nparams(yd); size_t llx = lx, lly = ly; @@ -5442,7 +5442,7 @@ static void flip_vars(jl_stenv_t *e) } // intersection where xd nominally inherits from yd -static jl_value_t *intersect_sub_datatype(jl_datatype_t *xd, jl_datatype_t *yd, jl_stenv_t *e, int R, jl_param_pos_t param) +static jl_value_t *intersect_sub_datatype(jl_datatype_t *xd, jl_datatype_t *yd, jl_stenv_t *e, int R, jl_param_pos_t param) JL_CANSAFEPOINT { // attempt to populate additional constraints into `e` // if that attempt fails, then return bottom @@ -5495,7 +5495,7 @@ static jl_value_t *intersect_invariant(jl_value_t *x, jl_value_t *y, jl_stenv_t } // intersection where x == Type{...} and y is not -static jl_value_t *intersect_type_type(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, int8_t R) +static jl_value_t *intersect_type_type(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, int8_t R) JL_CANSAFEPOINT { assert(e->Loffset == 0); // fast path: every member of a `Type{T}` is a type @@ -5980,7 +5980,7 @@ static jl_value_t *intersect(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, jl_par return jl_bottom_type; } -static int merge_env(jl_stenv_t *e, jl_savedenv_t *me, jl_savedenv_t *se, int count) +static int merge_env(jl_stenv_t *e, jl_savedenv_t *me, jl_savedenv_t *se, int count) JL_CANSAFEPOINT { if (count == 0) { save_env(e, me, 1); @@ -6125,7 +6125,7 @@ static jl_value_t *intersect_all(jl_value_t *x, jl_value_t *y, jl_stenv_t *e) // type intersection entry points -static jl_value_t *intersect_types(jl_value_t *x, jl_value_t *y, int emptiness_only) +static jl_value_t *intersect_types(jl_value_t *x, jl_value_t *y, int emptiness_only) JL_CANSAFEPOINT { jl_stenv_t e; if (obviously_disjoint(x, y, 0)) @@ -6146,7 +6146,7 @@ static jl_value_t *intersect_types(jl_value_t *x, jl_value_t *y, int emptiness_o return ans; } -JL_DLLEXPORT jl_value_t *jl_intersect_types(jl_value_t *x, jl_value_t *y) +JL_DLLEXPORT jl_value_t *jl_intersect_types(jl_value_t *x, jl_value_t *y) JL_CANSAFEPOINT { return intersect_types(x, y, 0); } @@ -6176,7 +6176,7 @@ jl_svec_t *jl_outer_unionall_vars(jl_value_t *u) // pointwise unions. Note that this may in general be wider than `Union{a,b}`. // If `a` and `b` are not (non va-)tuples of equal length (or unions or unionalls // of such), return NULL. -static jl_value_t *switch_union_tuple(jl_value_t *a, jl_value_t *b) +static jl_value_t *switch_union_tuple(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT { if (jl_is_unionall(a)) { jl_unionall_t *ua = (jl_unionall_t*)a; @@ -6400,7 +6400,7 @@ JL_DLLEXPORT jl_value_t *jl_type_intersection(jl_value_t *a, jl_value_t *b) return jl_type_intersection_env(a, b, NULL); } -JL_DLLEXPORT jl_svec_t *jl_type_intersection_with_env(jl_value_t *a, jl_value_t *b) +JL_DLLEXPORT jl_svec_t *jl_type_intersection_with_env(jl_value_t *a, jl_value_t *b) JL_CANSAFEPOINT { jl_svec_t *env = jl_emptysvec; jl_value_t *ti = NULL; @@ -6524,7 +6524,7 @@ static void check_diagonal(jl_value_t *t, jl_varbinding_t *troot, jl_param_pos_t } } -static jl_value_t *insert_nondiagonal(jl_value_t *type, jl_varbinding_t *troot, int widen2ub) +static jl_value_t *insert_nondiagonal(jl_value_t *type, jl_varbinding_t *troot, int widen2ub) JL_CANSAFEPOINT { if (jl_is_typevar(type)) { int concretekind = widen2ub > 1 ? 0 : 1; @@ -6648,7 +6648,7 @@ static jl_value_t *insert_nondiagonal(jl_value_t *type, jl_varbinding_t *troot, return type; } -static jl_value_t *_widen_diagonal(jl_value_t *t, jl_varbinding_t *troot) { +static jl_value_t *_widen_diagonal(jl_value_t *t, jl_varbinding_t *troot) JL_CANSAFEPOINT { check_diagonal(t, troot, PARAM_NONE); int any_concrete = 0; for (jl_varbinding_t *v = troot; v != NULL; v = v->prev) @@ -6658,7 +6658,7 @@ static jl_value_t *_widen_diagonal(jl_value_t *t, jl_varbinding_t *troot) { return insert_nondiagonal(t, troot, 0); } -static jl_value_t *widen_diagonal(jl_value_t *t, jl_unionall_t *u, jl_varbinding_t *troot) +static jl_value_t *widen_diagonal(jl_value_t *t, jl_unionall_t *u, jl_varbinding_t *troot) JL_CANSAFEPOINT { jl_varbinding_t vb; memset(&vb, 0, sizeof(vb)); @@ -6681,7 +6681,7 @@ static jl_value_t *widen_diagonal(jl_value_t *t, jl_unionall_t *u, jl_varbinding return nt; } -JL_DLLEXPORT jl_value_t *jl_widen_diagonal(jl_value_t *t, jl_unionall_t *ua) +JL_DLLEXPORT jl_value_t *jl_widen_diagonal(jl_value_t *t, jl_unionall_t *ua) JL_CANSAFEPOINT { return widen_diagonal(t, ua, NULL); } @@ -6738,7 +6738,7 @@ static int obvious_subtype_msp(jl_value_t *x, jl_value_t *y, jl_value_t *y0, int return obvious_subtype(x, y, y0, subtype); } -static int eq_msp(jl_value_t *a, jl_value_t *b, jl_value_t *a0, jl_value_t *b0, jl_typeenv_t *env) +static int eq_msp(jl_value_t *a, jl_value_t *b, jl_value_t *a0, jl_value_t *b0, jl_typeenv_t *env) JL_CANSAFEPOINT { if (!(jl_is_type(a) || jl_is_typevar(a)) || !(jl_is_type(b) || jl_is_typevar(b))) @@ -6833,7 +6833,7 @@ static int eq_msp(jl_value_t *a, jl_value_t *b, jl_value_t *a0, jl_value_t *b0, return subtype_ab && subtype_ba; } -static int sub_msp(jl_value_t *x, jl_value_t *y, jl_value_t *y0, jl_typeenv_t *env) +static int sub_msp(jl_value_t *x, jl_value_t *y, jl_value_t *y0, jl_typeenv_t *env) JL_CANSAFEPOINT { jl_stenv_t e; if (y == (jl_value_t*)jl_any_type || x == jl_bottom_type) @@ -6874,7 +6874,7 @@ static int sub_msp(jl_value_t *x, jl_value_t *y, jl_value_t *y0, jl_typeenv_t *e return subtype; } -static int type_morespecific_(jl_value_t *a, jl_value_t *b, jl_value_t *a0, jl_value_t *b0, int invariant, jl_typeenv_t *env); +static int type_morespecific_(jl_value_t *a, jl_value_t *b, jl_value_t *a0, jl_value_t *b0, int invariant, jl_typeenv_t *env) JL_CANSAFEPOINT; static int num_occurs(jl_tvar_t *v, jl_typeenv_t *env); @@ -6897,7 +6897,7 @@ static jl_value_t *nth_tuple_elt(jl_datatype_t *t JL_PROPAGATES_ROOT, size_t i) return NULL; } -static int tuple_morespecific(jl_datatype_t *cdt, jl_datatype_t *pdt, jl_value_t *c0, jl_value_t *p0, int invariant, jl_typeenv_t *env) +static int tuple_morespecific(jl_datatype_t *cdt, jl_datatype_t *pdt, jl_value_t *c0, jl_value_t *p0, int invariant, jl_typeenv_t *env) JL_CANSAFEPOINT { size_t plen = jl_nparams(pdt); if (plen == 0) return 0; @@ -6985,7 +6985,7 @@ static size_t tuple_full_length(jl_value_t *t) // Called when a is a bound-vararg and b is not a vararg. Sets the vararg length // in a to match b, as long as this makes some earlier argument more specific. -static int args_morespecific_fix1(jl_value_t *a, jl_value_t *b, jl_value_t *a0, jl_value_t *b0, int swap, jl_typeenv_t *env) +static int args_morespecific_fix1(jl_value_t *a, jl_value_t *b, jl_value_t *a0, jl_value_t *b0, int swap, jl_typeenv_t *env) JL_CANSAFEPOINT { size_t n = jl_nparams(a); int taillen = tuple_full_length(b)-n+1; diff --git a/src/support/analyzer_annotations.h b/src/support/analyzer_annotations.h index b3557b2edd7ac..6989a740248e8 100644 --- a/src/support/analyzer_annotations.h +++ b/src/support/analyzer_annotations.h @@ -1,5 +1,130 @@ // This file is a part of Julia. License is MIT: https://julialang.org/license +// This file defines the annotations Julia uses to drive its static +// safepoint/GC analyses. Each annotation is only meaningful when an analyzer is +// enabled; otherwise it compiles away. Three configurations are selected below: +// +// __clang_gcanalyzer__ the Clang static analyzer plugin in src/clangsa that +// checks GC rooting (see doc/src/devdocs/gc-sa.md). The +// annotations expand to `annotate(...)` attributes it +// reads. +// __clang_safetyanalysis__ Clang Thread Safety Analysis (-Wthread-safety +// -Wthread-safety-negative), which models safepoints as +// two "capability" tokens (see below). Enabled by +// compiling with -D__clang_safetyanalysis__. +// (neither) a normal compile: every annotation expands to nothing +// (prototype annotations) or to a no-op (function-like +// annotations), so code builds identically either way. +// +// The Thread Safety Analysis models the current thread's state with two token +// capabilities: +// +// jl_notsafepoint a REENTRANT capability, conceptually "held" whenever the +// thread is in a no-safepoint region -- between entering one +// (e.g. taking a no-gc lock) and leaving it. It is reentrant +// so that nested no-safepoint regions (e.g. nested no-gc +// locks) may acquire it more than once. +// jl_gcunsaferegion a (non-reentrant) capability, held whenever the thread is +// in a gc-unsafe region -- the state in which it is allowed +// to reach a safepoint. +// +// A safepoint is permissible only when the thread is gc-unsafe AND holds no +// no-gc lock. The tokens are pointers so the negative requirement +// `!jl_notsafepoint` is well-formed in C; jl_gcunsaferegion is not reentrant, so +// re-entering an already gc-unsafe region is a modeling error. +// +// -- Nullability -- +// +// JL_NONNULL Mark a pointer (argument, field, or return value) that is never +// NULL. On Clang with the nullability feature it expands to the +// real `_Nonnull` qualifier (the analyzer then flags passing or +// storing NULL where a non-null pointer is required); on every +// other compiler `_Nonnull`, and hence JL_NONNULL, is nothing. +// +// -- Safepoint annotations (on function prototypes) -- +// +// JL_NOTSAFEPOINT The function never reaches a GC safepoint, so callers may +// keep values unrooted across a call to it. Under the +// GCChecker this is the opt-in default (it carries no +// annotation: a function is assumed no-safepoint unless it +// opts in with JL_CANSAFEPOINT or a region transition). +// JL_CANSAFEPOINT The function may reach a GC safepoint (may trigger GC), so +// callers must keep live values rooted across the call. +// JL_NOTSAFEPOINT_ENTER The function enters a no-safepoint region (e.g. +// takes a no-gc lock). +// JL_NOTSAFEPOINT_LEAVE The function leaves a no-safepoint region (e.g. +// releases a no-gc lock). +// JL_NOTSAFEPOINT_ENTER_CONDITIONAL(success) A conditional enter (e.g. a +// no-gc trylock) that enters the no-safepoint region only +// when the function returns `success`. +// JL_NOTSAFEPOINT_LEAVE_ENTER The function leaves a no-safepoint region and +// then re-enters it (e.g. briefly drops a no-gc lock to +// permit a safepoint). This is unsafe, so use sparingly. +// JL_CANSAFEPOINT_ENTER The function enters a gc-unsafe region (becomes able +// to safepoint). +// JL_CANSAFEPOINT_LEAVE The function leaves a gc-unsafe region (becomes +// unable to safepoint). +// JL_CANSAFEPOINT_ENTER_LEAVE The function both enters and then leaves a +// gc-unsafe region within its own body. This permits the function body +// to be used as a callback from unknown contexts. +// JL_NOTSAFEPOINT_LEAVE_WITH_CANSAFEPOINT The function releases a no-gc lock +// and then will need to assert CANSAFEPOINT. +// JL_CANCALLBACK The function can call arbitrary user/foreign callback. +// This is a close dual of JL_CANSAFEPOINT_ENTER_LEAVE, +// when the body doesn't care about the incoming state of +// jl_gcunsaferegion. +// JL_NO_SAFEPOINT_ANALYSIS Opt this function's body out of the thread-safety analysis +// entirely, either because it is buggy or because it implements some of +// the primitives. +// +// -- Rooting annotations (on arguments, return values, or globals) -- +// +// JL_PROPAGATES_ROOT On an accessor's argument: the GC root protecting that +// argument also protects the value the function returns +// (e.g. a field or element read out of a rooted container). +// JL_PROPAGATES_ROOT_INDEXED(root, index) Like JL_PROPAGATES_ROOT, but the +// returned value is loaded from a specific indexed child of +// argument `root` (with `index` the zero-based argument index +// giving the position), letting the analyzer track later +// overwrites of that child precisely. +// JL_ROOTED_BY_ARG(n) The annotated argument is rooted by argument `n` (the +// assignment counterpart of JL_PROPAGATES_ROOT); `n` is a +// zero-based argument index. +// JL_ROOTED_BY_ARG_INDEXED(root, index) The annotated argument is rooted by +// being stored into an indexed child of argument `root`, +// where `index` is the zero-based index of the argument +// giving the position. +// JL_OUT_ROOTED_BY_ARG(n) The value written through this out-argument is +// rooted by argument `n` (zero-based). +// JL_ROOTED_BY_RETURN The annotated argument is rooted by the function's +// return value. +// JL_ROOTED_VARARGS On a varargs function: its variadic arguments are rooted +// by the return value (individual varargs cannot be +// annotated). +// JL_MAYBE_UNROOTED On an argument: it may be passed even when unrooted, +// waiving the usual ABI rule that callers root arguments. +// JL_GLOBALLY_ROOTED The value is always globally rooted. On a global +// variable it applies to the variable's value(s); on a +// function, to its return value. +// JL_ALWAYS_LEAFTYPE Like JL_GLOBALLY_ROOTED, but specifically because the +// value is a leaftype (rooted via its TypeName cache). Kept +// as a separate name so the reason for the rooting is +// explicit and can be refined later. +// JL_GC_DISABLED The function is only ever called with the GC +// runtime-disabled; checked against the gc enable/disable +// calls, so the analyzer knows if you lie. +// JL_REQUIRE_ROOTED_SLOT The caller must pass a rooted slot -- values +// assigned through the annotated pointer argument are treated +// as rooted. +// +// -- Escape hatches (function-like annotations) -- +// +// JL_GC_PROMISE_ROOTED(v) Treat `v` as rooted for the remainder of the +// current function. Use sparingly, in favor of improving the +// analyzer itself. +// jl_may_leak(v) Mark `v` as intentionally allowed to leak, +// suppressing the analyzer's leaked-value diagnostic for it. + #ifndef __has_feature #define __has_feature(x) 0 #endif @@ -12,8 +137,17 @@ #define JL_PROPAGATES_ROOT __attribute__((annotate("julia_propagates_root"))) #define JL_NOTSAFEPOINT __attribute__((annotate("julia_not_safepoint"))) +#define JL_CANSAFEPOINT __attribute__((annotate("julia_can_safepoint"))) +#define JL_CANSAFEPOINT_ENTER_LEAVE __attribute__((annotate("julia_notsafepoint_leave"),annotate("julia_notsafepoint_enter"))) +#define JL_NOTSAFEPOINT_LEAVE_ENTER JL_NOTSAFEPOINT +#define JL_CANSAFEPOINT_ENTER __attribute__((annotate("julia_notsafepoint_leave"))) +#define JL_CANSAFEPOINT_LEAVE __attribute__((annotate("julia_notsafepoint_enter"))) +#define JL_NO_SAFEPOINT_ANALYSIS __attribute__((annotate("julia_no_safepoint_analysis"))) #define JL_NOTSAFEPOINT_ENTER __attribute__((annotate("julia_notsafepoint_enter"))) +#define JL_NOTSAFEPOINT_ENTER_CONDITIONAL(success) __attribute__((annotate("julia_notsafepoint_enter_conditional:" #success))) #define JL_NOTSAFEPOINT_LEAVE __attribute__((annotate("julia_notsafepoint_leave"))) +#define JL_NOTSAFEPOINT_LEAVE_WITH_CANSAFEPOINT __attribute__((annotate("julia_notsafepoint_leave"))) +#define JL_CANCALLBACK __attribute__((annotate("julia_can_safepoint"))) #define JL_MAYBE_UNROOTED __attribute__((annotate("julia_maybe_unrooted"))) #define JL_GLOBALLY_ROOTED __attribute__((annotate("julia_globally_rooted"))) #define JL_ROOTED_VARARGS __attribute__((annotate("julia_rooted_varargs"))) @@ -24,7 +158,6 @@ #define JL_ROOTED_BY_RETURN __attribute__((annotate("julia_rooted_by_return"))) #define JL_GC_DISABLED __attribute__((annotate("julia_gc_disabled"))) #define JL_ALWAYS_LEAFTYPE JL_GLOBALLY_ROOTED -#define JL_ROOTS_TEMPORARILY __attribute__((annotate("julia_temporarily_roots"))) #define JL_REQUIRE_ROOTED_SLOT __attribute__((annotate("julia_require_rooted_slot"))) #ifdef __cplusplus extern "C" { @@ -35,12 +168,69 @@ extern "C" { } #endif +#elif defined(__clang_safetyanalysis__) + +#ifndef JL_NOTSAFEPOINT_TOKEN_DEFINED +#define JL_NOTSAFEPOINT_TOKEN_DEFINED +struct __attribute__((capability("notsafepoint"),reentrant_capability)) NOTSAFEPOINT { + char cpp_compat; +}; +struct __attribute__((capability("gcunsaferegion"))) GCUNSAFEREGION { + char cpp_compat; +}; +#ifdef __cplusplus +extern "C" { +#endif +extern struct NOTSAFEPOINT *jl_notsafepoint; +extern struct GCUNSAFEREGION *jl_gcunsaferegion; +#ifdef __cplusplus +} +#endif +#endif + +#define JL_PROPAGATES_ROOT +#define JL_NOTSAFEPOINT +#define JL_CANSAFEPOINT __attribute__((requires_capability(jl_gcunsaferegion), requires_capability(!jl_notsafepoint))) +#define JL_CANSAFEPOINT_ENTER __attribute__((requires_capability(!jl_gcunsaferegion), acquire_capability(jl_gcunsaferegion), requires_capability(!jl_notsafepoint))) +#define JL_CANSAFEPOINT_LEAVE __attribute__((release_capability(jl_gcunsaferegion), requires_capability(!jl_notsafepoint))) +#define JL_CANSAFEPOINT_ENTER_LEAVE __attribute__((requires_capability(!jl_gcunsaferegion), requires_capability(!jl_notsafepoint))) +#define JL_NOTSAFEPOINT_LEAVE_ENTER __attribute__((requires_capability(jl_notsafepoint))) +#define JL_NO_SAFEPOINT_ANALYSIS __attribute__((no_thread_safety_analysis)) +#define JL_NOTSAFEPOINT_ENTER __attribute__((acquire_capability(jl_notsafepoint))) +#define JL_NOTSAFEPOINT_ENTER_CONDITIONAL(success) __attribute__((try_acquire_capability(success, jl_notsafepoint))) +#define JL_NOTSAFEPOINT_LEAVE __attribute__((release_capability(jl_notsafepoint))) +#define JL_NOTSAFEPOINT_LEAVE_WITH_CANSAFEPOINT __attribute__((requires_capability(jl_gcunsaferegion),release_capability(jl_notsafepoint))) +#define JL_CANCALLBACK __attribute__((requires_capability(!jl_notsafepoint))) + +#define JL_MAYBE_UNROOTED +#define JL_GLOBALLY_ROOTED +#define JL_ROOTED_VARARGS +#define JL_ROOTED_BY_ARG(n) +#define JL_ROOTED_BY_ARG_INDEXED(root, index) +#define JL_PROPAGATES_ROOT_INDEXED(root, index) +#define JL_OUT_ROOTED_BY_ARG(n) +#define JL_ROOTED_BY_RETURN +#define JL_GC_DISABLED +#define JL_ALWAYS_LEAFTYPE +#define JL_REQUIRE_ROOTED_SLOT +#define JL_GC_PROMISE_ROOTED(x) (void)(x) +#define jl_may_leak(x) (void)(x) + #else #define JL_PROPAGATES_ROOT #define JL_NOTSAFEPOINT +#define JL_CANSAFEPOINT +#define JL_CANSAFEPOINT_ENTER +#define JL_CANSAFEPOINT_LEAVE +#define JL_CANSAFEPOINT_ENTER_LEAVE +#define JL_NOTSAFEPOINT_LEAVE_ENTER +#define JL_NO_SAFEPOINT_ANALYSIS #define JL_NOTSAFEPOINT_ENTER +#define JL_NOTSAFEPOINT_ENTER_CONDITIONAL(success) #define JL_NOTSAFEPOINT_LEAVE +#define JL_NOTSAFEPOINT_LEAVE_WITH_CANSAFEPOINT +#define JL_CANCALLBACK #define JL_MAYBE_UNROOTED #define JL_GLOBALLY_ROOTED #define JL_ROOTED_VARARGS @@ -51,7 +241,6 @@ extern "C" { #define JL_ROOTED_BY_RETURN #define JL_GC_DISABLED #define JL_ALWAYS_LEAFTYPE -#define JL_ROOTS_TEMPORARILY #define JL_REQUIRE_ROOTED_SLOT #define JL_GC_PROMISE_ROOTED(x) (void)(x) #define jl_may_leak(x) (void)(x) diff --git a/src/sys.c b/src/sys.c index e2ed570717a2e..fad9d1e217c2f 100644 --- a/src/sys.c +++ b/src/sys.c @@ -263,7 +263,7 @@ JL_DLLEXPORT jl_array_t *jl_take_buffer(ios_t *s) // 0 - keep delimiter // 1 - remove 1 byte delimiter // 2 - remove 2 bytes \r\n if present -JL_DLLEXPORT jl_value_t *jl_readuntil(ios_t *s, uint8_t delim, uint8_t str, uint8_t chomp) +JL_DLLEXPORT jl_value_t *jl_readuntil(ios_t *s, uint8_t delim, uint8_t str, uint8_t chomp) JL_CANSAFEPOINT { jl_array_t *a; // manually inlined common case @@ -788,6 +788,8 @@ JL_DLLEXPORT const char *jl_pathname_for_handle(void *handle) JL_NOTSAFEPOINT // dlopen() each image, check handle. const char *image_name = _dyld_get_image_name(i); void *probe_lib = jl_dlopen(image_name, JL_RTLD_DEFAULT | JL_RTLD_NOLOAD); + if (!probe_lib) + continue; jl_dlclose(probe_lib); // If the handle is the same as what was passed in (modulo mode bits), return this image name @@ -968,7 +970,7 @@ static int dllist_helper(struct dl_phdr_info *info, size_t size, void *vdata) JL // This is done in C, rather than a Julia `dl_iterate_phdr` callback, so that // no Julia code (which can allocate, run finalizers, or re-enter the linker // via (lazy) `ccall`) runs under the dynamic loader lock. See `dllist_helper` -JL_DLLEXPORT int jl_dllist(jl_array_t *list) +JL_DLLEXPORT int jl_dllist(jl_array_t *list) JL_CANSAFEPOINT { arraylist_t names; arraylist_new(&names, 0); diff --git a/src/task.c b/src/task.c index 7bba3ee3d83b1..1abd792a70c02 100644 --- a/src/task.c +++ b/src/task.c @@ -179,7 +179,7 @@ static void JL_NO_ASAN JL_NO_MSAN memcpy_stack_a16(uint64_t *to, uint64_t *from, #endif } -static void NOINLINE save_stack(jl_ptls_t ptls, jl_task_t *lastt, jl_task_t **pt) +static void NOINLINE save_stack(jl_ptls_t ptls, jl_task_t *lastt, jl_task_t **pt) JL_CANSAFEPOINT { char *frame_addr = (char*)((uintptr_t)jl_get_frame_addr() & ~15); char *stackbase = (char*)ptls->stackbase; @@ -419,7 +419,7 @@ JL_DLLEXPORT jl_task_t *jl_get_next_task(void) JL_NOTSAFEPOINT const char tsan_state_corruption[] = "TSAN state corrupted. Exiting HARD!\n"; #endif -JL_NO_ASAN static void ctx_switch(jl_task_t *lastt) +JL_NO_ASAN static void ctx_switch(jl_task_t *lastt) JL_CANSAFEPOINT { jl_ptls_t ptls = lastt->ptls; jl_task_t **pt = &ptls->next_task; @@ -657,7 +657,7 @@ JL_NO_ASAN static void ctx_switch(jl_task_t *lastt) sanitizer_finish_switch_fiber(&ptls->previous_task->ctx, &lastt->ctx); } -JL_DLLEXPORT void jl_switch(void) JL_NOTSAFEPOINT_LEAVE JL_NOTSAFEPOINT_ENTER +JL_DLLEXPORT void jl_switch(void) JL_CANSAFEPOINT_ENTER_LEAVE { jl_task_t *ct = jl_current_task; jl_ptls_t ptls = ct->ptls; @@ -713,13 +713,13 @@ JL_DLLEXPORT void jl_switch(void) JL_NOTSAFEPOINT_LEAVE JL_NOTSAFEPOINT_ENTER jl_gc_unsafe_leave(ptls, gc_state); } -JL_DLLEXPORT void jl_switchto(jl_task_t **pt) // n.b. this does not actually enter a safepoint +JL_DLLEXPORT void jl_switchto(jl_task_t **pt) { jl_set_next_task(*pt); jl_switch(); } -JL_DLLEXPORT JL_NORETURN void jl_no_exc_handler(jl_value_t *e, jl_task_t *ct) +JL_DLLEXPORT JL_NORETURN void JL_NO_SAFEPOINT_ANALYSIS jl_no_exc_handler(jl_value_t *e, jl_task_t *ct) { // NULL exception objects are used when rethrowing. we don't have a handler to process // the exception stack, so at least report the exception at the top of the stack. @@ -776,7 +776,7 @@ JL_DLLEXPORT JL_NORETURN void jl_no_exc_handler(jl_value_t *e, jl_task_t *ct) #define pop_timings_stack() /* Nothing */ #endif -static void JL_NORETURN throw_internal(jl_task_t *ct, jl_value_t *exception JL_MAYBE_UNROOTED) +static void JL_NORETURN throw_internal(jl_task_t *ct, jl_value_t *exception JL_MAYBE_UNROOTED) JL_CANSAFEPOINT_ENTER { JL_GC_PUSH1(&exception); jl_ptls_t ptls = ct->ptls; @@ -805,7 +805,7 @@ static void JL_NORETURN throw_internal(jl_task_t *ct, jl_value_t *exception JL_M } // record backtrace and raise an error -JL_DLLEXPORT void jl_throw(jl_value_t *e JL_MAYBE_UNROOTED) +JL_DLLEXPORT void JL_NO_SAFEPOINT_ANALYSIS jl_throw(jl_value_t *e JL_MAYBE_UNROOTED) { assert(e != NULL); jl_jmp_buf *safe_restore = jl_get_safe_restore(); @@ -821,7 +821,7 @@ JL_DLLEXPORT void jl_throw(jl_value_t *e JL_MAYBE_UNROOTED) } // rethrow with current excstack state -JL_DLLEXPORT void jl_rethrow(void) +JL_DLLEXPORT void JL_NO_SAFEPOINT_ANALYSIS jl_rethrow(void) { jl_task_t *ct = jl_current_task; jl_excstack_t *excstack = ct->excstack; @@ -830,7 +830,7 @@ JL_DLLEXPORT void jl_rethrow(void) throw_internal(ct, NULL); } -JL_DLLEXPORT void jl_rethrow_other(jl_value_t *e JL_MAYBE_UNROOTED) +JL_DLLEXPORT void JL_NO_SAFEPOINT_ANALYSIS jl_rethrow_other(jl_value_t *e JL_MAYBE_UNROOTED) { // TODO: Should uses of `rethrow(exc)` be replaced with a normal throw, now // that exception stacks allow root cause analysis? @@ -1142,7 +1142,7 @@ JL_DLLEXPORT jl_task_t *jl_get_current_task(void) } // Do one-time initializations for task system -void jl_init_tasks(void) JL_GC_DISABLED +void jl_init_tasks(void) { char *acs = getenv("JULIA_COPY_STACKS"); if (acs) { @@ -1175,10 +1175,10 @@ void jl_init_tasks(void) JL_GC_DISABLED } #if defined(_COMPILER_ASAN_ENABLED_) -static void NOINLINE JL_NORETURN _start_task(void); +static void NOINLINE JL_NORETURN _start_task(void) JL_CANSAFEPOINT; #endif -static void NOINLINE JL_NORETURN JL_NO_ASAN start_task(void) +static void NOINLINE JL_NORETURN JL_NO_ASAN start_task(void) JL_CANSAFEPOINT { CFI_NORETURN #if defined(_COMPILER_ASAN_ENABLED_) diff --git a/src/threading.c b/src/threading.c index 05d71b2d691ae..aa63c41b34d32 100644 --- a/src/threading.c +++ b/src/threading.c @@ -59,7 +59,7 @@ JL_DLLEXPORT void *jl_get_ptls_states(void) return jl_current_task->ptls; } -static void jl_delete_thread(void*) JL_NOTSAFEPOINT_ENTER; +static void jl_delete_thread(void*) JL_CANSAFEPOINT_ENTER_LEAVE; #if !defined(_OS_WINDOWS_) static pthread_key_t jl_task_exit_key; @@ -68,7 +68,7 @@ static pthread_key_t jl_safe_restore_key; static __attribute__((constructor)) void _jl_init_safe_restore(void) { pthread_key_create(&jl_safe_restore_key, NULL); - pthread_key_create(&jl_task_exit_key, jl_delete_thread); + pthread_key_create(&jl_task_exit_key, jl_delete_thread); // NOLINT[julia-first-decl-annotations] } JL_DLLEXPORT jl_jmp_buf *jl_get_safe_restore(void) @@ -375,7 +375,11 @@ jl_ptls_t jl_init_threadtls(int16_t tid) hMainThread = ptls->system_id; #endif } +#ifdef __clang_safetyanalysis__ + jl_gc_unsafe_enter(ptls); +#else jl_atomic_store_relaxed(&ptls->gc_state, JL_GC_STATE_UNSAFE); // GC unsafe +#endif // Conditionally initialize the safepoint address. See comment in // `safepoint.c` if (tid == 0) { @@ -429,7 +433,7 @@ jl_ptls_t jl_init_threadtls(int16_t tid) static _Atomic(jl_value_t*) init_task_lock_func JL_GLOBALLY_ROOTED = NULL; -static void jl_init_task_lock(jl_task_t *ct) +static void jl_init_task_lock(jl_task_t *ct) JL_CANSAFEPOINT { size_t last_age = ct->world_age; ct->world_age = jl_get_world_counter(); @@ -475,7 +479,7 @@ JL_DLLEXPORT jl_gcframe_t **jl_adopt_thread(void) return &ct->gcstack; } -JL_DLLEXPORT jl_gcframe_t **jl_autoinit_and_adopt_thread(void) +JL_DLLEXPORT jl_gcframe_t **jl_autoinit_and_adopt_thread(void) JL_CANSAFEPOINT_ENTER { if (!jl_is_initialized()) { void *retaddr = __builtin_extract_return_addr(__builtin_return_address(0)); @@ -629,7 +633,7 @@ static inline size_t jl_add_tls_size(size_t orig_size, size_t size, size_t align { return LLT_ALIGN(orig_size, align) + size; } -static inline ssize_t jl_check_tls_bound(void *tp, jl_gcframe_t ***k0, size_t tls_size) +static inline ssize_t jl_check_tls_bound(void *tp, jl_gcframe_t ***k0, size_t tls_size) JL_NOTSAFEPOINT { ssize_t offset = (char*)k0 - (char*)tp; if (offset < JL_ELF_TLS_INIT_SIZE || @@ -644,7 +648,7 @@ static inline size_t jl_add_tls_size(size_t orig_size, size_t size, size_t align { return LLT_ALIGN(orig_size + size, align); } -static inline ssize_t jl_check_tls_bound(void *tp, jl_gcframe_t ***k0, size_t tls_size) +static inline ssize_t jl_check_tls_bound(void *tp, jl_gcframe_t ***k0, size_t tls_size) JL_NOTSAFEPOINT { ssize_t offset = (char*)tp - (char*)k0; if (offset < sizeof(*k0) || offset > tls_size) @@ -680,10 +684,10 @@ static int check_tls_cb(struct dl_phdr_info *info, size_t size, void *_data) return 1; } -static void jl_check_tls(void) +static void jl_check_tls(void) JL_NOTSAFEPOINT { jl_get_pgcstack_func_t f; - jl_gcframe_t ***(*k)(void); + jl_pgcstack_key_t k; jl_pgcstack_getkey(&f, &k); jl_gcframe_t ***k0 = k(); if (k0 == NULL) @@ -886,7 +890,7 @@ void jl_start_threads(void) jl_threadarg_t *t = (jl_threadarg_t *)malloc_s(sizeof(jl_threadarg_t)); // ownership will be passed to the thread t->tid = i; t->barrier = &thread_init_done; - uv_thread_create(&uvtid, jl_threadfun, t); + uv_thread_create(&uvtid, jl_threadfun, t); // NOLINT[julia-first-decl-annotations] // Interactive pool threads get the low IDs, so check if this is a // default pool thread. The master thread is already on CPU 0. @@ -926,7 +930,7 @@ JL_DLLEXPORT void jl_exit_threaded_region(void) } } -JL_DLLEXPORT void jl_set_io_loop_tid(int16_t tid) +JL_DLLEXPORT void jl_set_io_loop_tid(int16_t tid) JL_CANSAFEPOINT { if (tid < 0 || tid >= jl_atomic_load_relaxed(&jl_n_threads)) { // TODO: do we care if this thread has exited or not started yet, @@ -963,7 +967,7 @@ void _jl_mutex_init(jl_mutex_t *lock, const char *name) JL_NOTSAFEPOINT #endif } -void _jl_mutex_wait(jl_task_t *self, jl_mutex_t *lock, int safepoint) +void _jl_mutex_wait(jl_task_t *self, jl_mutex_t *lock, int safepoint) JL_NO_SAFEPOINT_ANALYSIS { jl_task_t *owner = jl_atomic_load_relaxed(&lock->owner); if (jl_mutex_owner(owner) == self) { @@ -1025,7 +1029,7 @@ void _jl_mutex_wait(jl_task_t *self, jl_mutex_t *lock, int safepoint) #endif } -static void jl_lock_frame_push(jl_task_t *self, jl_mutex_t *lock) +static void jl_lock_frame_push(jl_task_t *self, jl_mutex_t *lock) JL_NOTSAFEPOINT { jl_ptls_t ptls = self->ptls; small_arraylist_t *locks = &ptls->locks; @@ -1059,7 +1063,7 @@ void _jl_mutex_lock(jl_task_t *self, jl_mutex_t *lock) #endif } -int _jl_mutex_trylock_nogc(jl_task_t *self, jl_mutex_t *lock) +int _jl_mutex_trylock_nogc(jl_task_t *self, jl_mutex_t *lock) JL_NO_SAFEPOINT_ANALYSIS { #ifdef _COMPILER_TSAN_ENABLED_ __tsan_mutex_pre_lock(lock, __tsan_mutex_try_lock | __tsan_mutex_write_reentrant); @@ -1091,7 +1095,7 @@ int _jl_mutex_trylock_nogc(jl_task_t *self, jl_mutex_t *lock) return ret; } -int _jl_mutex_trylock(jl_task_t *self, jl_mutex_t *lock) +int _jl_mutex_trylock(jl_task_t *self, jl_mutex_t *lock) JL_NO_SAFEPOINT_ANALYSIS { int got = _jl_mutex_trylock_nogc(self, lock); if (got) { @@ -1101,7 +1105,7 @@ int _jl_mutex_trylock(jl_task_t *self, jl_mutex_t *lock) return got; } -void _jl_mutex_unlock_nogc(jl_mutex_t *lock) +void _jl_mutex_unlock_nogc(jl_mutex_t *lock) JL_NO_SAFEPOINT_ANALYSIS { #ifndef __clang_gcanalyzer__ #ifdef _COMPILER_TSAN_ENABLED_ @@ -1128,7 +1132,7 @@ void _jl_mutex_unlock_nogc(jl_mutex_t *lock) #endif } -void _jl_mutex_unlock(jl_task_t *self, jl_mutex_t *lock) +void _jl_mutex_unlock(jl_task_t *self, jl_mutex_t *lock) JL_NO_SAFEPOINT_ANALYSIS { _jl_mutex_unlock_nogc(lock); jl_lock_frame_pop(self); diff --git a/src/threading.h b/src/threading.h index cb26537699713..2d6819781a3d5 100644 --- a/src/threading.h +++ b/src/threading.h @@ -23,13 +23,13 @@ typedef struct _jl_threadarg_t { } jl_threadarg_t; // each thread must initialize its TLS -jl_ptls_t jl_init_threadtls(int16_t tid) JL_NOTSAFEPOINT; +jl_ptls_t jl_init_threadtls(int16_t tid) JL_CANSAFEPOINT_ENTER; // provided by a threading infrastructure -void jl_init_threadinginfra(void); -void jl_parallel_gc_threadfun(void *arg); -void jl_concurrent_gc_threadfun(void *arg); -void jl_threadfun(void *arg); +void jl_init_threadinginfra(void) JL_NOTSAFEPOINT; +void jl_parallel_gc_threadfun(void *arg) JL_CANSAFEPOINT_ENTER_LEAVE; +void jl_concurrent_gc_threadfun(void *arg) JL_CANSAFEPOINT_ENTER_LEAVE; +void jl_threadfun(void *arg) JL_CANSAFEPOINT_ENTER_LEAVE; #ifdef __cplusplus } diff --git a/src/toplevel.c b/src/toplevel.c index 4dab941b5d9c8..92a1f0502d1ae 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -30,7 +30,7 @@ JL_DLLEXPORT _Atomic(int) jl_lineno = 0; // need to update jl_fprint_critical_er // current file name JL_DLLEXPORT _Atomic(const char *) jl_filename = "none"; // need to update jl_fprint_critical_error if this is TLS -static jl_value_t *jl_eval_toplevel_stmts(jl_module_t *JL_NONNULL m, jl_array_t *stmts, int fast, int need_value, const char **toplevel_filename, int *toplevel_lineno); +static jl_value_t *jl_eval_toplevel_stmts(jl_module_t *JL_NONNULL m, jl_array_t *stmts, int fast, int need_value, const char **toplevel_filename, int *toplevel_lineno) JL_CANSAFEPOINT; htable_t jl_current_modules; jl_mutex_t jl_modules_mutex; @@ -83,7 +83,7 @@ void jl_module_run_initializer(jl_module_t *m) } } -static void jl_register_root_module(jl_module_t *m) +static void jl_register_root_module(jl_module_t *m) JL_CANSAFEPOINT { jl_value_t *register_module_func = NULL; assert(jl_base_module); @@ -109,13 +109,13 @@ jl_array_t *jl_get_loaded_modules(void) return NULL; } -static int jl_is__toplevel__mod(jl_module_t *mod, jl_task_t *ct) +static int jl_is__toplevel__mod(jl_module_t *mod, jl_task_t *ct) JL_CANSAFEPOINT { return jl_base_module && (jl_value_t*)mod == jl_get_global_value(jl_base_module, jl_symbol("__toplevel__"), ct->world_age); } -JL_DLLEXPORT void jl_setup_new_module(jl_module_t *m, jl_value_t *syntax_version) +JL_DLLEXPORT void jl_setup_new_module(jl_module_t *m, jl_value_t *syntax_version) JL_CANSAFEPOINT { jl_task_t *ct = jl_current_task; size_t last_age = ct->world_age; @@ -134,7 +134,7 @@ JL_DLLEXPORT void jl_setup_new_module(jl_module_t *m, jl_value_t *syntax_version } JL_DLLEXPORT jl_module_t *jl_begin_new_module(jl_module_t *parent_module, jl_sym_t *name, jl_value_t *syntax_version, - int std_imports, const char *filename, int lineno) + int std_imports, const char *filename, int lineno) JL_CANSAFEPOINT { jl_task_t *ct = jl_current_task; int is_parent__toplevel__ = jl_is__toplevel__mod(parent_module, ct); @@ -176,7 +176,7 @@ JL_DLLEXPORT jl_module_t *jl_begin_new_module(jl_module_t *parent_module, jl_sym return newm; } -JL_DLLEXPORT void jl_end_new_module(jl_module_t *newm) { +JL_DLLEXPORT void jl_end_new_module(jl_module_t *newm) JL_CANSAFEPOINT { jl_value_t *form = NULL; JL_GC_PUSH1(&form); JL_LOCK(&jl_modules_mutex); @@ -224,7 +224,7 @@ JL_DLLEXPORT void jl_end_new_module(jl_module_t *newm) { JL_GC_POP(); } -static jl_value_t *jl_eval_module_expr(jl_module_t *parent_module, jl_expr_t *ex, const char **toplevel_filename, int *toplevel_lineno) +static jl_value_t *jl_eval_module_expr(jl_module_t *parent_module, jl_expr_t *ex, const char **toplevel_filename, int *toplevel_lineno) JL_CANSAFEPOINT { assert(ex->head == jl_module_sym); @@ -269,7 +269,7 @@ static jl_value_t *jl_eval_module_expr(jl_module_t *parent_module, jl_expr_t *ex return (jl_value_t*)newm; } -static jl_value_t *jl_eval_dot_expr(jl_task_t *ct, jl_module_t *m, jl_value_t *x, jl_value_t *f, int fast, const char **toplevel_filename, int *toplevel_lineno) +static jl_value_t *jl_eval_dot_expr(jl_task_t *ct, jl_module_t *m, jl_value_t *x, jl_value_t *f, int fast, const char **toplevel_filename, int *toplevel_lineno) JL_CANSAFEPOINT { jl_value_t **args; JL_GC_PUSHARGS(args, 3); @@ -377,7 +377,7 @@ JL_DLLEXPORT jl_module_t *jl_base_relative_to(jl_module_t *m) return jl_top_module; } -static void expr_attributes(jl_value_t *v, jl_array_t *body, int *has_ccall, int *has_defs, int *has_opaque) +static void expr_attributes(jl_value_t *v, jl_array_t *body, int *has_ccall, int *has_defs, int *has_opaque) JL_CANSAFEPOINT { if (!jl_is_expr(v)) return; @@ -463,7 +463,7 @@ int jl_code_requires_compiler(jl_code_info_t *src, int include_force_compile) return 0; } -static void body_attributes(jl_array_t *body, int *has_ccall, int *has_defs, int *has_loops, int *has_opaque, int *forced_compile) +static void body_attributes(jl_array_t *body, int *has_ccall, int *has_defs, int *has_loops, int *has_opaque, int *forced_compile) JL_CANSAFEPOINT { size_t i; *has_loops = 0; @@ -524,7 +524,7 @@ JL_DLLEXPORT jl_code_instance_t *jl_new_codeinst_for_uninferred(jl_method_instan return ci; } -JL_DLLEXPORT jl_method_instance_t *jl_method_instance_for_thunk(jl_code_info_t *src, jl_module_t *module) +JL_DLLEXPORT jl_method_instance_t *jl_method_instance_for_thunk(jl_code_info_t *src, jl_module_t *module) JL_CANSAFEPOINT { jl_method_instance_t *mi = jl_new_method_instance_uninit(); mi->specTypes = (jl_value_t*)jl_emptytuple_type; @@ -541,7 +541,7 @@ JL_DLLEXPORT jl_method_instance_t *jl_method_instance_for_thunk(jl_code_info_t * // Eval `throw(exc)` in module `m`. // Used in `jl_toplevel_eval_flex` instead of `jl_throw` so that the error // location in julia code gets into the backtrace. -static void jl_eval_throw(jl_module_t *m, jl_value_t *exc, const char *filename, int lineno) +static void jl_eval_throw(jl_module_t *m, jl_value_t *exc, const char *filename, int lineno) JL_CANSAFEPOINT { jl_value_t *throw_ex = (jl_value_t*)jl_exprn(jl_call_sym, 2); JL_GC_PUSH1(&throw_ex); @@ -552,7 +552,7 @@ static void jl_eval_throw(jl_module_t *m, jl_value_t *exc, const char *filename, } // Format error message and call jl_eval -static void jl_eval_errorf(jl_module_t *m, const char *filename, int lineno, const char* fmt, ...) +static void jl_eval_errorf(jl_module_t *m, const char *filename, int lineno, const char* fmt, ...) JL_CANSAFEPOINT { va_list args; va_start(args, fmt); @@ -782,7 +782,7 @@ JL_DLLEXPORT jl_value_t *jl_toplevel_eval(jl_module_t *m, jl_value_t *v) } // Check module `m` is open for `eval/include`, or throw an error. -JL_DLLEXPORT void jl_check_top_level_effect(jl_module_t *m, char *fname) +JL_DLLEXPORT void jl_check_top_level_effect(jl_module_t *m, char *fname) JL_CANSAFEPOINT { if (jl_current_task->ptls->in_pure_callback) jl_errorf("%s cannot be used in a generated function", fname); @@ -844,7 +844,7 @@ JL_DLLEXPORT jl_value_t *jl_toplevel_eval_in(jl_module_t *m, jl_value_t *ex) // `filename`. This is used during bootstrap, but the real Base.include() is // implemented in Julia code. static jl_value_t *jl_parse_eval_all(jl_module_t *module, jl_value_t *text, - jl_value_t *filename) + jl_value_t *filename) JL_CANSAFEPOINT { if (!jl_is_string(text) || !jl_is_string(filename)) { jl_errorf("Expected `String`s for `text` and `filename`"); @@ -904,7 +904,7 @@ static jl_value_t *jl_parse_eval_all(jl_module_t *module, jl_value_t *text, } // Synchronously read content of entire file into a julia String -static jl_value_t *jl_file_content_as_string(jl_value_t *filename) +static jl_value_t *jl_file_content_as_string(jl_value_t *filename) JL_CANSAFEPOINT { const char *fname = jl_string_data(filename); ios_t f; @@ -923,7 +923,7 @@ static jl_value_t *jl_file_content_as_string(jl_value_t *filename) // Load and parse julia code from the file `filename`. Eval the resulting // statements into `module` after applying `mapexpr` to each one. -JL_DLLEXPORT jl_value_t *jl_load_(jl_module_t *module, jl_value_t *filename) +JL_DLLEXPORT jl_value_t *jl_load_(jl_module_t *module, jl_value_t *filename) JL_CANSAFEPOINT { jl_value_t *text = jl_file_content_as_string(filename); JL_GC_PUSH1(&text); @@ -964,7 +964,7 @@ JL_DLLEXPORT jl_value_t *jl_load_file_string(const char *text, size_t len, //-------------------------------------------------- // Code loading helpers for bootstrap -JL_DLLEXPORT jl_value_t *jl_prepend_cwd(jl_value_t *str) +JL_DLLEXPORT jl_value_t *jl_prepend_cwd(jl_value_t *str) JL_CANSAFEPOINT { size_t sz = 1024; char path[1024]; @@ -981,7 +981,7 @@ JL_DLLEXPORT jl_value_t *jl_prepend_cwd(jl_value_t *str) return jl_cstr_to_string(path); } -JL_DLLEXPORT jl_value_t *jl_prepend_string(jl_value_t *prefix, jl_value_t *str) +JL_DLLEXPORT jl_value_t *jl_prepend_string(jl_value_t *prefix, jl_value_t *str) JL_CANSAFEPOINT { char path[1024]; const char *pstr = (const char*)jl_string_data(prefix); diff --git a/src/typemap.c b/src/typemap.c index ce2cc315908d6..90d93795c3640 100644 --- a/src/typemap.c +++ b/src/typemap.c @@ -117,7 +117,7 @@ static int jl_parameter_includes_bottom(jl_value_t *t1) // ----- Type Signature Subtype Testing ----- // -static int sig_match_by_type_leaf(jl_value_t **types, jl_tupletype_t *sig, size_t n) +static int sig_match_by_type_leaf(jl_value_t **types, jl_tupletype_t *sig, size_t n) JL_CANSAFEPOINT { size_t i; for (i = 0; i < n; i++) { @@ -152,7 +152,7 @@ static int jl_subtype_anytype(jl_value_t *a) JL_NOTSAFEPOINT } } -static int sig_match_by_type_simple(jl_value_t **types, size_t n, jl_tupletype_t *sig, size_t lensig, int va) +static int sig_match_by_type_simple(jl_value_t **types, size_t n, jl_tupletype_t *sig, size_t lensig, int va) JL_CANSAFEPOINT { size_t i; if (va) lensig -= 1; @@ -235,7 +235,7 @@ static inline int sig_match_leaf(jl_value_t *arg1, jl_value_t **args, jl_value_t } static inline int sig_match_simple(jl_value_t *arg1, jl_value_t **args, size_t n, jl_value_t **sig, - int va, size_t lensig) + int va, size_t lensig) JL_CANSAFEPOINT { // NOTE: This function is a performance hot spot!! size_t i; @@ -325,7 +325,7 @@ static _Atomic(jl_value_t*) *mtcache_hash_lookup_bp(jl_genericmemory_t *cache JL return pml; } -static void mtcache_hash_insert(_Atomic(jl_genericmemory_t*) *pcache, jl_value_t *parent, jl_value_t *key, jl_typemap_t *val) +static void mtcache_hash_insert(_Atomic(jl_genericmemory_t*) *pcache, jl_value_t *parent, jl_value_t *key, jl_typemap_t *val) JL_CANSAFEPOINT { int inserted = 0; jl_genericmemory_t *a = jl_atomic_load_relaxed(pcache); @@ -354,7 +354,7 @@ static jl_typemap_t *mtcache_hash_lookup(jl_genericmemory_t *cache JL_PROPAGATES // ----- Sorted Type Signature Lookup Matching ----- // -static int jl_typemap_memory_visitor(jl_genericmemory_t *a, jl_typemap_visitor_fptr fptr, void *closure) +static int jl_typemap_memory_visitor(jl_genericmemory_t *a, jl_typemap_visitor_fptr fptr, void *closure) JL_CANSAFEPOINT { size_t i, l = a->length; _Atomic(jl_typemap_t*) *data = (_Atomic(jl_typemap_t*)*) a->ptr; @@ -377,7 +377,7 @@ static int jl_typemap_memory_visitor(jl_genericmemory_t *a, jl_typemap_visitor_f // calls fptr on each jl_typemap_entry_t in cache in sort order, until fptr returns false -static int jl_typemap_node_visitor(jl_typemap_entry_t *ml, jl_typemap_visitor_fptr fptr, void *closure) +static int jl_typemap_node_visitor(jl_typemap_entry_t *ml, jl_typemap_visitor_fptr fptr, void *closure) JL_CANSAFEPOINT { while (ml != (void*)jl_nothing) { if (!fptr(ml, closure)) @@ -483,7 +483,7 @@ static int tname_intersection(jl_value_t *a, jl_typename_t *bname, int8_t tparam return 0; } -static int concrete_intersects(jl_value_t *t, jl_value_t *ty, int8_t tparam) +static int concrete_intersects(jl_value_t *t, jl_value_t *ty, int8_t tparam) JL_CANSAFEPOINT { if (ty == (jl_value_t*)jl_any_type) // easy case: Any always matches return 1; @@ -496,7 +496,7 @@ static int concrete_intersects(jl_value_t *t, jl_value_t *ty, int8_t tparam) // tparam bit 0 is ::Type{T} (vs. T) // tparam bit 1 is typename(T) (vs. T) static int jl_typemap_intersection_memory_visitor(jl_genericmemory_t *a, jl_value_t *ty, int8_t tparam, - int8_t offs, struct typemap_intersection_env *closure) + int8_t offs, struct typemap_intersection_env *closure) JL_CANSAFEPOINT { JL_GC_PUSH1(&a); size_t i, l = a->length; @@ -568,7 +568,7 @@ static int jl_typemap_intersection_memory_visitor(jl_genericmemory_t *a, jl_valu // calls fptr on each jl_typemap_entry_t in cache in sort order // for which type ∩ ml->type != Union{}, until fptr return false -static int jl_typemap_intersection_node_visitor(jl_typemap_entry_t *ml, struct typemap_intersection_env *closure) +static int jl_typemap_intersection_node_visitor(jl_typemap_entry_t *ml, struct typemap_intersection_env *closure) JL_CANSAFEPOINT { // slow-path scan everything in ml // mark this `register` because (for branch prediction) @@ -878,7 +878,7 @@ int jl_typemap_intersection_visitor(jl_typemap_t *map, int offs, */ static jl_typemap_entry_t *jl_typemap_entry_assoc_by_type( jl_typemap_entry_t *ml, - struct jl_typemap_assoc *search) + struct jl_typemap_assoc *search) JL_CANSAFEPOINT { jl_value_t *types = search->types; JL_GC_PROMISE_ROOTED(types); @@ -936,7 +936,7 @@ static jl_typemap_entry_t *jl_typemap_entry_assoc_by_type( } static jl_typemap_entry_t *jl_typemap_entry_lookup_by_type( - jl_typemap_entry_t *ml, struct jl_typemap_assoc *search) + jl_typemap_entry_t *ml, struct jl_typemap_assoc *search) JL_CANSAFEPOINT { for (; ml != (void*)jl_nothing; ml = jl_atomic_load_relaxed(&ml->next)) { if (search->world < jl_atomic_load_relaxed(&ml->min_world) || search->world > jl_atomic_load_relaxed(&ml->max_world)) @@ -1319,9 +1319,9 @@ static unsigned jl_typemap_list_count_locked(jl_typemap_entry_t *ml) JL_NOTSAFEP return count; } -static void jl_typemap_level_insert_(jl_typemap_t *map, jl_typemap_level_t *cache, jl_typemap_entry_t *newrec, int8_t offs); +static void jl_typemap_level_insert_(jl_typemap_t *map, jl_typemap_level_t *cache, jl_typemap_entry_t *newrec, int8_t offs) JL_CANSAFEPOINT; -static jl_typemap_level_t *jl_new_typemap_level(void) +static jl_typemap_level_t *jl_new_typemap_level(void) JL_CANSAFEPOINT { jl_task_t *ct = jl_current_task; jl_typemap_level_t *cache = @@ -1338,10 +1338,10 @@ static jl_typemap_level_t *jl_new_typemap_level(void) static void jl_typemap_memory_insert_( jl_typemap_t *map, _Atomic(jl_genericmemory_t*) *pcache, jl_value_t *key, jl_typemap_entry_t *newrec, - jl_value_t *parent, int8_t tparam, int8_t offs, jl_value_t *doublesplit); + jl_value_t *parent, int8_t tparam, int8_t offs, jl_value_t *doublesplit) JL_CANSAFEPOINT; static jl_value_t *jl_method_convert_list_to_cache( - jl_typemap_t *map, jl_typemap_entry_t *ml, int8_t tparam, int8_t offs, int8_t doublesplit) + jl_typemap_t *map, jl_typemap_entry_t *ml, int8_t tparam, int8_t offs, int8_t doublesplit) JL_CANSAFEPOINT { _Atomic(jl_genericmemory_t*) dblcache = (jl_genericmemory_t*)jl_an_empty_memory_any; jl_typemap_level_t *cache = doublesplit ? NULL : jl_new_typemap_level(); @@ -1400,7 +1400,7 @@ static void jl_typemap_list_insert_( // n.b. tparam value only needed if doublesplit is set (for jl_method_convert_list_to_cache) static void jl_typemap_insert_generic( jl_typemap_t *map, _Atomic(jl_value_t*) *pml, jl_value_t *parent, - jl_typemap_entry_t *newrec, int8_t tparam, int8_t offs, jl_value_t *doublesplit) + jl_typemap_entry_t *newrec, int8_t tparam, int8_t offs, jl_value_t *doublesplit) JL_CANSAFEPOINT { jl_value_t *ml = jl_atomic_load_relaxed(pml); if (jl_is_genericmemory(ml)) { diff --git a/test/clangsa/FirstDeclAnnotationsTest.c b/test/clangsa/FirstDeclAnnotationsTest.c index 4238fca4500d3..9fb597638e531 100644 --- a/test/clangsa/FirstDeclAnnotationsTest.c +++ b/test/clangsa/FirstDeclAnnotationsTest.c @@ -18,12 +18,12 @@ #include "FirstDeclAnnotationsTest.h" -void fda_ok_both(void) JL_NOTSAFEPOINT {} +void fda_ok_both(void) JL_CANSAFEPOINT {} void fda_ok_header_only(void) {} -// CHECK: warning: Julia annotation "julia_not_safepoint" is on this declaration of 'fda_missing_func' but missing from its first declaration +// CHECK: warning: Julia annotation "julia_can_safepoint" is on this declaration of 'fda_missing_func' but missing from its first declaration // CHECK-FIXES: {{^}}void fda_missing_func(void) {}{{$}} -// CHECK-FIXES-H: {{^}}void fda_missing_func(void) JL_NOTSAFEPOINT;{{$}} -void fda_missing_func(void) JL_NOTSAFEPOINT {} +// CHECK-FIXES-H: {{^}}void fda_missing_func(void) JL_CANSAFEPOINT;{{$}} +void fda_missing_func(void) JL_CANSAFEPOINT {} int fda_ok_param(int *p) { return *p; } // CHECK: warning: Julia annotation "julia_propagates_root" is on parameter 1 of this declaration of 'fda_missing_param' but missing from its first declaration @@ -31,6 +31,12 @@ int fda_ok_param(int *p) { return *p; } // CHECK-FIXES-H: {{^}}int fda_missing_param(int *p JL_PROPAGATES_ROOT);{{$}} int fda_missing_param(int *p JL_PROPAGATES_ROOT) { return *p; } +int fda_ok_cbparam(void (*cb)(int) JL_CANSAFEPOINT) { cb(0); return 0; } +// CHECK: warning: Julia annotation "julia_can_safepoint" is on parameter 1 of this declaration of 'fda_missing_cbparam' but missing from its first declaration +// CHECK-FIXES: {{^}}int fda_missing_cbparam(void (*cb)(int)) { cb(0); return 0; }{{$}} +// CHECK-FIXES-H: {{^}}int fda_missing_cbparam(void (*cb)(int) JL_CANSAFEPOINT);{{$}} +int fda_missing_cbparam(void (*cb)(int) JL_CANSAFEPOINT) { cb(0); return 0; } + void fda_ok_vis(void) JL_DLLEXPORT {} // CHECK: warning: Julia annotation "visibility("default")" is on this declaration of 'fda_missing_vis' but missing from its first declaration // CHECK-FIXES: {{^}}void fda_missing_vis(void) {}{{$}} @@ -41,84 +47,85 @@ void fda_missing_vis(void) JL_DLLEXPORT {} // CHECK-FIXES: {{^}}void fda_raw_vis(void) __attribute__((visibility("default"))) {}{{$}} void fda_raw_vis(void) __attribute__((visibility("default"))) {} -// CHECK: warning: Julia annotation "julia_not_safepoint" is on this declaration of 'fda_chain' but missing from its first declaration -// CHECK-FIXES: {{^}}void fda_chain(void) JL_NOTSAFEPOINT;{{$}} +// CHECK: warning: Julia annotation "julia_can_safepoint" is on this declaration of 'fda_chain' but missing from its first declaration +// CHECK-FIXES: {{^}}void fda_chain(void) JL_CANSAFEPOINT;{{$}} // CHECK-FIXES: {{^}}void fda_chain(void);{{$}} void fda_chain(void); -void fda_chain(void) JL_NOTSAFEPOINT; +void fda_chain(void) JL_CANSAFEPOINT; void fda_chain(void) {} // CHECK-FIXES: {{^}}void fda_local(void);{{$}} -// CHECK-FIXES: {{^ *}}void fda_local(void) JL_NOTSAFEPOINT;{{$}} +// CHECK-FIXES: {{^ *}}void fda_local(void) JL_CANSAFEPOINT;{{$}} void fda_local(void); void fda_local_caller(void) { - void fda_local(void) JL_NOTSAFEPOINT; + void fda_local(void) JL_CANSAFEPOINT; fda_local(); } void fda_local(void) {} // CHECK-FIXES: {{^}}void fda_localdef(void) {}{{$}} -// CHECK-FIXES: {{^ *}}void fda_localdef(void) JL_NOTSAFEPOINT;{{$}} +// CHECK-FIXES: {{^ *}}void fda_localdef(void) JL_CANSAFEPOINT;{{$}} void fda_localdef(void) {} void fda_localdef_caller(void) { - void fda_localdef(void) JL_NOTSAFEPOINT; + void fda_localdef(void) JL_CANSAFEPOINT; fda_localdef(); } -// CHECK: warning: Julia annotation "julia_not_safepoint" is on this declaration of 'fda_blockonly' but missing from its first declaration +// CHECK: warning: Julia annotation "julia_can_safepoint" is on this declaration of 'fda_blockonly' but missing from its first declaration void fda_blockonly_caller1(void) { void fda_blockonly(void); fda_blockonly(); } void fda_blockonly_caller2(void) { - void fda_blockonly(void) JL_NOTSAFEPOINT; + void fda_blockonly(void) JL_CANSAFEPOINT; fda_blockonly(); } -// Function-pointer annotation compatibility. Converting a function to fda_cb_t -// (which is JL_NOTSAFEPOINT) requires the function to carry that annotation, in -// every context where the conversion happens. fda_cb_t fda_cb_okglobal = fda_cb_ok; +fda_cb_safepoint_t fda_cb_okglobal2 = fda_cb_bad; +fda_cb_safepoint_t fda_cb_okglobal3 = fda_cb_ok; -// CHECK: warning: 'fda_cb_bad' is converted to a function pointer of type 'fda_cb_t'{{.*}}requires Julia annotation "julia_not_safepoint", but 'fda_cb_bad' is not annotated "julia_not_safepoint" +// CHECK: warning: 'fda_cb_bad' is annotated "julia_can_safepoint" but is converted to a function pointer of type 'fda_cb_t'{{.*}}that is not fda_cb_t fda_cb_badglobal = fda_cb_bad; void fda_cb_uses(void) { fda_cb_t a = fda_cb_ok; fda_cb_t b = uv_fda_fake; - // CHECK: warning: 'fda_cb_bad' is converted to a function pointer of type 'fda_cb_t'{{.*}}"julia_not_safepoint" + // CHECK: warning: 'fda_cb_bad' is annotated "julia_can_safepoint" but is converted to a function pointer of type 'fda_cb_t'{{.*}}that is not fda_cb_t c = fda_cb_bad; - // CHECK: warning: 'fda_cb_bad' is converted to a function pointer of type 'fda_cb_t'{{.*}}"julia_not_safepoint" + // CHECK: warning: 'fda_cb_bad' is annotated "julia_can_safepoint" but is converted to a function pointer of type 'fda_cb_t'{{.*}}that is not a = fda_cb_bad; - // CHECK: warning: 'fda_cb_bad' is converted to a function pointer of type 'fda_cb_t'{{.*}}"julia_not_safepoint" + // CHECK: warning: 'fda_cb_bad' is annotated "julia_can_safepoint" but is converted to a function pointer of type 'fda_cb_t'{{.*}}that is not fda_take_cb(fda_cb_bad); - // CHECK: warning: 'fda_cb_bad' is converted to a function pointer of type 'fda_cb_t'{{.*}}"julia_not_safepoint" + // CHECK: warning: 'fda_cb_bad' is annotated "julia_can_safepoint" but is converted to a function pointer of type 'fda_cb_t'{{.*}}that is not fda_take_cb(&fda_cb_bad); + // JL_CANSAFEPOINT, so passing a JL_CANSAFEPOINT function is sound (no warning). + fda_take_cansafepoint_cb(fda_cb_bad); (void)a; (void)b; (void)c; } -// CHECK: warning: 'fda_cb_bad' is converted to a function pointer of type 'fda_cb_t'{{.*}}"julia_not_safepoint" +// CHECK: warning: 'fda_cb_bad' is annotated "julia_can_safepoint" but is converted to a function pointer of type 'fda_cb_t'{{.*}}that is not fda_cb_t fda_cb_ret(void) { return fda_cb_bad; } struct fda_cb_holder { fda_cb_t cb; }; -// CHECK: warning: 'fda_cb_bad' is converted to a function pointer of type 'fda_cb_t'{{.*}}"julia_not_safepoint" +// CHECK: warning: 'fda_cb_bad' is annotated "julia_can_safepoint" but is converted to a function pointer of type 'fda_cb_t'{{.*}}that is not struct fda_cb_holder fda_cb_inst = { fda_cb_bad }; #ifdef __cplusplus -// CHECK-CXX: warning: Julia annotation "julia_not_safepoint" is on this declaration of 'm' but missing from its first declaration +// CHECK-CXX: warning: Julia annotation "julia_can_safepoint" is on this declaration of 'm' but missing from its first declaration struct fda_S { void m(void); }; -void fda_S::m(void) JL_NOTSAFEPOINT {} +void fda_S::m(void) JL_CANSAFEPOINT {} struct fda_Base { - virtual void fda_ovr_ok(void) JL_NOTSAFEPOINT; - virtual void fda_ovr_bad(void) JL_NOTSAFEPOINT; - virtual void fda_ovr_plain(void); + virtual void fda_ovr_ok(void) JL_CANSAFEPOINT; + virtual void fda_ovr_bad(void); + virtual void fda_ovr_plain(void) JL_CANSAFEPOINT; }; struct fda_Derived : fda_Base { - void fda_ovr_ok(void) JL_NOTSAFEPOINT override; - // CHECK-CXX: warning: 'fda_ovr_bad' overrides a method that requires Julia annotation "julia_not_safepoint", but 'fda_ovr_bad' is not annotated "julia_not_safepoint" - void fda_ovr_bad(void) override; + void fda_ovr_ok(void) JL_CANSAFEPOINT override; + // CHECK-CXX: warning: 'fda_ovr_bad' is annotated "julia_can_safepoint" but overrides a method that is not + void fda_ovr_bad(void) JL_CANSAFEPOINT override; void fda_ovr_plain(void) override; }; #endif @@ -127,8 +134,8 @@ struct fda_Derived : fda_Base { // the region as a system header. // Kept last so the line-marker renumbering does not affect the cases above. // CHECK-FIXES: {{^}}void fda_sysproto(void);{{$}} -// CHECK-FIXES: {{^}}void fda_sysproto(void) JL_NOTSAFEPOINT {}{{$}} +// CHECK-FIXES: {{^}}void fda_sysproto(void) JL_CANSAFEPOINT {}{{$}} # 1 "fda_first_decl_annotations_fake_sys.h" 1 3 void fda_sysproto(void); # 1 "FirstDeclAnnotationsTest.c" 2 -void fda_sysproto(void) JL_NOTSAFEPOINT {} +void fda_sysproto(void) JL_CANSAFEPOINT {} diff --git a/test/clangsa/FirstDeclAnnotationsTest.h b/test/clangsa/FirstDeclAnnotationsTest.h index e0e9de995710b..79f52a23d2357 100644 --- a/test/clangsa/FirstDeclAnnotationsTest.h +++ b/test/clangsa/FirstDeclAnnotationsTest.h @@ -12,26 +12,24 @@ #define JL_DLLEXPORT __attribute__((visibility("default"))) #define JL_HIDDEN __attribute__((visibility("hidden"))) -// Annotation present here: definitions may repeat it or inherit it -> OK. -void fda_ok_both(void) JL_NOTSAFEPOINT; -void fda_ok_header_only(void) JL_NOTSAFEPOINT; +void fda_ok_both(void) JL_CANSAFEPOINT; +void fda_ok_header_only(void) JL_CANSAFEPOINT; int fda_ok_param(int *p JL_PROPAGATES_ROOT); -// No annotation here: a definition that adds one is what the check flags. void fda_missing_func(void); int fda_missing_param(int *p); -// Visibility attribute (as JL_DLLEXPORT/JL_HIDDEN expand to) present here -> OK; -// absent here but added on the definition is what the check flags. +int fda_ok_cbparam(void (*cb)(int) JL_CANSAFEPOINT); +int fda_missing_cbparam(void (*cb)(int)); + void fda_ok_vis(void) JL_DLLEXPORT; void fda_missing_vis(void); void fda_raw_vis(void); -// Function-pointer annotation compatibility: a function converted to this -// typedef must carry at least its JL_NOTSAFEPOINT, or calls through the pointer -// would be analyzed unsoundly. -typedef void (*fda_cb_t)(int) JL_NOTSAFEPOINT; -void fda_cb_ok(int x) JL_NOTSAFEPOINT; -void fda_cb_bad(int x); +typedef void (*fda_cb_t)(int); +typedef void (*fda_cb_safepoint_t)(int) JL_CANSAFEPOINT; +void fda_cb_ok(int x); +void fda_cb_bad(int x) JL_CANSAFEPOINT; void uv_fda_fake(int x); void fda_take_cb(fda_cb_t cb); +void fda_take_cansafepoint_cb(void (*cb)(int) JL_CANSAFEPOINT); diff --git a/test/clangsa/MissingRoots.c b/test/clangsa/MissingRoots.c index 71dff4e1b3e95..5433c1f2f10f6 100644 --- a/test/clangsa/MissingRoots.c +++ b/test/clangsa/MissingRoots.c @@ -1027,3 +1027,63 @@ JL_DLLEXPORT jl_value_t *jl_totally_used_function(int i) return v; // expected-warning{{Return value may have been GCed}} // expected-note@-1{{Return value may have been GCed}} } + +// A function explicitly annotated JL_CANSAFEPOINT is treated as a possible +// safepoint even when it is defined locally (so the analyzer inlines it) and +// its body reaches no recognized safepoint. +void inlinable_cansafepoint(void) JL_CANSAFEPOINT { +} +jl_value_t *inlined_cansafepoint_is_safepoint() { + jl_svec_t *val = jl_svec1(NULL); // expected-note{{Started tracking value here}} + inlinable_cansafepoint(); // expected-note{{Value may have been GCed here}} + return jl_svecref(val, 0); // expected-warning{{Argument value may have been GCed}} + // expected-note@-1{{Argument value may have been GCed}} +} + +// Contrast: a locally-defined function with no safepoint in its body and no +// JL_CANSAFEPOINT annotation is not a safepoint, so val survives the call. +void inlinable_no_safepoint(void) JL_NOTSAFEPOINT { +} +jl_value_t *inlined_no_safepoint_is_not_safepoint() { + jl_svec_t *val = jl_svec1(NULL); + inlinable_no_safepoint(); + return jl_svecref(val, 0); +} + +// A conditional enter (e.g. a no-gc trylock) only disables safepoints on the +// branch where it succeeds; the failure branch leaves them enabled. +extern void ce_safepoint(void); // expected-note 2 {{Tried to call method defined here}} +extern int ce_trylock(void) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_ENTER_CONDITIONAL(1); +extern void ce_unlock(void) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_LEAVE; +void conditional_enter_disables_on_success(void) { + if (ce_trylock()) { // expected-note{{Safepoints re-enabled here}} + // expected-note@-1{{Tracking JL_NOTSAFEPOINT annotation here}} + // expected-note@-2{{Taking true branch}} + ce_safepoint(); // expected-warning{{Calling potential safepoint as SimpleFunctionCall from function annotated JL_NOTSAFEPOINT}} + // expected-note@-1{{Calling potential safepoint as SimpleFunctionCall from function annotated JL_NOTSAFEPOINT}} + ce_unlock(); + } +} +void conditional_enter_ok_when_not_taken(void) { + if (ce_trylock()) + ce_unlock(); + else + ce_safepoint(); +} + +// The success value is read from the annotation: a conditional enter that +// signals success with a zero return (JL_NOTSAFEPOINT_ENTER_CONDITIONAL(0), e.g. +// a pthread-style trylock) disables safepoints on the zero-return branch, so a +// safepoint is flagged there and allowed on the nonzero (failure) branch. +extern int ce_trylock0(void) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_ENTER_CONDITIONAL(0); +void conditional_enter_zero_success(void) { + if (ce_trylock0()) { // expected-note{{Safepoints re-enabled here}} + // expected-note@-1{{Tracking JL_NOTSAFEPOINT annotation here}} + // expected-note@-2{{Taking false branch}} + ce_safepoint(); + } else { + ce_safepoint(); // expected-warning{{Calling potential safepoint as SimpleFunctionCall from function annotated JL_NOTSAFEPOINT}} + // expected-note@-1{{Calling potential safepoint as SimpleFunctionCall from function annotated JL_NOTSAFEPOINT}} + ce_unlock(); + } +} diff --git a/test/clangsa/SafepointCapability.c b/test/clangsa/SafepointCapability.c new file mode 100644 index 0000000000000..aa1a63f3e3e20 --- /dev/null +++ b/test/clangsa/SafepointCapability.c @@ -0,0 +1,93 @@ +// This file is a part of Julia. License is MIT: https://julialang.org/license + +// RUN: clang -D__clang_safetyanalysis__ -Wthread-safety -Wthread-safety-negative -Xclang -verify -fsyntax-only -I%julia_home/src -I%julia_home/src/support -I%julia_home/usr/include ${CLANGSA_FLAGS} ${CPPFLAGS} ${CFLAGS} -x c %s + +// Exercises the Clang Thread Safety Analysis ("capability") model of Julia +// safepoints that -D__clang_safetyanalysis__ selects in analyzer_annotations.h. +// Two tokens are modeled: the reentrant `jl_notsafepoint`, held inside a no-safepoint +// region (a no-gc lock), and the non-reentrant `jl_gcunsaferegion`, held while +// the thread is in a gc-unsafe region. A safepoint (JL_CANSAFEPOINT) requires +// jl_gcunsaferegion held and jl_notsafepoint NOT held. + +#include "analyzer_annotations.h" + +void may_safepoint(void) JL_CANSAFEPOINT; +void notsafepoint(void); +void lock_nogc(void) JL_NOTSAFEPOINT_ENTER; +void unlock_nogc(void) JL_NOTSAFEPOINT_LEAVE; +int trylock_nogc(void) JL_NOTSAFEPOINT_ENTER_CONDITIONAL(1); +int trylock0_nogc(void) JL_NOTSAFEPOINT_ENTER_CONDITIONAL(0); // acquires on a zero return +int gc_unsafe_enter(void) JL_CANSAFEPOINT_ENTER; // becomes gc-unsafe +void gc_unsafe_leave(void) JL_CANSAFEPOINT_LEAVE; // becomes gc-safe + +void cansafepoint_calls_both(void) JL_CANSAFEPOINT { + may_safepoint(); + notsafepoint(); +} + +void notsafepoint_body(void) { + may_safepoint(); // expected-warning{{calling function 'may_safepoint' requires holding gcunsaferegion 'jl_gcunsaferegion' exclusively}} + // expected-warning@-1{{calling function 'may_safepoint' requires negative capability '!jl_notsafepoint'}} +} + +void nogc_region(void) JL_CANSAFEPOINT { + may_safepoint(); + lock_nogc(); + notsafepoint(); + may_safepoint(); // expected-warning{{cannot call function 'may_safepoint' while notsafepoint 'jl_notsafepoint' is held}} + unlock_nogc(); + may_safepoint(); +} + +void nested_regions(void) JL_CANSAFEPOINT { + lock_nogc(); + lock_nogc(); + notsafepoint(); + unlock_nogc(); + unlock_nogc(); + may_safepoint(); +} + +void conditional_region(void) JL_CANSAFEPOINT { + if (trylock_nogc()) { + may_safepoint(); // expected-warning{{cannot call function 'may_safepoint' while notsafepoint 'jl_notsafepoint' is held}} + unlock_nogc(); + } + may_safepoint(); +} + +void conditional_region_zero(void) JL_CANSAFEPOINT { + if (trylock0_nogc()) { + may_safepoint(); + } else { + may_safepoint(); // expected-warning{{cannot call function 'may_safepoint' while notsafepoint 'jl_notsafepoint' is held}} + unlock_nogc(); + } +} + +void gc_safe_region(void) JL_CANSAFEPOINT { + may_safepoint(); + gc_unsafe_leave(); + may_safepoint(); // expected-warning{{calling function 'may_safepoint' requires holding gcunsaferegion 'jl_gcunsaferegion' exclusively}} + gc_unsafe_enter(); + may_safepoint(); +} + +void enter_leave_balanced(void) JL_CANSAFEPOINT_ENTER_LEAVE { + gc_unsafe_enter(); + may_safepoint(); + gc_unsafe_leave(); +} + +void enter_leave_unbalanced(void) JL_CANSAFEPOINT_ENTER_LEAVE { + gc_unsafe_enter(); // expected-note{{gcunsaferegion acquired here}} + may_safepoint(); + // expected-warning@+1{{gcunsaferegion 'jl_gcunsaferegion' is still held at the end of function}} +} + +// JL_NO_SAFEPOINT_ANALYSIS opts a body out of the analysis entirely: the +// unbalanced acquire below is not flagged. +void opted_out(void) JL_NO_SAFEPOINT_ANALYSIS { + lock_nogc(); + may_safepoint(); +} From 49411bd02574d1baa9b827ba8c79a742a8b6766d Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Wed, 8 Jul 2026 17:20:04 +0000 Subject: [PATCH 2/4] squash! clangsa: add thread-safety capability analysis of safepoint annotations Simplifying the logical flow of jl_record_backtrace also revealed some latent suboptimal behavior, which we can address, though is not functionally relevant normally. --- src/gc-stock.c | 2 +- src/jitlayers.cpp | 2 +- src/jitlayers.h | 2 +- src/objcache.cpp | 8 ++++---- src/objcache.h | 4 ++-- src/signal-handling.c | 4 ++-- src/signals-mach.c | 2 ++ src/signals-unix.c | 2 ++ src/signals-win.c | 2 ++ src/stackwalk.c | 38 +++++++++++++++++++++----------------- 10 files changed, 38 insertions(+), 28 deletions(-) diff --git a/src/gc-stock.c b/src/gc-stock.c index 039e424949f51..f992374536b29 100644 --- a/src/gc-stock.c +++ b/src/gc-stock.c @@ -2338,7 +2338,7 @@ FORCE_INLINE void gc_mark_outrefs(jl_ptls_t ptls, jl_gc_markqueue_t *mq, void *_ if (gc_cblist_task_scanner) { int16_t tid = jl_atomic_load_relaxed(&ta->tid); gc_invoke_callbacks(jl_gc_cb_task_scanner_t, gc_cblist_task_scanner, - (ta, tid != -1 && ta == gc_all_tls_states[tid]->root_task)); + (ta, tid >= 0 && tid < gc_n_threads && ta == gc_all_tls_states[tid]->root_task)); } #ifdef COPY_STACKS void *stkbuf = ta->ctx.stkbuf; diff --git a/src/jitlayers.cpp b/src/jitlayers.cpp index e05adfe554a49..1ad2a788d4472 100644 --- a/src/jitlayers.cpp +++ b/src/jitlayers.cpp @@ -901,7 +901,7 @@ class JLMaterializationUnit : public orc::MaterializationUnit { MDString::get(*Out.ctx, JIT.getTargetFeatureString())); Obj = JIT.OCache.get(*Out.module, - [this]() JL_NOTSAFEPOINT_ENTER JL_NOTSAFEPOINT_LEAVE { + [this]() JL_CANSAFEPOINT_ENTER_LEAVE { JIT.optimizeModule(*Out.module); return JIT.compileModule(*Out.module); }); diff --git a/src/jitlayers.h b/src/jitlayers.h index f8e183fe80d95..d0b34155f881e 100644 --- a/src/jitlayers.h +++ b/src/jitlayers.h @@ -915,7 +915,7 @@ class JuliaOJIT { // returning a pointer into CISymbols or NULL if the CI is not compiled. CISymbolPtr *linkCISymbol(jl_code_instance_t *CI) JL_NOTSAFEPOINT; - void optimizeModule(Module &M) JL_NOTSAFEPOINT_ENTER JL_NOTSAFEPOINT_LEAVE; + void optimizeModule(Module &M) JL_CANSAFEPOINT_ENTER_LEAVE; std::unique_ptr compileModule(Module &M) JL_NOTSAFEPOINT; private: diff --git a/src/objcache.cpp b/src/objcache.cpp index 4bf54414056c5..1a3e20387fad6 100644 --- a/src/objcache.cpp +++ b/src/objcache.cpp @@ -49,7 +49,7 @@ static FILE *getLogFile() return nullptr; FILE *F = fopen(Path, "a"); if (!F) { - jl_printf(JL_STDERR, "objcache: failed to open log file %s\n", Path); + jl_safe_printf("objcache: failed to open log file %s\n", Path); return nullptr; } return F; @@ -57,7 +57,7 @@ static FILE *getLogFile() static FILE *LogFile = getLogFile(); -static std::optional getCachePath() +static std::optional getCachePath() JL_CANSAFEPOINT { // Useful to be able to override the objcache path for testing, or to use // the cache during bootstrapping. @@ -307,9 +307,9 @@ static std::pair fromMetaKey(const char *Key) JL_NOTSAF return {Time, Hash}; } -std::unique_ptr ObjCache::get(llvm::Module &M, CompileFn Compile) +std::unique_ptr ObjCache::get(llvm::Module &M, CompileFn Compile) JL_CANSAFEPOINT_ENTER_LEAVE { - auto doCompile = [&]() JL_NOTSAFEPOINT_ENTER JL_NOTSAFEPOINT_LEAVE + auto doCompile = [&]() JL_CANSAFEPOINT_ENTER_LEAVE -> std::unique_ptr { #ifndef __clang_gcanalyzer__ return Compile(); diff --git a/src/objcache.h b/src/objcache.h index 76c4442a26f40..30d8d45f9559c 100644 --- a/src/objcache.h +++ b/src/objcache.h @@ -35,7 +35,7 @@ class ObjCache { ObjCache() = default; ~ObjCache() JL_NOTSAFEPOINT; std::unique_ptr - get(llvm::Module &M, CompileFn Compile) JL_NOTSAFEPOINT_ENTER JL_NOTSAFEPOINT_LEAVE; + get(llvm::Module &M, CompileFn Compile) JL_CANSAFEPOINT_ENTER_LEAVE; bool isEnabled() const JL_NOTSAFEPOINT; void shutdown() JL_NOTSAFEPOINT; @@ -43,7 +43,7 @@ class ObjCache { protected: void writerThread(); - void initDB() JL_NOTSAFEPOINT_ENTER JL_NOTSAFEPOINT_LEAVE; + void initDB() JL_CANSAFEPOINT_ENTER_LEAVE; bool updateATime(MDBTxn &Txn, const Hash &H, int64_t Time, bool Fresh); bool maybeEvictLRU(MDBTxn &Txn, size_t RoomFor); size_t dbiSize(MDBTxn &Txn, MDB_dbi Dbi); diff --git a/src/signal-handling.c b/src/signal-handling.c index 02b64144b2c91..2824cd96661c9 100644 --- a/src/signal-handling.c +++ b/src/signal-handling.c @@ -274,7 +274,7 @@ void jl_profile_task(void) JL_NOTSAFEPOINT JL_NO_SAFEPOINT_ANALYSIS return; } - jl_record_backtrace_result_t r = {0, INT16_MAX}; + jl_record_backtrace_result_t r = {0, -1}; jl_bt_element_t *bt_data_prof = (jl_bt_element_t*)(profile_bt_data_prof + profile_bt_size_cur); size_t bt_size_max = profile_bt_size_max - profile_bt_size_cur - 1; if (t == NULL || PROFILE_TASK_DEBUG_FORCE_SAMPLING_FAILURE) { @@ -295,7 +295,7 @@ void jl_profile_task(void) JL_NOTSAFEPOINT JL_NO_SAFEPOINT_ANALYSIS profile_bt_size_cur += r.bt_size; // store threadid but add 1 as 0 is preserved to indicate end of block - profile_bt_data_prof[profile_bt_size_cur++].uintptr = (uintptr_t)r.tid + 1; + profile_bt_data_prof[profile_bt_size_cur++].uintptr = r.tid == -1 ? -1 : (uintptr_t)r.tid + 1; // store task id (never null) profile_bt_data_prof[profile_bt_size_cur++].jlvalue = (jl_value_t*)t; diff --git a/src/signals-mach.c b/src/signals-mach.c index 0de524b3404fa..e9f00fafb00e9 100644 --- a/src/signals-mach.c +++ b/src/signals-mach.c @@ -568,6 +568,8 @@ static void attach_exception_port(thread_port_t thread, int segv_only) static int jl_thread_suspend_and_get_state2(int tid, host_thread_state_t *ctx) JL_NOTSAFEPOINT { + if (tid < 0 || tid >= jl_atomic_load_acquire(&jl_n_threads)) + return 0; jl_ptls_t ptls2 = jl_atomic_load_relaxed(&jl_all_tls_states)[tid]; if (ptls2 == NULL) // this thread is not alive return 0; diff --git a/src/signals-unix.c b/src/signals-unix.c index 9a1ed37242d55..63bfb18782e27 100644 --- a/src/signals-unix.c +++ b/src/signals-unix.c @@ -572,6 +572,8 @@ static int signals_inflight = 0; static int jl_thread_suspend_and_get_state(int tid, int timeout, bt_context_t *ctx) JL_NOTSAFEPOINT_ENTER_CONDITIONAL(1) { + if (tid < 0 || tid >= jl_atomic_load_acquire(&jl_n_threads)) + return 0; int err; pthread_mutex_lock(&in_signal_lock); jl_ptls_t ptls2 = jl_atomic_load_relaxed(&jl_all_tls_states)[tid]; diff --git a/src/signals-win.c b/src/signals-win.c index 2ca38f274b6b9..3b92d4835f7da 100644 --- a/src/signals-win.c +++ b/src/signals-win.c @@ -429,6 +429,8 @@ static void CALLBACK profile_timeout_cb(PVOID lpParam, BOOLEAN TimerOrWaitFired) static int jl_thread_suspend_and_get_state(int tid, int timeout, bt_context_t *ctx) { (void)timeout; + if (tid < 0 || tid >= jl_atomic_load_acquire(&jl_n_threads)) + return 0; jl_ptls_t ptls2 = jl_atomic_load_relaxed(&jl_all_tls_states)[tid]; if (ptls2 == NULL) // this thread is not alive return 0; diff --git a/src/stackwalk.c b/src/stackwalk.c index aaa8e46a6ede2..79a15ecdd8097 100644 --- a/src/stackwalk.c +++ b/src/stackwalk.c @@ -1471,28 +1471,31 @@ static size_t rec_backtrace_task(jl_task_t *t, bt_context_t *c, int use_ctx, jl JL_DLLEXPORT jl_record_backtrace_result_t jl_record_backtrace(jl_task_t *t, jl_bt_element_t *bt_data, size_t max_bt_size, int all_tasks_profiler) JL_NOTSAFEPOINT { - int16_t tid = INT16_MAX; - jl_record_backtrace_result_t result = {0, tid}; + jl_record_backtrace_result_t result = {0, -1}; + int16_t tid = INT16_MAX; // assign invalid id to non-native tasks jl_task_t *ct = NULL; - jl_ptls_t ptls = NULL; if (!all_tasks_profiler) { - ct = jl_current_task; - ptls = ct->ptls; - ptls->bt_size = 0; - tid = ptls->tid; - } - if (t == ct) { - result.bt_size = rec_backtrace(bt_data, max_bt_size, 0); - result.tid = tid; - return result; + ct = jl_get_current_task(); + if (ct) { + tid = ct->ptls->tid; + if (t == ct) { + result.bt_size = rec_backtrace(bt_data, max_bt_size, 0); + result.tid = tid; + return result; + } + } } bt_context_t c; int16_t old; while (1) { - old = INT16_MAX; + old = -1; // Try to lock this task, if free, otherwise get the id of the thread running it - if (jl_atomic_cmpswap(&t->tid, &old, tid) || old == tid) - break; + if (jl_atomic_cmpswap(&t->tid, &old, tid)) + break; // temporary claim successful + if (old == INT16_MAX) + return result; // another (non-native) thread already claimed it + if (old == tid) + break; // already claimed by this thread // Try to stop that thread if (!jl_thread_suspend(old, &c)) { if (jl_atomic_load_relaxed(&t->tid) != old) @@ -1518,7 +1521,7 @@ JL_DLLEXPORT jl_record_backtrace_result_t jl_record_backtrace(jl_task_t *t, jl_b // This task is locked to our thread result.bt_size = rec_backtrace_task(t, &c, 0, bt_data, max_bt_size, all_tasks_profiler); result.tid = old; - if (old == INT16_MAX) + if (old == -1) jl_atomic_store_relaxed(&t->tid, old); return result; } @@ -1568,7 +1571,8 @@ JL_DLLEXPORT void jl_fprint_backtracet(ios_t *s, jl_task_t *t) JL_NOTSAFEPOINT ptls->bt_size = 0; bt_data = ptls->bt_data; max_bt_size = JL_MAX_BT_SIZE; - } else { + } + else { max_bt_size = 1024; //8kb of stack should be safe bt_data = (jl_bt_element_t *)alloca(max_bt_size * sizeof(jl_bt_element_t)); } From e3b01dde3f3ba23203aabf6a7cfb76ea4efdea8d Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 13 Jul 2026 16:59:56 +0000 Subject: [PATCH 3/4] fixup! clangsa: add thread-safety capability analysis of safepoint annotations --- doc/src/devdocs/gc-sa.md | 7 +++---- src/staticdata_utils.c | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/doc/src/devdocs/gc-sa.md b/doc/src/devdocs/gc-sa.md index 202c6e450a4f3..62d6abd79c0da 100644 --- a/doc/src/devdocs/gc-sa.md +++ b/doc/src/devdocs/gc-sa.md @@ -4,9 +4,7 @@ The analyzer plugin that drives the analysis ships with julia. Its source code can be found in `src/clangsa`. Running it uses the -the clang dependency option from deps. - -Alternatively (or if these do not suffice), try +the optional clang dependency from `deps`. This can be installed by running: ```sh make -C src install-analysis-deps @@ -15,7 +13,8 @@ make -C src install-analysis-deps from Julia's toplevel directory. -Afterwards, running the analysis over the source tree is as simple as running `make -C src analyzegc`. +Afterwards, running the analysis over the source tree is as simple as running +`make -C src analyzegc`. ## General Overview diff --git a/src/staticdata_utils.c b/src/staticdata_utils.c index 63dd2f434cf4e..db6def80fda02 100644 --- a/src/staticdata_utils.c +++ b/src/staticdata_utils.c @@ -156,7 +156,7 @@ JL_DLLEXPORT void jl_finalize_precompile_inferred(int8_t cleanup_keep_ir) static jl_array_t *queue_used(jl_array_t *list, jl_query_cache *query_cache) JL_CANSAFEPOINT; -JL_DLLEXPORT jl_array_t* jl_compute_new_used_ci(void) +JL_DLLEXPORT jl_array_t* jl_compute_new_used_ci(void) JL_CANSAFEPOINT { if (newly_inferred == NULL) return jl_alloc_vec_any(0); From 58adf053d8e8dc30cbd6b13fa61d8064d3a99294 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Tue, 14 Jul 2026 17:40:26 +0000 Subject: [PATCH 4/4] fixup! clangsa: add thread-safety capability analysis of safepoint annotations --- src/julia.h | 2 +- src/staticdata_utils.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/julia.h b/src/julia.h index 3072a9e5e5960..529b2b25163ad 100644 --- a/src/julia.h +++ b/src/julia.h @@ -2385,7 +2385,7 @@ JL_DLLEXPORT void jl_restore_system_image(jl_image_t *image, jl_image_buf_t buf) JL_DLLEXPORT jl_value_t *jl_restore_incremental(const char *fname, jl_array_t *depmods, int complete, const char *pkgimage) JL_CANSAFEPOINT; JL_DLLEXPORT jl_value_t *jl_object_top_module(jl_value_t* v) JL_NOTSAFEPOINT; -JL_DLLEXPORT void jl_set_newly_inferred(jl_value_t *newly_inferred); +JL_DLLEXPORT void jl_set_newly_inferred(jl_value_t *newly_inferred) JL_CANSAFEPOINT; JL_DLLEXPORT void jl_finalize_precompile_inferred(int8_t cleanup_keep_ir); JL_DLLEXPORT jl_array_t* jl_compute_new_ext(void) JL_CANSAFEPOINT; JL_DLLEXPORT void jl_push_newly_inferred(jl_value_t *ci) JL_CANSAFEPOINT; diff --git a/src/staticdata_utils.c b/src/staticdata_utils.c index db6def80fda02..826be6dc3d2b3 100644 --- a/src/staticdata_utils.c +++ b/src/staticdata_utils.c @@ -589,7 +589,7 @@ static int jl_collect_methcache_from_mod(jl_typemap_entry_t *ml, void *closure) // Collect every currently-valid method of a worklist-owned method table, whose // contents are dropped from the image (see jl_prune_internal_mtable) -static int jl_collect_methcache_internal(jl_typemap_entry_t *ml, void *closure) +static int jl_collect_methcache_internal(jl_typemap_entry_t *ml, void *closure) JL_CANSAFEPOINT { jl_array_t *s = (jl_array_t*)closure; if (jl_atomic_load_relaxed(&ml->max_world) == ~(size_t)0)