diff options
Diffstat (limited to 'llvm/include')
28 files changed, 425 insertions, 1240 deletions
diff --git a/llvm/include/llvm/ADT/IndexedMap.h b/llvm/include/llvm/ADT/IndexedMap.h index 55935a7..02193c7 100644 --- a/llvm/include/llvm/ADT/IndexedMap.h +++ b/llvm/include/llvm/ADT/IndexedMap.h @@ -43,40 +43,40 @@ class IndexedMap { // is trivially copyable. using StorageT = SmallVector<T, 0>; - StorageT storage_; - T nullVal_ = T(); - ToIndexT toIndex_; + StorageT Storage; + T NullVal = T(); + ToIndexT ToIndex; public: IndexedMap() = default; - explicit IndexedMap(const T &val) : nullVal_(val) {} + explicit IndexedMap(const T &Val) : NullVal(Val) {} - typename StorageT::reference operator[](IndexT n) { - assert(toIndex_(n) < storage_.size() && "index out of bounds!"); - return storage_[toIndex_(n)]; + typename StorageT::reference operator[](IndexT N) { + assert(ToIndex(N) < Storage.size() && "index out of bounds!"); + return Storage[ToIndex(N)]; } - typename StorageT::const_reference operator[](IndexT n) const { - assert(toIndex_(n) < storage_.size() && "index out of bounds!"); - return storage_[toIndex_(n)]; + typename StorageT::const_reference operator[](IndexT N) const { + assert(ToIndex(N) < Storage.size() && "index out of bounds!"); + return Storage[ToIndex(N)]; } - void reserve(typename StorageT::size_type s) { storage_.reserve(s); } + void reserve(typename StorageT::size_type S) { Storage.reserve(S); } - void resize(typename StorageT::size_type s) { storage_.resize(s, nullVal_); } + void resize(typename StorageT::size_type S) { Storage.resize(S, NullVal); } - void clear() { storage_.clear(); } + void clear() { Storage.clear(); } - void grow(IndexT n) { - unsigned NewSize = toIndex_(n) + 1; - if (NewSize > storage_.size()) + void grow(IndexT N) { + unsigned NewSize = ToIndex(N) + 1; + if (NewSize > Storage.size()) resize(NewSize); } - bool inBounds(IndexT n) const { return toIndex_(n) < storage_.size(); } + bool inBounds(IndexT N) const { return ToIndex(N) < Storage.size(); } - typename StorageT::size_type size() const { return storage_.size(); } + typename StorageT::size_type size() const { return Storage.size(); } }; } // namespace llvm diff --git a/llvm/include/llvm/ADT/RadixTree.h b/llvm/include/llvm/ADT/RadixTree.h new file mode 100644 index 0000000..a65acdd --- /dev/null +++ b/llvm/include/llvm/ADT/RadixTree.h @@ -0,0 +1,351 @@ +//===-- llvm/ADT/RadixTree.h - Radix Tree implementation --------*- C++ -*-===// +// +// 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 +//===----------------------------------------------------------------------===// +// +// This file implements a Radix Tree. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_RADIXTREE_H +#define LLVM_ADT_RADIXTREE_H + +#include "llvm/ADT/ADL.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/iterator.h" +#include "llvm/ADT/iterator_range.h" +#include <cassert> +#include <cstddef> +#include <iterator> +#include <limits> +#include <list> +#include <utility> +#include <vector> + +namespace llvm { + +/// \brief A Radix Tree implementation. +/// +/// A Radix Tree (also known as a compact prefix tree or radix trie) is a +/// data structure that stores a dynamic set or associative array where keys +/// are strings and values are associated with these keys. Unlike a regular +/// trie, the edges of a radix tree can be labeled with sequences of characters +/// as well as single characters. This makes radix trees more efficient for +/// storing sparse data sets, where many nodes in a regular trie would have +/// only one child. +/// +/// This implementation supports arbitrary key types that can be iterated over +/// (e.g., `std::string`, `std::vector<char>`, `ArrayRef<char>`). The key type +/// must provide `begin()` and `end()` for iteration. +/// +/// The tree stores `std::pair<const KeyType, T>` as its value type. +/// +/// Example usage: +/// \code +/// llvm::RadixTree<StringRef, int> Tree; +/// Tree.emplace("apple", 1); +/// Tree.emplace("grapefruit", 2); +/// Tree.emplace("grape", 3); +/// +/// // Find prefixes +/// for (const auto &[Key, Value] : Tree.find_prefixes("grapefruit juice")) { +/// // pair will be {"grape", 3} +/// // pair will be {"grapefruit", 2} +/// llvm::outs() << Key << ": " << Value << "\n"; +/// } +/// +/// // Iterate over all elements +/// for (const auto &[Key, Value] : Tree) +/// llvm::outs() << Key << ": " << Value << "\n"; +/// \endcode +/// +/// \note +/// The `RadixTree` takes ownership of the `KeyType` and `T` objects +/// inserted into it. When an element is removed or the tree is destroyed, +/// these objects will be destructed. +/// However, if `KeyType` is a reference-like type, e.g., StringRef or range, +/// the user must guarantee that the referenced data has a lifetime longer than +/// the tree. +template <typename KeyType, typename T> class RadixTree { +public: + using key_type = KeyType; + using mapped_type = T; + using value_type = std::pair<const KeyType, mapped_type>; + +private: + using KeyConstIteratorType = + decltype(adl_begin(std::declval<const key_type &>())); + using KeyConstIteratorRangeType = iterator_range<KeyConstIteratorType>; + using KeyValueType = + remove_cvref_t<decltype(*adl_begin(std::declval<key_type &>()))>; + using ContainerType = std::list<value_type>; + + /// Represents an internal node in the Radix Tree. + struct Node { + KeyConstIteratorRangeType Key{KeyConstIteratorType{}, + KeyConstIteratorType{}}; + std::vector<Node> Children; + + /// An iterator to the value associated with this node. + /// + /// If this node does not have a value (i.e., it's an internal node that + /// only serves as a path to other values), this iterator will be equal + /// to default constructed `ContainerType::iterator()`. + typename ContainerType::iterator Value; + + /// The first character of the Key. Used for fast child lookup. + KeyValueType KeyFront; + + Node() = default; + Node(const KeyConstIteratorRangeType &Key) + : Key(Key), KeyFront(*Key.begin()) { + assert(!Key.empty()); + } + + Node(Node &&) = default; + Node &operator=(Node &&) = default; + + Node(const Node &) = delete; + Node &operator=(const Node &) = delete; + + const Node *findChild(const KeyConstIteratorRangeType &Key) const { + if (Key.empty()) + return nullptr; + for (const Node &Child : Children) { + assert(!Child.Key.empty()); // Only root can be empty. + if (Child.KeyFront == *Key.begin()) + return &Child; + } + return nullptr; + } + + Node *findChild(const KeyConstIteratorRangeType &Query) { + const Node *This = this; + return const_cast<Node *>(This->findChild(Query)); + } + + size_t countNodes() const { + size_t R = 1; + for (const Node &C : Children) + R += C.countNodes(); + return R; + } + + /// + /// Splits the current node into two. + /// + /// This function is used when a new key needs to be inserted that shares + /// a common prefix with the current node's key, but then diverges. + /// The current `Key` is truncated to the common prefix, and a new child + /// node is created for the remainder of the original node's `Key`. + /// + /// \param SplitPoint An iterator pointing to the character in the current + /// `Key` where the split should occur. + void split(KeyConstIteratorType SplitPoint) { + Node Child(make_range(SplitPoint, Key.end())); + Key = make_range(Key.begin(), SplitPoint); + + Children.swap(Child.Children); + std::swap(Value, Child.Value); + + Children.emplace_back(std::move(Child)); + } + }; + + /// Root always corresponds to the empty key, which is the shortest possible + /// prefix for everything. + Node Root; + ContainerType KeyValuePairs; + + /// Finds or creates a new tail or leaf node corresponding to the `Key`. + Node &findOrCreate(KeyConstIteratorRangeType Key) { + Node *Curr = &Root; + if (Key.empty()) + return *Curr; + + for (;;) { + auto [I1, I2] = llvm::mismatch(Key, Curr->Key); + Key = make_range(I1, Key.end()); + + if (I2 != Curr->Key.end()) { + // Match is partial. Either query is too short, or there is mismatching + // character. Split either way, and put new node in between of the + // current and its children. + Curr->split(I2); + + // Split was caused by mismatch, so `findChild` would fail. + break; + } + + Node *Child = Curr->findChild(Key); + if (!Child) + break; + + // Move to child with the same first character. + Curr = Child; + } + + if (Key.empty()) { + // The current node completely matches the key, return it. + return *Curr; + } + + // `Key` is a suffix of original `Key` unmatched by path from the `Root` to + // the `Curr`, and we have no candidate in the children to match more. + // Create a new one. + return Curr->Children.emplace_back(Key); + } + + /// + /// An iterator for traversing prefixes search results. + /// + /// This iterator is used by `find_prefixes` to traverse the tree and find + /// elements that are prefixes to the given key. It's a forward iterator. + /// + /// \tparam MappedType The type of the value pointed to by the iterator. + /// This will be `value_type` for non-const iterators + /// and `const value_type` for const iterators. + template <typename MappedType> + class IteratorImpl + : public iterator_facade_base<IteratorImpl<MappedType>, + std::forward_iterator_tag, MappedType> { + const Node *Curr = nullptr; + KeyConstIteratorRangeType Query{KeyConstIteratorType{}, + KeyConstIteratorType{}}; + + void findNextValid() { + while (Curr && Curr->Value == typename ContainerType::iterator()) + advance(); + } + + void advance() { + assert(Curr); + if (Query.empty()) { + Curr = nullptr; + return; + } + + Curr = Curr->findChild(Query); + if (!Curr) { + Curr = nullptr; + return; + } + + auto [I1, I2] = llvm::mismatch(Query, Curr->Key); + if (I2 != Curr->Key.end()) { + Curr = nullptr; + return; + } + Query = make_range(I1, Query.end()); + } + + friend class RadixTree; + IteratorImpl(const Node *C, const KeyConstIteratorRangeType &Q) + : Curr(C), Query(Q) { + findNextValid(); + } + + public: + IteratorImpl() = default; + + MappedType &operator*() const { return *Curr->Value; } + + IteratorImpl &operator++() { + advance(); + findNextValid(); + return *this; + } + + bool operator==(const IteratorImpl &Other) const { + return Curr == Other.Curr; + } + }; + +public: + RadixTree() = default; + RadixTree(RadixTree &&) = default; + RadixTree &operator=(RadixTree &&) = default; + + using prefix_iterator = IteratorImpl<value_type>; + using const_prefix_iterator = IteratorImpl<const value_type>; + + using iterator = typename ContainerType::iterator; + using const_iterator = typename ContainerType::const_iterator; + + /// Returns true if the tree is empty. + bool empty() const { return KeyValuePairs.empty(); } + + /// Returns the number of elements in the tree. + size_t size() const { return KeyValuePairs.size(); } + + /// Returns the number of nodes in the tree. + /// + /// This function counts all internal nodes in the tree. It can be useful for + /// understanding the memory footprint or complexity of the tree structure. + size_t countNodes() const { return Root.countNodes(); } + + /// Returns an iterator to the first element. + iterator begin() { return KeyValuePairs.begin(); } + const_iterator begin() const { return KeyValuePairs.begin(); } + + /// Returns an iterator to the end of the tree. + iterator end() { return KeyValuePairs.end(); } + const_iterator end() const { return KeyValuePairs.end(); } + + /// Constructs and inserts a new element into the tree. + /// + /// This function constructs an element in place within the tree. If an + /// element with the same key already exists, the insertion fails and the + /// function returns an iterator to the existing element along with `false`. + /// Otherwise, the new element is inserted and the function returns an + /// iterator to the new element along with `true`. + /// + /// \param Key The key of the element to construct. + /// \param Args Arguments to forward to the constructor of the mapped_type. + /// \return A pair consisting of an iterator to the inserted element (or to + /// the element that prevented insertion) and a boolean value + /// indicating whether the insertion took place. + template <typename... Ts> + std::pair<iterator, bool> emplace(key_type &&Key, Ts &&...Args) { + // We want to make new `Node` to refer key in the container, not the one + // from the argument. + // FIXME: Determine that we need a new node, before expanding + // `KeyValuePairs`. + const value_type &NewValue = KeyValuePairs.emplace_front( + std::move(Key), T(std::forward<Ts>(Args)...)); + Node &Node = findOrCreate(NewValue.first); + bool HasValue = Node.Value != typename ContainerType::iterator(); + if (!HasValue) + Node.Value = KeyValuePairs.begin(); + else + KeyValuePairs.pop_front(); + return {Node.Value, !HasValue}; + } + + /// + /// Finds all elements whose keys are prefixes of the given `Key`. + /// + /// This function returns an iterator range over all elements in the tree + /// whose keys are prefixes of the provided `Key`. For example, if the tree + /// contains "abcde", "abc", "abcdefgh", and `Key` is "abcde", this function + /// would return iterators to "abcde" and "abc". + /// + /// \param Key The key to search for prefixes of. + /// \return An `iterator_range` of `const_prefix_iterator`s, allowing + /// iteration over the found prefix elements. + /// \note The returned iterators reference the `Key` provided by the caller. + /// The caller must ensure that `Key` remains valid for the lifetime + /// of the iterators. + iterator_range<const_prefix_iterator> + find_prefixes(const key_type &Key) const { + return iterator_range<const_prefix_iterator>{ + const_prefix_iterator(&Root, KeyConstIteratorRangeType(Key)), + const_prefix_iterator{}}; + } +}; + +} // namespace llvm + +#endif // LLVM_ADT_RADIXTREE_H diff --git a/llvm/include/llvm/ADT/STLForwardCompat.h b/llvm/include/llvm/ADT/STLForwardCompat.h index 9c81981..e02694f 100644 --- a/llvm/include/llvm/ADT/STLForwardCompat.h +++ b/llvm/include/llvm/ADT/STLForwardCompat.h @@ -125,7 +125,7 @@ struct detector<std::void_t<Op<Args...>>, Op, Args...> { template <template <class...> class Op, class... Args> using is_detected = typename detail::detector<void, Op, Args...>::value_t; -struct identity_cxx20 // NOLINT(readability-identifier-naming) +struct identity // NOLINT(readability-identifier-naming) { using is_transparent = void; diff --git a/llvm/include/llvm/ADT/SparseMultiSet.h b/llvm/include/llvm/ADT/SparseMultiSet.h index 5e4e170..59de4cf 100644 --- a/llvm/include/llvm/ADT/SparseMultiSet.h +++ b/llvm/include/llvm/ADT/SparseMultiSet.h @@ -82,7 +82,7 @@ namespace llvm { /// @tparam SparseT An unsigned integer type. See above. /// template <typename ValueT, typename KeyT = unsigned, - typename KeyFunctorT = identity_cxx20, typename SparseT = uint8_t> + typename KeyFunctorT = identity, typename SparseT = uint8_t> class SparseMultiSet { static_assert(std::is_unsigned_v<SparseT>, "SparseT must be an unsigned integer type"); diff --git a/llvm/include/llvm/ADT/SparseSet.h b/llvm/include/llvm/ADT/SparseSet.h index 4697de09..41fd501 100644 --- a/llvm/include/llvm/ADT/SparseSet.h +++ b/llvm/include/llvm/ADT/SparseSet.h @@ -59,24 +59,20 @@ template <typename ValueT> struct SparseSetValTraits { } }; -/// SparseSetValFunctor - Helper class for selecting SparseSetValTraits. The -/// generic implementation handles ValueT classes which either provide -/// getSparseSetIndex() or specialize SparseSetValTraits<>. +/// SparseSetValFunctor - Helper class for getting a value's index. /// +/// In the generic case, this is done via SparseSetValTraits. When the value +/// type is the same as the key type, the KeyFunctor is used directly. template <typename KeyT, typename ValueT, typename KeyFunctorT> struct SparseSetValFunctor { unsigned operator()(const ValueT &Val) const { - return SparseSetValTraits<ValueT>::getValIndex(Val); + if constexpr (std::is_same_v<KeyT, ValueT>) + return KeyFunctorT()(Val); + else + return SparseSetValTraits<ValueT>::getValIndex(Val); } }; -/// SparseSetValFunctor<KeyT, KeyT> - Helper class for the common case of -/// identity key/value sets. -template <typename KeyT, typename KeyFunctorT> -struct SparseSetValFunctor<KeyT, KeyT, KeyFunctorT> { - unsigned operator()(const KeyT &Key) const { return KeyFunctorT()(Key); } -}; - /// SparseSet - Fast set implementation for objects that can be identified by /// small unsigned keys. /// @@ -117,7 +113,7 @@ struct SparseSetValFunctor<KeyT, KeyT, KeyFunctorT> { /// @tparam SparseT An unsigned integer type. See above. /// template <typename ValueT, typename KeyT = unsigned, - typename KeyFunctorT = identity_cxx20, typename SparseT = uint8_t> + typename KeyFunctorT = identity, typename SparseT = uint8_t> class SparseSet { static_assert(std::is_unsigned_v<SparseT>, "SparseT must be an unsigned integer type"); diff --git a/llvm/include/llvm/CodeGen/Passes.h b/llvm/include/llvm/CodeGen/Passes.h index 9fddd47..a852555 100644 --- a/llvm/include/llvm/CodeGen/Passes.h +++ b/llvm/include/llvm/CodeGen/Passes.h @@ -610,14 +610,6 @@ LLVM_ABI ModulePass *createCheckDebugMachineModulePass(); /// caller saved registers with stack slots. LLVM_ABI extern char &FixupStatepointCallerSavedID; -/// The pass transforms load/store <256 x i32> to AMX load/store intrinsics -/// or split the data to two <128 x i32>. -LLVM_ABI FunctionPass *createX86LowerAMXTypePass(); - -/// The pass transforms amx intrinsics to scalar operation if the function has -/// optnone attribute or it is O0. -LLVM_ABI FunctionPass *createX86LowerAMXIntrinsicsPass(); - /// When learning an eviction policy, extract score(reward) information, /// otherwise this does nothing LLVM_ABI FunctionPass *createRegAllocScoringPass(); diff --git a/llvm/include/llvm/CodeGen/ScheduleDAGInstrs.h b/llvm/include/llvm/CodeGen/ScheduleDAGInstrs.h index 26d7080..ab0d7e3 100644 --- a/llvm/include/llvm/CodeGen/ScheduleDAGInstrs.h +++ b/llvm/include/llvm/CodeGen/ScheduleDAGInstrs.h @@ -89,7 +89,7 @@ namespace llvm { /// allocated once for the pass. It can be cleared in constant time and reused /// without any frees. using RegUnit2SUnitsMap = - SparseMultiSet<PhysRegSUOper, unsigned, identity_cxx20, uint16_t>; + SparseMultiSet<PhysRegSUOper, unsigned, identity, uint16_t>; /// Track local uses of virtual registers. These uses are gathered by the DAG /// builder and may be consulted by the scheduler to avoid iterating an entire diff --git a/llvm/include/llvm/DebugInfo/CodeView/AppendingTypeTableBuilder.h b/llvm/include/llvm/DebugInfo/CodeView/AppendingTypeTableBuilder.h index 3a36863..5a46207 100644 --- a/llvm/include/llvm/DebugInfo/CodeView/AppendingTypeTableBuilder.h +++ b/llvm/include/llvm/DebugInfo/CodeView/AppendingTypeTableBuilder.h @@ -34,7 +34,7 @@ class LLVM_ABI AppendingTypeTableBuilder : public TypeCollection { public: explicit AppendingTypeTableBuilder(BumpPtrAllocator &Storage); - ~AppendingTypeTableBuilder(); + ~AppendingTypeTableBuilder() override; // TypeCollection overrides std::optional<TypeIndex> getFirst() override; diff --git a/llvm/include/llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h b/llvm/include/llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h index a587b3e..93e1c99 100644 --- a/llvm/include/llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h +++ b/llvm/include/llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h @@ -47,7 +47,7 @@ class LLVM_ABI GlobalTypeTableBuilder : public TypeCollection { public: explicit GlobalTypeTableBuilder(BumpPtrAllocator &Storage); - ~GlobalTypeTableBuilder(); + ~GlobalTypeTableBuilder() override; // TypeCollection overrides std::optional<TypeIndex> getFirst() override; diff --git a/llvm/include/llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h b/llvm/include/llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h index 7302784..b9b2669 100644 --- a/llvm/include/llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h +++ b/llvm/include/llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h @@ -43,7 +43,7 @@ class LLVM_ABI MergingTypeTableBuilder : public TypeCollection { public: explicit MergingTypeTableBuilder(BumpPtrAllocator &Storage); - ~MergingTypeTableBuilder(); + ~MergingTypeTableBuilder() override; // TypeCollection overrides std::optional<TypeIndex> getFirst() override; diff --git a/llvm/include/llvm/DebugInfo/GSYM/GsymContext.h b/llvm/include/llvm/DebugInfo/GSYM/GsymContext.h index 07d599c..e3e9b2b 100644 --- a/llvm/include/llvm/DebugInfo/GSYM/GsymContext.h +++ b/llvm/include/llvm/DebugInfo/GSYM/GsymContext.h @@ -30,7 +30,7 @@ class GsymReader; class GsymContext : public DIContext { public: GsymContext(std::unique_ptr<GsymReader> Reader); - ~GsymContext(); + ~GsymContext() override; GsymContext(GsymContext &) = delete; GsymContext &operator=(GsymContext &) = delete; diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h index 0e7be45..34bace8 100644 --- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h +++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h @@ -143,7 +143,7 @@ public: VirtualityCode(0) {} LVElement(const LVElement &) = delete; LVElement &operator=(const LVElement &) = delete; - virtual ~LVElement() = default; + ~LVElement() override = default; LVSubclassID getSubclassID() const { return SubclassID; } diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLine.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLine.h index 3618ce7..dd17f76 100644 --- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLine.h +++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLine.h @@ -53,7 +53,7 @@ public: } LVLine(const LVLine &) = delete; LVLine &operator=(const LVLine &) = delete; - virtual ~LVLine() = default; + ~LVLine() override = default; static bool classof(const LVElement *Element) { return Element->getSubclassID() == LVSubclassID::LV_LINE; @@ -117,7 +117,7 @@ public: LVLineDebug() : LVLine() { setIsLineDebug(); } LVLineDebug(const LVLineDebug &) = delete; LVLineDebug &operator=(const LVLineDebug &) = delete; - ~LVLineDebug() = default; + ~LVLineDebug() override = default; // Additional line information. It includes attributes that describes // states in the machine instructions (basic block, end prologue, etc). @@ -142,7 +142,7 @@ public: LVLineAssembler() : LVLine() { setIsLineAssembler(); } LVLineAssembler(const LVLineAssembler &) = delete; LVLineAssembler &operator=(const LVLineAssembler &) = delete; - ~LVLineAssembler() = default; + ~LVLineAssembler() override = default; // Print blanks as the line number. std::string noLineAsString(bool ShowZero) const override { diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLocation.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLocation.h index 0718e33..090af54 100644 --- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLocation.h +++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLocation.h @@ -100,7 +100,7 @@ public: LVLocation() : LVObject() { setIsLocation(); } LVLocation(const LVLocation &) = delete; LVLocation &operator=(const LVLocation &) = delete; - virtual ~LVLocation() = default; + ~LVLocation() override = default; PROPERTY(Property, IsAddressRange); PROPERTY(Property, IsBaseClassOffset); @@ -171,7 +171,7 @@ public: LVLocationSymbol() : LVLocation() {} LVLocationSymbol(const LVLocationSymbol &) = delete; LVLocationSymbol &operator=(const LVLocationSymbol &) = delete; - ~LVLocationSymbol() = default; + ~LVLocationSymbol() override = default; void addObject(LVAddress LowPC, LVAddress HighPC, LVUnsigned SectionOffset, uint64_t LocDescOffset) override; diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVRange.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVRange.h index b5c8333..4fa6a9a 100644 --- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVRange.h +++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVRange.h @@ -62,7 +62,7 @@ public: LVRange() : LVObject(), RangesTree(Allocator) {} LVRange(const LVRange &) = delete; LVRange &operator=(const LVRange &) = delete; - ~LVRange() = default; + ~LVRange() override = default; void addEntry(LVScope *Scope, LVAddress LowerAddress, LVAddress UpperAddress); void addEntry(LVScope *Scope); diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h index f4f3516..2e2619c 100644 --- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h +++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h @@ -153,7 +153,7 @@ public: } LVScope(const LVScope &) = delete; LVScope &operator=(const LVScope &) = delete; - virtual ~LVScope() = default; + ~LVScope() override = default; static bool classof(const LVElement *Element) { return Element->getSubclassID() == LVSubclassID::LV_SCOPE; @@ -349,7 +349,7 @@ public: LVScopeAggregate() : LVScope() {} LVScopeAggregate(const LVScopeAggregate &) = delete; LVScopeAggregate &operator=(const LVScopeAggregate &) = delete; - ~LVScopeAggregate() = default; + ~LVScopeAggregate() override = default; // DW_AT_specification, DW_AT_abstract_origin. LVScope *getReference() const override { return Reference; } @@ -387,7 +387,7 @@ public: } LVScopeAlias(const LVScopeAlias &) = delete; LVScopeAlias &operator=(const LVScopeAlias &) = delete; - ~LVScopeAlias() = default; + ~LVScopeAlias() override = default; // Returns true if current scope is logically equal to the given 'Scope'. bool equals(const LVScope *Scope) const override; @@ -401,7 +401,7 @@ public: LVScopeArray() : LVScope() { setIsArray(); } LVScopeArray(const LVScopeArray &) = delete; LVScopeArray &operator=(const LVScopeArray &) = delete; - ~LVScopeArray() = default; + ~LVScopeArray() override = default; void resolveExtra() override; @@ -513,7 +513,7 @@ public: } LVScopeCompileUnit(const LVScopeCompileUnit &) = delete; LVScopeCompileUnit &operator=(const LVScopeCompileUnit &) = delete; - ~LVScopeCompileUnit() = default; + ~LVScopeCompileUnit() override = default; LVScope *getCompileUnitParent() const override { return static_cast<LVScope *>(const_cast<LVScopeCompileUnit *>(this)); @@ -643,7 +643,7 @@ public: LVScopeEnumeration() : LVScope() { setIsEnumeration(); } LVScopeEnumeration(const LVScopeEnumeration &) = delete; LVScopeEnumeration &operator=(const LVScopeEnumeration &) = delete; - ~LVScopeEnumeration() = default; + ~LVScopeEnumeration() override = default; // Returns true if current scope is logically equal to the given 'Scope'. bool equals(const LVScope *Scope) const override; @@ -658,7 +658,7 @@ public: LVScopeFormalPack() : LVScope() { setIsTemplatePack(); } LVScopeFormalPack(const LVScopeFormalPack &) = delete; LVScopeFormalPack &operator=(const LVScopeFormalPack &) = delete; - ~LVScopeFormalPack() = default; + ~LVScopeFormalPack() override = default; // Returns true if current scope is logically equal to the given 'Scope'. bool equals(const LVScope *Scope) const override; @@ -676,7 +676,7 @@ public: LVScopeFunction() : LVScope() {} LVScopeFunction(const LVScopeFunction &) = delete; LVScopeFunction &operator=(const LVScopeFunction &) = delete; - virtual ~LVScopeFunction() = default; + ~LVScopeFunction() override = default; // DW_AT_specification, DW_AT_abstract_origin. LVScope *getReference() const override { return Reference; } @@ -728,7 +728,7 @@ public: LVScopeFunctionInlined() : LVScopeFunction() { setIsInlinedFunction(); } LVScopeFunctionInlined(const LVScopeFunctionInlined &) = delete; LVScopeFunctionInlined &operator=(const LVScopeFunctionInlined &) = delete; - ~LVScopeFunctionInlined() = default; + ~LVScopeFunctionInlined() override = default; uint32_t getDiscriminator() const override { return Discriminator; } void setDiscriminator(uint32_t Value) override { @@ -767,7 +767,7 @@ public: LVScopeFunctionType() : LVScopeFunction() { setIsFunctionType(); } LVScopeFunctionType(const LVScopeFunctionType &) = delete; LVScopeFunctionType &operator=(const LVScopeFunctionType &) = delete; - ~LVScopeFunctionType() = default; + ~LVScopeFunctionType() override = default; void resolveExtra() override; }; @@ -781,7 +781,7 @@ public: } LVScopeModule(const LVScopeModule &) = delete; LVScopeModule &operator=(const LVScopeModule &) = delete; - ~LVScopeModule() = default; + ~LVScopeModule() override = default; // Returns true if current scope is logically equal to the given 'Scope'. bool equals(const LVScope *Scope) const override; @@ -797,7 +797,7 @@ public: LVScopeNamespace() : LVScope() { setIsNamespace(); } LVScopeNamespace(const LVScopeNamespace &) = delete; LVScopeNamespace &operator=(const LVScopeNamespace &) = delete; - ~LVScopeNamespace() = default; + ~LVScopeNamespace() override = default; // Access DW_AT_extension reference. LVScope *getReference() const override { return Reference; } @@ -827,7 +827,7 @@ public: LVScopeRoot() : LVScope() { setIsRoot(); } LVScopeRoot(const LVScopeRoot &) = delete; LVScopeRoot &operator=(const LVScopeRoot &) = delete; - ~LVScopeRoot() = default; + ~LVScopeRoot() override = default; StringRef getFileFormatName() const { return getStringPool().getString(FileFormatNameIndex); @@ -859,7 +859,7 @@ public: LVScopeTemplatePack() : LVScope() { setIsTemplatePack(); } LVScopeTemplatePack(const LVScopeTemplatePack &) = delete; LVScopeTemplatePack &operator=(const LVScopeTemplatePack &) = delete; - ~LVScopeTemplatePack() = default; + ~LVScopeTemplatePack() override = default; // Returns true if current scope is logically equal to the given 'Scope'. bool equals(const LVScope *Scope) const override; diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSymbol.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSymbol.h index ec9017e..c5314fc 100644 --- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSymbol.h +++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSymbol.h @@ -74,7 +74,7 @@ public: } LVSymbol(const LVSymbol &) = delete; LVSymbol &operator=(const LVSymbol &) = delete; - ~LVSymbol() = default; + ~LVSymbol() override = default; static bool classof(const LVElement *Element) { return Element->getSubclassID() == LVSubclassID::LV_SYMBOL; diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVType.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVType.h index 59e6a92..af4abcf 100644 --- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVType.h +++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVType.h @@ -67,7 +67,7 @@ public: LVType() : LVElement(LVSubclassID::LV_TYPE) { setIsType(); } LVType(const LVType &) = delete; LVType &operator=(const LVType &) = delete; - virtual ~LVType() = default; + ~LVType() override = default; static bool classof(const LVElement *Element) { return Element->getSubclassID() == LVSubclassID::LV_TYPE; @@ -157,7 +157,7 @@ public: } LVTypeDefinition(const LVTypeDefinition &) = delete; LVTypeDefinition &operator=(const LVTypeDefinition &) = delete; - ~LVTypeDefinition() = default; + ~LVTypeDefinition() override = default; // Return the underlying type for a type definition. LVElement *getUnderlyingType() override; @@ -183,7 +183,7 @@ public: } LVTypeEnumerator(const LVTypeEnumerator &) = delete; LVTypeEnumerator &operator=(const LVTypeEnumerator &) = delete; - ~LVTypeEnumerator() = default; + ~LVTypeEnumerator() override = default; // Process the values for a DW_TAG_enumerator. StringRef getValue() const override { @@ -206,7 +206,7 @@ public: LVTypeImport() : LVType() { setIncludeInPrint(); } LVTypeImport(const LVTypeImport &) = delete; LVTypeImport &operator=(const LVTypeImport &) = delete; - ~LVTypeImport() = default; + ~LVTypeImport() override = default; // Returns true if current type is logically equal to the given 'Type'. bool equals(const LVType *Type) const override; @@ -223,7 +223,7 @@ public: LVTypeParam(); LVTypeParam(const LVTypeParam &) = delete; LVTypeParam &operator=(const LVTypeParam &) = delete; - ~LVTypeParam() = default; + ~LVTypeParam() override = default; // Template parameter value. StringRef getValue() const override { @@ -256,7 +256,7 @@ public: } LVTypeSubrange(const LVTypeSubrange &) = delete; LVTypeSubrange &operator=(const LVTypeSubrange &) = delete; - ~LVTypeSubrange() = default; + ~LVTypeSubrange() override = default; int64_t getCount() const override { return getIsSubrangeCount() ? LowerBound : 0; diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVBinaryReader.h b/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVBinaryReader.h index 2cf4a8e..cc8dda2 100644 --- a/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVBinaryReader.h +++ b/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVBinaryReader.h @@ -192,7 +192,7 @@ public: : LVReader(Filename, FileFormatName, W, BinaryType) {} LVBinaryReader(const LVBinaryReader &) = delete; LVBinaryReader &operator=(const LVBinaryReader &) = delete; - virtual ~LVBinaryReader() = default; + ~LVBinaryReader() override = default; void addInlineeLines(LVScope *Scope, LVLines &Lines) { CUInlineeLines.emplace(Scope, std::make_unique<LVLines>(std::move(Lines))); diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVCodeViewReader.h b/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVCodeViewReader.h index 4dd7c96..9f6fd553 100644 --- a/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVCodeViewReader.h +++ b/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVCodeViewReader.h @@ -200,7 +200,7 @@ public: Input(&Pdb), ExePath(ExePath), LogicalVisitor(this, W, Input) {} LVCodeViewReader(const LVCodeViewReader &) = delete; LVCodeViewReader &operator=(const LVCodeViewReader &) = delete; - ~LVCodeViewReader() = default; + ~LVCodeViewReader() override = default; void getLinkageName(const llvm::object::coff_section *CoffSection, uint32_t RelocOffset, uint32_t Offset, diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVDWARFReader.h b/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVDWARFReader.h index 2abc18b..1cf2914 100644 --- a/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVDWARFReader.h +++ b/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVDWARFReader.h @@ -123,7 +123,7 @@ public: Obj(Obj) {} LVDWARFReader(const LVDWARFReader &) = delete; LVDWARFReader &operator=(const LVDWARFReader &) = delete; - ~LVDWARFReader() = default; + ~LVDWARFReader() override = default; LVAddress getCUBaseAddress() const { return CUBaseAddress; } void setCUBaseAddress(LVAddress Address) { CUBaseAddress = Address; } diff --git a/llvm/include/llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h b/llvm/include/llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h index b21cd09..c0b3151 100644 --- a/llvm/include/llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h +++ b/llvm/include/llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h @@ -20,7 +20,7 @@ namespace pdb { class LLVM_ABI PDBSymbolTypeBuiltin : public PDBSymbol { DECLARE_PDB_SYMBOL_CONCRETE_TYPE(PDB_SymType::BuiltinType) public: - ~PDBSymbolTypeBuiltin(); + ~PDBSymbolTypeBuiltin() override; void dump(PDBSymDumper &Dumper) const override; FORWARD_SYMBOL_METHOD(getBuiltinType) diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Core.h b/llvm/include/llvm/ExecutionEngine/Orc/Core.h index f05febf..24a0cb7 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/Core.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/Core.h @@ -1768,7 +1768,7 @@ private: // FIXME: We should be able to derive FailedSymsForQuery from each query once // we fix how the detach operation works. struct EmitQueries { - JITDylib::AsynchronousSymbolQuerySet Updated; + JITDylib::AsynchronousSymbolQuerySet Completed; JITDylib::AsynchronousSymbolQuerySet Failed; DenseMap<AsynchronousSymbolQuery *, std::shared_ptr<SymbolDependenceMap>> FailedSymsForQuery; diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h b/llvm/include/llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h index 4a32113b..6adaa8a 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h @@ -34,7 +34,7 @@ using ExecutorAddrDiff = uint64_t; class ExecutorAddr { public: /// A wrap/unwrap function that leaves pointers unmodified. - using rawPtr = llvm::identity_cxx20; + using rawPtr = llvm::identity; #if __has_feature(ptrauth_calls) template <typename T> class PtrauthSignDefault { diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Shared/SymbolFilter.h b/llvm/include/llvm/ExecutionEngine/Orc/Shared/SymbolFilter.h deleted file mode 100644 index 5170893..0000000 --- a/llvm/include/llvm/ExecutionEngine/Orc/Shared/SymbolFilter.h +++ /dev/null @@ -1,173 +0,0 @@ -//===- SymbolFilter.h - Utilities for Symbol Filtering ---------*- C++ -*-===// -// -// 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 -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_EXECUTIONENGINE_ORC_SHARED_SYMBOLFILTER_H -#define LLVM_EXECUTIONENGINE_ORC_SHARED_SYMBOLFILTER_H - -#include "llvm/ExecutionEngine/Orc/Shared/SimplePackedSerialization.h" - -#include <cmath> -#include <type_traits> -#include <vector> - -namespace llvm { -namespace orc { - -namespace shared { -using SPSBloomFilter = - SPSTuple<bool, uint32_t, uint32_t, uint32_t, SPSSequence<uint64_t>>; -} - -class BloomFilter { -public: - using HashFunc = std::function<uint32_t(StringRef)>; - - BloomFilter() = default; - BloomFilter(BloomFilter &&) noexcept = default; - BloomFilter &operator=(BloomFilter &&) noexcept = default; - BloomFilter(const BloomFilter &) = delete; - BloomFilter &operator=(const BloomFilter &) = delete; - - BloomFilter(uint32_t SymbolCount, float FalsePositiveRate, HashFunc hashFn) - : HashFn(std::move(hashFn)) { - initialize(SymbolCount, FalsePositiveRate); - } - bool isInitialized() const { return Initialized; } - - void add(StringRef Sym) { - assert(Initialized); - addHash(HashFn(Sym)); - } - - bool mayContain(StringRef Sym) const { - return !isEmpty() && testHash(HashFn(Sym)); - } - - bool isEmpty() const { return SymbolCount == 0; } - -private: - friend class shared::SPSSerializationTraits<shared::SPSBloomFilter, - BloomFilter>; - static constexpr uint32_t BitsPerEntry = 64; - - bool Initialized = false; - uint32_t SymbolCount = 0; - uint32_t BloomSize = 0; - uint32_t BloomShift = 0; - std::vector<uint64_t> BloomTable; - HashFunc HashFn; - - void initialize(uint32_t SymCount, float FalsePositiveRate) { - assert(SymCount > 0); - SymbolCount = SymCount; - Initialized = true; - - float ln2 = std::log(2.0f); - float M = -1.0f * SymbolCount * std::log(FalsePositiveRate) / (ln2 * ln2); - BloomSize = static_cast<uint32_t>(std::ceil(M / BitsPerEntry)); - BloomShift = std::min(6u, log2ceil(SymbolCount)); - BloomTable.resize(BloomSize, 0); - } - - void addHash(uint32_t Hash) { - uint32_t Hash2 = Hash >> BloomShift; - uint32_t N = (Hash / BitsPerEntry) % BloomSize; - uint64_t Mask = - (1ULL << (Hash % BitsPerEntry)) | (1ULL << (Hash2 % BitsPerEntry)); - BloomTable[N] |= Mask; - } - - bool testHash(uint32_t Hash) const { - uint32_t Hash2 = Hash >> BloomShift; - uint32_t N = (Hash / BitsPerEntry) % BloomSize; - uint64_t Mask = - (1ULL << (Hash % BitsPerEntry)) | (1ULL << (Hash2 % BitsPerEntry)); - return (BloomTable[N] & Mask) == Mask; - } - - static constexpr uint32_t log2ceil(uint32_t V) { - return V <= 1 ? 0 : 32 - countl_zero(V - 1); - } -}; - -class BloomFilterBuilder { -public: - using HashFunc = BloomFilter::HashFunc; - - BloomFilterBuilder() = default; - - BloomFilterBuilder &setFalsePositiveRate(float Rate) { - assert(Rate > 0.0f && Rate < 1.0f); - FalsePositiveRate = Rate; - return *this; - } - - BloomFilterBuilder &setHashFunction(HashFunc Fn) { - HashFn = std::move(Fn); - return *this; - } - - BloomFilter build(ArrayRef<StringRef> Symbols) const { - assert(!Symbols.empty() && "Cannot build filter from empty symbol list."); - BloomFilter F(static_cast<uint32_t>(Symbols.size()), FalsePositiveRate, - HashFn); - for (const auto &Sym : Symbols) - F.add(Sym); - - return F; - } - -private: - float FalsePositiveRate = 0.02f; - HashFunc HashFn = [](StringRef S) -> uint32_t { - uint32_t H = 5381; - for (char C : S) - H = ((H << 5) + H) + static_cast<uint8_t>(C); // H * 33 + C - return H; - }; -}; - -namespace shared { - -template <> class SPSSerializationTraits<SPSBloomFilter, BloomFilter> { -public: - static size_t size(const BloomFilter &Filter) { - return SPSBloomFilter::AsArgList::size( - Filter.Initialized, Filter.SymbolCount, Filter.BloomSize, - Filter.BloomShift, Filter.BloomTable); - } - - static bool serialize(SPSOutputBuffer &OB, const BloomFilter &Filter) { - return SPSBloomFilter::AsArgList::serialize( - OB, Filter.Initialized, Filter.SymbolCount, Filter.BloomSize, - Filter.BloomShift, Filter.BloomTable); - } - - static bool deserialize(SPSInputBuffer &IB, BloomFilter &Filter) { - bool IsInitialized; - uint32_t SymbolCount = 0, BloomSize = 0, BloomShift = 0; - std::vector<uint64_t> BloomTable; - - if (!SPSBloomFilter::AsArgList::deserialize( - IB, IsInitialized, SymbolCount, BloomSize, BloomShift, BloomTable)) - return false; - - Filter.Initialized = IsInitialized; - Filter.SymbolCount = SymbolCount; - Filter.BloomSize = BloomSize; - Filter.BloomShift = BloomShift; - Filter.BloomTable = std::move(BloomTable); - - return true; - } -}; - -} // end namespace shared -} // end namespace orc -} // end namespace llvm -#endif // LLVM_EXECUTIONENGINE_ORC_SHARED_SYMBOLFILTER_H diff --git a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryResolver.h b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryResolver.h deleted file mode 100644 index 50d4f6d041..0000000 --- a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryResolver.h +++ /dev/null @@ -1,514 +0,0 @@ -//===- LibraryResolver.h - Automatic Library Symbol Resolution -*- C++ -*-===// -// -// 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 -// -//===----------------------------------------------------------------------===// -// -// This file provides support for automatically searching symbols across -// dynamic libraries that have not yet been loaded. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_LIBRARYRESOLVER_H -#define LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_LIBRARYRESOLVER_H - -#include "llvm/ADT/FunctionExtras.h" -#include "llvm/ExecutionEngine/Orc/Shared/SymbolFilter.h" -#include "llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h" -#include "llvm/Support/Path.h" - -#include <atomic> -#include <shared_mutex> -#include <unordered_map> - -namespace llvm { -namespace orc { - -/// Manages library metadata and state for symbol resolution. -/// -/// Tracks libraries by load state and kind (user/system), and stores -/// associated Bloom filters and hash maps to speed up symbol lookups. -/// Thread-safe for concurrent access. -class LibraryManager { -public: - enum class LibState : uint8_t { Unloaded = 0, Loaded = 1, Queried = 2 }; - - class LibraryInfo { - public: - LibraryInfo(const LibraryInfo &) = delete; - LibraryInfo &operator=(const LibraryInfo &) = delete; - - LibraryInfo(std::string FilePath, LibState S, PathType K, - std::optional<BloomFilter> Filter = std::nullopt) - : FilePath(std::move(FilePath)), S(S), K(K), Filter(std::move(Filter)) { - } - - StringRef getBasePath() const { return sys::path::parent_path(FilePath); } - StringRef getFileName() const { return sys::path::filename(FilePath); } - - std::string getFullPath() const { return FilePath; } - - bool setFilter(BloomFilter F) { - std::lock_guard<std::shared_mutex> Lock(Mtx); - if (Filter) - return false; - Filter.emplace(std::move(F)); - return true; - } - - bool ensureFilterBuilt(const BloomFilterBuilder &FB, - ArrayRef<StringRef> Symbols) { - std::lock_guard<std::shared_mutex> Lock(Mtx); - if (Filter) - return false; - Filter.emplace(FB.build(Symbols)); - return true; - } - - bool mayContain(StringRef Symbol) const { - assert(hasFilter()); - std::shared_lock<std::shared_mutex> Lock(Mtx); - return Filter->mayContain(Symbol); - } - - bool hasFilter() const { - std::shared_lock<std::shared_mutex> Lock(Mtx); - return Filter.has_value(); - } - - LibState getState() const { return S.load(); } - PathType getKind() const { return K; } - - void setState(LibState s) { S.store(s); } - - bool operator==(const LibraryInfo &other) const { - return FilePath == other.FilePath; - } - - private: - std::string FilePath; - std::atomic<LibState> S; - PathType K; - std::optional<BloomFilter> Filter; - mutable std::shared_mutex Mtx; - }; - - /// A read-only view of libraries filtered by state and kind. - /// - /// Lets you loop over only the libraries in a map that match a given State - /// and PathType. - class FilteredView { - public: - using Map = StringMap<std::shared_ptr<LibraryInfo>>; - using Iterator = typename Map::const_iterator; - class FilterIterator { - public: - FilterIterator(Iterator it_, Iterator end_, LibState S, PathType K) - : it(it_), end(end_), S(S), K(K) { - advance(); - } - - bool operator!=(const FilterIterator &other) const { - return it != other.it; - } - - const std::shared_ptr<LibraryInfo> &operator*() const { - return it->second; - } - - FilterIterator &operator++() { - ++it; - advance(); - return *this; - } - - private: - void advance() { - for (; it != end; ++it) - if (it->second->getState() == S && it->second->getKind() == K) - break; - } - Iterator it; - Iterator end; - LibState S; - PathType K; - }; - FilteredView(Iterator begin, Iterator end, LibState s, PathType k) - : mapBegin(begin), mapEnd(end), state(s), kind(k) {} - - FilterIterator begin() const { - return FilterIterator(mapBegin, mapEnd, state, kind); - } - - FilterIterator end() const { - return FilterIterator(mapEnd, mapEnd, state, kind); - } - - private: - Iterator mapBegin; - Iterator mapEnd; - LibState state; - PathType kind; - }; - -private: - StringMap<std::shared_ptr<LibraryInfo>> Libraries; - mutable std::shared_mutex Mtx; - -public: - using LibraryVisitor = std::function<bool(const LibraryInfo &)>; - - LibraryManager() = default; - ~LibraryManager() = default; - - bool addLibrary(std::string Path, PathType Kind, - std::optional<BloomFilter> Filter = std::nullopt) { - std::unique_lock<std::shared_mutex> Lock(Mtx); - if (Libraries.count(Path) > 0) - return false; - Libraries.insert({std::move(Path), - std::make_shared<LibraryInfo>(Path, LibState::Unloaded, - Kind, std::move(Filter))}); - return true; - } - - bool hasLibrary(StringRef Path) const { - std::shared_lock<std::shared_mutex> Lock(Mtx); - if (Libraries.count(Path) > 0) - return true; - return false; - } - - bool removeLibrary(StringRef Path) { - std::unique_lock<std::shared_mutex> Lock(Mtx); - auto I = Libraries.find(Path); - if (I == Libraries.end()) - return false; - Libraries.erase(I); - return true; - } - - void markLoaded(StringRef Path) { - std::unique_lock<std::shared_mutex> Lock(Mtx); - if (auto It = Libraries.find(Path); It != Libraries.end()) - It->second->setState(LibState::Loaded); - } - - void markQueried(StringRef Path) { - std::unique_lock<std::shared_mutex> Lock(Mtx); - if (auto It = Libraries.find(Path); It != Libraries.end()) - It->second->setState(LibState::Queried); - } - - std::shared_ptr<LibraryInfo> getLibrary(StringRef Path) { - std::shared_lock<std::shared_mutex> Lock(Mtx); - if (auto It = Libraries.find(Path); It != Libraries.end()) - return It->second; - return nullptr; - } - - FilteredView getView(LibState S, PathType K) const { - std::shared_lock<std::shared_mutex> Lock(Mtx); - return FilteredView(Libraries.begin(), Libraries.end(), S, K); - } - - void forEachLibrary(const LibraryVisitor &visitor) const { - std::unique_lock<std::shared_mutex> Lock(Mtx); - for (const auto &[_, entry] : Libraries) { - if (!visitor(*entry)) - break; - } - } - - bool isLoaded(StringRef Path) const { - std::unique_lock<std::shared_mutex> Lock(Mtx); - if (auto It = Libraries.find(Path.str()); It != Libraries.end()) - return It->second->getState() == LibState::Loaded; - return false; - } - - bool isQueried(StringRef Path) const { - std::unique_lock<std::shared_mutex> Lock(Mtx); - if (auto It = Libraries.find(Path.str()); It != Libraries.end()) - return It->second->getState() == LibState::Queried; - return false; - } - - void clear() { - std::unique_lock<std::shared_mutex> Lock(Mtx); - Libraries.clear(); - } -}; - -using LibraryInfo = LibraryManager::LibraryInfo; - -struct SearchPlanEntry { - LibraryManager::LibState State; // Loaded, Queried, Unloaded - PathType Type; // User, System -}; - -struct SearchPolicy { - std::vector<SearchPlanEntry> Plan; - - static SearchPolicy defaultPlan() { - return {{{LibraryManager::LibState::Loaded, PathType::User}, - {LibraryManager::LibState::Queried, PathType::User}, - {LibraryManager::LibState::Unloaded, PathType::User}, - {LibraryManager::LibState::Loaded, PathType::System}, - {LibraryManager::LibState::Queried, PathType::System}, - {LibraryManager::LibState::Unloaded, PathType::System}}}; - } -}; - -struct SymbolEnumeratorOptions { - enum Filter : uint32_t { - None = 0, - IgnoreUndefined = 1 << 0, - IgnoreWeak = 1 << 1, - IgnoreIndirect = 1 << 2, - IgnoreHidden = 1 << 3, - IgnoreNonGlobal = 1 << 4 - }; - - static SymbolEnumeratorOptions defaultOptions() { - return {Filter::IgnoreUndefined | Filter::IgnoreWeak | - Filter::IgnoreIndirect}; - } - uint32_t FilterFlags = Filter::None; -}; - -struct SearchConfig { - SearchPolicy Policy; - SymbolEnumeratorOptions Options; - - SearchConfig() - : Policy(SearchPolicy::defaultPlan()), // default plan - Options(SymbolEnumeratorOptions::defaultOptions()) {} -}; - -/// Scans libraries and resolves Symbols across user and system paths. -/// -/// Supports symbol enumeration and filtering via SymbolEnumerator, and tracks -/// symbol resolution results through SymbolQuery. Thread-safe and uses -/// LibraryScanHelper for efficient path resolution and caching. -class LibraryResolver { - friend class LibraryResolutionDriver; - -public: - class SymbolEnumerator { - public: - enum class EnumerateResult { Continue, Stop, Error }; - - using OnEachSymbolFn = std::function<EnumerateResult(StringRef Sym)>; - - static bool enumerateSymbols(StringRef Path, OnEachSymbolFn OnEach, - const SymbolEnumeratorOptions &Opts); - }; - - /// Tracks a set of symbols and the libraries where they are resolved. - /// - /// SymbolQuery is used to keep track of which symbols have been resolved - /// to which libraries. It supports concurrent read/write access using a - /// shared mutex, allowing multiple readers or a single writer at a time. - class SymbolQuery { - public: - /// Holds the result for a single symbol. - struct Result { - std::string Name; - std::string ResolvedLibPath; - }; - - private: - mutable std::shared_mutex Mtx; - StringMap<Result> Results; - std::atomic<size_t> ResolvedCount = 0; - - public: - explicit SymbolQuery(const std::vector<std::string> &Symbols) { - for (const auto &s : Symbols) { - if (!Results.contains(s)) - Results.insert({s, Result{s, ""}}); - } - } - - SmallVector<StringRef> getUnresolvedSymbols() const { - SmallVector<StringRef> Unresolved; - std::shared_lock<std::shared_mutex> Lock(Mtx); - for (const auto &[name, res] : Results) { - if (res.ResolvedLibPath.empty()) - Unresolved.push_back(name); - } - return Unresolved; - } - - void resolve(StringRef Sym, const std::string &LibPath) { - std::unique_lock<std::shared_mutex> Lock(Mtx); - auto It = Results.find(Sym); - if (It != Results.end() && It->second.ResolvedLibPath.empty()) { - It->second.ResolvedLibPath = LibPath; - ResolvedCount.fetch_add(1, std::memory_order_relaxed); - } - } - - bool allResolved() const { - return ResolvedCount.load(std::memory_order_relaxed) == Results.size(); - } - - bool hasUnresolved() const { - return ResolvedCount.load(std::memory_order_relaxed) < Results.size(); - } - - std::optional<StringRef> getResolvedLib(StringRef Sym) const { - std::shared_lock<std::shared_mutex> Lock(Mtx); - auto It = Results.find(Sym); - if (It != Results.end() && !It->second.ResolvedLibPath.empty()) - return StringRef(It->second.ResolvedLibPath); - return std::nullopt; - } - - bool isResolved(StringRef Sym) const { - std::shared_lock<std::shared_mutex> Lock(Mtx); - auto It = Results.find(Sym.str()); - return It != Results.end() && !It->second.ResolvedLibPath.empty(); - } - - std::vector<const Result *> getAllResults() const { - std::shared_lock<std::shared_mutex> Lock(Mtx); - std::vector<const Result *> Out; - Out.reserve(Results.size()); - for (const auto &[_, res] : Results) - Out.push_back(&res); - return Out; - } - }; - - struct Setup { - std::vector<std::string> BasePaths; - std::shared_ptr<LibraryPathCache> Cache; - std::shared_ptr<PathResolver> PResolver; - - size_t ScanBatchSize = 0; - - LibraryScanner::ShouldScanFn ShouldScanCall = [](StringRef) { - return true; - }; - - BloomFilterBuilder FilterBuilder = BloomFilterBuilder(); - - static Setup - create(std::vector<std::string> BasePaths, - std::shared_ptr<LibraryPathCache> existingCache = nullptr, - std::shared_ptr<PathResolver> existingResolver = nullptr, - LibraryScanner::ShouldScanFn customShouldScan = nullptr) { - Setup S; - S.BasePaths = std::move(BasePaths); - - S.Cache = - existingCache ? existingCache : std::make_shared<LibraryPathCache>(); - - S.PResolver = existingResolver ? existingResolver - : std::make_shared<PathResolver>(S.Cache); - - if (customShouldScan) - S.ShouldScanCall = std::move(customShouldScan); - - return S; - } - }; - - LibraryResolver() = delete; - explicit LibraryResolver(const Setup &S); - ~LibraryResolver() = default; - - using OnSearchComplete = unique_function<void(SymbolQuery &)>; - - void dump() { - int i = 0; - LibMgr.forEachLibrary([&](const LibraryInfo &Lib) -> bool { - dbgs() << ++i << ". Library Path : " << Lib.getFullPath() << " -> \n\t\t:" - << " ({Type : (" - << (Lib.getKind() == PathType::User ? "User" : "System") - << ") }, { State : " - << (Lib.getState() == LibraryManager::LibState::Loaded - ? "Loaded" - : "Unloaded") - << "})\n"; - return true; - }); - } - - void searchSymbolsInLibraries(std::vector<std::string> &SymList, - OnSearchComplete OnComplete, - const SearchConfig &Config = SearchConfig()); - -private: - bool scanLibrariesIfNeeded(PathType K, size_t BatchSize = 0); - void resolveSymbolsInLibrary(LibraryInfo &Lib, SymbolQuery &Q, - const SymbolEnumeratorOptions &Opts); - bool - symbolExistsInLibrary(const LibraryInfo &Lib, StringRef Sym, - std::vector<std::string> *MatchedSymbols = nullptr); - - bool symbolExistsInLibrary(const LibraryInfo &Lib, StringRef SymName, - std::vector<std::string> *AllSymbols, - const SymbolEnumeratorOptions &Opts); - - std::shared_ptr<LibraryPathCache> LibPathCache; - std::shared_ptr<PathResolver> LibPathResolver; - LibraryScanHelper ScanHelper; - BloomFilterBuilder FB; - LibraryManager LibMgr; - LibraryScanner::ShouldScanFn ShouldScanCall; - size_t scanBatchSize; -}; - -using SymbolEnumerator = LibraryResolver::SymbolEnumerator; -using SymbolQuery = LibraryResolver::SymbolQuery; -using EnumerateResult = SymbolEnumerator::EnumerateResult; - -class LibraryResolutionDriver { -public: - static std::unique_ptr<LibraryResolutionDriver> - create(const LibraryResolver::Setup &S); - - void addScanPath(const std::string &Path, PathType Kind); - bool markLibraryLoaded(StringRef Path); - bool markLibraryUnLoaded(StringRef Path); - bool isLibraryLoaded(StringRef Path) const { - return LR->LibMgr.isLoaded(Path); - } - - void resetAll() { - LR->LibMgr.clear(); - LR->ScanHelper.resetToScan(); - LR->LibPathCache->clear(); - } - - void scanAll(size_t BatchSize = 0) { - LR->scanLibrariesIfNeeded(PathType::User, BatchSize); - LR->scanLibrariesIfNeeded(PathType::System, BatchSize); - } - - void scan(PathType PK, size_t BatchSize = 0) { - LR->scanLibrariesIfNeeded(PK, BatchSize); - } - - void resolveSymbols(std::vector<std::string> Symbols, - LibraryResolver::OnSearchComplete OnCompletion, - const SearchConfig &Config = SearchConfig()); - - ~LibraryResolutionDriver() = default; - -private: - LibraryResolutionDriver(std::unique_ptr<LibraryResolver> L) - : LR(std::move(L)) {} - - std::unique_ptr<LibraryResolver> LR; -}; - -} // end namespace orc -} // end namespace llvm - -#endif // LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_LIBRARYRESOLVER_H diff --git a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h deleted file mode 100644 index d1c2013..0000000 --- a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h +++ /dev/null @@ -1,474 +0,0 @@ -//===- LibraryScanner.h - Scanner for Shared Libraries ---------*- C++ -*-===// -// -// 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 -// -//===----------------------------------------------------------------------===// -// -// This file provides functionality for scanning dynamic (shared) libraries. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_LIBRARYSCANNER_H -#define LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_LIBRARYSCANNER_H - -#include "llvm/ADT/FunctionExtras.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/StringSet.h" -#include "llvm/Object/ObjectFile.h" -#include "llvm/Support/Allocator.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/StringSaver.h" - -#include <atomic> -#include <mutex> -#include <queue> -#include <shared_mutex> -#include <string> -#include <unordered_map> -#include <unordered_set> - -namespace llvm { -namespace orc { - -class LibraryManager; - -class LibraryPathCache { - friend class PathResolver; - -public: - LibraryPathCache() = default; - - void clear(bool isRealPathCache = false) { - std::unique_lock<std::shared_mutex> lock(Mtx); - Seen.clear(); - if (isRealPathCache) { - RealPathCache.clear(); -#ifndef _WIN32 - ReadlinkCache.clear(); - LstatCache.clear(); -#endif - } - } - - void markSeen(const std::string &CanonPath) { - std::unique_lock<std::shared_mutex> lock(Mtx); - Seen.insert(CanonPath); - } - - bool hasSeen(StringRef CanonPath) const { - std::shared_lock<std::shared_mutex> lock(Mtx); - return Seen.contains(CanonPath); - } - - bool hasSeenOrMark(StringRef CanonPath) { - std::string s = CanonPath.str(); - { - std::shared_lock<std::shared_mutex> lock(Mtx); - if (Seen.contains(s)) - return true; - } - { - std::unique_lock<std::shared_mutex> lock(Mtx); - Seen.insert(s); - } - return false; - } - -private: - mutable std::shared_mutex Mtx; - - struct PathInfo { - std::string canonicalPath; - std::error_code ErrnoCode; - }; - - void insert_realpath(StringRef Path, const PathInfo &Info) { - std::unique_lock<std::shared_mutex> lock(Mtx); - RealPathCache.insert({Path, Info}); - } - - std::optional<PathInfo> read_realpath(StringRef Path) const { - std::shared_lock<std::shared_mutex> lock(Mtx); - auto It = RealPathCache.find(Path); - if (It != RealPathCache.end()) - return It->second; - - return std::nullopt; - } - - StringSet<> Seen; - StringMap<PathInfo> RealPathCache; - -#ifndef _WIN32 - StringMap<std::string> ReadlinkCache; - StringMap<mode_t> LstatCache; - - void insert_link(StringRef Path, const std::string &s) { - std::unique_lock<std::shared_mutex> lock(Mtx); - ReadlinkCache.insert({Path, s}); - } - - std::optional<std::string> read_link(StringRef Path) const { - std::shared_lock<std::shared_mutex> lock(Mtx); - auto It = ReadlinkCache.find(Path); - if (It != ReadlinkCache.end()) - return It->second; - - return std::nullopt; - } - - void insert_lstat(StringRef Path, mode_t m) { - std::unique_lock<std::shared_mutex> lock(Mtx); - LstatCache.insert({Path, m}); - } - - std::optional<mode_t> read_lstat(StringRef Path) const { - std::shared_lock<std::shared_mutex> lock(Mtx); - auto It = LstatCache.find(Path); - if (It != LstatCache.end()) - return It->second; - - return std::nullopt; - } - -#endif -}; - -/// Resolves file system paths with optional caching of results. -/// -/// Supports lstat, readlink, and realpath operations. Can resolve paths -/// relative to a base and handle symbolic links. Caches results to reduce -/// repeated system calls when enabled. -class PathResolver { -private: - std::shared_ptr<LibraryPathCache> LibPathCache; - -public: - PathResolver(std::shared_ptr<LibraryPathCache> cache) - : LibPathCache(std::move(cache)) {} - - std::optional<std::string> resolve(StringRef Path, std::error_code &ec) { - return realpathCached(Path, ec); - } -#ifndef _WIN32 - mode_t lstatCached(StringRef Path); - std::optional<std::string> readlinkCached(StringRef Path); -#endif - std::optional<std::string> realpathCached(StringRef Path, std::error_code &ec, - StringRef base = "", - bool baseIsResolved = false, - long symloopLevel = 40); -}; - -/// Performs placeholder substitution in dynamic library paths. -/// -/// Configures known placeholders (like @loader_path) and replaces them -/// in input paths with their resolved values. -class DylibSubstitutor { -public: - void configure(StringRef loaderPath); - - std::string substitute(StringRef input) const { - for (const auto &[ph, value] : Placeholders) { - if (input.starts_with_insensitive(ph)) - return (Twine(value) + input.drop_front(ph.size())).str(); - } - return input.str(); - } - -private: - StringMap<std::string> Placeholders; -}; - -/// Validates and normalizes dynamic library paths. -/// -/// Uses a `PathResolver` to resolve paths to their canonical form and -/// checks whether they point to valid shared libraries. -class DylibPathValidator { -public: - DylibPathValidator(PathResolver &PR) : LibPathResolver(PR) {} - - static bool isSharedLibrary(StringRef Path); - - std::optional<std::string> normalize(StringRef Path) const { - std::error_code ec; - auto real = LibPathResolver.resolve(Path, ec); - if (!real || ec) - return std::nullopt; - - return real; - } - - /// Validate the given path as a shared library. - std::optional<std::string> validate(StringRef Path) const { - auto realOpt = normalize(Path); - if (!realOpt) - return std::nullopt; - - if (!isSharedLibrary(*realOpt)) - return std::nullopt; - - return realOpt; - } - -private: - PathResolver &LibPathResolver; -}; - -enum class SearchPathType { - RPath, - UsrOrSys, - RunPath, -}; - -struct SearchPathConfig { - ArrayRef<StringRef> Paths; - SearchPathType type; -}; - -class SearchPathResolver { -public: - SearchPathResolver(const SearchPathConfig &Cfg, - StringRef PlaceholderPrefix = "") - : Kind(Cfg.type), PlaceholderPrefix(PlaceholderPrefix) { - for (auto &path : Cfg.Paths) - Paths.emplace_back(path.str()); - } - - std::optional<std::string> resolve(StringRef libStem, - const DylibSubstitutor &Subst, - DylibPathValidator &Validator) const; - SearchPathType searchPathType() const { return Kind; } - -private: - std::vector<std::string> Paths; - SearchPathType Kind; - std::string PlaceholderPrefix; -}; - -class DylibResolverImpl { -public: - DylibResolverImpl(DylibSubstitutor Substitutor, DylibPathValidator &Validator, - std::vector<SearchPathResolver> Resolvers) - : Substitutor(std::move(Substitutor)), Validator(Validator), - Resolvers(std::move(Resolvers)) {} - - std::optional<std::string> resolve(StringRef Stem, - bool VariateLibStem = false) const; - -private: - std::optional<std::string> tryWithExtensions(StringRef libstem) const; - - DylibSubstitutor Substitutor; - DylibPathValidator &Validator; - std::vector<SearchPathResolver> Resolvers; -}; - -class DylibResolver { -public: - DylibResolver(DylibPathValidator &Validator) : Validator(Validator) {} - - void configure(StringRef loaderPath, - ArrayRef<SearchPathConfig> SearchPathCfg) { - DylibSubstitutor Substitutor; - Substitutor.configure(loaderPath); - - std::vector<SearchPathResolver> Resolvers; - for (const auto &cfg : SearchPathCfg) { - Resolvers.emplace_back(cfg, - cfg.type == SearchPathType::RPath ? "@rpath" : ""); - } - - impl_ = std::make_unique<DylibResolverImpl>( - std::move(Substitutor), Validator, std::move(Resolvers)); - } - - std::optional<std::string> resolve(StringRef libStem, - bool VariateLibStem = false) const { - if (!impl_) - return std::nullopt; - return impl_->resolve(libStem, VariateLibStem); - } - - static std::string resolvelinkerFlag(StringRef libStem, - StringRef loaderPath) { - DylibSubstitutor Substitutor; - Substitutor.configure(loaderPath); - return Substitutor.substitute(libStem); - } - -private: - DylibPathValidator &Validator; - std::unique_ptr<DylibResolverImpl> impl_; -}; - -enum class PathType : uint8_t { User, System, Unknown }; - -enum class ScanState : uint8_t { NotScanned, Scanning, Scanned }; - -struct LibrarySearchPath { - std::string BasePath; // Canonical base directory path - PathType Kind; // User or System - std::atomic<ScanState> State; - - LibrarySearchPath(std::string Base, PathType K) - : BasePath(std::move(Base)), Kind(K), State(ScanState::NotScanned) {} -}; - -/// Scans and tracks libraries for symbol resolution. -/// -/// Maintains a list of library paths to scan, caches scanned units, -/// and resolves paths canonically for consistent tracking. -class LibraryScanHelper { -public: - explicit LibraryScanHelper(const std::vector<std::string> &SPaths, - std::shared_ptr<LibraryPathCache> LibPathCache, - std::shared_ptr<PathResolver> LibPathResolver) - : LibPathCache(std::move(LibPathCache)), - LibPathResolver(std::move(LibPathResolver)) { - DEBUG_WITH_TYPE( - "orc", dbgs() << "LibraryScanHelper::LibraryScanHelper: base paths : " - << SPaths.size() << "\n";); - for (const auto &p : SPaths) - addBasePath(p); - } - - void - addBasePath(const std::string &P, - PathType Kind = - PathType::Unknown); // Add a canonical directory for scanning - std::vector<std::shared_ptr<LibrarySearchPath>> - getNextBatch(PathType Kind, size_t batchSize); - - bool leftToScan(PathType K) const; - void resetToScan(); - - bool isTrackedBasePath(StringRef P) const; - std::vector<std::shared_ptr<LibrarySearchPath>> getAllUnits() const; - - SmallVector<StringRef> getSearchPaths() const { - SmallVector<StringRef> SearchPaths; - for (const auto &[_, SP] : LibSearchPaths) - SearchPaths.push_back(SP->BasePath); - return SearchPaths; - } - - PathResolver &getPathResolver() const { return *LibPathResolver; } - - LibraryPathCache &getCache() const { return *LibPathCache; } - - bool hasSeenOrMark(StringRef P) const { - return LibPathCache->hasSeenOrMark(P); - } - - std::optional<std::string> resolve(StringRef P, std::error_code &ec) const { - return LibPathResolver->resolve(P.str(), ec); - } - -private: - std::string resolveCanonical(StringRef P, std::error_code &ec) const; - PathType classifyKind(StringRef P) const; - - mutable std::shared_mutex Mtx; - std::shared_ptr<LibraryPathCache> LibPathCache; - std::shared_ptr<PathResolver> LibPathResolver; - - StringMap<std::shared_ptr<LibrarySearchPath>> - LibSearchPaths; // key: canonical path - std::deque<StringRef> UnscannedUsr; - std::deque<StringRef> UnscannedSys; -}; - -/// Loads an object file and provides access to it. -/// -/// Owns the underlying `ObjectFile` and ensures it is valid. -/// Any errors encountered during construction are stored and -/// returned when attempting to access the file. -class ObjectFileLoader { -public: - /// Construct an object file loader from the given path. - explicit ObjectFileLoader(StringRef Path) { - auto ObjOrErr = loadObjectFileWithOwnership(Path); - if (ObjOrErr) - Obj = std::move(*ObjOrErr); - else { - consumeError(std::move(Err)); - Err = ObjOrErr.takeError(); - } - } - - ObjectFileLoader(const ObjectFileLoader &) = delete; - ObjectFileLoader &operator=(const ObjectFileLoader &) = delete; - - ObjectFileLoader(ObjectFileLoader &&) = default; - ObjectFileLoader &operator=(ObjectFileLoader &&) = default; - - /// Get the loaded object file, or return an error if loading failed. - Expected<object::ObjectFile &> getObjectFile() { - if (Err) - return std::move(Err); - return *Obj.getBinary(); - } - - static bool isArchitectureCompatible(const object::ObjectFile &Obj); - -private: - object::OwningBinary<object::ObjectFile> Obj; - Error Err = Error::success(); - - static Expected<object::OwningBinary<object::ObjectFile>> - loadObjectFileWithOwnership(StringRef FilePath); -}; - -/// Scans libraries, resolves dependencies, and registers them. -class LibraryScanner { -public: - using ShouldScanFn = std::function<bool(StringRef)>; - - LibraryScanner( - LibraryScanHelper &H, LibraryManager &LibMgr, - ShouldScanFn ShouldScanCall = [](StringRef path) { return true; }) - : ScanHelper(H), LibMgr(LibMgr), - ShouldScanCall(std::move(ShouldScanCall)) {} - - void scanNext(PathType Kind, size_t batchSize = 1); - - /// Dependency info for a library. - struct LibraryDepsInfo { - llvm::BumpPtrAllocator Alloc; - llvm::StringSaver Saver{Alloc}; - - SmallVector<StringRef, 2> rpath; - SmallVector<StringRef, 2> runPath; - SmallVector<StringRef, 4> deps; - bool isPIE = false; - - void addRPath(StringRef s) { rpath.push_back(Saver.save(s)); } - - void addRunPath(StringRef s) { runPath.push_back(Saver.save(s)); } - - void addDep(StringRef s) { deps.push_back(Saver.save(s)); } - }; - -private: - LibraryScanHelper &ScanHelper; - LibraryManager &LibMgr; - ShouldScanFn ShouldScanCall; - - std::optional<std::string> shouldScan(StringRef FilePath); - Expected<LibraryDepsInfo> extractDeps(StringRef FilePath); - - void handleLibrary(StringRef P, PathType K, int level = 1); - - void scanBaseDir(std::shared_ptr<LibrarySearchPath> U); -}; - -using LibraryDepsInfo = LibraryScanner::LibraryDepsInfo; - -} // end namespace orc -} // end namespace llvm - -#endif // LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_LIBRARYSCANNER_H diff --git a/llvm/include/llvm/Support/SpecialCaseList.h b/llvm/include/llvm/Support/SpecialCaseList.h index ead7655..a235975 100644 --- a/llvm/include/llvm/Support/SpecialCaseList.h +++ b/llvm/include/llvm/Support/SpecialCaseList.h @@ -13,7 +13,10 @@ #define LLVM_SUPPORT_SPECIALCASELIST_H #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/RadixTree.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" +#include "llvm/ADT/iterator_range.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/GlobPattern.h" @@ -162,6 +165,10 @@ private: }; std::vector<GlobMatcher::Glob> Globs; + + RadixTree<iterator_range<StringRef::const_iterator>, + SmallVector<const GlobMatcher::Glob *, 1>> + PrefixToGlob; }; /// Represents a set of patterns and their line numbers |
