diff options
author | orivej <[email protected]> | 2022-02-10 16:44:49 +0300 |
---|---|---|
committer | Daniil Cherednik <[email protected]> | 2022-02-10 16:44:49 +0300 |
commit | 718c552901d703c502ccbefdfc3c9028d608b947 (patch) | |
tree | 46534a98bbefcd7b1f3faa5b52c138ab27db75b7 /contrib/libs/libunwind/src/FrameHeaderCache.hpp | |
parent | e9656aae26e0358d5378e5b63dcac5c8dbe0e4d0 (diff) |
Restoring authorship annotation for <[email protected]>. Commit 1 of 2.
Diffstat (limited to 'contrib/libs/libunwind/src/FrameHeaderCache.hpp')
-rw-r--r-- | contrib/libs/libunwind/src/FrameHeaderCache.hpp | 298 |
1 files changed, 149 insertions, 149 deletions
diff --git a/contrib/libs/libunwind/src/FrameHeaderCache.hpp b/contrib/libs/libunwind/src/FrameHeaderCache.hpp index 54d5d33c3cd..2df7e5cd09b 100644 --- a/contrib/libs/libunwind/src/FrameHeaderCache.hpp +++ b/contrib/libs/libunwind/src/FrameHeaderCache.hpp @@ -1,149 +1,149 @@ -//===-FrameHeaderCache.hpp ------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -// Cache the elf program headers necessary to unwind the stack more efficiently -// in the presence of many dsos. -// -//===----------------------------------------------------------------------===// - -#ifndef __FRAMEHEADER_CACHE_HPP__ -#define __FRAMEHEADER_CACHE_HPP__ - -#include "config.h" -#include <limits.h> - -#ifdef _LIBUNWIND_DEBUG_FRAMEHEADER_CACHE -#define _LIBUNWIND_FRAMEHEADERCACHE_TRACE0(x) _LIBUNWIND_LOG0(x) -#define _LIBUNWIND_FRAMEHEADERCACHE_TRACE(msg, ...) \ - _LIBUNWIND_LOG(msg, __VA_ARGS__) -#else -#define _LIBUNWIND_FRAMEHEADERCACHE_TRACE0(x) -#define _LIBUNWIND_FRAMEHEADERCACHE_TRACE(msg, ...) -#endif - -// This cache should only be be used from within a dl_iterate_phdr callback. -// dl_iterate_phdr does the necessary synchronization to prevent problems -// with concurrent access via the libc load lock. Adding synchronization -// for other uses is possible, but not currently done. - -class _LIBUNWIND_HIDDEN FrameHeaderCache { - struct CacheEntry { - uintptr_t LowPC() { return Info.dso_base; }; - uintptr_t HighPC() { return Info.dso_base + Info.text_segment_length; }; - UnwindInfoSections Info; - CacheEntry *Next; - }; - - static const size_t kCacheEntryCount = 8; - - // Can't depend on the C++ standard library in libunwind, so use an array to - // allocate the entries, and two linked lists for ordering unused and recently - // used entries. FIXME: Would the the extra memory for a doubly-linked list - // be better than the runtime cost of traversing a very short singly-linked - // list on a cache miss? The entries themselves are all small and consecutive, - // so unlikely to cause page faults when following the pointers. The memory - // spent on additional pointers could also be spent on more entries. - - CacheEntry Entries[kCacheEntryCount]; - CacheEntry *MostRecentlyUsed; - CacheEntry *Unused; - - void resetCache() { - _LIBUNWIND_FRAMEHEADERCACHE_TRACE0("FrameHeaderCache reset"); - MostRecentlyUsed = nullptr; - Unused = &Entries[0]; - for (size_t i = 0; i < kCacheEntryCount - 1; i++) { - Entries[i].Next = &Entries[i + 1]; - } - Entries[kCacheEntryCount - 1].Next = nullptr; - } - - bool cacheNeedsReset(dl_phdr_info *PInfo) { - // C libraries increment dl_phdr_info.adds and dl_phdr_info.subs when - // loading and unloading shared libraries. If these values change between - // iterations of dl_iterate_phdr, then invalidate the cache. - - // These are static to avoid needing an initializer, and unsigned long long - // because that is their type within the extended dl_phdr_info. Initialize - // these to something extremely unlikely to be found upon the first call to - // dl_iterate_phdr. - static unsigned long long LastAdds = ULLONG_MAX; - static unsigned long long LastSubs = ULLONG_MAX; - if (PInfo->dlpi_adds != LastAdds || PInfo->dlpi_subs != LastSubs) { - // Resetting the entire cache is a big hammer, but this path is rare-- - // usually just on the very first call, when the cache is empty anyway--so - // added complexity doesn't buy much. - LastAdds = PInfo->dlpi_adds; - LastSubs = PInfo->dlpi_subs; - resetCache(); - return true; - } - return false; - } - -public: - bool find(dl_phdr_info *PInfo, size_t, void *data) { - if (cacheNeedsReset(PInfo) || MostRecentlyUsed == nullptr) - return false; - - auto *CBData = static_cast<dl_iterate_cb_data *>(data); - CacheEntry *Current = MostRecentlyUsed; - CacheEntry *Previous = nullptr; - while (Current != nullptr) { - _LIBUNWIND_FRAMEHEADERCACHE_TRACE( - "FrameHeaderCache check %lx in [%lx - %lx)", CBData->targetAddr, - Current->LowPC(), Current->HighPC()); - if (Current->LowPC() <= CBData->targetAddr && - CBData->targetAddr < Current->HighPC()) { - _LIBUNWIND_FRAMEHEADERCACHE_TRACE( - "FrameHeaderCache hit %lx in [%lx - %lx)", CBData->targetAddr, - Current->LowPC(), Current->HighPC()); - if (Previous) { - // If there is no Previous, then Current is already the - // MostRecentlyUsed, and no need to move it up. - Previous->Next = Current->Next; - Current->Next = MostRecentlyUsed; - MostRecentlyUsed = Current; - } - *CBData->sects = Current->Info; - return true; - } - Previous = Current; - Current = Current->Next; - } - _LIBUNWIND_FRAMEHEADERCACHE_TRACE("FrameHeaderCache miss for address %lx", - CBData->targetAddr); - return false; - } - - void add(const UnwindInfoSections *UIS) { - CacheEntry *Current = nullptr; - - if (Unused != nullptr) { - Current = Unused; - Unused = Unused->Next; - } else { - Current = MostRecentlyUsed; - CacheEntry *Previous = nullptr; - while (Current->Next != nullptr) { - Previous = Current; - Current = Current->Next; - } - Previous->Next = nullptr; - _LIBUNWIND_FRAMEHEADERCACHE_TRACE("FrameHeaderCache evict [%lx - %lx)", - Current->LowPC(), Current->HighPC()); - } - - Current->Info = *UIS; - Current->Next = MostRecentlyUsed; - MostRecentlyUsed = Current; - _LIBUNWIND_FRAMEHEADERCACHE_TRACE("FrameHeaderCache add [%lx - %lx)", - MostRecentlyUsed->LowPC(), - MostRecentlyUsed->HighPC()); - } -}; - -#endif // __FRAMEHEADER_CACHE_HPP__ +//===-FrameHeaderCache.hpp ------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// Cache the elf program headers necessary to unwind the stack more efficiently +// in the presence of many dsos. +// +//===----------------------------------------------------------------------===// + +#ifndef __FRAMEHEADER_CACHE_HPP__ +#define __FRAMEHEADER_CACHE_HPP__ + +#include "config.h" +#include <limits.h> + +#ifdef _LIBUNWIND_DEBUG_FRAMEHEADER_CACHE +#define _LIBUNWIND_FRAMEHEADERCACHE_TRACE0(x) _LIBUNWIND_LOG0(x) +#define _LIBUNWIND_FRAMEHEADERCACHE_TRACE(msg, ...) \ + _LIBUNWIND_LOG(msg, __VA_ARGS__) +#else +#define _LIBUNWIND_FRAMEHEADERCACHE_TRACE0(x) +#define _LIBUNWIND_FRAMEHEADERCACHE_TRACE(msg, ...) +#endif + +// This cache should only be be used from within a dl_iterate_phdr callback. +// dl_iterate_phdr does the necessary synchronization to prevent problems +// with concurrent access via the libc load lock. Adding synchronization +// for other uses is possible, but not currently done. + +class _LIBUNWIND_HIDDEN FrameHeaderCache { + struct CacheEntry { + uintptr_t LowPC() { return Info.dso_base; }; + uintptr_t HighPC() { return Info.dso_base + Info.text_segment_length; }; + UnwindInfoSections Info; + CacheEntry *Next; + }; + + static const size_t kCacheEntryCount = 8; + + // Can't depend on the C++ standard library in libunwind, so use an array to + // allocate the entries, and two linked lists for ordering unused and recently + // used entries. FIXME: Would the the extra memory for a doubly-linked list + // be better than the runtime cost of traversing a very short singly-linked + // list on a cache miss? The entries themselves are all small and consecutive, + // so unlikely to cause page faults when following the pointers. The memory + // spent on additional pointers could also be spent on more entries. + + CacheEntry Entries[kCacheEntryCount]; + CacheEntry *MostRecentlyUsed; + CacheEntry *Unused; + + void resetCache() { + _LIBUNWIND_FRAMEHEADERCACHE_TRACE0("FrameHeaderCache reset"); + MostRecentlyUsed = nullptr; + Unused = &Entries[0]; + for (size_t i = 0; i < kCacheEntryCount - 1; i++) { + Entries[i].Next = &Entries[i + 1]; + } + Entries[kCacheEntryCount - 1].Next = nullptr; + } + + bool cacheNeedsReset(dl_phdr_info *PInfo) { + // C libraries increment dl_phdr_info.adds and dl_phdr_info.subs when + // loading and unloading shared libraries. If these values change between + // iterations of dl_iterate_phdr, then invalidate the cache. + + // These are static to avoid needing an initializer, and unsigned long long + // because that is their type within the extended dl_phdr_info. Initialize + // these to something extremely unlikely to be found upon the first call to + // dl_iterate_phdr. + static unsigned long long LastAdds = ULLONG_MAX; + static unsigned long long LastSubs = ULLONG_MAX; + if (PInfo->dlpi_adds != LastAdds || PInfo->dlpi_subs != LastSubs) { + // Resetting the entire cache is a big hammer, but this path is rare-- + // usually just on the very first call, when the cache is empty anyway--so + // added complexity doesn't buy much. + LastAdds = PInfo->dlpi_adds; + LastSubs = PInfo->dlpi_subs; + resetCache(); + return true; + } + return false; + } + +public: + bool find(dl_phdr_info *PInfo, size_t, void *data) { + if (cacheNeedsReset(PInfo) || MostRecentlyUsed == nullptr) + return false; + + auto *CBData = static_cast<dl_iterate_cb_data *>(data); + CacheEntry *Current = MostRecentlyUsed; + CacheEntry *Previous = nullptr; + while (Current != nullptr) { + _LIBUNWIND_FRAMEHEADERCACHE_TRACE( + "FrameHeaderCache check %lx in [%lx - %lx)", CBData->targetAddr, + Current->LowPC(), Current->HighPC()); + if (Current->LowPC() <= CBData->targetAddr && + CBData->targetAddr < Current->HighPC()) { + _LIBUNWIND_FRAMEHEADERCACHE_TRACE( + "FrameHeaderCache hit %lx in [%lx - %lx)", CBData->targetAddr, + Current->LowPC(), Current->HighPC()); + if (Previous) { + // If there is no Previous, then Current is already the + // MostRecentlyUsed, and no need to move it up. + Previous->Next = Current->Next; + Current->Next = MostRecentlyUsed; + MostRecentlyUsed = Current; + } + *CBData->sects = Current->Info; + return true; + } + Previous = Current; + Current = Current->Next; + } + _LIBUNWIND_FRAMEHEADERCACHE_TRACE("FrameHeaderCache miss for address %lx", + CBData->targetAddr); + return false; + } + + void add(const UnwindInfoSections *UIS) { + CacheEntry *Current = nullptr; + + if (Unused != nullptr) { + Current = Unused; + Unused = Unused->Next; + } else { + Current = MostRecentlyUsed; + CacheEntry *Previous = nullptr; + while (Current->Next != nullptr) { + Previous = Current; + Current = Current->Next; + } + Previous->Next = nullptr; + _LIBUNWIND_FRAMEHEADERCACHE_TRACE("FrameHeaderCache evict [%lx - %lx)", + Current->LowPC(), Current->HighPC()); + } + + Current->Info = *UIS; + Current->Next = MostRecentlyUsed; + MostRecentlyUsed = Current; + _LIBUNWIND_FRAMEHEADERCACHE_TRACE("FrameHeaderCache add [%lx - %lx)", + MostRecentlyUsed->LowPC(), + MostRecentlyUsed->HighPC()); + } +}; + +#endif // __FRAMEHEADER_CACHE_HPP__ |