From ee13ca047091366e5c0e71fff730e38cf851308f Mon Sep 17 00:00:00 2001 From: Prem Chintalapudi Date: Sun, 17 Apr 2022 14:10:03 -0400 Subject: [PATCH 01/21] Move debuginfo global variables to the top of debuginfo.cpp --- src/debuginfo.cpp | 333 ++++++++++++++++++++++++---------------------- 1 file changed, 177 insertions(+), 156 deletions(-) diff --git a/src/debuginfo.cpp b/src/debuginfo.cpp index 02e2b9c3ac683..45475243b4a79 100644 --- a/src/debuginfo.cpp +++ b/src/debuginfo.cpp @@ -42,63 +42,15 @@ using namespace llvm; typedef object::SymbolRef SymRef; -// Any function that acquires this lock must be either a unmanaged thread -// or in the GC safe region and must NOT allocate anything through the GC -// while holding this lock. -// Certain functions in this file might be called from an unmanaged thread -// and cannot have any interaction with the julia runtime -// They also may be re-entrant, and operating while threads are paused, so we -// separately manage the re-entrant count behavior for safety across platforms -// Note that we cannot safely upgrade read->write -static uv_rwlock_t debuginfo_asyncsafe; -static pthread_key_t debuginfo_asyncsafe_held; - -void jl_init_debuginfo(void) -{ - uv_rwlock_init(&debuginfo_asyncsafe); - if (pthread_key_create(&debuginfo_asyncsafe_held, NULL)) - jl_error("fatal: pthread_key_create failed"); -} - -extern "C" JL_DLLEXPORT void jl_lock_profile_impl(void) JL_NOTSAFEPOINT -{ - uintptr_t held = (uintptr_t)pthread_getspecific(debuginfo_asyncsafe_held); - if (held++ == 0) - uv_rwlock_rdlock(&debuginfo_asyncsafe); - pthread_setspecific(debuginfo_asyncsafe_held, (void*)held); -} - -extern "C" JL_DLLEXPORT void jl_unlock_profile_impl(void) JL_NOTSAFEPOINT -{ - uintptr_t held = (uintptr_t)pthread_getspecific(debuginfo_asyncsafe_held); - assert(held); - if (--held == 0) - uv_rwlock_rdunlock(&debuginfo_asyncsafe); - pthread_setspecific(debuginfo_asyncsafe_held, (void*)held); -} - -// some actions aren't signal (especially profiler) safe so we acquire a lock -// around them to establish a mutual exclusion with unwinding from a signal -template -static void jl_profile_atomic(T f) -{ - assert(0 == (uintptr_t)pthread_getspecific(debuginfo_asyncsafe_held)); - uv_rwlock_wrlock(&debuginfo_asyncsafe); -#ifndef _OS_WINDOWS_ - sigset_t sset; - sigset_t oset; - sigfillset(&sset); - pthread_sigmask(SIG_BLOCK, &sset, &oset); -#endif - f(); -#ifndef _OS_WINDOWS_ - pthread_sigmask(SIG_SETMASK, &oset, NULL); -#endif - uv_rwlock_wrunlock(&debuginfo_asyncsafe); -} - +struct revcomp { + bool operator() (const size_t& lhs, const size_t& rhs) const + { return lhs>rhs; } +}; -// --- storing and accessing source location metadata --- +struct debug_link_info { + StringRef filename; + uint32_t crc32; +}; struct ObjectInfo { const object::ObjectFile *object; @@ -108,83 +60,20 @@ struct ObjectInfo { DIContext *context; }; -// Maintain a mapping of unrealized function names -> linfo objects -// so that when we see it get emitted, we can add a link back to the linfo -// that it came from (providing name, type signature, file info, etc.) -static StringMap codeinst_in_flight; -static std::string mangle(StringRef Name, const DataLayout &DL) -{ - std::string MangledName; - { - raw_string_ostream MangledNameStream(MangledName); - Mangler::getNameWithPrefix(MangledNameStream, Name, DL); - } - return MangledName; -} -void jl_add_code_in_flight(StringRef name, jl_code_instance_t *codeinst, const DataLayout &DL) -{ - codeinst_in_flight[mangle(name, DL)] = codeinst; -} +typedef struct { + const llvm::object::ObjectFile *obj; + DIContext *ctx; + int64_t slide; +} objfileentry_t; +typedef std::map obfiletype; +extern "C" JL_DLLEXPORT void jl_lock_profile_impl(void) JL_NOTSAFEPOINT; +extern "C" JL_DLLEXPORT void jl_unlock_profile_impl(void) JL_NOTSAFEPOINT; -#if defined(_OS_WINDOWS_) -static void create_PRUNTIME_FUNCTION(uint8_t *Code, size_t Size, StringRef fnname, - uint8_t *Section, size_t Allocated, uint8_t *UnwindData) -{ - // GC safe - DWORD mod_size = 0; -#if defined(_CPU_X86_64_) - PRUNTIME_FUNCTION tbl = (PRUNTIME_FUNCTION)malloc_s(sizeof(RUNTIME_FUNCTION)); - tbl->BeginAddress = (DWORD)(Code - Section); - tbl->EndAddress = (DWORD)(Code - Section + Size); - tbl->UnwindData = (DWORD)(UnwindData - Section); - assert(Code >= Section && Code + Size <= Section + Allocated); - assert(UnwindData >= Section && UnwindData <= Section + Allocated); -#else // defined(_CPU_X86_64_) - Section += (uintptr_t)Code; - mod_size = Size; -#endif - if (0) { - uv_mutex_lock(&jl_in_stackwalk); - if (mod_size && !SymLoadModuleEx(GetCurrentProcess(), NULL, NULL, NULL, (DWORD64)Section, mod_size, NULL, SLMFLAG_VIRTUAL)) { - static int warned = 0; - if (!warned) { - jl_printf(JL_STDERR, "WARNING: failed to insert module info for backtrace: %lu\n", GetLastError()); - warned = 1; - } - } - else { - size_t len = fnname.size()+1; - if (len > MAX_SYM_NAME) - len = MAX_SYM_NAME; - char *name = (char*)alloca(len); - memcpy(name, fnname.data(), len-1); - name[len-1] = 0; - if (!SymAddSymbol(GetCurrentProcess(), (ULONG64)Section, name, - (DWORD64)Code, (DWORD)Size, 0)) { - jl_printf(JL_STDERR, "WARNING: failed to insert function name %s into debug info: %lu\n", name, GetLastError()); - } - } - uv_mutex_unlock(&jl_in_stackwalk); - } -#if defined(_CPU_X86_64_) - jl_profile_atomic([&]() { - if (!RtlAddFunctionTable(tbl, 1, (DWORD64)Section)) { - static int warned = 0; - if (!warned) { - jl_printf(JL_STDERR, "WARNING: failed to insert function stack unwind info: %lu\n", GetLastError()); - warned = 1; - } - } - }); -#endif -} -#endif +template +static void jl_profile_atomic(T f); -struct revcomp { - bool operator() (const size_t& lhs, const size_t& rhs) const - { return lhs>rhs; } -}; +static std::string mangle(StringRef Name, const DataLayout &DL); // Central registry for resolving function addresses to `jl_method_instance_t`s and @@ -199,7 +88,17 @@ class JITObjectRegistry std::map objectmap; std::map, revcomp> linfomap; + // Maintain a mapping of unrealized function names -> linfo objects + // so that when we see it get emitted, we can add a link back to the linfo + // that it came from (providing name, type signature, file info, etc.) + StringMap codeinst_in_flight; + public: + + void add_code_in_flight(StringRef name, jl_code_instance_t *codeinst, const DataLayout &DL) { + codeinst_in_flight[mangle(name, DL)] = codeinst; + } + jl_method_instance_t *lookupLinfo(size_t pointer) JL_NOTSAFEPOINT { jl_lock_profile_impl(); @@ -381,7 +280,155 @@ class JITObjectRegistry } }; + +#if defined(_OS_DARWIN_) && defined(LLVM_SHLIB) + +static void (*libc_register_frame)(void*) = NULL; +static void (*libc_deregister_frame)(void*) = NULL; + +#endif + +struct unw_table_entry +{ + int32_t start_ip_offset; + int32_t fde_offset; +}; + +static obfiletype objfilemap; + +// Any function that acquires this lock must be either a unmanaged thread +// or in the GC safe region and must NOT allocate anything through the GC +// while holding this lock. +// Certain functions in this file might be called from an unmanaged thread +// and cannot have any interaction with the julia runtime +// They also may be re-entrant, and operating while threads are paused, so we +// separately manage the re-entrant count behavior for safety across platforms +// Note that we cannot safely upgrade read->write +static uv_rwlock_t debuginfo_asyncsafe; +static pthread_key_t debuginfo_asyncsafe_held; + +static uint64_t jl_sysimage_base; +static jl_sysimg_fptrs_t sysimg_fptrs; +static jl_method_instance_t **sysimg_fvars_linfo; +static size_t sysimg_fvars_n; + static JITObjectRegistry jl_jit_object_registry; + +void jl_init_debuginfo(void) +{ + uv_rwlock_init(&debuginfo_asyncsafe); + if (pthread_key_create(&debuginfo_asyncsafe_held, NULL)) + jl_error("fatal: pthread_key_create failed"); +} + +extern "C" JL_DLLEXPORT void jl_lock_profile_impl(void) JL_NOTSAFEPOINT +{ + uintptr_t held = (uintptr_t)pthread_getspecific(debuginfo_asyncsafe_held); + if (held++ == 0) + uv_rwlock_rdlock(&debuginfo_asyncsafe); + pthread_setspecific(debuginfo_asyncsafe_held, (void*)held); +} + +extern "C" JL_DLLEXPORT void jl_unlock_profile_impl(void) JL_NOTSAFEPOINT +{ + uintptr_t held = (uintptr_t)pthread_getspecific(debuginfo_asyncsafe_held); + assert(held); + if (--held == 0) + uv_rwlock_rdunlock(&debuginfo_asyncsafe); + pthread_setspecific(debuginfo_asyncsafe_held, (void*)held); +} + +// some actions aren't signal (especially profiler) safe so we acquire a lock +// around them to establish a mutual exclusion with unwinding from a signal +template +static void jl_profile_atomic(T f) +{ + assert(0 == (uintptr_t)pthread_getspecific(debuginfo_asyncsafe_held)); + uv_rwlock_wrlock(&debuginfo_asyncsafe); +#ifndef _OS_WINDOWS_ + sigset_t sset; + sigset_t oset; + sigfillset(&sset); + pthread_sigmask(SIG_BLOCK, &sset, &oset); +#endif + f(); +#ifndef _OS_WINDOWS_ + pthread_sigmask(SIG_SETMASK, &oset, NULL); +#endif + uv_rwlock_wrunlock(&debuginfo_asyncsafe); +} + + +// --- storing and accessing source location metadata --- +static std::string mangle(StringRef Name, const DataLayout &DL) +{ + std::string MangledName; + { + raw_string_ostream MangledNameStream(MangledName); + Mangler::getNameWithPrefix(MangledNameStream, Name, DL); + } + return MangledName; +} +void jl_add_code_in_flight(StringRef name, jl_code_instance_t *codeinst, const DataLayout &DL) +{ + jl_jit_object_registry.add_code_in_flight(name, codeinst, DL); +} + + +#if defined(_OS_WINDOWS_) +static void create_PRUNTIME_FUNCTION(uint8_t *Code, size_t Size, StringRef fnname, + uint8_t *Section, size_t Allocated, uint8_t *UnwindData) +{ + // GC safe + DWORD mod_size = 0; +#if defined(_CPU_X86_64_) + PRUNTIME_FUNCTION tbl = (PRUNTIME_FUNCTION)malloc_s(sizeof(RUNTIME_FUNCTION)); + tbl->BeginAddress = (DWORD)(Code - Section); + tbl->EndAddress = (DWORD)(Code - Section + Size); + tbl->UnwindData = (DWORD)(UnwindData - Section); + assert(Code >= Section && Code + Size <= Section + Allocated); + assert(UnwindData >= Section && UnwindData <= Section + Allocated); +#else // defined(_CPU_X86_64_) + Section += (uintptr_t)Code; + mod_size = Size; +#endif + if (0) { + uv_mutex_lock(&jl_in_stackwalk); + if (mod_size && !SymLoadModuleEx(GetCurrentProcess(), NULL, NULL, NULL, (DWORD64)Section, mod_size, NULL, SLMFLAG_VIRTUAL)) { + static int warned = 0; + if (!warned) { + jl_printf(JL_STDERR, "WARNING: failed to insert module info for backtrace: %lu\n", GetLastError()); + warned = 1; + } + } + else { + size_t len = fnname.size()+1; + if (len > MAX_SYM_NAME) + len = MAX_SYM_NAME; + char *name = (char*)alloca(len); + memcpy(name, fnname.data(), len-1); + name[len-1] = 0; + if (!SymAddSymbol(GetCurrentProcess(), (ULONG64)Section, name, + (DWORD64)Code, (DWORD)Size, 0)) { + jl_printf(JL_STDERR, "WARNING: failed to insert function name %s into debug info: %lu\n", name, GetLastError()); + } + } + uv_mutex_unlock(&jl_in_stackwalk); + } +#if defined(_CPU_X86_64_) + jl_profile_atomic([&]() { + if (!RtlAddFunctionTable(tbl, 1, (DWORD64)Section)) { + static int warned = 0; + if (!warned) { + jl_printf(JL_STDERR, "WARNING: failed to insert function stack unwind info: %lu\n", GetLastError()); + warned = 1; + } + } + }); +#endif +} +#endif + void jl_register_jit_object(const object::ObjectFile &Object, std::function getLoadAddress, std::function lookupWriteAddress) @@ -528,13 +575,6 @@ static int lookup_pointer( #ifndef _OS_WINDOWS_ #include #endif -typedef struct { - const llvm::object::ObjectFile *obj; - DIContext *ctx; - int64_t slide; -} objfileentry_t; -typedef std::map obfiletype; -static obfiletype objfilemap; static bool getObjUUID(llvm::object::MachOObjectFile *obj, uint8_t uuid[16]) JL_NOTSAFEPOINT { @@ -547,11 +587,6 @@ static bool getObjUUID(llvm::object::MachOObjectFile *obj, uint8_t uuid[16]) JL_ } return false; } - -struct debug_link_info { - StringRef filename; - uint32_t crc32; -}; static debug_link_info getDebuglink(const object::ObjectFile &Obj) JL_NOTSAFEPOINT { debug_link_info info = {}; @@ -662,11 +697,6 @@ openDebugInfo(StringRef debuginfopath, const debug_link_info &info) std::move(error_splitobj.get()), std::move(SplitFile.get())); } - -static uint64_t jl_sysimage_base; -static jl_sysimg_fptrs_t sysimg_fptrs; -static jl_method_instance_t **sysimg_fvars_linfo; -static size_t sysimg_fvars_n; extern "C" JL_DLLEXPORT void jl_register_fptrs_impl(uint64_t sysimage_base, const jl_sysimg_fptrs_t *fptrs, jl_method_instance_t **linfos, size_t n) @@ -1242,9 +1272,6 @@ static void processFDEs(const char *EHFrameAddr, size_t EHFrameSize, callback f) * ourselves to ensure the right one gets picked. */ -static void (*libc_register_frame)(void*) = NULL; -static void (*libc_deregister_frame)(void*) = NULL; - // This implementation handles frame registration for local targets. void register_eh_frames(uint8_t *Addr, size_t Size) { @@ -1281,12 +1308,6 @@ void deregister_eh_frames(uint8_t *Addr, size_t Size) !defined(_CPU_ARM_) // ARM does not have/use .eh_frame, so we handle this elsewhere #include -struct unw_table_entry -{ - int32_t start_ip_offset; - int32_t fde_offset; -}; - // Skip over an arbitrary long LEB128 encoding. // Return the pointer to the first unprocessed byte. static const uint8_t *consume_leb128(const uint8_t *Addr, const uint8_t *End) From 463560a15e4895000840b1b1587b45c457f7e8ee Mon Sep 17 00:00:00 2001 From: Prem Chintalapudi Date: Sun, 17 Apr 2022 15:07:53 -0400 Subject: [PATCH 02/21] Lock around codeinst_in_flight --- src/debuginfo.cpp | 67 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 50 insertions(+), 17 deletions(-) diff --git a/src/debuginfo.cpp b/src/debuginfo.cpp index 45475243b4a79..2e5b595398f52 100644 --- a/src/debuginfo.cpp +++ b/src/debuginfo.cpp @@ -34,6 +34,7 @@ using namespace llvm; #include #include #include +#include #include "julia_assert.h" #ifdef _OS_DARWIN_ @@ -73,8 +74,6 @@ extern "C" JL_DLLEXPORT void jl_unlock_profile_impl(void) JL_NOTSAFEPOINT; template static void jl_profile_atomic(T f); -static std::string mangle(StringRef Name, const DataLayout &DL); - // Central registry for resolving function addresses to `jl_method_instance_t`s and // originating `ObjectFile`s (for the DWARF debug info). @@ -85,18 +84,57 @@ static std::string mangle(StringRef Name, const DataLayout &DL); // functionality). class JITObjectRegistry { +public: + template + struct Locked { + struct Lock { + std::unique_lock lock; + ResourceT &resource; + + Lock(std::mutex &mutex, ResourceT &resource) : lock(mutex), resource(resource) {} + + ResourceT &operator*() { + return resource; + } + + operator const ResourceT &() const { + return resource; + } + }; + private: + + std::mutex mutex; + ResourceT resource; + public: + Locked(ResourceT resource = ResourceT()) : mutex(), resource(std::move(resource)) {} + + Lock operator*() { + return Lock(mutex, resource); + } + }; +private: std::map objectmap; std::map, revcomp> linfomap; // Maintain a mapping of unrealized function names -> linfo objects // so that when we see it get emitted, we can add a link back to the linfo // that it came from (providing name, type signature, file info, etc.) - StringMap codeinst_in_flight; + Locked> codeinst_in_flight; + + static std::string mangle(StringRef Name, const DataLayout &DL) + { + std::string MangledName; + { + raw_string_ostream MangledNameStream(MangledName); + Mangler::getNameWithPrefix(MangledNameStream, Name, DL); + } + return MangledName; + } public: void add_code_in_flight(StringRef name, jl_code_instance_t *codeinst, const DataLayout &DL) { - codeinst_in_flight[mangle(name, DL)] = codeinst; + (**codeinst_in_flight)[mangle(name, DL)] = codeinst; } jl_method_instance_t *lookupLinfo(size_t pointer) JL_NOTSAFEPOINT @@ -251,11 +289,15 @@ class JITObjectRegistry (uint8_t*)(uintptr_t)Addr, (size_t)Size, sName, (uint8_t*)(uintptr_t)SectionLoadAddr, (size_t)SectionSize, UnwindData); #endif - StringMap::iterator codeinst_it = codeinst_in_flight.find(sName); jl_code_instance_t *codeinst = NULL; - if (codeinst_it != codeinst_in_flight.end()) { - codeinst = codeinst_it->second; - codeinst_in_flight.erase(codeinst_it); + { + auto lock = *this->codeinst_in_flight; + auto &codeinst_in_flight = *lock; + StringMap::iterator codeinst_it = codeinst_in_flight.find(sName); + if (codeinst_it != codeinst_in_flight.end()) { + codeinst = codeinst_it->second; + codeinst_in_flight.erase(codeinst_it); + } } jl_profile_atomic([&]() { if (codeinst) @@ -360,15 +402,6 @@ static void jl_profile_atomic(T f) // --- storing and accessing source location metadata --- -static std::string mangle(StringRef Name, const DataLayout &DL) -{ - std::string MangledName; - { - raw_string_ostream MangledNameStream(MangledName); - Mangler::getNameWithPrefix(MangledNameStream, Name, DL); - } - return MangledName; -} void jl_add_code_in_flight(StringRef name, jl_code_instance_t *codeinst, const DataLayout &DL) { jl_jit_object_registry.add_code_in_flight(name, codeinst, DL); From 56040d620e1c88e42f349d094f4ded57faee3fac Mon Sep 17 00:00:00 2001 From: Prem Chintalapudi Date: Sun, 17 Apr 2022 15:36:50 -0400 Subject: [PATCH 03/21] Lock around jl_sysimg_vars --- src/debuginfo.cpp | 118 ++++++++++++++++++++++++++++------------------ 1 file changed, 72 insertions(+), 46 deletions(-) diff --git a/src/debuginfo.cpp b/src/debuginfo.cpp index 2e5b595398f52..925330f7f4b25 100644 --- a/src/debuginfo.cpp +++ b/src/debuginfo.cpp @@ -43,11 +43,6 @@ using namespace llvm; typedef object::SymbolRef SymRef; -struct revcomp { - bool operator() (const size_t& lhs, const size_t& rhs) const - { return lhs>rhs; } -}; - struct debug_link_info { StringRef filename; uint32_t crc32; @@ -66,7 +61,7 @@ typedef struct { DIContext *ctx; int64_t slide; } objfileentry_t; -typedef std::map obfiletype; +typedef std::map> obfiletype; extern "C" JL_DLLEXPORT void jl_lock_profile_impl(void) JL_NOTSAFEPOINT; extern "C" JL_DLLEXPORT void jl_unlock_profile_impl(void) JL_NOTSAFEPOINT; @@ -87,40 +82,67 @@ class JITObjectRegistry public: template struct Locked { + + template struct Lock { std::unique_lock lock; - ResourceT &resource; + CResourceT &resource; - Lock(std::mutex &mutex, ResourceT &resource) : lock(mutex), resource(resource) {} + Lock(std::mutex &mutex, CResourceT &resource) : lock(mutex), resource(resource) {} - ResourceT &operator*() { + CResourceT &operator*() { return resource; } - operator const ResourceT &() const { + const CResourceT &operator*() const { + return resource; + } + + CResourceT *operator->() { + return &**this; + } + + const CResourceT *operator->() const { + return &**this; + } + + operator const CResourceT &() const { return resource; } }; private: - std::mutex mutex; + mutable std::mutex mutex; ResourceT resource; public: Locked(ResourceT resource = ResourceT()) : mutex(), resource(std::move(resource)) {} - Lock operator*() { - return Lock(mutex, resource); + Lock operator*() { + return Lock(mutex, resource); + } + + Lock operator*() const { + return Lock(mutex, resource); } }; + + struct sysimg_info_t { + uint64_t jl_sysimage_base; + jl_sysimg_fptrs_t sysimg_fptrs; + jl_method_instance_t **sysimg_fvars_linfo; + size_t sysimg_fvars_n; + }; private: - std::map objectmap; - std::map, revcomp> linfomap; + std::map> objectmap; + std::map, std::greater> linfomap; // Maintain a mapping of unrealized function names -> linfo objects // so that when we see it get emitted, we can add a link back to the linfo // that it came from (providing name, type signature, file info, etc.) Locked> codeinst_in_flight; + Locked sysimg_info; + static std::string mangle(StringRef Name, const DataLayout &DL) { std::string MangledName; @@ -316,10 +338,19 @@ class JITObjectRegistry } } - std::map& getObjectMap() JL_NOTSAFEPOINT + //Protected by debuginfo_asyncsafe + auto& getObjectMap() JL_NOTSAFEPOINT { return objectmap; } + + void set_sysimg_info(sysimg_info_t info) { + (**this->sysimg_info) = info; + } + + auto get_sysimg_info() const { + return *this->sysimg_info; + } }; @@ -349,11 +380,6 @@ static obfiletype objfilemap; static uv_rwlock_t debuginfo_asyncsafe; static pthread_key_t debuginfo_asyncsafe_held; -static uint64_t jl_sysimage_base; -static jl_sysimg_fptrs_t sysimg_fptrs; -static jl_method_instance_t **sysimg_fvars_linfo; -static size_t sysimg_fvars_n; - static JITObjectRegistry jl_jit_object_registry; void jl_init_debuginfo(void) @@ -734,10 +760,7 @@ extern "C" JL_DLLEXPORT void jl_register_fptrs_impl(uint64_t sysimage_base, const jl_sysimg_fptrs_t *fptrs, jl_method_instance_t **linfos, size_t n) { - jl_sysimage_base = (uintptr_t)sysimage_base; - sysimg_fptrs = *fptrs; - sysimg_fvars_linfo = linfos; - sysimg_fvars_n = n; + jl_jit_object_registry.set_sysimg_info({(uintptr_t) sysimage_base, *fptrs, linfos, n}); } template @@ -752,7 +775,7 @@ static void get_function_name_and_base(llvm::object::SectionRef Section, size_t void **saddr, char **name, bool untrusted_dladdr) JL_NOTSAFEPOINT { // Assume we only need base address for sysimg for now - if (!insysimage || !sysimg_fptrs.base) + if (!insysimage || !jl_jit_object_registry.get_sysimg_info()->sysimg_fptrs.base) saddr = nullptr; bool needs_saddr = saddr && (!*saddr || untrusted_dladdr); bool needs_name = name && (!*name || untrusted_dladdr); @@ -1100,7 +1123,7 @@ bool jl_dylib_DI_for_fptr(size_t pointer, object::SectionRef *Section, int64_t * if (fname.empty()) // empirically, LoadedImageName might be missing fname = ModuleInfo.ImageName; DWORD64 fbase = ModuleInfo.BaseOfImage; - bool insysimage = (fbase == jl_sysimage_base); + bool insysimage = (fbase == jl_jit_object_registry.get_sysimg_info()->jl_sysimage_base); if (isSysImg) *isSysImg = insysimage; if (onlySysImg && !insysimage) @@ -1140,7 +1163,7 @@ bool jl_dylib_DI_for_fptr(size_t pointer, object::SectionRef *Section, int64_t * fbase = (uintptr_t)dlinfo.dli_fbase; #endif StringRef fname; - bool insysimage = (fbase == jl_sysimage_base); + bool insysimage = (fbase == jl_jit_object_registry.get_sysimg_info()->jl_sysimage_base); if (saddr && !(insysimage && untrusted_dladdr)) *saddr = dlinfo.dli_saddr; if (isSysImg) @@ -1196,20 +1219,23 @@ static int jl_getDylibFunctionInfo(jl_frame_t **frames, size_t pointer, int skip return 1; } frame0->fromC = !isSysImg; - if (isSysImg && sysimg_fptrs.base && saddr) { - intptr_t diff = (uintptr_t)saddr - (uintptr_t)sysimg_fptrs.base; - for (size_t i = 0; i < sysimg_fptrs.nclones; i++) { - if (diff == sysimg_fptrs.clone_offsets[i]) { - uint32_t idx = sysimg_fptrs.clone_idxs[i] & jl_sysimg_val_mask; - if (idx < sysimg_fvars_n) // items after this were cloned but not referenced directly by a method (such as our ccall PLT thunks) - frame0->linfo = sysimg_fvars_linfo[idx]; - break; + { + auto sysimg_locked = jl_jit_object_registry.get_sysimg_info(); + if (isSysImg && sysimg_locked->sysimg_fptrs.base && saddr) { + intptr_t diff = (uintptr_t)saddr - (uintptr_t)sysimg_locked->sysimg_fptrs.base; + for (size_t i = 0; i < sysimg_locked->sysimg_fptrs.nclones; i++) { + if (diff == sysimg_locked->sysimg_fptrs.clone_offsets[i]) { + uint32_t idx = sysimg_locked->sysimg_fptrs.clone_idxs[i] & jl_sysimg_val_mask; + if (idx < sysimg_locked->sysimg_fvars_n) // items after this were cloned but not referenced directly by a method (such as our ccall PLT thunks) + frame0->linfo = sysimg_locked->sysimg_fvars_linfo[idx]; + break; + } } - } - for (size_t i = 0; i < sysimg_fvars_n; i++) { - if (diff == sysimg_fptrs.offsets[i]) { - frame0->linfo = sysimg_fvars_linfo[i]; - break; + for (size_t i = 0; i < sysimg_locked->sysimg_fvars_n; i++) { + if (diff == sysimg_locked->sysimg_fptrs.offsets[i]) { + frame0->linfo = sysimg_locked->sysimg_fvars_linfo[i]; + break; + } } } } @@ -1222,11 +1248,11 @@ int jl_DI_for_fptr(uint64_t fptr, uint64_t *symsize, int64_t *slide, int found = 0; assert(0 == (uintptr_t)pthread_getspecific(debuginfo_asyncsafe_held)); uv_rwlock_wrlock(&debuginfo_asyncsafe); - std::map &objmap = jl_jit_object_registry.getObjectMap(); - std::map::iterator fit = objmap.lower_bound(fptr); - if (symsize) *symsize = 0; + + auto &objmap = jl_jit_object_registry.getObjectMap(); + auto fit = objmap.lower_bound(fptr); if (fit != objmap.end() && fptr < fit->first + fit->second.SectionSize) { *slide = fit->second.slide; *Section = fit->second.Section; @@ -1678,8 +1704,8 @@ uint64_t jl_getUnwindInfo_impl(uint64_t dwAddr) { // Might be called from unmanaged thread jl_lock_profile_impl(); - std::map &objmap = jl_jit_object_registry.getObjectMap(); - std::map::iterator it = objmap.lower_bound(dwAddr); + auto &objmap = jl_jit_object_registry.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; From dc4ce813f6ea79672b5d1c6321d9d750e200866a Mon Sep 17 00:00:00 2001 From: Prem Chintalapudi Date: Sun, 17 Apr 2022 16:56:12 -0400 Subject: [PATCH 04/21] Lock around objfilemap --- src/debuginfo.cpp | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/src/debuginfo.cpp b/src/debuginfo.cpp index 925330f7f4b25..003eb7d4b359e 100644 --- a/src/debuginfo.cpp +++ b/src/debuginfo.cpp @@ -61,7 +61,6 @@ typedef struct { DIContext *ctx; int64_t slide; } objfileentry_t; -typedef std::map> obfiletype; extern "C" JL_DLLEXPORT void jl_lock_profile_impl(void) JL_NOTSAFEPOINT; extern "C" JL_DLLEXPORT void jl_unlock_profile_impl(void) JL_NOTSAFEPOINT; @@ -133,8 +132,11 @@ class JITObjectRegistry size_t sysimg_fvars_n; }; private: - std::map> objectmap; - std::map, std::greater> linfomap; + template + using rev_map = std::map>; + + rev_map objectmap; + rev_map> linfomap; // Maintain a mapping of unrealized function names -> linfo objects // so that when we see it get emitted, we can add a link back to the linfo @@ -143,6 +145,8 @@ class JITObjectRegistry Locked sysimg_info; + Locked> objfilemap; + static std::string mangle(StringRef Name, const DataLayout &DL) { std::string MangledName; @@ -351,6 +355,10 @@ class JITObjectRegistry auto get_sysimg_info() const { return *this->sysimg_info; } + + auto get_objfile_map() { + return *this->objfilemap; + } }; @@ -367,8 +375,6 @@ struct unw_table_entry int32_t fde_offset; }; -static obfiletype objfilemap; - // Any function that acquires this lock must be either a unmanaged thread // or in the GC safe region and must NOT allocate anything through the GC // while holding this lock. @@ -876,7 +882,7 @@ static void get_function_name_and_base(llvm::object::SectionRef Section, size_t #endif } -static objfileentry_t &find_object_file(uint64_t fbase, StringRef fname) JL_NOTSAFEPOINT +static objfileentry_t find_object_file(uint64_t fbase, StringRef fname) JL_NOTSAFEPOINT { int isdarwin = 0, islinux = 0, iswindows = 0; #if defined(_OS_DARWIN_) @@ -889,12 +895,13 @@ static objfileentry_t &find_object_file(uint64_t fbase, StringRef fname) JL_NOTS (void)iswindows; // GOAL: Read debuginfo from file - // TODO: need read/write lock here for objfilemap synchronization - obfiletype::iterator it = objfilemap.find(fbase); - if (it != objfilemap.end()) - // Return cached value - return it->second; - auto &entry = objfilemap[fbase]; // default initialized + objfileentry_t entry{nullptr, nullptr, 0}; + { + auto success = jl_jit_object_registry.get_objfile_map()->emplace(fbase, entry); + if (!success.second) + // Return cached value + return success.first->second; + } // GOAL: Assign errorobj StringRef objpath; @@ -1064,8 +1071,11 @@ static objfileentry_t &find_object_file(uint64_t fbase, StringRef fname) JL_NOTS auto binary = errorobj->takeBinary(); binary.first.release(); binary.second.release(); - // update cache entry = {debugobj, context, slide}; + // update cache + { + (*jl_jit_object_registry.get_objfile_map())[fbase] = entry; + } } else { // TODO: report the error instead of silently consuming it? @@ -1178,7 +1188,7 @@ bool jl_dylib_DI_for_fptr(size_t pointer, object::SectionRef *Section, int64_t * jl_copy_str(filename, dlinfo.dli_fname); fname = dlinfo.dli_fname; #endif // ifdef _OS_WINDOWS_ - auto &entry = find_object_file(fbase, fname); + auto entry = find_object_file(fbase, fname); *slide = entry.slide; *context = entry.ctx; if (entry.obj) From d8bad04df95460c572cd4e34d80c301ed484ba62 Mon Sep 17 00:00:00 2001 From: Prem Chintalapudi Date: Sun, 17 Apr 2022 17:42:46 -0400 Subject: [PATCH 05/21] wrap pthread functions in a struct --- src/debuginfo.cpp | 46 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/src/debuginfo.cpp b/src/debuginfo.cpp index 003eb7d4b359e..d27bd87c39a6d 100644 --- a/src/debuginfo.cpp +++ b/src/debuginfo.cpp @@ -35,6 +35,7 @@ using namespace llvm; #include #include #include +#include #include "julia_assert.h" #ifdef _OS_DARWIN_ @@ -62,6 +63,32 @@ typedef struct { int64_t slide; } objfileentry_t; +template +struct jl_pthread_key_t { + static_assert(std::is_trivially_default_constructible::value, "Invalid datatype for pthread key!"); + static_assert(std::is_trivially_destructible::value, "Expected datatype to be trivially destructible!"); + static_assert(sizeof(datatype) == sizeof(void*), "Expected datatype to be like a void*!"); + pthread_key_t key; + + void init() { + if (pthread_key_create(&key, NULL)) + jl_error("fatal: pthread_key_create failed"); + } + + operator datatype() { + return reinterpret_cast(pthread_getspecific(key)); + } + + jl_pthread_key_t &operator=(datatype val) { + pthread_setspecific(key, reinterpret_cast(val)); + return *this; + } + + void destroy() { + pthread_key_delete(key); + } +}; + extern "C" JL_DLLEXPORT void jl_lock_profile_impl(void) JL_NOTSAFEPOINT; extern "C" JL_DLLEXPORT void jl_unlock_profile_impl(void) JL_NOTSAFEPOINT; @@ -384,32 +411,31 @@ struct unw_table_entry // separately manage the re-entrant count behavior for safety across platforms // Note that we cannot safely upgrade read->write static uv_rwlock_t debuginfo_asyncsafe; -static pthread_key_t debuginfo_asyncsafe_held; +static jl_pthread_key_t debuginfo_asyncsafe_held; static JITObjectRegistry jl_jit_object_registry; void jl_init_debuginfo(void) { uv_rwlock_init(&debuginfo_asyncsafe); - if (pthread_key_create(&debuginfo_asyncsafe_held, NULL)) - jl_error("fatal: pthread_key_create failed"); + debuginfo_asyncsafe_held.init(); } extern "C" JL_DLLEXPORT void jl_lock_profile_impl(void) JL_NOTSAFEPOINT { - uintptr_t held = (uintptr_t)pthread_getspecific(debuginfo_asyncsafe_held); + uintptr_t held = debuginfo_asyncsafe_held; if (held++ == 0) uv_rwlock_rdlock(&debuginfo_asyncsafe); - pthread_setspecific(debuginfo_asyncsafe_held, (void*)held); + debuginfo_asyncsafe_held = held; } extern "C" JL_DLLEXPORT void jl_unlock_profile_impl(void) JL_NOTSAFEPOINT { - uintptr_t held = (uintptr_t)pthread_getspecific(debuginfo_asyncsafe_held); + uintptr_t held = debuginfo_asyncsafe_held; assert(held); if (--held == 0) uv_rwlock_rdunlock(&debuginfo_asyncsafe); - pthread_setspecific(debuginfo_asyncsafe_held, (void*)held); + debuginfo_asyncsafe_held = held; } // some actions aren't signal (especially profiler) safe so we acquire a lock @@ -417,7 +443,7 @@ extern "C" JL_DLLEXPORT void jl_unlock_profile_impl(void) JL_NOTSAFEPOINT template static void jl_profile_atomic(T f) { - assert(0 == (uintptr_t)pthread_getspecific(debuginfo_asyncsafe_held)); + assert(0 == debuginfo_asyncsafe_held); uv_rwlock_wrlock(&debuginfo_asyncsafe); #ifndef _OS_WINDOWS_ sigset_t sset; @@ -568,7 +594,7 @@ static int lookup_pointer( // DWARFContext/DWARFUnit update some internal tables during these queries, so // a lock is needed. - assert(0 == (uintptr_t)pthread_getspecific(debuginfo_asyncsafe_held)); + assert(0 == debuginfo_asyncsafe_held); uv_rwlock_wrlock(&debuginfo_asyncsafe); auto inlineInfo = context->getInliningInfoForAddress(makeAddress(Section, pointer + slide), infoSpec); uv_rwlock_wrunlock(&debuginfo_asyncsafe); @@ -1256,7 +1282,7 @@ int jl_DI_for_fptr(uint64_t fptr, uint64_t *symsize, int64_t *slide, object::SectionRef *Section, llvm::DIContext **context) JL_NOTSAFEPOINT { int found = 0; - assert(0 == (uintptr_t)pthread_getspecific(debuginfo_asyncsafe_held)); + assert(0 == debuginfo_asyncsafe_held); uv_rwlock_wrlock(&debuginfo_asyncsafe); if (symsize) *symsize = 0; From 65a684287a3e9dbba0aba49c4895ca52af0c85bd Mon Sep 17 00:00:00 2001 From: Prem Chintalapudi Date: Sun, 17 Apr 2022 17:48:28 -0400 Subject: [PATCH 06/21] Move debuginfo threading resources to object registry --- src/debuginfo.cpp | 67 +++++++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 31 deletions(-) diff --git a/src/debuginfo.cpp b/src/debuginfo.cpp index d27bd87c39a6d..c8ad066e94e24 100644 --- a/src/debuginfo.cpp +++ b/src/debuginfo.cpp @@ -159,6 +159,7 @@ class JITObjectRegistry size_t sysimg_fvars_n; }; private: + template using rev_map = std::map>; @@ -186,6 +187,17 @@ class JITObjectRegistry public: + // Any function that acquires this lock must be either a unmanaged thread + // or in the GC safe region and must NOT allocate anything through the GC + // while holding this lock. + // Certain functions in this file might be called from an unmanaged thread + // and cannot have any interaction with the julia runtime + // They also may be re-entrant, and operating while threads are paused, so we + // separately manage the re-entrant count behavior for safety across platforms + // Note that we cannot safely upgrade read->write + uv_rwlock_t debuginfo_asyncsafe; + jl_pthread_key_t debuginfo_asyncsafe_held; + void add_code_in_flight(StringRef name, jl_code_instance_t *codeinst, const DataLayout &DL) { (**codeinst_in_flight)[mangle(name, DL)] = codeinst; } @@ -386,6 +398,11 @@ class JITObjectRegistry auto get_objfile_map() { return *this->objfilemap; } + + void init() { + uv_rwlock_init(&debuginfo_asyncsafe); + debuginfo_asyncsafe_held.init(); + } }; @@ -402,40 +419,28 @@ struct unw_table_entry int32_t fde_offset; }; -// Any function that acquires this lock must be either a unmanaged thread -// or in the GC safe region and must NOT allocate anything through the GC -// while holding this lock. -// Certain functions in this file might be called from an unmanaged thread -// and cannot have any interaction with the julia runtime -// They also may be re-entrant, and operating while threads are paused, so we -// separately manage the re-entrant count behavior for safety across platforms -// Note that we cannot safely upgrade read->write -static uv_rwlock_t debuginfo_asyncsafe; -static jl_pthread_key_t debuginfo_asyncsafe_held; - static JITObjectRegistry jl_jit_object_registry; -void jl_init_debuginfo(void) +void jl_init_debuginfo() { - uv_rwlock_init(&debuginfo_asyncsafe); - debuginfo_asyncsafe_held.init(); + jl_jit_object_registry.init(); } extern "C" JL_DLLEXPORT void jl_lock_profile_impl(void) JL_NOTSAFEPOINT { - uintptr_t held = debuginfo_asyncsafe_held; + uintptr_t held = jl_jit_object_registry.debuginfo_asyncsafe_held; if (held++ == 0) - uv_rwlock_rdlock(&debuginfo_asyncsafe); - debuginfo_asyncsafe_held = held; + uv_rwlock_rdlock(&jl_jit_object_registry.debuginfo_asyncsafe); + jl_jit_object_registry.debuginfo_asyncsafe_held = held; } extern "C" JL_DLLEXPORT void jl_unlock_profile_impl(void) JL_NOTSAFEPOINT { - uintptr_t held = debuginfo_asyncsafe_held; + uintptr_t held = jl_jit_object_registry.debuginfo_asyncsafe_held; assert(held); if (--held == 0) - uv_rwlock_rdunlock(&debuginfo_asyncsafe); - debuginfo_asyncsafe_held = held; + uv_rwlock_rdunlock(&jl_jit_object_registry.debuginfo_asyncsafe); + jl_jit_object_registry.debuginfo_asyncsafe_held = held; } // some actions aren't signal (especially profiler) safe so we acquire a lock @@ -443,8 +448,8 @@ extern "C" JL_DLLEXPORT void jl_unlock_profile_impl(void) JL_NOTSAFEPOINT template static void jl_profile_atomic(T f) { - assert(0 == debuginfo_asyncsafe_held); - uv_rwlock_wrlock(&debuginfo_asyncsafe); + assert(0 == jl_jit_object_registry.debuginfo_asyncsafe_held); + uv_rwlock_wrlock(&jl_jit_object_registry.debuginfo_asyncsafe); #ifndef _OS_WINDOWS_ sigset_t sset; sigset_t oset; @@ -455,7 +460,7 @@ static void jl_profile_atomic(T f) #ifndef _OS_WINDOWS_ pthread_sigmask(SIG_SETMASK, &oset, NULL); #endif - uv_rwlock_wrunlock(&debuginfo_asyncsafe); + uv_rwlock_wrunlock(&jl_jit_object_registry.debuginfo_asyncsafe); } @@ -594,10 +599,10 @@ static int lookup_pointer( // DWARFContext/DWARFUnit update some internal tables during these queries, so // a lock is needed. - assert(0 == debuginfo_asyncsafe_held); - uv_rwlock_wrlock(&debuginfo_asyncsafe); + assert(0 == jl_jit_object_registry.debuginfo_asyncsafe_held); + uv_rwlock_wrlock(&jl_jit_object_registry.debuginfo_asyncsafe); auto inlineInfo = context->getInliningInfoForAddress(makeAddress(Section, pointer + slide), infoSpec); - uv_rwlock_wrunlock(&debuginfo_asyncsafe); + uv_rwlock_wrunlock(&jl_jit_object_registry.debuginfo_asyncsafe); int fromC = (*frames)[0].fromC; int n_frames = inlineInfo.getNumberOfFrames(); @@ -620,9 +625,9 @@ static int lookup_pointer( info = inlineInfo.getFrame(i); } else { - uv_rwlock_wrlock(&debuginfo_asyncsafe); + uv_rwlock_wrlock(&jl_jit_object_registry.debuginfo_asyncsafe); info = context->getLineInfoForAddress(makeAddress(Section, pointer + slide), infoSpec); - uv_rwlock_wrunlock(&debuginfo_asyncsafe); + uv_rwlock_wrunlock(&jl_jit_object_registry.debuginfo_asyncsafe); } jl_frame_t *frame = &(*frames)[i]; @@ -1282,8 +1287,8 @@ int jl_DI_for_fptr(uint64_t fptr, uint64_t *symsize, int64_t *slide, object::SectionRef *Section, llvm::DIContext **context) JL_NOTSAFEPOINT { int found = 0; - assert(0 == debuginfo_asyncsafe_held); - uv_rwlock_wrlock(&debuginfo_asyncsafe); + assert(0 == jl_jit_object_registry.debuginfo_asyncsafe_held); + uv_rwlock_wrlock(&jl_jit_object_registry.debuginfo_asyncsafe); if (symsize) *symsize = 0; @@ -1299,7 +1304,7 @@ int jl_DI_for_fptr(uint64_t fptr, uint64_t *symsize, int64_t *slide, } found = 1; } - uv_rwlock_wrunlock(&debuginfo_asyncsafe); + uv_rwlock_wrunlock(&jl_jit_object_registry.debuginfo_asyncsafe); return found; } From ffba4c7587b74ba0c98f8b8163efe169b6450deb Mon Sep 17 00:00:00 2001 From: Prem Chintalapudi Date: Sun, 17 Apr 2022 18:11:53 -0400 Subject: [PATCH 07/21] Move libc frame registration into jit object registry --- src/debuginfo.cpp | 114 +++++++++++++++++++++++++--------------------- 1 file changed, 63 insertions(+), 51 deletions(-) diff --git a/src/debuginfo.cpp b/src/debuginfo.cpp index c8ad066e94e24..901ae50027946 100644 --- a/src/debuginfo.cpp +++ b/src/debuginfo.cpp @@ -95,6 +95,66 @@ extern "C" JL_DLLEXPORT void jl_unlock_profile_impl(void) JL_NOTSAFEPOINT; template static void jl_profile_atomic(T f); +#if (defined(_OS_LINUX_) || defined(_OS_FREEBSD_) || (defined(_OS_DARWIN_) && defined(LLVM_SHLIB))) +extern "C" void __register_frame(void*); +extern "C" void __deregister_frame(void*); + +template +static void processFDEs(const char *EHFrameAddr, size_t EHFrameSize, callback f) +{ + const char *P = EHFrameAddr; + const char *End = P + EHFrameSize; + do { + const char *Entry = P; + P += 4; + assert(P <= End); + uint32_t Length = *(const uint32_t*)Entry; + // Length == 0: Terminator + if (Length == 0) + break; + assert(P + Length <= End); + uint32_t Offset = *(const uint32_t*)P; + // Offset == 0: CIE + if (Offset != 0) + f(Entry); + P += Length; + } while (P != End); +} +#endif + +struct libc_frames_t { +#if defined(_OS_DARWIN_) && defined(LLVM_SHLIB) + std::atomic libc_register_frame_{nullptr}; + std::atomic libc_deregister_frame_{nullptr}; + + void libc_register_frame(const char *Entry) { + auto libc_register_frame_ = jl_atomic_load_relaxed(&this->libc_register_frame_); + if (!libc_register_frame_) { + libc_register_frame_ = (void(*)(void*))dlsym(RTLD_NEXT, "__register_frame"); + jl_atomic_store_relaxed(&this->libc_register_frame_, libc_register_frame_); + } + assert(libc_register_frame_); + jl_profile_atomic([&]() { + libc_register_frame_(const_cast(Entry)); + __register_frame(const_cast(Entry)); + }); + } + + void libc_deregister_frame(const char *Entry) { + auto libc_deregister_frame_ = jl_atomic_load_relaxed(&this->libc_deregister_frame_); + if (!libc_deregister_frame_) { + libc_deregister_frame_ = (void(*)(void*))dlsym(RTLD_NEXT, "__deregister_frame"); + jl_atomic_store_relaxed(&this->libc_deregister_frame_, libc_deregister_frame_); + } + assert(libc_deregister_frame_); + jl_profile_atomic([&]() { + libc_deregister_frame_(const_cast(Entry)); + __deregister_frame(const_cast(Entry)); + }); + } +#endif +}; + // Central registry for resolving function addresses to `jl_method_instance_t`s and // originating `ObjectFile`s (for the DWARF debug info). @@ -197,6 +257,7 @@ class JITObjectRegistry // Note that we cannot safely upgrade read->write uv_rwlock_t debuginfo_asyncsafe; jl_pthread_key_t debuginfo_asyncsafe_held; + libc_frames_t libc_frames; void add_code_in_flight(StringRef name, jl_code_instance_t *codeinst, const DataLayout &DL) { (**codeinst_in_flight)[mangle(name, DL)] = codeinst; @@ -405,14 +466,6 @@ class JITObjectRegistry } }; - -#if defined(_OS_DARWIN_) && defined(LLVM_SHLIB) - -static void (*libc_register_frame)(void*) = NULL; -static void (*libc_deregister_frame)(void*) = NULL; - -#endif - struct unw_table_entry { int32_t start_ip_offset; @@ -1335,33 +1388,6 @@ extern "C" jl_method_instance_t *jl_gdblookuplinfo(void *p) JL_NOTSAFEPOINT return jl_jit_object_registry.lookupLinfo((size_t)p); } -#if (defined(_OS_LINUX_) || defined(_OS_FREEBSD_) || (defined(_OS_DARWIN_) && defined(LLVM_SHLIB))) -extern "C" void __register_frame(void*); -extern "C" void __deregister_frame(void*); - -template -static void processFDEs(const char *EHFrameAddr, size_t EHFrameSize, callback f) -{ - const char *P = EHFrameAddr; - const char *End = P + EHFrameSize; - do { - const char *Entry = P; - P += 4; - assert(P <= End); - uint32_t Length = *(const uint32_t*)Entry; - // Length == 0: Terminator - if (Length == 0) - break; - assert(P + Length <= End); - uint32_t Offset = *(const uint32_t*)P; - // Offset == 0: CIE - if (Offset != 0) - f(Entry); - P += Length; - } while (P != End); -} -#endif - #if defined(_OS_DARWIN_) && defined(LLVM_SHLIB) /* @@ -1378,28 +1404,14 @@ void register_eh_frames(uint8_t *Addr, size_t Size) // On OS X OS X __register_frame takes a single FDE as an argument. // See http://lists.cs.uiuc.edu/pipermail/llvmdev/2013-April/061768.html processFDEs((char*)Addr, Size, [](const char *Entry) { - if (!libc_register_frame) { - libc_register_frame = (void(*)(void*))dlsym(RTLD_NEXT, "__register_frame"); - } - assert(libc_register_frame); - jl_profile_atomic([&]() { - libc_register_frame(const_cast(Entry)); - __register_frame(const_cast(Entry)); - }); + jl_jit_object_registry.libc_frames.libc_register_frame(Entry); }); } void deregister_eh_frames(uint8_t *Addr, size_t Size) { processFDEs((char*)Addr, Size, [](const char *Entry) { - if (!libc_deregister_frame) { - libc_deregister_frame = (void(*)(void*))dlsym(RTLD_NEXT, "__deregister_frame"); - } - assert(libc_deregister_frame); - jl_profile_atomic([&]() { - libc_deregister_frame(const_cast(Entry)); - __deregister_frame(const_cast(Entry)); - }); + jl_jit_object_registry.libc_frames.libc_deregister_frame(Entry); }); } From 814929cfdb13af544b27d53056076e470ba2c0c1 Mon Sep 17 00:00:00 2001 From: Prem Chintalapudi Date: Sun, 17 Apr 2022 18:17:19 -0400 Subject: [PATCH 08/21] Rename object registry to debug info registry --- src/debuginfo.cpp | 70 +++++++++++++++++++++++------------------------ 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/src/debuginfo.cpp b/src/debuginfo.cpp index 901ae50027946..5bc20fb57b6e4 100644 --- a/src/debuginfo.cpp +++ b/src/debuginfo.cpp @@ -163,7 +163,7 @@ struct libc_frames_t { // and later queried by the various function info APIs. We also use the chance to handle // some platform-specific unwind info registration (which is unrelated to the query // functionality). -class JITObjectRegistry +class JITDebugInfoRegistry { public: template @@ -472,28 +472,28 @@ struct unw_table_entry int32_t fde_offset; }; -static JITObjectRegistry jl_jit_object_registry; +static JITDebugInfoRegistry jl_jit_debug_info; void jl_init_debuginfo() { - jl_jit_object_registry.init(); + jl_jit_debug_info.init(); } extern "C" JL_DLLEXPORT void jl_lock_profile_impl(void) JL_NOTSAFEPOINT { - uintptr_t held = jl_jit_object_registry.debuginfo_asyncsafe_held; + uintptr_t held = jl_jit_debug_info.debuginfo_asyncsafe_held; if (held++ == 0) - uv_rwlock_rdlock(&jl_jit_object_registry.debuginfo_asyncsafe); - jl_jit_object_registry.debuginfo_asyncsafe_held = held; + uv_rwlock_rdlock(&jl_jit_debug_info.debuginfo_asyncsafe); + jl_jit_debug_info.debuginfo_asyncsafe_held = held; } extern "C" JL_DLLEXPORT void jl_unlock_profile_impl(void) JL_NOTSAFEPOINT { - uintptr_t held = jl_jit_object_registry.debuginfo_asyncsafe_held; + uintptr_t held = jl_jit_debug_info.debuginfo_asyncsafe_held; assert(held); if (--held == 0) - uv_rwlock_rdunlock(&jl_jit_object_registry.debuginfo_asyncsafe); - jl_jit_object_registry.debuginfo_asyncsafe_held = held; + uv_rwlock_rdunlock(&jl_jit_debug_info.debuginfo_asyncsafe); + jl_jit_debug_info.debuginfo_asyncsafe_held = held; } // some actions aren't signal (especially profiler) safe so we acquire a lock @@ -501,8 +501,8 @@ extern "C" JL_DLLEXPORT void jl_unlock_profile_impl(void) JL_NOTSAFEPOINT template static void jl_profile_atomic(T f) { - assert(0 == jl_jit_object_registry.debuginfo_asyncsafe_held); - uv_rwlock_wrlock(&jl_jit_object_registry.debuginfo_asyncsafe); + assert(0 == jl_jit_debug_info.debuginfo_asyncsafe_held); + uv_rwlock_wrlock(&jl_jit_debug_info.debuginfo_asyncsafe); #ifndef _OS_WINDOWS_ sigset_t sset; sigset_t oset; @@ -513,14 +513,14 @@ static void jl_profile_atomic(T f) #ifndef _OS_WINDOWS_ pthread_sigmask(SIG_SETMASK, &oset, NULL); #endif - uv_rwlock_wrunlock(&jl_jit_object_registry.debuginfo_asyncsafe); + uv_rwlock_wrunlock(&jl_jit_debug_info.debuginfo_asyncsafe); } // --- storing and accessing source location metadata --- void jl_add_code_in_flight(StringRef name, jl_code_instance_t *codeinst, const DataLayout &DL) { - jl_jit_object_registry.add_code_in_flight(name, codeinst, DL); + jl_jit_debug_info.add_code_in_flight(name, codeinst, DL); } @@ -582,7 +582,7 @@ void jl_register_jit_object(const object::ObjectFile &Object, std::function getLoadAddress, std::function lookupWriteAddress) { - jl_jit_object_registry.registerJITObject(Object, getLoadAddress, lookupWriteAddress); + jl_jit_debug_info.registerJITObject(Object, getLoadAddress, lookupWriteAddress); } // TODO: convert the safe names from aotcomile.cpp:makeSafeName back into symbols @@ -652,10 +652,10 @@ static int lookup_pointer( // DWARFContext/DWARFUnit update some internal tables during these queries, so // a lock is needed. - assert(0 == jl_jit_object_registry.debuginfo_asyncsafe_held); - uv_rwlock_wrlock(&jl_jit_object_registry.debuginfo_asyncsafe); + assert(0 == jl_jit_debug_info.debuginfo_asyncsafe_held); + uv_rwlock_wrlock(&jl_jit_debug_info.debuginfo_asyncsafe); auto inlineInfo = context->getInliningInfoForAddress(makeAddress(Section, pointer + slide), infoSpec); - uv_rwlock_wrunlock(&jl_jit_object_registry.debuginfo_asyncsafe); + uv_rwlock_wrunlock(&jl_jit_debug_info.debuginfo_asyncsafe); int fromC = (*frames)[0].fromC; int n_frames = inlineInfo.getNumberOfFrames(); @@ -678,9 +678,9 @@ static int lookup_pointer( info = inlineInfo.getFrame(i); } else { - uv_rwlock_wrlock(&jl_jit_object_registry.debuginfo_asyncsafe); + uv_rwlock_wrlock(&jl_jit_debug_info.debuginfo_asyncsafe); info = context->getLineInfoForAddress(makeAddress(Section, pointer + slide), infoSpec); - uv_rwlock_wrunlock(&jl_jit_object_registry.debuginfo_asyncsafe); + uv_rwlock_wrunlock(&jl_jit_debug_info.debuginfo_asyncsafe); } jl_frame_t *frame = &(*frames)[i]; @@ -850,7 +850,7 @@ extern "C" JL_DLLEXPORT void jl_register_fptrs_impl(uint64_t sysimage_base, const jl_sysimg_fptrs_t *fptrs, jl_method_instance_t **linfos, size_t n) { - jl_jit_object_registry.set_sysimg_info({(uintptr_t) sysimage_base, *fptrs, linfos, n}); + jl_jit_debug_info.set_sysimg_info({(uintptr_t) sysimage_base, *fptrs, linfos, n}); } template @@ -865,7 +865,7 @@ static void get_function_name_and_base(llvm::object::SectionRef Section, size_t void **saddr, char **name, bool untrusted_dladdr) JL_NOTSAFEPOINT { // Assume we only need base address for sysimg for now - if (!insysimage || !jl_jit_object_registry.get_sysimg_info()->sysimg_fptrs.base) + if (!insysimage || !jl_jit_debug_info.get_sysimg_info()->sysimg_fptrs.base) saddr = nullptr; bool needs_saddr = saddr && (!*saddr || untrusted_dladdr); bool needs_name = name && (!*name || untrusted_dladdr); @@ -981,7 +981,7 @@ static objfileentry_t find_object_file(uint64_t fbase, StringRef fname) JL_NOTSA // GOAL: Read debuginfo from file objfileentry_t entry{nullptr, nullptr, 0}; { - auto success = jl_jit_object_registry.get_objfile_map()->emplace(fbase, entry); + auto success = jl_jit_debug_info.get_objfile_map()->emplace(fbase, entry); if (!success.second) // Return cached value return success.first->second; @@ -1158,7 +1158,7 @@ static objfileentry_t find_object_file(uint64_t fbase, StringRef fname) JL_NOTSA entry = {debugobj, context, slide}; // update cache { - (*jl_jit_object_registry.get_objfile_map())[fbase] = entry; + (*jl_jit_debug_info.get_objfile_map())[fbase] = entry; } } else { @@ -1217,7 +1217,7 @@ bool jl_dylib_DI_for_fptr(size_t pointer, object::SectionRef *Section, int64_t * if (fname.empty()) // empirically, LoadedImageName might be missing fname = ModuleInfo.ImageName; DWORD64 fbase = ModuleInfo.BaseOfImage; - bool insysimage = (fbase == jl_jit_object_registry.get_sysimg_info()->jl_sysimage_base); + bool insysimage = (fbase == jl_jit_debug_info.get_sysimg_info()->jl_sysimage_base); if (isSysImg) *isSysImg = insysimage; if (onlySysImg && !insysimage) @@ -1257,7 +1257,7 @@ bool jl_dylib_DI_for_fptr(size_t pointer, object::SectionRef *Section, int64_t * fbase = (uintptr_t)dlinfo.dli_fbase; #endif StringRef fname; - bool insysimage = (fbase == jl_jit_object_registry.get_sysimg_info()->jl_sysimage_base); + bool insysimage = (fbase == jl_jit_debug_info.get_sysimg_info()->jl_sysimage_base); if (saddr && !(insysimage && untrusted_dladdr)) *saddr = dlinfo.dli_saddr; if (isSysImg) @@ -1314,7 +1314,7 @@ static int jl_getDylibFunctionInfo(jl_frame_t **frames, size_t pointer, int skip } frame0->fromC = !isSysImg; { - auto sysimg_locked = jl_jit_object_registry.get_sysimg_info(); + auto sysimg_locked = jl_jit_debug_info.get_sysimg_info(); if (isSysImg && sysimg_locked->sysimg_fptrs.base && saddr) { intptr_t diff = (uintptr_t)saddr - (uintptr_t)sysimg_locked->sysimg_fptrs.base; for (size_t i = 0; i < sysimg_locked->sysimg_fptrs.nclones; i++) { @@ -1340,12 +1340,12 @@ int jl_DI_for_fptr(uint64_t fptr, uint64_t *symsize, int64_t *slide, object::SectionRef *Section, llvm::DIContext **context) JL_NOTSAFEPOINT { int found = 0; - assert(0 == jl_jit_object_registry.debuginfo_asyncsafe_held); - uv_rwlock_wrlock(&jl_jit_object_registry.debuginfo_asyncsafe); + assert(0 == jl_jit_debug_info.debuginfo_asyncsafe_held); + uv_rwlock_wrlock(&jl_jit_debug_info.debuginfo_asyncsafe); if (symsize) *symsize = 0; - auto &objmap = jl_jit_object_registry.getObjectMap(); + auto &objmap = jl_jit_debug_info.getObjectMap(); auto fit = objmap.lower_bound(fptr); if (fit != objmap.end() && fptr < fit->first + fit->second.SectionSize) { *slide = fit->second.slide; @@ -1357,7 +1357,7 @@ int jl_DI_for_fptr(uint64_t fptr, uint64_t *symsize, int64_t *slide, } found = 1; } - uv_rwlock_wrunlock(&jl_jit_object_registry.debuginfo_asyncsafe); + uv_rwlock_wrunlock(&jl_jit_debug_info.debuginfo_asyncsafe); return found; } @@ -1376,7 +1376,7 @@ extern "C" JL_DLLEXPORT int jl_getFunctionInfo_impl(jl_frame_t **frames_out, siz int64_t slide; uint64_t symsize; if (jl_DI_for_fptr(pointer, &symsize, &slide, &Section, &context)) { - frames[0].linfo = jl_jit_object_registry.lookupLinfo(pointer); + frames[0].linfo = jl_jit_debug_info.lookupLinfo(pointer); int nf = lookup_pointer(Section, context, frames_out, pointer, slide, true, noInline); return nf; } @@ -1385,7 +1385,7 @@ extern "C" JL_DLLEXPORT int jl_getFunctionInfo_impl(jl_frame_t **frames_out, siz extern "C" jl_method_instance_t *jl_gdblookuplinfo(void *p) JL_NOTSAFEPOINT { - return jl_jit_object_registry.lookupLinfo((size_t)p); + return jl_jit_debug_info.lookupLinfo((size_t)p); } #if defined(_OS_DARWIN_) && defined(LLVM_SHLIB) @@ -1404,14 +1404,14 @@ void register_eh_frames(uint8_t *Addr, size_t Size) // On OS X OS X __register_frame takes a single FDE as an argument. // See http://lists.cs.uiuc.edu/pipermail/llvmdev/2013-April/061768.html processFDEs((char*)Addr, Size, [](const char *Entry) { - jl_jit_object_registry.libc_frames.libc_register_frame(Entry); + jl_jit_debug_info.libc_frames.libc_register_frame(Entry); }); } void deregister_eh_frames(uint8_t *Addr, size_t Size) { processFDEs((char*)Addr, Size, [](const char *Entry) { - jl_jit_object_registry.libc_frames.libc_deregister_frame(Entry); + jl_jit_debug_info.libc_frames.libc_deregister_frame(Entry); }); } @@ -1757,7 +1757,7 @@ uint64_t jl_getUnwindInfo_impl(uint64_t dwAddr) { // Might be called from unmanaged thread jl_lock_profile_impl(); - auto &objmap = jl_jit_object_registry.getObjectMap(); + auto &objmap = jl_jit_debug_info.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) { From 982df3812ddb3716317b3d5cda8ab595ae6e4e2b Mon Sep 17 00:00:00 2001 From: Prem Chintalapudi Date: Sun, 17 Apr 2022 21:14:41 -0400 Subject: [PATCH 09/21] Scope debug info structs --- src/debuginfo.cpp | 599 ++++++++++++++++++++++++---------------------- 1 file changed, 308 insertions(+), 291 deletions(-) diff --git a/src/debuginfo.cpp b/src/debuginfo.cpp index 5bc20fb57b6e4..faa097e2f8b2b 100644 --- a/src/debuginfo.cpp +++ b/src/debuginfo.cpp @@ -42,119 +42,12 @@ using namespace llvm; #include #endif -typedef object::SymbolRef SymRef; - -struct debug_link_info { - StringRef filename; - uint32_t crc32; -}; - -struct ObjectInfo { - const object::ObjectFile *object; - size_t SectionSize; - ptrdiff_t slide; - object::SectionRef Section; - DIContext *context; -}; - typedef struct { const llvm::object::ObjectFile *obj; DIContext *ctx; int64_t slide; } objfileentry_t; -template -struct jl_pthread_key_t { - static_assert(std::is_trivially_default_constructible::value, "Invalid datatype for pthread key!"); - static_assert(std::is_trivially_destructible::value, "Expected datatype to be trivially destructible!"); - static_assert(sizeof(datatype) == sizeof(void*), "Expected datatype to be like a void*!"); - pthread_key_t key; - - void init() { - if (pthread_key_create(&key, NULL)) - jl_error("fatal: pthread_key_create failed"); - } - - operator datatype() { - return reinterpret_cast(pthread_getspecific(key)); - } - - jl_pthread_key_t &operator=(datatype val) { - pthread_setspecific(key, reinterpret_cast(val)); - return *this; - } - - void destroy() { - pthread_key_delete(key); - } -}; - -extern "C" JL_DLLEXPORT void jl_lock_profile_impl(void) JL_NOTSAFEPOINT; -extern "C" JL_DLLEXPORT void jl_unlock_profile_impl(void) JL_NOTSAFEPOINT; - -template -static void jl_profile_atomic(T f); - -#if (defined(_OS_LINUX_) || defined(_OS_FREEBSD_) || (defined(_OS_DARWIN_) && defined(LLVM_SHLIB))) -extern "C" void __register_frame(void*); -extern "C" void __deregister_frame(void*); - -template -static void processFDEs(const char *EHFrameAddr, size_t EHFrameSize, callback f) -{ - const char *P = EHFrameAddr; - const char *End = P + EHFrameSize; - do { - const char *Entry = P; - P += 4; - assert(P <= End); - uint32_t Length = *(const uint32_t*)Entry; - // Length == 0: Terminator - if (Length == 0) - break; - assert(P + Length <= End); - uint32_t Offset = *(const uint32_t*)P; - // Offset == 0: CIE - if (Offset != 0) - f(Entry); - P += Length; - } while (P != End); -} -#endif - -struct libc_frames_t { -#if defined(_OS_DARWIN_) && defined(LLVM_SHLIB) - std::atomic libc_register_frame_{nullptr}; - std::atomic libc_deregister_frame_{nullptr}; - - void libc_register_frame(const char *Entry) { - auto libc_register_frame_ = jl_atomic_load_relaxed(&this->libc_register_frame_); - if (!libc_register_frame_) { - libc_register_frame_ = (void(*)(void*))dlsym(RTLD_NEXT, "__register_frame"); - jl_atomic_store_relaxed(&this->libc_register_frame_, libc_register_frame_); - } - assert(libc_register_frame_); - jl_profile_atomic([&]() { - libc_register_frame_(const_cast(Entry)); - __register_frame(const_cast(Entry)); - }); - } - - void libc_deregister_frame(const char *Entry) { - auto libc_deregister_frame_ = jl_atomic_load_relaxed(&this->libc_deregister_frame_); - if (!libc_deregister_frame_) { - libc_deregister_frame_ = (void(*)(void*))dlsym(RTLD_NEXT, "__deregister_frame"); - jl_atomic_store_relaxed(&this->libc_deregister_frame_, libc_deregister_frame_); - } - assert(libc_deregister_frame_); - jl_profile_atomic([&]() { - libc_deregister_frame_(const_cast(Entry)); - __deregister_frame(const_cast(Entry)); - }); - } -#endif -}; - // Central registry for resolving function addresses to `jl_method_instance_t`s and // originating `ObjectFile`s (for the DWARF debug info). @@ -212,14 +105,59 @@ class JITDebugInfoRegistry } }; + template + struct jl_pthread_key_t { + static_assert(std::is_trivially_default_constructible::value, "Invalid datatype for pthread key!"); + static_assert(std::is_trivially_destructible::value, "Expected datatype to be trivially destructible!"); + static_assert(sizeof(datatype) == sizeof(void*), "Expected datatype to be like a void*!"); + pthread_key_t key; + + void init() { + if (pthread_key_create(&key, NULL)) + jl_error("fatal: pthread_key_create failed"); + } + + operator datatype() { + return reinterpret_cast(pthread_getspecific(key)); + } + + jl_pthread_key_t &operator=(datatype val) { + pthread_setspecific(key, reinterpret_cast(val)); + return *this; + } + + void destroy() { + pthread_key_delete(key); + } + }; + struct sysimg_info_t { uint64_t jl_sysimage_base; jl_sysimg_fptrs_t sysimg_fptrs; jl_method_instance_t **sysimg_fvars_linfo; size_t sysimg_fvars_n; }; + + struct libc_frames_t { +#if defined(_OS_DARWIN_) && defined(LLVM_SHLIB) + std::atomic libc_register_frame_{nullptr}; + std::atomic libc_deregister_frame_{nullptr}; + + void libc_register_frame(const char *Entry); + + void libc_deregister_frame(const char *Entry); +#endif + }; private: + struct ObjectInfo { + const object::ObjectFile *object; + size_t SectionSize; + ptrdiff_t slide; + object::SectionRef Section; + DIContext *context; + }; + template using rev_map = std::map>; @@ -235,15 +173,7 @@ class JITDebugInfoRegistry Locked> objfilemap; - static std::string mangle(StringRef Name, const DataLayout &DL) - { - std::string MangledName; - { - raw_string_ostream MangledNameStream(MangledName); - Mangler::getNameWithPrefix(MangledNameStream, Name, DL); - } - return MangledName; - } + static std::string mangle(StringRef Name, const DataLayout &DL); public: @@ -259,212 +189,299 @@ class JITDebugInfoRegistry jl_pthread_key_t debuginfo_asyncsafe_held; libc_frames_t libc_frames; - void add_code_in_flight(StringRef name, jl_code_instance_t *codeinst, const DataLayout &DL) { - (**codeinst_in_flight)[mangle(name, DL)] = codeinst; + void add_code_in_flight(StringRef name, jl_code_instance_t *codeinst, const DataLayout &DL); + jl_method_instance_t *lookupLinfo(size_t pointer) JL_NOTSAFEPOINT; + void registerJITObject(const object::ObjectFile &Object, + std::function getLoadAddress, + std::function lookupWriteAddress); + auto& getObjectMap() JL_NOTSAFEPOINT; + void set_sysimg_info(sysimg_info_t info); + auto get_sysimg_info() const; + auto get_objfile_map(); + void init(); +}; + +struct debug_link_info { + StringRef filename; + uint32_t crc32; +}; + +extern "C" JL_DLLEXPORT void jl_lock_profile_impl(void) JL_NOTSAFEPOINT; +extern "C" JL_DLLEXPORT void jl_unlock_profile_impl(void) JL_NOTSAFEPOINT; + +template +static void jl_profile_atomic(T f); + +#if (defined(_OS_LINUX_) || defined(_OS_FREEBSD_) || (defined(_OS_DARWIN_) && defined(LLVM_SHLIB))) +extern "C" void __register_frame(void*); +extern "C" void __deregister_frame(void*); + +template +static void processFDEs(const char *EHFrameAddr, size_t EHFrameSize, callback f) +{ + const char *P = EHFrameAddr; + const char *End = P + EHFrameSize; + do { + const char *Entry = P; + P += 4; + assert(P <= End); + uint32_t Length = *(const uint32_t*)Entry; + // Length == 0: Terminator + if (Length == 0) + break; + assert(P + Length <= End); + uint32_t Offset = *(const uint32_t*)P; + // Offset == 0: CIE + if (Offset != 0) + f(Entry); + P += Length; + } while (P != End); +} +#endif + +#if defined(_OS_DARWIN_) && defined(LLVM_SHLIB) + +void JITDebugInfoRegistry::libc_frames_t::libc_register_frame(const char *Entry) { + auto libc_register_frame_ = jl_atomic_load_relaxed(&this->libc_register_frame_); + if (!libc_register_frame_) { + libc_register_frame_ = (void(*)(void*))dlsym(RTLD_NEXT, "__register_frame"); + jl_atomic_store_relaxed(&this->libc_register_frame_, libc_register_frame_); } + assert(libc_register_frame_); + jl_profile_atomic([&]() { + libc_register_frame_(const_cast(Entry)); + __register_frame(const_cast(Entry)); + }); +} - jl_method_instance_t *lookupLinfo(size_t pointer) JL_NOTSAFEPOINT - { - jl_lock_profile_impl(); - auto region = linfomap.lower_bound(pointer); - jl_method_instance_t *linfo = NULL; - if (region != linfomap.end() && pointer < region->first + region->second.first) - linfo = region->second.second; - jl_unlock_profile_impl(); - return linfo; +void JITDebugInfoRegistry::libc_frames_t::libc_deregister_frame(const char *Entry) { + auto libc_deregister_frame_ = jl_atomic_load_relaxed(&this->libc_deregister_frame_); + if (!libc_deregister_frame_) { + libc_deregister_frame_ = (void(*)(void*))dlsym(RTLD_NEXT, "__deregister_frame"); + jl_atomic_store_relaxed(&this->libc_deregister_frame_, libc_deregister_frame_); } + assert(libc_deregister_frame_); + jl_profile_atomic([&]() { + libc_deregister_frame_(const_cast(Entry)); + __deregister_frame(const_cast(Entry)); + }); +} +#endif - void registerJITObject(const object::ObjectFile &Object, - std::function getLoadAddress, - std::function lookupWriteAddress) +std::string JITDebugInfoRegistry::mangle(StringRef Name, const DataLayout &DL) +{ + std::string MangledName; { - object::section_iterator EndSection = Object.section_end(); + raw_string_ostream MangledNameStream(MangledName); + Mangler::getNameWithPrefix(MangledNameStream, Name, DL); + } + return MangledName; +} + +void JITDebugInfoRegistry::add_code_in_flight(StringRef name, jl_code_instance_t *codeinst, const DataLayout &DL) { + (**codeinst_in_flight)[mangle(name, DL)] = codeinst; +} + +jl_method_instance_t *JITDebugInfoRegistry::lookupLinfo(size_t pointer) JL_NOTSAFEPOINT +{ + jl_lock_profile_impl(); + auto region = linfomap.lower_bound(pointer); + jl_method_instance_t *linfo = NULL; + if (region != linfomap.end() && pointer < region->first + region->second.first) + linfo = region->second.second; + jl_unlock_profile_impl(); + return linfo; +} + +void JITDebugInfoRegistry::registerJITObject(const object::ObjectFile &Object, + std::function getLoadAddress, + std::function lookupWriteAddress) +{ + object::section_iterator EndSection = Object.section_end(); #ifdef _CPU_ARM_ - // ARM does not have/use .eh_frame - uint64_t arm_exidx_addr = 0; - size_t arm_exidx_len = 0; - uint64_t arm_text_addr = 0; - size_t arm_text_len = 0; - for (auto §ion: Object.sections()) { - bool istext = false; - if (section.isText()) { - istext = true; - } - else { - auto sName = section.getName(); - if (!sName) - continue; - if (sName.get() != ".ARM.exidx") { - continue; - } + // ARM does not have/use .eh_frame + uint64_t arm_exidx_addr = 0; + size_t arm_exidx_len = 0; + uint64_t arm_text_addr = 0; + size_t arm_text_len = 0; + for (auto §ion: Object.sections()) { + bool istext = false; + if (section.isText()) { + istext = true; + } + else { + auto sName = section.getName(); + if (!sName) + continue; + if (sName.get() != ".ARM.exidx") { + continue; } - uint64_t loadaddr = getLoadAddress(section.getName().get()); - size_t seclen = section.getSize(); - if (istext) { - arm_text_addr = loadaddr; - arm_text_len = seclen; - if (!arm_exidx_addr) { - continue; - } + } + uint64_t loadaddr = getLoadAddress(section.getName().get()); + size_t seclen = section.getSize(); + if (istext) { + arm_text_addr = loadaddr; + arm_text_len = seclen; + if (!arm_exidx_addr) { + continue; } - else { - arm_exidx_addr = loadaddr; - arm_exidx_len = seclen; - if (!arm_text_addr) { - continue; - } + } + else { + arm_exidx_addr = loadaddr; + arm_exidx_len = seclen; + if (!arm_text_addr) { + continue; } - unw_dyn_info_t *di = new unw_dyn_info_t; - di->gp = 0; - di->format = UNW_INFO_FORMAT_ARM_EXIDX; - di->start_ip = (uintptr_t)arm_text_addr; - di->end_ip = (uintptr_t)(arm_text_addr + arm_text_len); - di->u.rti.name_ptr = 0; - di->u.rti.table_data = arm_exidx_addr; - di->u.rti.table_len = arm_exidx_len; - jl_profile_atomic([&]() { - _U_dyn_register(di); - }); - break; } + unw_dyn_info_t *di = new unw_dyn_info_t; + di->gp = 0; + di->format = UNW_INFO_FORMAT_ARM_EXIDX; + di->start_ip = (uintptr_t)arm_text_addr; + di->end_ip = (uintptr_t)(arm_text_addr + arm_text_len); + di->u.rti.name_ptr = 0; + di->u.rti.table_data = arm_exidx_addr; + di->u.rti.table_len = arm_exidx_len; + jl_profile_atomic([&]() { + _U_dyn_register(di); + }); + break; + } #endif #if defined(_OS_WINDOWS_) - uint64_t SectionAddrCheck = 0; - uint64_t SectionLoadCheck = 0; (void)SectionLoadCheck; - uint64_t SectionWriteCheck = 0; (void)SectionWriteCheck; - uint8_t *UnwindData = NULL; + uint64_t SectionAddrCheck = 0; + uint64_t SectionLoadCheck = 0; (void)SectionLoadCheck; + uint64_t SectionWriteCheck = 0; (void)SectionWriteCheck; + uint8_t *UnwindData = NULL; #if defined(_CPU_X86_64_) - uint8_t *catchjmp = NULL; - for (const object::SymbolRef &sym_iter : Object.symbols()) { - StringRef sName = cantFail(sym_iter.getName()); - if (sName.equals("__UnwindData") || sName.equals("__catchjmp")) { - uint64_t Addr = cantFail(sym_iter.getAddress()); - auto Section = cantFail(sym_iter.getSection()); - assert(Section != EndSection && Section->isText()); - uint64_t SectionAddr = Section->getAddress(); - StringRef secName = cantFail(Section->getName()); - uint64_t SectionLoadAddr = getLoadAddress(secName); - assert(SectionLoadAddr); - if (SectionAddrCheck) // assert that all of the Sections are at the same location - assert(SectionAddrCheck == SectionAddr && - SectionLoadCheck == SectionLoadAddr); - SectionAddrCheck = SectionAddr; - SectionLoadCheck = SectionLoadAddr; - SectionWriteCheck = SectionLoadAddr; - if (lookupWriteAddress) - SectionWriteCheck = (uintptr_t)lookupWriteAddress((void*)SectionLoadAddr); - Addr += SectionWriteCheck - SectionLoadCheck; - if (sName.equals("__UnwindData")) { - UnwindData = (uint8_t*)Addr; - } - else if (sName.equals("__catchjmp")) { - catchjmp = (uint8_t*)Addr; - } - } - } - assert(catchjmp); - assert(UnwindData); - assert(SectionAddrCheck); - assert(SectionLoadCheck); - assert(!memcmp(catchjmp, "\0\0\0\0\0\0\0\0\0\0\0\0", 12) && - !memcmp(UnwindData, "\0\0\0\0\0\0\0\0\0\0\0\0", 12)); - catchjmp[0] = 0x48; - catchjmp[1] = 0xb8; // mov RAX, QWORD PTR [&__julia_personality] - *(uint64_t*)(&catchjmp[2]) = (uint64_t)&__julia_personality; - catchjmp[10] = 0xff; - catchjmp[11] = 0xe0; // jmp RAX - UnwindData[0] = 0x09; // version info, UNW_FLAG_EHANDLER - UnwindData[1] = 4; // size of prolog (bytes) - UnwindData[2] = 2; // count of unwind codes (slots) - UnwindData[3] = 0x05; // frame register (rbp) = rsp - UnwindData[4] = 4; // second instruction - UnwindData[5] = 0x03; // mov RBP, RSP - UnwindData[6] = 1; // first instruction - UnwindData[7] = 0x50; // push RBP - *(DWORD*)&UnwindData[8] = (DWORD)(catchjmp - (uint8_t*)SectionWriteCheck); // relative location of catchjmp - UnwindData -= SectionWriteCheck - SectionLoadCheck; -#endif // defined(_OS_X86_64_) -#endif // defined(_OS_WINDOWS_) - - auto symbols = object::computeSymbolSizes(Object); - bool first = true; - for (const auto &sym_size : symbols) { - const object::SymbolRef &sym_iter = sym_size.first; - object::SymbolRef::Type SymbolType = cantFail(sym_iter.getType()); - if (SymbolType != object::SymbolRef::ST_Function) continue; + uint8_t *catchjmp = NULL; + for (const object::SymbolRef &sym_iter : Object.symbols()) { + StringRef sName = cantFail(sym_iter.getName()); + if (sName.equals("__UnwindData") || sName.equals("__catchjmp")) { uint64_t Addr = cantFail(sym_iter.getAddress()); auto Section = cantFail(sym_iter.getSection()); - if (Section == EndSection) continue; - if (!Section->isText()) continue; + assert(Section != EndSection && Section->isText()); uint64_t SectionAddr = Section->getAddress(); StringRef secName = cantFail(Section->getName()); uint64_t SectionLoadAddr = getLoadAddress(secName); - Addr -= SectionAddr - SectionLoadAddr; - StringRef sName = cantFail(sym_iter.getName()); - uint64_t SectionSize = Section->getSize(); - size_t Size = sym_size.second; -#if defined(_OS_WINDOWS_) - if (SectionAddrCheck) + assert(SectionLoadAddr); + if (SectionAddrCheck) // assert that all of the Sections are at the same location assert(SectionAddrCheck == SectionAddr && - SectionLoadCheck == SectionLoadAddr); + SectionLoadCheck == SectionLoadAddr); SectionAddrCheck = SectionAddr; SectionLoadCheck = SectionLoadAddr; - create_PRUNTIME_FUNCTION( - (uint8_t*)(uintptr_t)Addr, (size_t)Size, sName, - (uint8_t*)(uintptr_t)SectionLoadAddr, (size_t)SectionSize, UnwindData); -#endif - jl_code_instance_t *codeinst = NULL; - { - auto lock = *this->codeinst_in_flight; - auto &codeinst_in_flight = *lock; - StringMap::iterator codeinst_it = codeinst_in_flight.find(sName); - if (codeinst_it != codeinst_in_flight.end()) { - codeinst = codeinst_it->second; - codeinst_in_flight.erase(codeinst_it); - } + SectionWriteCheck = SectionLoadAddr; + if (lookupWriteAddress) + SectionWriteCheck = (uintptr_t)lookupWriteAddress((void*)SectionLoadAddr); + Addr += SectionWriteCheck - SectionLoadCheck; + if (sName.equals("__UnwindData")) { + UnwindData = (uint8_t*)Addr; + } + else if (sName.equals("__catchjmp")) { + catchjmp = (uint8_t*)Addr; } - jl_profile_atomic([&]() { - if (codeinst) - linfomap[Addr] = std::make_pair(Size, codeinst->def); - if (first) { - ObjectInfo tmp = {&Object, - (size_t)SectionSize, - (ptrdiff_t)(SectionAddr - SectionLoadAddr), - *Section, - nullptr, - }; - objectmap[SectionLoadAddr] = tmp; - first = false; - } - }); } } + assert(catchjmp); + assert(UnwindData); + assert(SectionAddrCheck); + assert(SectionLoadCheck); + assert(!memcmp(catchjmp, "\0\0\0\0\0\0\0\0\0\0\0\0", 12) && + !memcmp(UnwindData, "\0\0\0\0\0\0\0\0\0\0\0\0", 12)); + catchjmp[0] = 0x48; + catchjmp[1] = 0xb8; // mov RAX, QWORD PTR [&__julia_personality] + *(uint64_t*)(&catchjmp[2]) = (uint64_t)&__julia_personality; + catchjmp[10] = 0xff; + catchjmp[11] = 0xe0; // jmp RAX + UnwindData[0] = 0x09; // version info, UNW_FLAG_EHANDLER + UnwindData[1] = 4; // size of prolog (bytes) + UnwindData[2] = 2; // count of unwind codes (slots) + UnwindData[3] = 0x05; // frame register (rbp) = rsp + UnwindData[4] = 4; // second instruction + UnwindData[5] = 0x03; // mov RBP, RSP + UnwindData[6] = 1; // first instruction + UnwindData[7] = 0x50; // push RBP + *(DWORD*)&UnwindData[8] = (DWORD)(catchjmp - (uint8_t*)SectionWriteCheck); // relative location of catchjmp + UnwindData -= SectionWriteCheck - SectionLoadCheck; +#endif // defined(_OS_X86_64_) +#endif // defined(_OS_WINDOWS_) - //Protected by debuginfo_asyncsafe - auto& getObjectMap() JL_NOTSAFEPOINT - { - return objectmap; + auto symbols = object::computeSymbolSizes(Object); + bool first = true; + for (const auto &sym_size : symbols) { + const object::SymbolRef &sym_iter = sym_size.first; + object::SymbolRef::Type SymbolType = cantFail(sym_iter.getType()); + if (SymbolType != object::SymbolRef::ST_Function) continue; + uint64_t Addr = cantFail(sym_iter.getAddress()); + auto Section = cantFail(sym_iter.getSection()); + if (Section == EndSection) continue; + if (!Section->isText()) continue; + uint64_t SectionAddr = Section->getAddress(); + StringRef secName = cantFail(Section->getName()); + uint64_t SectionLoadAddr = getLoadAddress(secName); + Addr -= SectionAddr - SectionLoadAddr; + StringRef sName = cantFail(sym_iter.getName()); + uint64_t SectionSize = Section->getSize(); + size_t Size = sym_size.second; +#if defined(_OS_WINDOWS_) + if (SectionAddrCheck) + assert(SectionAddrCheck == SectionAddr && + SectionLoadCheck == SectionLoadAddr); + SectionAddrCheck = SectionAddr; + SectionLoadCheck = SectionLoadAddr; + create_PRUNTIME_FUNCTION( + (uint8_t*)(uintptr_t)Addr, (size_t)Size, sName, + (uint8_t*)(uintptr_t)SectionLoadAddr, (size_t)SectionSize, UnwindData); +#endif + jl_code_instance_t *codeinst = NULL; + { + auto lock = *this->codeinst_in_flight; + auto &codeinst_in_flight = *lock; + StringMap::iterator codeinst_it = codeinst_in_flight.find(sName); + if (codeinst_it != codeinst_in_flight.end()) { + codeinst = codeinst_it->second; + codeinst_in_flight.erase(codeinst_it); + } + } + jl_profile_atomic([&]() { + if (codeinst) + linfomap[Addr] = std::make_pair(Size, codeinst->def); + if (first) { + objectmap[SectionLoadAddr] = {&Object, + (size_t)SectionSize, + (ptrdiff_t)(SectionAddr - SectionLoadAddr), + *Section, + nullptr, + }; + first = false; + } + }); } +} - void set_sysimg_info(sysimg_info_t info) { - (**this->sysimg_info) = info; - } +//Protected by debuginfo_asyncsafe +auto& JITDebugInfoRegistry::getObjectMap() JL_NOTSAFEPOINT +{ + return objectmap; +} - auto get_sysimg_info() const { - return *this->sysimg_info; - } +void JITDebugInfoRegistry::set_sysimg_info(sysimg_info_t info) { + (**this->sysimg_info) = info; +} - auto get_objfile_map() { - return *this->objfilemap; - } +auto JITDebugInfoRegistry::get_sysimg_info() const { + return *this->sysimg_info; +} - void init() { - uv_rwlock_init(&debuginfo_asyncsafe); - debuginfo_asyncsafe_held.init(); - } -}; +auto JITDebugInfoRegistry::get_objfile_map() { + return *this->objfilemap; +} + +void JITDebugInfoRegistry::init() { + uv_rwlock_init(&debuginfo_asyncsafe); + debuginfo_asyncsafe_held.init(); +} struct unw_table_entry { @@ -891,7 +908,7 @@ static void get_function_name_and_base(llvm::object::SectionRef Section, size_t } if (Section.getObject() && (needs_saddr || needs_name)) { size_t distance = (size_t)-1; - SymRef sym_found; + object::SymbolRef sym_found; for (auto sym : Section.getObject()->symbols()) { if (!Section.containsSymbol(sym)) continue; From 29ff6e84bab9f969f745bbac05c90f6b493fe0a7 Mon Sep 17 00:00:00 2001 From: Prem Chintalapudi Date: Sun, 17 Apr 2022 21:54:21 -0400 Subject: [PATCH 10/21] Move JITDebugInfoRegistry to its own file --- src/Makefile | 2 +- src/debug-registry.h | 175 +++++++++++++++++++++++++++++++++++++++++++ src/debuginfo.cpp | 169 ++--------------------------------------- src/processor.h | 5 ++ 4 files changed, 188 insertions(+), 163 deletions(-) create mode 100644 src/debug-registry.h diff --git a/src/Makefile b/src/Makefile index 9c200b9085eb9..1bedd99052dad 100644 --- a/src/Makefile +++ b/src/Makefile @@ -279,7 +279,7 @@ $(BUILDDIR)/ast.o $(BUILDDIR)/ast.dbg.obj: $(BUILDDIR)/julia_flisp.boot.inc $(SR $(BUILDDIR)/builtins.o $(BUILDDIR)/builtins.dbg.obj: $(SRCDIR)/iddict.c $(SRCDIR)/builtin_proto.h $(BUILDDIR)/codegen.o $(BUILDDIR)/codegen.dbg.obj: $(addprefix $(SRCDIR)/,\ intrinsics.cpp jitlayers.h intrinsics.h codegen_shared.h cgutils.cpp ccall.cpp abi_*.cpp processor.h builtin_proto.h) -$(BUILDDIR)/debuginfo.o $(BUILDDIR)/debuginfo.dbg.obj: $(addprefix $(SRCDIR)/,debuginfo.h processor.h) +$(BUILDDIR)/debuginfo.o $(BUILDDIR)/debuginfo.dbg.obj: $(addprefix $(SRCDIR)/,debuginfo.h processor.h debug-registry.h) $(BUILDDIR)/disasm.o $(BUILDDIR)/disasm.dbg.obj: $(SRCDIR)/debuginfo.h $(SRCDIR)/processor.h $(BUILDDIR)/dump.o $(BUILDDIR)/dump.dbg.obj: $(addprefix $(SRCDIR)/,common_symbols1.inc common_symbols2.inc builtin_proto.h serialize.h) $(BUILDDIR)/gc-debug.o $(BUILDDIR)/gc-debug.dbg.obj: $(SRCDIR)/gc.h diff --git a/src/debug-registry.h b/src/debug-registry.h new file mode 100644 index 0000000000000..d4b0c8edb2d77 --- /dev/null +++ b/src/debug-registry.h @@ -0,0 +1,175 @@ +#include +#include +#include + +#include "julia_internal.h" +#include "processor.h" + +#include +#include +#include + +typedef struct { + const llvm::object::ObjectFile *obj; + llvm::DIContext *ctx; + int64_t slide; +} objfileentry_t; + + +// Central registry for resolving function addresses to `jl_method_instance_t`s and +// originating `ObjectFile`s (for the DWARF debug info). +// +// A global singleton instance is notified by the JIT whenever a new object is emitted, +// and later queried by the various function info APIs. We also use the chance to handle +// some platform-specific unwind info registration (which is unrelated to the query +// functionality). +class JITDebugInfoRegistry +{ +public: + template + struct Locked { + + template + struct Lock { + std::unique_lock lock; + CResourceT &resource; + + Lock(std::mutex &mutex, CResourceT &resource) : lock(mutex), resource(resource) {} + + CResourceT &operator*() { + return resource; + } + + const CResourceT &operator*() const { + return resource; + } + + CResourceT *operator->() { + return &**this; + } + + const CResourceT *operator->() const { + return &**this; + } + + operator const CResourceT &() const { + return resource; + } + }; + private: + + mutable std::mutex mutex; + ResourceT resource; + public: + typedef Lock LockT; + typedef Lock ConstLockT; + + Locked(ResourceT resource = ResourceT()) : mutex(), resource(std::move(resource)) {} + + LockT operator*() { + return LockT(mutex, resource); + } + + ConstLockT operator*() const { + return ConstLockT(mutex, resource); + } + }; + + template + struct jl_pthread_key_t { + static_assert(std::is_trivially_default_constructible::value, "Invalid datatype for pthread key!"); + static_assert(std::is_trivially_destructible::value, "Expected datatype to be trivially destructible!"); + static_assert(sizeof(datatype) == sizeof(void*), "Expected datatype to be like a void*!"); + pthread_key_t key; + + void init() { + if (pthread_key_create(&key, NULL)) + jl_error("fatal: pthread_key_create failed"); + } + + operator datatype() { + return reinterpret_cast(pthread_getspecific(key)); + } + + jl_pthread_key_t &operator=(datatype val) { + pthread_setspecific(key, reinterpret_cast(val)); + return *this; + } + + void destroy() { + pthread_key_delete(key); + } + }; + + struct sysimg_info_t { + uint64_t jl_sysimage_base; + jl_sysimg_fptrs_t sysimg_fptrs; + jl_method_instance_t **sysimg_fvars_linfo; + size_t sysimg_fvars_n; + }; + + struct libc_frames_t { +#if defined(_OS_DARWIN_) && defined(LLVM_SHLIB) + std::atomic libc_register_frame_{nullptr}; + std::atomic libc_deregister_frame_{nullptr}; + + void libc_register_frame(const char *Entry); + + void libc_deregister_frame(const char *Entry); +#endif + }; +private: + + struct ObjectInfo { + const llvm::object::ObjectFile *object; + size_t SectionSize; + ptrdiff_t slide; + llvm::object::SectionRef Section; + llvm::DIContext *context; + }; + + template + using rev_map = std::map>; + + typedef rev_map objectmap_t; + typedef rev_map objfilemap_t; + + objectmap_t objectmap; + rev_map> linfomap; + + // Maintain a mapping of unrealized function names -> linfo objects + // so that when we see it get emitted, we can add a link back to the linfo + // that it came from (providing name, type signature, file info, etc.) + Locked> codeinst_in_flight; + + Locked sysimg_info; + + Locked objfilemap; + + static std::string mangle(llvm::StringRef Name, const llvm::DataLayout &DL); + +public: + + // Any function that acquires this lock must be either a unmanaged thread + // or in the GC safe region and must NOT allocate anything through the GC + // while holding this lock. + // Certain functions in this file might be called from an unmanaged thread + // and cannot have any interaction with the julia runtime + // They also may be re-entrant, and operating while threads are paused, so we + // separately manage the re-entrant count behavior for safety across platforms + // Note that we cannot safely upgrade read->write + uv_rwlock_t debuginfo_asyncsafe; + jl_pthread_key_t debuginfo_asyncsafe_held; + libc_frames_t libc_frames; + + void add_code_in_flight(llvm::StringRef name, jl_code_instance_t *codeinst, const llvm::DataLayout &DL); + jl_method_instance_t *lookupLinfo(size_t pointer) JL_NOTSAFEPOINT; + void registerJITObject(const llvm::object::ObjectFile &Object, + std::function getLoadAddress, + std::function lookupWriteAddress); + objectmap_t& getObjectMap() JL_NOTSAFEPOINT; + void set_sysimg_info(sysimg_info_t info); + Locked::ConstLockT get_sysimg_info() const; + Locked::LockT get_objfile_map(); + void init(); +}; \ No newline at end of file diff --git a/src/debuginfo.cpp b/src/debuginfo.cpp index faa097e2f8b2b..42c78520772ea 100644 --- a/src/debuginfo.cpp +++ b/src/debuginfo.cpp @@ -35,171 +35,13 @@ using namespace llvm; #include #include #include -#include #include "julia_assert.h" #ifdef _OS_DARWIN_ #include #endif -typedef struct { - const llvm::object::ObjectFile *obj; - DIContext *ctx; - int64_t slide; -} objfileentry_t; - - -// Central registry for resolving function addresses to `jl_method_instance_t`s and -// originating `ObjectFile`s (for the DWARF debug info). -// -// A global singleton instance is notified by the JIT whenever a new object is emitted, -// and later queried by the various function info APIs. We also use the chance to handle -// some platform-specific unwind info registration (which is unrelated to the query -// functionality). -class JITDebugInfoRegistry -{ -public: - template - struct Locked { - - template - struct Lock { - std::unique_lock lock; - CResourceT &resource; - - Lock(std::mutex &mutex, CResourceT &resource) : lock(mutex), resource(resource) {} - - CResourceT &operator*() { - return resource; - } - - const CResourceT &operator*() const { - return resource; - } - - CResourceT *operator->() { - return &**this; - } - - const CResourceT *operator->() const { - return &**this; - } - - operator const CResourceT &() const { - return resource; - } - }; - private: - - mutable std::mutex mutex; - ResourceT resource; - public: - Locked(ResourceT resource = ResourceT()) : mutex(), resource(std::move(resource)) {} - - Lock operator*() { - return Lock(mutex, resource); - } - - Lock operator*() const { - return Lock(mutex, resource); - } - }; - - template - struct jl_pthread_key_t { - static_assert(std::is_trivially_default_constructible::value, "Invalid datatype for pthread key!"); - static_assert(std::is_trivially_destructible::value, "Expected datatype to be trivially destructible!"); - static_assert(sizeof(datatype) == sizeof(void*), "Expected datatype to be like a void*!"); - pthread_key_t key; - - void init() { - if (pthread_key_create(&key, NULL)) - jl_error("fatal: pthread_key_create failed"); - } - - operator datatype() { - return reinterpret_cast(pthread_getspecific(key)); - } - - jl_pthread_key_t &operator=(datatype val) { - pthread_setspecific(key, reinterpret_cast(val)); - return *this; - } - - void destroy() { - pthread_key_delete(key); - } - }; - - struct sysimg_info_t { - uint64_t jl_sysimage_base; - jl_sysimg_fptrs_t sysimg_fptrs; - jl_method_instance_t **sysimg_fvars_linfo; - size_t sysimg_fvars_n; - }; - - struct libc_frames_t { -#if defined(_OS_DARWIN_) && defined(LLVM_SHLIB) - std::atomic libc_register_frame_{nullptr}; - std::atomic libc_deregister_frame_{nullptr}; - - void libc_register_frame(const char *Entry); - - void libc_deregister_frame(const char *Entry); -#endif - }; -private: - - struct ObjectInfo { - const object::ObjectFile *object; - size_t SectionSize; - ptrdiff_t slide; - object::SectionRef Section; - DIContext *context; - }; - - template - using rev_map = std::map>; - - rev_map objectmap; - rev_map> linfomap; - - // Maintain a mapping of unrealized function names -> linfo objects - // so that when we see it get emitted, we can add a link back to the linfo - // that it came from (providing name, type signature, file info, etc.) - Locked> codeinst_in_flight; - - Locked sysimg_info; - - Locked> objfilemap; - - static std::string mangle(StringRef Name, const DataLayout &DL); - -public: - - // Any function that acquires this lock must be either a unmanaged thread - // or in the GC safe region and must NOT allocate anything through the GC - // while holding this lock. - // Certain functions in this file might be called from an unmanaged thread - // and cannot have any interaction with the julia runtime - // They also may be re-entrant, and operating while threads are paused, so we - // separately manage the re-entrant count behavior for safety across platforms - // Note that we cannot safely upgrade read->write - uv_rwlock_t debuginfo_asyncsafe; - jl_pthread_key_t debuginfo_asyncsafe_held; - libc_frames_t libc_frames; - - void add_code_in_flight(StringRef name, jl_code_instance_t *codeinst, const DataLayout &DL); - jl_method_instance_t *lookupLinfo(size_t pointer) JL_NOTSAFEPOINT; - void registerJITObject(const object::ObjectFile &Object, - std::function getLoadAddress, - std::function lookupWriteAddress); - auto& getObjectMap() JL_NOTSAFEPOINT; - void set_sysimg_info(sysimg_info_t info); - auto get_sysimg_info() const; - auto get_objfile_map(); - void init(); -}; +#include "debug-registry.h" struct debug_link_info { StringRef filename; @@ -461,7 +303,8 @@ void JITDebugInfoRegistry::registerJITObject(const object::ObjectFile &Object, } //Protected by debuginfo_asyncsafe -auto& JITDebugInfoRegistry::getObjectMap() JL_NOTSAFEPOINT +JITDebugInfoRegistry::objectmap_t & +JITDebugInfoRegistry::getObjectMap() JL_NOTSAFEPOINT { return objectmap; } @@ -470,11 +313,13 @@ void JITDebugInfoRegistry::set_sysimg_info(sysimg_info_t info) { (**this->sysimg_info) = info; } -auto JITDebugInfoRegistry::get_sysimg_info() const { +JITDebugInfoRegistry::Locked::ConstLockT +JITDebugInfoRegistry::get_sysimg_info() const { return *this->sysimg_info; } -auto JITDebugInfoRegistry::get_objfile_map() { +JITDebugInfoRegistry::Locked::LockT +JITDebugInfoRegistry::get_objfile_map() { return *this->objfilemap; } diff --git a/src/processor.h b/src/processor.h index 1d385cfc80b98..ff39465364bb5 100644 --- a/src/processor.h +++ b/src/processor.h @@ -1,5 +1,8 @@ // This file is a part of Julia. License is MIT: https://julialang.org/license +#ifndef JL_PROCESSOR_H +#define JL_PROCESSOR_H + #include "support/dtypes.h" #include "julia.h" @@ -215,3 +218,5 @@ extern "C" JL_DLLEXPORT std::vector jl_get_llvm_clone_targets( std::string jl_get_cpu_name_llvm(void); std::string jl_get_cpu_features_llvm(void); #endif + +#endif \ No newline at end of file From aa898e5c115934c293436fea4f9c4e0cec64fab5 Mon Sep 17 00:00:00 2001 From: Prem Chintalapudi Date: Sun, 17 Apr 2022 22:08:48 -0400 Subject: [PATCH 11/21] Add debug info to the JIT --- src/debug-registry.h | 4 ++- src/debuginfo.cpp | 68 +++++++++++++++++++++----------------------- src/jitlayers.cpp | 8 ++++++ src/jitlayers.h | 5 ++++ 4 files changed, 49 insertions(+), 36 deletions(-) diff --git a/src/debug-registry.h b/src/debug-registry.h index d4b0c8edb2d77..8b192a4a7d5de 100644 --- a/src/debug-registry.h +++ b/src/debug-registry.h @@ -172,4 +172,6 @@ class JITDebugInfoRegistry Locked::ConstLockT get_sysimg_info() const; Locked::LockT get_objfile_map(); void init(); -}; \ No newline at end of file +}; + +JITDebugInfoRegistry &getJITDebugRegistry(); diff --git a/src/debuginfo.cpp b/src/debuginfo.cpp index 42c78520772ea..1fdeb710458a5 100644 --- a/src/debuginfo.cpp +++ b/src/debuginfo.cpp @@ -334,28 +334,26 @@ struct unw_table_entry int32_t fde_offset; }; -static JITDebugInfoRegistry jl_jit_debug_info; - void jl_init_debuginfo() { - jl_jit_debug_info.init(); + getJITDebugRegistry().init(); } extern "C" JL_DLLEXPORT void jl_lock_profile_impl(void) JL_NOTSAFEPOINT { - uintptr_t held = jl_jit_debug_info.debuginfo_asyncsafe_held; + uintptr_t held = getJITDebugRegistry().debuginfo_asyncsafe_held; if (held++ == 0) - uv_rwlock_rdlock(&jl_jit_debug_info.debuginfo_asyncsafe); - jl_jit_debug_info.debuginfo_asyncsafe_held = held; + uv_rwlock_rdlock(&getJITDebugRegistry().debuginfo_asyncsafe); + getJITDebugRegistry().debuginfo_asyncsafe_held = held; } extern "C" JL_DLLEXPORT void jl_unlock_profile_impl(void) JL_NOTSAFEPOINT { - uintptr_t held = jl_jit_debug_info.debuginfo_asyncsafe_held; + uintptr_t held = getJITDebugRegistry().debuginfo_asyncsafe_held; assert(held); if (--held == 0) - uv_rwlock_rdunlock(&jl_jit_debug_info.debuginfo_asyncsafe); - jl_jit_debug_info.debuginfo_asyncsafe_held = held; + uv_rwlock_rdunlock(&getJITDebugRegistry().debuginfo_asyncsafe); + getJITDebugRegistry().debuginfo_asyncsafe_held = held; } // some actions aren't signal (especially profiler) safe so we acquire a lock @@ -363,8 +361,8 @@ extern "C" JL_DLLEXPORT void jl_unlock_profile_impl(void) JL_NOTSAFEPOINT template static void jl_profile_atomic(T f) { - assert(0 == jl_jit_debug_info.debuginfo_asyncsafe_held); - uv_rwlock_wrlock(&jl_jit_debug_info.debuginfo_asyncsafe); + assert(0 == getJITDebugRegistry().debuginfo_asyncsafe_held); + uv_rwlock_wrlock(&getJITDebugRegistry().debuginfo_asyncsafe); #ifndef _OS_WINDOWS_ sigset_t sset; sigset_t oset; @@ -375,14 +373,14 @@ static void jl_profile_atomic(T f) #ifndef _OS_WINDOWS_ pthread_sigmask(SIG_SETMASK, &oset, NULL); #endif - uv_rwlock_wrunlock(&jl_jit_debug_info.debuginfo_asyncsafe); + uv_rwlock_wrunlock(&getJITDebugRegistry().debuginfo_asyncsafe); } // --- storing and accessing source location metadata --- void jl_add_code_in_flight(StringRef name, jl_code_instance_t *codeinst, const DataLayout &DL) { - jl_jit_debug_info.add_code_in_flight(name, codeinst, DL); + getJITDebugRegistry().add_code_in_flight(name, codeinst, DL); } @@ -444,7 +442,7 @@ void jl_register_jit_object(const object::ObjectFile &Object, std::function getLoadAddress, std::function lookupWriteAddress) { - jl_jit_debug_info.registerJITObject(Object, getLoadAddress, lookupWriteAddress); + getJITDebugRegistry().registerJITObject(Object, getLoadAddress, lookupWriteAddress); } // TODO: convert the safe names from aotcomile.cpp:makeSafeName back into symbols @@ -514,10 +512,10 @@ static int lookup_pointer( // DWARFContext/DWARFUnit update some internal tables during these queries, so // a lock is needed. - assert(0 == jl_jit_debug_info.debuginfo_asyncsafe_held); - uv_rwlock_wrlock(&jl_jit_debug_info.debuginfo_asyncsafe); + assert(0 == getJITDebugRegistry().debuginfo_asyncsafe_held); + uv_rwlock_wrlock(&getJITDebugRegistry().debuginfo_asyncsafe); auto inlineInfo = context->getInliningInfoForAddress(makeAddress(Section, pointer + slide), infoSpec); - uv_rwlock_wrunlock(&jl_jit_debug_info.debuginfo_asyncsafe); + uv_rwlock_wrunlock(&getJITDebugRegistry().debuginfo_asyncsafe); int fromC = (*frames)[0].fromC; int n_frames = inlineInfo.getNumberOfFrames(); @@ -540,9 +538,9 @@ static int lookup_pointer( info = inlineInfo.getFrame(i); } else { - uv_rwlock_wrlock(&jl_jit_debug_info.debuginfo_asyncsafe); + uv_rwlock_wrlock(&getJITDebugRegistry().debuginfo_asyncsafe); info = context->getLineInfoForAddress(makeAddress(Section, pointer + slide), infoSpec); - uv_rwlock_wrunlock(&jl_jit_debug_info.debuginfo_asyncsafe); + uv_rwlock_wrunlock(&getJITDebugRegistry().debuginfo_asyncsafe); } jl_frame_t *frame = &(*frames)[i]; @@ -712,7 +710,7 @@ extern "C" JL_DLLEXPORT void jl_register_fptrs_impl(uint64_t sysimage_base, const jl_sysimg_fptrs_t *fptrs, jl_method_instance_t **linfos, size_t n) { - jl_jit_debug_info.set_sysimg_info({(uintptr_t) sysimage_base, *fptrs, linfos, n}); + getJITDebugRegistry().set_sysimg_info({(uintptr_t) sysimage_base, *fptrs, linfos, n}); } template @@ -727,7 +725,7 @@ static void get_function_name_and_base(llvm::object::SectionRef Section, size_t void **saddr, char **name, bool untrusted_dladdr) JL_NOTSAFEPOINT { // Assume we only need base address for sysimg for now - if (!insysimage || !jl_jit_debug_info.get_sysimg_info()->sysimg_fptrs.base) + if (!insysimage || !getJITDebugRegistry().get_sysimg_info()->sysimg_fptrs.base) saddr = nullptr; bool needs_saddr = saddr && (!*saddr || untrusted_dladdr); bool needs_name = name && (!*name || untrusted_dladdr); @@ -843,7 +841,7 @@ static objfileentry_t find_object_file(uint64_t fbase, StringRef fname) JL_NOTSA // GOAL: Read debuginfo from file objfileentry_t entry{nullptr, nullptr, 0}; { - auto success = jl_jit_debug_info.get_objfile_map()->emplace(fbase, entry); + auto success = getJITDebugRegistry().get_objfile_map()->emplace(fbase, entry); if (!success.second) // Return cached value return success.first->second; @@ -1020,7 +1018,7 @@ static objfileentry_t find_object_file(uint64_t fbase, StringRef fname) JL_NOTSA entry = {debugobj, context, slide}; // update cache { - (*jl_jit_debug_info.get_objfile_map())[fbase] = entry; + (*getJITDebugRegistry().get_objfile_map())[fbase] = entry; } } else { @@ -1079,7 +1077,7 @@ bool jl_dylib_DI_for_fptr(size_t pointer, object::SectionRef *Section, int64_t * if (fname.empty()) // empirically, LoadedImageName might be missing fname = ModuleInfo.ImageName; DWORD64 fbase = ModuleInfo.BaseOfImage; - bool insysimage = (fbase == jl_jit_debug_info.get_sysimg_info()->jl_sysimage_base); + bool insysimage = (fbase == getJITDebugRegistry().get_sysimg_info()->jl_sysimage_base); if (isSysImg) *isSysImg = insysimage; if (onlySysImg && !insysimage) @@ -1119,7 +1117,7 @@ bool jl_dylib_DI_for_fptr(size_t pointer, object::SectionRef *Section, int64_t * fbase = (uintptr_t)dlinfo.dli_fbase; #endif StringRef fname; - bool insysimage = (fbase == jl_jit_debug_info.get_sysimg_info()->jl_sysimage_base); + bool insysimage = (fbase == getJITDebugRegistry().get_sysimg_info()->jl_sysimage_base); if (saddr && !(insysimage && untrusted_dladdr)) *saddr = dlinfo.dli_saddr; if (isSysImg) @@ -1176,7 +1174,7 @@ static int jl_getDylibFunctionInfo(jl_frame_t **frames, size_t pointer, int skip } frame0->fromC = !isSysImg; { - auto sysimg_locked = jl_jit_debug_info.get_sysimg_info(); + auto sysimg_locked = getJITDebugRegistry().get_sysimg_info(); if (isSysImg && sysimg_locked->sysimg_fptrs.base && saddr) { intptr_t diff = (uintptr_t)saddr - (uintptr_t)sysimg_locked->sysimg_fptrs.base; for (size_t i = 0; i < sysimg_locked->sysimg_fptrs.nclones; i++) { @@ -1202,12 +1200,12 @@ int jl_DI_for_fptr(uint64_t fptr, uint64_t *symsize, int64_t *slide, object::SectionRef *Section, llvm::DIContext **context) JL_NOTSAFEPOINT { int found = 0; - assert(0 == jl_jit_debug_info.debuginfo_asyncsafe_held); - uv_rwlock_wrlock(&jl_jit_debug_info.debuginfo_asyncsafe); + assert(0 == getJITDebugRegistry().debuginfo_asyncsafe_held); + uv_rwlock_wrlock(&getJITDebugRegistry().debuginfo_asyncsafe); if (symsize) *symsize = 0; - auto &objmap = jl_jit_debug_info.getObjectMap(); + auto &objmap = getJITDebugRegistry().getObjectMap(); auto fit = objmap.lower_bound(fptr); if (fit != objmap.end() && fptr < fit->first + fit->second.SectionSize) { *slide = fit->second.slide; @@ -1219,7 +1217,7 @@ int jl_DI_for_fptr(uint64_t fptr, uint64_t *symsize, int64_t *slide, } found = 1; } - uv_rwlock_wrunlock(&jl_jit_debug_info.debuginfo_asyncsafe); + uv_rwlock_wrunlock(&getJITDebugRegistry().debuginfo_asyncsafe); return found; } @@ -1238,7 +1236,7 @@ extern "C" JL_DLLEXPORT int jl_getFunctionInfo_impl(jl_frame_t **frames_out, siz int64_t slide; uint64_t symsize; if (jl_DI_for_fptr(pointer, &symsize, &slide, &Section, &context)) { - frames[0].linfo = jl_jit_debug_info.lookupLinfo(pointer); + frames[0].linfo = getJITDebugRegistry().lookupLinfo(pointer); int nf = lookup_pointer(Section, context, frames_out, pointer, slide, true, noInline); return nf; } @@ -1247,7 +1245,7 @@ extern "C" JL_DLLEXPORT int jl_getFunctionInfo_impl(jl_frame_t **frames_out, siz extern "C" jl_method_instance_t *jl_gdblookuplinfo(void *p) JL_NOTSAFEPOINT { - return jl_jit_debug_info.lookupLinfo((size_t)p); + return getJITDebugRegistry().lookupLinfo((size_t)p); } #if defined(_OS_DARWIN_) && defined(LLVM_SHLIB) @@ -1266,14 +1264,14 @@ void register_eh_frames(uint8_t *Addr, size_t Size) // On OS X OS X __register_frame takes a single FDE as an argument. // See http://lists.cs.uiuc.edu/pipermail/llvmdev/2013-April/061768.html processFDEs((char*)Addr, Size, [](const char *Entry) { - jl_jit_debug_info.libc_frames.libc_register_frame(Entry); + getJITDebugRegistry().libc_frames.libc_register_frame(Entry); }); } void deregister_eh_frames(uint8_t *Addr, size_t Size) { processFDEs((char*)Addr, Size, [](const char *Entry) { - jl_jit_debug_info.libc_frames.libc_deregister_frame(Entry); + getJITDebugRegistry().libc_frames.libc_deregister_frame(Entry); }); } @@ -1619,7 +1617,7 @@ uint64_t jl_getUnwindInfo_impl(uint64_t dwAddr) { // Might be called from unmanaged thread jl_lock_profile_impl(); - auto &objmap = jl_jit_debug_info.getObjectMap(); + 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) { diff --git a/src/jitlayers.cpp b/src/jitlayers.cpp index 22b54fc5291e0..ba4f57b5b362c 100644 --- a/src/jitlayers.cpp +++ b/src/jitlayers.cpp @@ -1398,6 +1398,10 @@ void JuliaOJIT::shareStrings(Module &M) GV->eraseFromParent(); } +JITDebugInfoRegistry &JuliaOJIT::getDebugInfoRegistry() { + return DebugRegistry; +} + static void jl_decorate_module(Module &M) { #if defined(_CPU_X86_64_) && defined(_OS_WINDOWS_) // Add special values used by debuginfo to build the UnwindData table registration for Win64 @@ -1503,3 +1507,7 @@ size_t jl_jit_total_bytes_impl(void) { return jl_ExecutionEngine->getTotalBytes(); } + +JITDebugInfoRegistry &getJITDebugRegistry() { + return jl_ExecutionEngine->getDebugInfoRegistry(); +} diff --git a/src/jitlayers.h b/src/jitlayers.h index d4530de41e45d..b046140554fa1 100644 --- a/src/jitlayers.h +++ b/src/jitlayers.h @@ -13,6 +13,7 @@ #include #include "julia_assert.h" +#include "debug-registry.h" // As of LLVM 13, there are two runtime JIT linker implementations, the older // RuntimeDyld (used via orc::RTDyldObjectLinkingLayer) and the newer JITLink @@ -334,6 +335,8 @@ class JuliaOJIT { TargetMachine &getTargetMachine(); const Triple& getTargetTriple() const; size_t getTotalBytes() const; + + JITDebugInfoRegistry &getDebugInfoRegistry(); private: std::string getMangledName(StringRef Name); std::string getMangledName(const GlobalValue *GV); @@ -346,6 +349,8 @@ class JuliaOJIT { orc::JITDylib &GlobalJD; orc::JITDylib &JD; + JITDebugInfoRegistry DebugRegistry; + ResourcePool ContextPool; #ifndef JL_USE_JITLINK From d326db89e00a8d7a53b9ef4c3e981e35fe35115a Mon Sep 17 00:00:00 2001 From: Prem Chintalapudi Date: Sun, 17 Apr 2022 22:33:57 -0400 Subject: [PATCH 12/21] Fix build --- src/codegen.cpp | 3 -- src/debug-registry.h | 29 ++++++++++--------- src/debuginfo.cpp | 67 +++++++++++++++++++++----------------------- 3 files changed, 47 insertions(+), 52 deletions(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index 218c58c081f23..b4194945e33cc 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -8328,14 +8328,11 @@ char jl_using_oprofile_jitevents = 0; // Non-zero if running under OProfile char jl_using_perf_jitevents = 0; #endif -void jl_init_debuginfo(void); - extern "C" void jl_init_llvm(void) { jl_page_size = jl_getpagesize(); jl_default_debug_info_kind = (int) DICompileUnit::DebugEmissionKind::FullDebug; jl_default_cgparams.generic_context = jl_nothing; - jl_init_debuginfo(); InitializeNativeTarget(); InitializeNativeTargetAsmPrinter(); diff --git a/src/debug-registry.h b/src/debug-registry.h index 8b192a4a7d5de..482a34793c729 100644 --- a/src/debug-registry.h +++ b/src/debug-registry.h @@ -121,11 +121,11 @@ class JITDebugInfoRegistry private: struct ObjectInfo { - const llvm::object::ObjectFile *object; - size_t SectionSize; - ptrdiff_t slide; - llvm::object::SectionRef Section; - llvm::DIContext *context; + const llvm::object::ObjectFile *object = nullptr; + size_t SectionSize = 0; + ptrdiff_t slide = 0; + llvm::object::SectionRef Section{}; + llvm::DIContext *context = nullptr; }; template @@ -134,22 +134,24 @@ class JITDebugInfoRegistry typedef rev_map objectmap_t; typedef rev_map objfilemap_t; - objectmap_t objectmap; - rev_map> linfomap; + objectmap_t objectmap{}; + rev_map> linfomap{}; // Maintain a mapping of unrealized function names -> linfo objects // so that when we see it get emitted, we can add a link back to the linfo // that it came from (providing name, type signature, file info, etc.) - Locked> codeinst_in_flight; + Locked> codeinst_in_flight{}; - Locked sysimg_info; + Locked sysimg_info{}; - Locked objfilemap; + Locked objfilemap{}; static std::string mangle(llvm::StringRef Name, const llvm::DataLayout &DL); public: + JITDebugInfoRegistry(); + // Any function that acquires this lock must be either a unmanaged thread // or in the GC safe region and must NOT allocate anything through the GC // while holding this lock. @@ -158,9 +160,9 @@ class JITDebugInfoRegistry // They also may be re-entrant, and operating while threads are paused, so we // separately manage the re-entrant count behavior for safety across platforms // Note that we cannot safely upgrade read->write - uv_rwlock_t debuginfo_asyncsafe; - jl_pthread_key_t debuginfo_asyncsafe_held; - libc_frames_t libc_frames; + uv_rwlock_t debuginfo_asyncsafe{}; + jl_pthread_key_t debuginfo_asyncsafe_held{}; + libc_frames_t libc_frames{}; void add_code_in_flight(llvm::StringRef name, jl_code_instance_t *codeinst, const llvm::DataLayout &DL); jl_method_instance_t *lookupLinfo(size_t pointer) JL_NOTSAFEPOINT; @@ -171,7 +173,6 @@ class JITDebugInfoRegistry void set_sysimg_info(sysimg_info_t info); Locked::ConstLockT get_sysimg_info() const; Locked::LockT get_objfile_map(); - void init(); }; JITDebugInfoRegistry &getJITDebugRegistry(); diff --git a/src/debuginfo.cpp b/src/debuginfo.cpp index 1fdeb710458a5..ea11ced7b9f6a 100644 --- a/src/debuginfo.cpp +++ b/src/debuginfo.cpp @@ -81,35 +81,6 @@ static void processFDEs(const char *EHFrameAddr, size_t EHFrameSize, callback f) } #endif -#if defined(_OS_DARWIN_) && defined(LLVM_SHLIB) - -void JITDebugInfoRegistry::libc_frames_t::libc_register_frame(const char *Entry) { - auto libc_register_frame_ = jl_atomic_load_relaxed(&this->libc_register_frame_); - if (!libc_register_frame_) { - libc_register_frame_ = (void(*)(void*))dlsym(RTLD_NEXT, "__register_frame"); - jl_atomic_store_relaxed(&this->libc_register_frame_, libc_register_frame_); - } - assert(libc_register_frame_); - jl_profile_atomic([&]() { - libc_register_frame_(const_cast(Entry)); - __register_frame(const_cast(Entry)); - }); -} - -void JITDebugInfoRegistry::libc_frames_t::libc_deregister_frame(const char *Entry) { - auto libc_deregister_frame_ = jl_atomic_load_relaxed(&this->libc_deregister_frame_); - if (!libc_deregister_frame_) { - libc_deregister_frame_ = (void(*)(void*))dlsym(RTLD_NEXT, "__deregister_frame"); - jl_atomic_store_relaxed(&this->libc_deregister_frame_, libc_deregister_frame_); - } - assert(libc_deregister_frame_); - jl_profile_atomic([&]() { - libc_deregister_frame_(const_cast(Entry)); - __deregister_frame(const_cast(Entry)); - }); -} -#endif - std::string JITDebugInfoRegistry::mangle(StringRef Name, const DataLayout &DL) { std::string MangledName; @@ -323,7 +294,7 @@ JITDebugInfoRegistry::get_objfile_map() { return *this->objfilemap; } -void JITDebugInfoRegistry::init() { +JITDebugInfoRegistry::JITDebugInfoRegistry() { uv_rwlock_init(&debuginfo_asyncsafe); debuginfo_asyncsafe_held.init(); } @@ -334,11 +305,6 @@ struct unw_table_entry int32_t fde_offset; }; -void jl_init_debuginfo() -{ - getJITDebugRegistry().init(); -} - extern "C" JL_DLLEXPORT void jl_lock_profile_impl(void) JL_NOTSAFEPOINT { uintptr_t held = getJITDebugRegistry().debuginfo_asyncsafe_held; @@ -585,6 +551,37 @@ static int lookup_pointer( #include #endif + + +#if defined(_OS_DARWIN_) && defined(LLVM_SHLIB) + +void JITDebugInfoRegistry::libc_frames_t::libc_register_frame(const char *Entry) { + auto libc_register_frame_ = jl_atomic_load_relaxed(&this->libc_register_frame_); + if (!libc_register_frame_) { + libc_register_frame_ = (void(*)(void*))dlsym(RTLD_NEXT, "__register_frame"); + jl_atomic_store_relaxed(&this->libc_register_frame_, libc_register_frame_); + } + assert(libc_register_frame_); + jl_profile_atomic([&]() { + libc_register_frame_(const_cast(Entry)); + __register_frame(const_cast(Entry)); + }); +} + +void JITDebugInfoRegistry::libc_frames_t::libc_deregister_frame(const char *Entry) { + auto libc_deregister_frame_ = jl_atomic_load_relaxed(&this->libc_deregister_frame_); + if (!libc_deregister_frame_) { + libc_deregister_frame_ = (void(*)(void*))dlsym(RTLD_NEXT, "__deregister_frame"); + jl_atomic_store_relaxed(&this->libc_deregister_frame_, libc_deregister_frame_); + } + assert(libc_deregister_frame_); + jl_profile_atomic([&]() { + libc_deregister_frame_(const_cast(Entry)); + __deregister_frame(const_cast(Entry)); + }); +} +#endif + static bool getObjUUID(llvm::object::MachOObjectFile *obj, uint8_t uuid[16]) JL_NOTSAFEPOINT { for (auto Load : obj->load_commands()) From 07eb7bfb364f8889d28b64137e3a5bb8103746d2 Mon Sep 17 00:00:00 2001 From: Prem Chintalapudi Date: Sun, 17 Apr 2022 22:37:20 -0400 Subject: [PATCH 13/21] Fix whitespace --- src/debug-registry.h | 2 +- src/processor.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/debug-registry.h b/src/debug-registry.h index 482a34793c729..f6290eb673d6f 100644 --- a/src/debug-registry.h +++ b/src/debug-registry.h @@ -28,7 +28,7 @@ class JITDebugInfoRegistry public: template struct Locked { - + template struct Lock { std::unique_lock lock; diff --git a/src/processor.h b/src/processor.h index ff39465364bb5..f3b571cf9b937 100644 --- a/src/processor.h +++ b/src/processor.h @@ -219,4 +219,4 @@ std::string jl_get_cpu_name_llvm(void); std::string jl_get_cpu_features_llvm(void); #endif -#endif \ No newline at end of file +#endif From 36cd1fee1306930bb1e6167e970653fcc1560a80 Mon Sep 17 00:00:00 2001 From: Prem Chintalapudi Date: Sun, 17 Apr 2022 23:03:37 -0400 Subject: [PATCH 14/21] Fix windows and analyzegc failures --- src/debug-registry.h | 2 +- src/debuginfo.cpp | 262 +++++++++++++++++++++---------------------- src/jitlayers.cpp | 2 +- 3 files changed, 133 insertions(+), 133 deletions(-) diff --git a/src/debug-registry.h b/src/debug-registry.h index f6290eb673d6f..7c139c4e6dd71 100644 --- a/src/debug-registry.h +++ b/src/debug-registry.h @@ -175,4 +175,4 @@ class JITDebugInfoRegistry Locked::LockT get_objfile_map(); }; -JITDebugInfoRegistry &getJITDebugRegistry(); +JITDebugInfoRegistry &getJITDebugRegistry() JL_NOTSAFEPOINT; diff --git a/src/debuginfo.cpp b/src/debuginfo.cpp index ea11ced7b9f6a..389537a245b8a 100644 --- a/src/debuginfo.cpp +++ b/src/debuginfo.cpp @@ -106,6 +106,137 @@ jl_method_instance_t *JITDebugInfoRegistry::lookupLinfo(size_t pointer) JL_NOTSA return linfo; } +//Protected by debuginfo_asyncsafe +JITDebugInfoRegistry::objectmap_t & +JITDebugInfoRegistry::getObjectMap() JL_NOTSAFEPOINT +{ + return objectmap; +} + +void JITDebugInfoRegistry::set_sysimg_info(sysimg_info_t info) { + (**this->sysimg_info) = info; +} + +JITDebugInfoRegistry::Locked::ConstLockT +JITDebugInfoRegistry::get_sysimg_info() const { + return *this->sysimg_info; +} + +JITDebugInfoRegistry::Locked::LockT +JITDebugInfoRegistry::get_objfile_map() { + return *this->objfilemap; +} + +JITDebugInfoRegistry::JITDebugInfoRegistry() { + uv_rwlock_init(&debuginfo_asyncsafe); + debuginfo_asyncsafe_held.init(); +} + +struct unw_table_entry +{ + int32_t start_ip_offset; + int32_t fde_offset; +}; + +extern "C" JL_DLLEXPORT void jl_lock_profile_impl(void) JL_NOTSAFEPOINT +{ + uintptr_t held = getJITDebugRegistry().debuginfo_asyncsafe_held; + if (held++ == 0) + uv_rwlock_rdlock(&getJITDebugRegistry().debuginfo_asyncsafe); + getJITDebugRegistry().debuginfo_asyncsafe_held = held; +} + +extern "C" JL_DLLEXPORT void jl_unlock_profile_impl(void) JL_NOTSAFEPOINT +{ + uintptr_t held = getJITDebugRegistry().debuginfo_asyncsafe_held; + assert(held); + if (--held == 0) + uv_rwlock_rdunlock(&getJITDebugRegistry().debuginfo_asyncsafe); + getJITDebugRegistry().debuginfo_asyncsafe_held = held; +} + +// some actions aren't signal (especially profiler) safe so we acquire a lock +// around them to establish a mutual exclusion with unwinding from a signal +template +static void jl_profile_atomic(T f) +{ + assert(0 == getJITDebugRegistry().debuginfo_asyncsafe_held); + uv_rwlock_wrlock(&getJITDebugRegistry().debuginfo_asyncsafe); +#ifndef _OS_WINDOWS_ + sigset_t sset; + sigset_t oset; + sigfillset(&sset); + pthread_sigmask(SIG_BLOCK, &sset, &oset); +#endif + f(); +#ifndef _OS_WINDOWS_ + pthread_sigmask(SIG_SETMASK, &oset, NULL); +#endif + uv_rwlock_wrunlock(&getJITDebugRegistry().debuginfo_asyncsafe); +} + + +// --- storing and accessing source location metadata --- +void jl_add_code_in_flight(StringRef name, jl_code_instance_t *codeinst, const DataLayout &DL) +{ + getJITDebugRegistry().add_code_in_flight(name, codeinst, DL); +} + + +#if defined(_OS_WINDOWS_) +static void create_PRUNTIME_FUNCTION(uint8_t *Code, size_t Size, StringRef fnname, + uint8_t *Section, size_t Allocated, uint8_t *UnwindData) +{ + // GC safe + DWORD mod_size = 0; +#if defined(_CPU_X86_64_) + PRUNTIME_FUNCTION tbl = (PRUNTIME_FUNCTION)malloc_s(sizeof(RUNTIME_FUNCTION)); + tbl->BeginAddress = (DWORD)(Code - Section); + tbl->EndAddress = (DWORD)(Code - Section + Size); + tbl->UnwindData = (DWORD)(UnwindData - Section); + assert(Code >= Section && Code + Size <= Section + Allocated); + assert(UnwindData >= Section && UnwindData <= Section + Allocated); +#else // defined(_CPU_X86_64_) + Section += (uintptr_t)Code; + mod_size = Size; +#endif + if (0) { + uv_mutex_lock(&jl_in_stackwalk); + if (mod_size && !SymLoadModuleEx(GetCurrentProcess(), NULL, NULL, NULL, (DWORD64)Section, mod_size, NULL, SLMFLAG_VIRTUAL)) { + static int warned = 0; + if (!warned) { + jl_printf(JL_STDERR, "WARNING: failed to insert module info for backtrace: %lu\n", GetLastError()); + warned = 1; + } + } + else { + size_t len = fnname.size()+1; + if (len > MAX_SYM_NAME) + len = MAX_SYM_NAME; + char *name = (char*)alloca(len); + memcpy(name, fnname.data(), len-1); + name[len-1] = 0; + if (!SymAddSymbol(GetCurrentProcess(), (ULONG64)Section, name, + (DWORD64)Code, (DWORD)Size, 0)) { + jl_printf(JL_STDERR, "WARNING: failed to insert function name %s into debug info: %lu\n", name, GetLastError()); + } + } + uv_mutex_unlock(&jl_in_stackwalk); + } +#if defined(_CPU_X86_64_) + jl_profile_atomic([&]() { + if (!RtlAddFunctionTable(tbl, 1, (DWORD64)Section)) { + static int warned = 0; + if (!warned) { + jl_printf(JL_STDERR, "WARNING: failed to insert function stack unwind info: %lu\n", GetLastError()); + warned = 1; + } + } + }); +#endif +} +#endif + void JITDebugInfoRegistry::registerJITObject(const object::ObjectFile &Object, std::function getLoadAddress, std::function lookupWriteAddress) @@ -273,137 +404,6 @@ void JITDebugInfoRegistry::registerJITObject(const object::ObjectFile &Object, } } -//Protected by debuginfo_asyncsafe -JITDebugInfoRegistry::objectmap_t & -JITDebugInfoRegistry::getObjectMap() JL_NOTSAFEPOINT -{ - return objectmap; -} - -void JITDebugInfoRegistry::set_sysimg_info(sysimg_info_t info) { - (**this->sysimg_info) = info; -} - -JITDebugInfoRegistry::Locked::ConstLockT -JITDebugInfoRegistry::get_sysimg_info() const { - return *this->sysimg_info; -} - -JITDebugInfoRegistry::Locked::LockT -JITDebugInfoRegistry::get_objfile_map() { - return *this->objfilemap; -} - -JITDebugInfoRegistry::JITDebugInfoRegistry() { - uv_rwlock_init(&debuginfo_asyncsafe); - debuginfo_asyncsafe_held.init(); -} - -struct unw_table_entry -{ - int32_t start_ip_offset; - int32_t fde_offset; -}; - -extern "C" JL_DLLEXPORT void jl_lock_profile_impl(void) JL_NOTSAFEPOINT -{ - uintptr_t held = getJITDebugRegistry().debuginfo_asyncsafe_held; - if (held++ == 0) - uv_rwlock_rdlock(&getJITDebugRegistry().debuginfo_asyncsafe); - getJITDebugRegistry().debuginfo_asyncsafe_held = held; -} - -extern "C" JL_DLLEXPORT void jl_unlock_profile_impl(void) JL_NOTSAFEPOINT -{ - uintptr_t held = getJITDebugRegistry().debuginfo_asyncsafe_held; - assert(held); - if (--held == 0) - uv_rwlock_rdunlock(&getJITDebugRegistry().debuginfo_asyncsafe); - getJITDebugRegistry().debuginfo_asyncsafe_held = held; -} - -// some actions aren't signal (especially profiler) safe so we acquire a lock -// around them to establish a mutual exclusion with unwinding from a signal -template -static void jl_profile_atomic(T f) -{ - assert(0 == getJITDebugRegistry().debuginfo_asyncsafe_held); - uv_rwlock_wrlock(&getJITDebugRegistry().debuginfo_asyncsafe); -#ifndef _OS_WINDOWS_ - sigset_t sset; - sigset_t oset; - sigfillset(&sset); - pthread_sigmask(SIG_BLOCK, &sset, &oset); -#endif - f(); -#ifndef _OS_WINDOWS_ - pthread_sigmask(SIG_SETMASK, &oset, NULL); -#endif - uv_rwlock_wrunlock(&getJITDebugRegistry().debuginfo_asyncsafe); -} - - -// --- storing and accessing source location metadata --- -void jl_add_code_in_flight(StringRef name, jl_code_instance_t *codeinst, const DataLayout &DL) -{ - getJITDebugRegistry().add_code_in_flight(name, codeinst, DL); -} - - -#if defined(_OS_WINDOWS_) -static void create_PRUNTIME_FUNCTION(uint8_t *Code, size_t Size, StringRef fnname, - uint8_t *Section, size_t Allocated, uint8_t *UnwindData) -{ - // GC safe - DWORD mod_size = 0; -#if defined(_CPU_X86_64_) - PRUNTIME_FUNCTION tbl = (PRUNTIME_FUNCTION)malloc_s(sizeof(RUNTIME_FUNCTION)); - tbl->BeginAddress = (DWORD)(Code - Section); - tbl->EndAddress = (DWORD)(Code - Section + Size); - tbl->UnwindData = (DWORD)(UnwindData - Section); - assert(Code >= Section && Code + Size <= Section + Allocated); - assert(UnwindData >= Section && UnwindData <= Section + Allocated); -#else // defined(_CPU_X86_64_) - Section += (uintptr_t)Code; - mod_size = Size; -#endif - if (0) { - uv_mutex_lock(&jl_in_stackwalk); - if (mod_size && !SymLoadModuleEx(GetCurrentProcess(), NULL, NULL, NULL, (DWORD64)Section, mod_size, NULL, SLMFLAG_VIRTUAL)) { - static int warned = 0; - if (!warned) { - jl_printf(JL_STDERR, "WARNING: failed to insert module info for backtrace: %lu\n", GetLastError()); - warned = 1; - } - } - else { - size_t len = fnname.size()+1; - if (len > MAX_SYM_NAME) - len = MAX_SYM_NAME; - char *name = (char*)alloca(len); - memcpy(name, fnname.data(), len-1); - name[len-1] = 0; - if (!SymAddSymbol(GetCurrentProcess(), (ULONG64)Section, name, - (DWORD64)Code, (DWORD)Size, 0)) { - jl_printf(JL_STDERR, "WARNING: failed to insert function name %s into debug info: %lu\n", name, GetLastError()); - } - } - uv_mutex_unlock(&jl_in_stackwalk); - } -#if defined(_CPU_X86_64_) - jl_profile_atomic([&]() { - if (!RtlAddFunctionTable(tbl, 1, (DWORD64)Section)) { - static int warned = 0; - if (!warned) { - jl_printf(JL_STDERR, "WARNING: failed to insert function stack unwind info: %lu\n", GetLastError()); - warned = 1; - } - } - }); -#endif -} -#endif - void jl_register_jit_object(const object::ObjectFile &Object, std::function getLoadAddress, std::function lookupWriteAddress) diff --git a/src/jitlayers.cpp b/src/jitlayers.cpp index ba4f57b5b362c..4ec05edcb8588 100644 --- a/src/jitlayers.cpp +++ b/src/jitlayers.cpp @@ -1508,6 +1508,6 @@ size_t jl_jit_total_bytes_impl(void) return jl_ExecutionEngine->getTotalBytes(); } -JITDebugInfoRegistry &getJITDebugRegistry() { +JITDebugInfoRegistry &getJITDebugRegistry() JL_NOTSAFEPOINT { return jl_ExecutionEngine->getDebugInfoRegistry(); } From 95475b8d43fdcab54add0fb45f5253297aba47b2 Mon Sep 17 00:00:00 2001 From: Prem Chintalapudi Date: Mon, 18 Apr 2022 13:15:49 -0400 Subject: [PATCH 15/21] Address review comments --- src/debuginfo.cpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/debuginfo.cpp b/src/debuginfo.cpp index 389537a245b8a..d6332dce0e9a9 100644 --- a/src/debuginfo.cpp +++ b/src/debuginfo.cpp @@ -837,12 +837,10 @@ static objfileentry_t find_object_file(uint64_t fbase, StringRef fname) JL_NOTSA // GOAL: Read debuginfo from file objfileentry_t entry{nullptr, nullptr, 0}; - { - auto success = getJITDebugRegistry().get_objfile_map()->emplace(fbase, entry); - if (!success.second) - // Return cached value - return success.first->second; - } + auto success = getJITDebugRegistry().get_objfile_map()->emplace(fbase, entry); + if (!success.second) + // Return cached value + return success.first->second; // GOAL: Assign errorobj StringRef objpath; @@ -1014,9 +1012,7 @@ static objfileentry_t find_object_file(uint64_t fbase, StringRef fname) JL_NOTSA binary.second.release(); entry = {debugobj, context, slide}; // update cache - { - (*getJITDebugRegistry().get_objfile_map())[fbase] = entry; - } + (*getJITDebugRegistry().get_objfile_map())[fbase] = entry; } else { // TODO: report the error instead of silently consuming it? From 488d69e55d532139662ae2ec994a583bd03020d8 Mon Sep 17 00:00:00 2001 From: Prem Chintalapudi Date: Mon, 18 Apr 2022 16:53:39 -0400 Subject: [PATCH 16/21] move getDebugIfoRegistry to debuginfo.cpp --- src/Makefile | 10 +++++----- src/debug-registry.h | 2 -- src/debuginfo.cpp | 6 +++++- src/jitlayers.cpp | 4 ---- 4 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/Makefile b/src/Makefile index 1bedd99052dad..e6d83b1e1f4e9 100644 --- a/src/Makefile +++ b/src/Makefile @@ -274,12 +274,12 @@ $(BUILDDIR)/julia_flisp.boot: $(addprefix $(SRCDIR)/,jlfrontend.scm flisp/aliase # additional dependency links $(BUILDDIR)/codegen-stubs.o $(BUILDDIR)/codegen-stubs.dbg.obj: $(SRCDIR)/intrinsics.h -$(BUILDDIR)/aotcompile.o $(BUILDDIR)/aotcompile.dbg.obj: $(SRCDIR)/jitlayers.h $(SRCDIR)/codegen_shared.h +$(BUILDDIR)/aotcompile.o $(BUILDDIR)/aotcompile.dbg.obj: $(SRCDIR)/jitlayers.h $(SRCDIR)/codegen_shared.h $(SRCDIR)/debug-registry.h $(BUILDDIR)/ast.o $(BUILDDIR)/ast.dbg.obj: $(BUILDDIR)/julia_flisp.boot.inc $(SRCDIR)/flisp/*.h $(BUILDDIR)/builtins.o $(BUILDDIR)/builtins.dbg.obj: $(SRCDIR)/iddict.c $(SRCDIR)/builtin_proto.h $(BUILDDIR)/codegen.o $(BUILDDIR)/codegen.dbg.obj: $(addprefix $(SRCDIR)/,\ - intrinsics.cpp jitlayers.h intrinsics.h codegen_shared.h cgutils.cpp ccall.cpp abi_*.cpp processor.h builtin_proto.h) -$(BUILDDIR)/debuginfo.o $(BUILDDIR)/debuginfo.dbg.obj: $(addprefix $(SRCDIR)/,debuginfo.h processor.h debug-registry.h) + intrinsics.cpp jitlayers.h debug-registry.h intrinsics.h codegen_shared.h cgutils.cpp ccall.cpp abi_*.cpp processor.h builtin_proto.h) +$(BUILDDIR)/debuginfo.o $(BUILDDIR)/debuginfo.dbg.obj: $(addprefix $(SRCDIR)/,debuginfo.h processor.h jitlayers.h debug-registry.h) $(BUILDDIR)/disasm.o $(BUILDDIR)/disasm.dbg.obj: $(SRCDIR)/debuginfo.h $(SRCDIR)/processor.h $(BUILDDIR)/dump.o $(BUILDDIR)/dump.dbg.obj: $(addprefix $(SRCDIR)/,common_symbols1.inc common_symbols2.inc builtin_proto.h serialize.h) $(BUILDDIR)/gc-debug.o $(BUILDDIR)/gc-debug.dbg.obj: $(SRCDIR)/gc.h @@ -287,12 +287,12 @@ $(BUILDDIR)/gc-pages.o $(BUILDDIR)/gc-pages.dbg.obj: $(SRCDIR)/gc.h $(BUILDDIR)/gc.o $(BUILDDIR)/gc.dbg.obj: $(SRCDIR)/gc.h $(SRCDIR)/gc-alloc-profiler.h $(BUILDDIR)/init.o $(BUILDDIR)/init.dbg.obj: $(SRCDIR)/builtin_proto.h $(BUILDDIR)/interpreter.o $(BUILDDIR)/interpreter.dbg.obj: $(SRCDIR)/builtin_proto.h -$(BUILDDIR)/jitlayers.o $(BUILDDIR)/jitlayers.dbg.obj: $(SRCDIR)/jitlayers.h $(SRCDIR)/codegen_shared.h +$(BUILDDIR)/jitlayers.o $(BUILDDIR)/jitlayers.dbg.obj: $(SRCDIR)/jitlayers.h $(SRCDIR)/codegen_shared.h $(SRCDIR)/debug-registry.h $(BUILDDIR)/jltypes.o $(BUILDDIR)/jltypes.dbg.obj: $(SRCDIR)/builtin_proto.h $(build_shlibdir)/libllvmcalltest.$(SHLIB_EXT): $(SRCDIR)/codegen_shared.h $(BUILDDIR)/julia_version.h $(BUILDDIR)/llvm-alloc-helpers.o $(BUILDDIR)/llvm-alloc-helpers.dbg.obj: $(SRCDIR)/codegen_shared.h $(SRCDIR)/llvm-pass-helpers.h $(SRCDIR)/llvm-alloc-helpers.h $(BUILDDIR)/llvm-alloc-opt.o $(BUILDDIR)/llvm-alloc-opt.dbg.obj: $(SRCDIR)/codegen_shared.h $(SRCDIR)/llvm-pass-helpers.h $(SRCDIR)/llvm-alloc-helpers.h -$(BUILDDIR)/llvm-cpufeatures.o $(BUILDDIR)/llvm-cpufeatures.dbg.obj: $(SRCDIR)/jitlayers.h +$(BUILDDIR)/llvm-cpufeatures.o $(BUILDDIR)/llvm-cpufeatures.dbg.obj: $(SRCDIR)/jitlayers.h $(SRCDIR)/debug-registry.h $(BUILDDIR)/llvm-final-gc-lowering.o $(BUILDDIR)/llvm-final-gc-lowering.dbg.obj: $(SRCDIR)/llvm-pass-helpers.h $(SRCDIR)/codegen_shared.h $(BUILDDIR)/llvm-gc-invariant-verifier.o $(BUILDDIR)/llvm-gc-invariant-verifier.dbg.obj: $(SRCDIR)/codegen_shared.h $(BUILDDIR)/llvm-julia-licm.o $(BUILDDIR)/llvm-julia-licm.dbg.obj: $(SRCDIR)/codegen_shared.h $(SRCDIR)/llvm-alloc-helpers.h $(SRCDIR)/llvm-pass-helpers.h diff --git a/src/debug-registry.h b/src/debug-registry.h index 7c139c4e6dd71..d0c33673304b6 100644 --- a/src/debug-registry.h +++ b/src/debug-registry.h @@ -174,5 +174,3 @@ class JITDebugInfoRegistry Locked::ConstLockT get_sysimg_info() const; Locked::LockT get_objfile_map(); }; - -JITDebugInfoRegistry &getJITDebugRegistry() JL_NOTSAFEPOINT; diff --git a/src/debuginfo.cpp b/src/debuginfo.cpp index d6332dce0e9a9..6d2dc35c5da23 100644 --- a/src/debuginfo.cpp +++ b/src/debuginfo.cpp @@ -41,7 +41,11 @@ using namespace llvm; #include #endif -#include "debug-registry.h" +#include "jitlayers.h" + +static JITDebugInfoRegistry &getJITDebugRegistry() JL_NOTSAFEPOINT { + return jl_ExecutionEngine->getDebugInfoRegistry(); +} struct debug_link_info { StringRef filename; diff --git a/src/jitlayers.cpp b/src/jitlayers.cpp index 4ec05edcb8588..870b35dad15dd 100644 --- a/src/jitlayers.cpp +++ b/src/jitlayers.cpp @@ -1507,7 +1507,3 @@ size_t jl_jit_total_bytes_impl(void) { return jl_ExecutionEngine->getTotalBytes(); } - -JITDebugInfoRegistry &getJITDebugRegistry() JL_NOTSAFEPOINT { - return jl_ExecutionEngine->getDebugInfoRegistry(); -} From 604089684b55e463175426988909ff0b6bbec01c Mon Sep 17 00:00:00 2001 From: Prem Chintalapudi Date: Mon, 18 Apr 2022 17:00:08 -0400 Subject: [PATCH 17/21] Mark getDebugInfoRegistry as not a safepoint --- src/jitlayers.cpp | 4 ---- src/jitlayers.h | 4 +++- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/jitlayers.cpp b/src/jitlayers.cpp index 870b35dad15dd..22b54fc5291e0 100644 --- a/src/jitlayers.cpp +++ b/src/jitlayers.cpp @@ -1398,10 +1398,6 @@ void JuliaOJIT::shareStrings(Module &M) GV->eraseFromParent(); } -JITDebugInfoRegistry &JuliaOJIT::getDebugInfoRegistry() { - return DebugRegistry; -} - static void jl_decorate_module(Module &M) { #if defined(_CPU_X86_64_) && defined(_OS_WINDOWS_) // Add special values used by debuginfo to build the UnwindData table registration for Win64 diff --git a/src/jitlayers.h b/src/jitlayers.h index b046140554fa1..d1a886f87d96b 100644 --- a/src/jitlayers.h +++ b/src/jitlayers.h @@ -336,7 +336,9 @@ class JuliaOJIT { const Triple& getTargetTriple() const; size_t getTotalBytes() const; - JITDebugInfoRegistry &getDebugInfoRegistry(); + JITDebugInfoRegistry &getDebugInfoRegistry() JL_NOTSAFEPOINT { + return DebugRegistry; + } private: std::string getMangledName(StringRef Name); std::string getMangledName(const GlobalValue *GV); From 6a25133c5e69540314888f3915ca435001cd4e7f Mon Sep 17 00:00:00 2001 From: Prem Chintalapudi Date: Mon, 18 Apr 2022 17:07:58 -0400 Subject: [PATCH 18/21] Mark many methods as not safepoints --- src/debug-registry.h | 36 ++++++++++++++++++------------------ src/debuginfo.cpp | 10 +++++----- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/debug-registry.h b/src/debug-registry.h index d0c33673304b6..06b32ef801c54 100644 --- a/src/debug-registry.h +++ b/src/debug-registry.h @@ -36,11 +36,11 @@ class JITDebugInfoRegistry Lock(std::mutex &mutex, CResourceT &resource) : lock(mutex), resource(resource) {} - CResourceT &operator*() { + CResourceT &operator*() JL_NOTSAFEPOINT { return resource; } - const CResourceT &operator*() const { + const CResourceT &operator*() const JL_NOTSAFEPOINT { return resource; } @@ -48,11 +48,11 @@ class JITDebugInfoRegistry return &**this; } - const CResourceT *operator->() const { + const CResourceT *operator->() const JL_NOTSAFEPOINT { return &**this; } - operator const CResourceT &() const { + operator const CResourceT &() const JL_NOTSAFEPOINT { return resource; } }; @@ -66,11 +66,11 @@ class JITDebugInfoRegistry Locked(ResourceT resource = ResourceT()) : mutex(), resource(std::move(resource)) {} - LockT operator*() { + LockT operator*() JL_NOTSAFEPOINT { return LockT(mutex, resource); } - ConstLockT operator*() const { + ConstLockT operator*() const JL_NOTSAFEPOINT { return ConstLockT(mutex, resource); } }; @@ -82,21 +82,21 @@ class JITDebugInfoRegistry static_assert(sizeof(datatype) == sizeof(void*), "Expected datatype to be like a void*!"); pthread_key_t key; - void init() { + void init() JL_NOTSAFEPOINT { if (pthread_key_create(&key, NULL)) jl_error("fatal: pthread_key_create failed"); } - operator datatype() { + operator datatype() JL_NOTSAFEPOINT { return reinterpret_cast(pthread_getspecific(key)); } - jl_pthread_key_t &operator=(datatype val) { + jl_pthread_key_t &operator=(datatype val) JL_NOTSAFEPOINT { pthread_setspecific(key, reinterpret_cast(val)); return *this; } - void destroy() { + void destroy() JL_NOTSAFEPOINT { pthread_key_delete(key); } }; @@ -113,9 +113,9 @@ class JITDebugInfoRegistry std::atomic libc_register_frame_{nullptr}; std::atomic libc_deregister_frame_{nullptr}; - void libc_register_frame(const char *Entry); + void libc_register_frame(const char *Entry) JL_NOTSAFEPOINT; - void libc_deregister_frame(const char *Entry); + void libc_deregister_frame(const char *Entry) JL_NOTSAFEPOINT; #endif }; private: @@ -146,7 +146,7 @@ class JITDebugInfoRegistry Locked objfilemap{}; - static std::string mangle(llvm::StringRef Name, const llvm::DataLayout &DL); + static std::string mangle(llvm::StringRef Name, const llvm::DataLayout &DL) JL_NOTSAFEPOINT; public: @@ -164,13 +164,13 @@ class JITDebugInfoRegistry jl_pthread_key_t debuginfo_asyncsafe_held{}; libc_frames_t libc_frames{}; - void add_code_in_flight(llvm::StringRef name, jl_code_instance_t *codeinst, const llvm::DataLayout &DL); + void add_code_in_flight(llvm::StringRef name, jl_code_instance_t *codeinst, const llvm::DataLayout &DL) JL_NOTSAFEPOINT; jl_method_instance_t *lookupLinfo(size_t pointer) JL_NOTSAFEPOINT; void registerJITObject(const llvm::object::ObjectFile &Object, std::function getLoadAddress, - std::function lookupWriteAddress); + std::function lookupWriteAddress) JL_NOTSAFEPOINT; objectmap_t& getObjectMap() JL_NOTSAFEPOINT; - void set_sysimg_info(sysimg_info_t info); - Locked::ConstLockT get_sysimg_info() const; - Locked::LockT get_objfile_map(); + void set_sysimg_info(sysimg_info_t info) JL_NOTSAFEPOINT; + Locked::ConstLockT get_sysimg_info() const JL_NOTSAFEPOINT; + Locked::LockT get_objfile_map() JL_NOTSAFEPOINT; }; diff --git a/src/debuginfo.cpp b/src/debuginfo.cpp index 6d2dc35c5da23..77b5a8fe5e0c7 100644 --- a/src/debuginfo.cpp +++ b/src/debuginfo.cpp @@ -85,7 +85,7 @@ static void processFDEs(const char *EHFrameAddr, size_t EHFrameSize, callback f) } #endif -std::string JITDebugInfoRegistry::mangle(StringRef Name, const DataLayout &DL) +std::string JITDebugInfoRegistry::mangle(StringRef Name, const DataLayout &DL) JL_NOTSAFEPOINT { std::string MangledName; { @@ -95,7 +95,7 @@ std::string JITDebugInfoRegistry::mangle(StringRef Name, const DataLayout &DL) return MangledName; } -void JITDebugInfoRegistry::add_code_in_flight(StringRef name, jl_code_instance_t *codeinst, const DataLayout &DL) { +void JITDebugInfoRegistry::add_code_in_flight(StringRef name, jl_code_instance_t *codeinst, const DataLayout &DL) JL_NOTSAFEPOINT { (**codeinst_in_flight)[mangle(name, DL)] = codeinst; } @@ -117,17 +117,17 @@ JITDebugInfoRegistry::getObjectMap() JL_NOTSAFEPOINT return objectmap; } -void JITDebugInfoRegistry::set_sysimg_info(sysimg_info_t info) { +void JITDebugInfoRegistry::set_sysimg_info(sysimg_info_t info) JL_NOTSAFEPOINT { (**this->sysimg_info) = info; } JITDebugInfoRegistry::Locked::ConstLockT -JITDebugInfoRegistry::get_sysimg_info() const { +JITDebugInfoRegistry::get_sysimg_info() const JL_NOTSAFEPOINT { return *this->sysimg_info; } JITDebugInfoRegistry::Locked::LockT -JITDebugInfoRegistry::get_objfile_map() { +JITDebugInfoRegistry::get_objfile_map() JL_NOTSAFEPOINT { return *this->objfilemap; } From 17b999edd1f6f36fe70de3f98fa228ed4bb175b7 Mon Sep 17 00:00:00 2001 From: Prem Chintalapudi Date: Mon, 18 Apr 2022 17:12:42 -0400 Subject: [PATCH 19/21] Mark constructors as not safepoints --- src/debug-registry.h | 8 ++++---- src/debuginfo.cpp | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/debug-registry.h b/src/debug-registry.h index 06b32ef801c54..9be1deee683c0 100644 --- a/src/debug-registry.h +++ b/src/debug-registry.h @@ -34,7 +34,7 @@ class JITDebugInfoRegistry std::unique_lock lock; CResourceT &resource; - Lock(std::mutex &mutex, CResourceT &resource) : lock(mutex), resource(resource) {} + Lock(std::mutex &mutex, CResourceT &resource) JL_NOTSAFEPOINT : lock(mutex), resource(resource) {} CResourceT &operator*() JL_NOTSAFEPOINT { return resource; @@ -44,7 +44,7 @@ class JITDebugInfoRegistry return resource; } - CResourceT *operator->() { + CResourceT *operator->() JL_NOTSAFEPOINT { return &**this; } @@ -64,7 +64,7 @@ class JITDebugInfoRegistry typedef Lock LockT; typedef Lock ConstLockT; - Locked(ResourceT resource = ResourceT()) : mutex(), resource(std::move(resource)) {} + Locked(ResourceT resource = ResourceT()) JL_NOTSAFEPOINT : mutex(), resource(std::move(resource)) {} LockT operator*() JL_NOTSAFEPOINT { return LockT(mutex, resource); @@ -150,7 +150,7 @@ class JITDebugInfoRegistry public: - JITDebugInfoRegistry(); + JITDebugInfoRegistry() JL_NOTSAFEPOINT; // Any function that acquires this lock must be either a unmanaged thread // or in the GC safe region and must NOT allocate anything through the GC diff --git a/src/debuginfo.cpp b/src/debuginfo.cpp index 77b5a8fe5e0c7..ec79486da55fe 100644 --- a/src/debuginfo.cpp +++ b/src/debuginfo.cpp @@ -131,7 +131,7 @@ JITDebugInfoRegistry::get_objfile_map() JL_NOTSAFEPOINT { return *this->objfilemap; } -JITDebugInfoRegistry::JITDebugInfoRegistry() { +JITDebugInfoRegistry::JITDebugInfoRegistry() JL_NOTSAFEPOINT { uv_rwlock_init(&debuginfo_asyncsafe); debuginfo_asyncsafe_held.init(); } From 70ae826c7f45264ec1b42752853c6b774948164d Mon Sep 17 00:00:00 2001 From: Prem Chintalapudi Date: Mon, 18 Apr 2022 17:17:57 -0400 Subject: [PATCH 20/21] Mark destructors as not safepoints --- src/debug-registry.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/debug-registry.h b/src/debug-registry.h index 9be1deee683c0..dd184565d9ac7 100644 --- a/src/debug-registry.h +++ b/src/debug-registry.h @@ -55,6 +55,8 @@ class JITDebugInfoRegistry operator const CResourceT &() const JL_NOTSAFEPOINT { return resource; } + + ~Lock() JL_NOTSAFEPOINT {} }; private: @@ -73,6 +75,8 @@ class JITDebugInfoRegistry ConstLockT operator*() const JL_NOTSAFEPOINT { return ConstLockT(mutex, resource); } + + ~Locked() JL_NOTSAFEPOINT {} }; template @@ -151,6 +155,7 @@ class JITDebugInfoRegistry public: JITDebugInfoRegistry() JL_NOTSAFEPOINT; + ~JITDebugInfoRegistry() JL_NOTSAFEPOINT {} // Any function that acquires this lock must be either a unmanaged thread // or in the GC safe region and must NOT allocate anything through the GC From d411d0a302da06d565ecd9eb39ef205483675980 Mon Sep 17 00:00:00 2001 From: Prem Chintalapudi Date: Mon, 18 Apr 2022 17:24:30 -0400 Subject: [PATCH 21/21] Add move constructors for user-supplied destructors --- src/debug-registry.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/debug-registry.h b/src/debug-registry.h index dd184565d9ac7..dfdb09ca84519 100644 --- a/src/debug-registry.h +++ b/src/debug-registry.h @@ -35,6 +35,8 @@ class JITDebugInfoRegistry CResourceT &resource; Lock(std::mutex &mutex, CResourceT &resource) JL_NOTSAFEPOINT : lock(mutex), resource(resource) {} + Lock(Lock &&) JL_NOTSAFEPOINT = default; + Lock &operator=(Lock &&) JL_NOTSAFEPOINT = default; CResourceT &operator*() JL_NOTSAFEPOINT { return resource; @@ -56,7 +58,7 @@ class JITDebugInfoRegistry return resource; } - ~Lock() JL_NOTSAFEPOINT {} + ~Lock() JL_NOTSAFEPOINT = default; }; private: @@ -76,7 +78,7 @@ class JITDebugInfoRegistry return ConstLockT(mutex, resource); } - ~Locked() JL_NOTSAFEPOINT {} + ~Locked() JL_NOTSAFEPOINT = default; }; template @@ -155,7 +157,7 @@ class JITDebugInfoRegistry public: JITDebugInfoRegistry() JL_NOTSAFEPOINT; - ~JITDebugInfoRegistry() JL_NOTSAFEPOINT {} + ~JITDebugInfoRegistry() JL_NOTSAFEPOINT = default; // Any function that acquires this lock must be either a unmanaged thread // or in the GC safe region and must NOT allocate anything through the GC