diff --git a/gnu/llvm/libunwind/src/AddressSpace.hpp b/gnu/llvm/libunwind/src/AddressSpace.hpp index 5551c7d4bef..ab6bec9bc3c 100644 --- a/gnu/llvm/libunwind/src/AddressSpace.hpp +++ b/gnu/llvm/libunwind/src/AddressSpace.hpp @@ -16,6 +16,7 @@ #include #include #include +#include #include "libunwind.h" #include "config.h" @@ -152,6 +153,72 @@ struct UnwindInfoSections { #endif }; +class UnwindInfoSectionsCache { +public: + + struct CacheItem { + /* + * Implement new operator to avoid depending on libcxx. By declaring + * it noexcept we can let it return nullptr under memory shortage. + */ + void *operator new(size_t sz) noexcept { + return malloc(sz); + } + + CacheItem(UnwindInfoSections &uis, uintptr_t pc) + : m_uis(uis), m_pc(pc) { + } + CacheItem(uintptr_t pc) + : m_pc(pc) { + } + + UnwindInfoSections m_uis; + uintptr_t m_pc; + + RB_ENTRY(CacheItem) entry; + }; + + typedef uintptr_t CacheItemKey; + + int CacheCmp(struct CacheItem *c1, struct CacheItem *c2) { + return (c1->m_pc < c2->m_pc ? -1 : c1->m_pc > c2->m_pc); + } + + UnwindInfoSectionsCache() { + m_head = RB_INITIALIZER(&head); + } + + bool getUnwindInfoSectionsForPC(CacheItemKey key, UnwindInfoSections &uis) { + UnwindInfoSections *result = nullptr; + if (m_prev_req_item && m_prev_req_item->m_pc == key) + result = &m_prev_req_item->m_uis; + else { + struct CacheItem find(key), *res; + res = RB_FIND(CacheTree, &m_head, &find); + if (res) { + m_prev_req_item = res; + result = &res->m_uis; + } + } + if (result) { + uis = *result; + return true; + } + return false; + } + + void setUnwindInfoSectionsForPC(CacheItemKey key, UnwindInfoSections &uis) { + CacheItem *p_item = new CacheItem(uis, key); + if (p_item == nullptr) + return; + RB_INSERT(CacheTree, &m_head, p_item); + } + +private: + CacheItem *m_prev_req_item = nullptr; + RB_HEAD(CacheTree, CacheItem) m_head; + RB_GENERATE(CacheTree, CacheItem, entry, CacheCmp); +}; /// LocalAddressSpace is used as a template parameter to UnwindCursor when /// unwinding a thread in the same process. The wrappers compile away, diff --git a/gnu/llvm/libunwind/src/UnwindCursor.hpp b/gnu/llvm/libunwind/src/UnwindCursor.hpp index 06e65419735..6f6165fdd2b 100644 --- a/gnu/llvm/libunwind/src/UnwindCursor.hpp +++ b/gnu/llvm/libunwind/src/UnwindCursor.hpp @@ -90,6 +90,8 @@ extern "C" _Unwind_Reason_Code __libunwind_seh_personality( namespace libunwind { +static thread_local UnwindInfoSectionsCache uwis_cache; + #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) /// Cache of recently found FDEs. template @@ -2600,7 +2602,14 @@ void UnwindCursor::setInfoBasedOnIPRegister(bool isReturnAddress) { // Ask address space object to find unwind sections for this pc. UnwindInfoSections sects; - if (_addressSpace.findUnwindSections(pc, sects)) { + bool have_sects = false; + if (uwis_cache.getUnwindInfoSectionsForPC(pc, sects)) + have_sects = true; + else if (_addressSpace.findUnwindSections(pc, sects)) { + uwis_cache.setUnwindInfoSectionsForPC(pc, sects); + have_sects = true; + } + if (have_sects) { #if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) // If there is a compact unwind encoding table, look there first. if (sects.compact_unwind_section != 0) {