1 //===- llvm/TextAPI/SymbolSet.h - TAPI Symbol Set --------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef LLVM_TEXTAPI_SYMBOLSET_H
10 #define LLVM_TEXTAPI_SYMBOLSET_H
11 
12 #include "llvm/ADT/DenseMap.h"
13 #include "llvm/ADT/Hashing.h"
14 #include "llvm/ADT/StringRef.h"
15 #include "llvm/ADT/iterator.h"
16 #include "llvm/ADT/iterator_range.h"
17 #include "llvm/Support/Allocator.h"
18 #include "llvm/TextAPI/Architecture.h"
19 #include "llvm/TextAPI/ArchitectureSet.h"
20 #include "llvm/TextAPI/Symbol.h"
21 #include <stddef.h>
22 
23 namespace llvm {
24 
25 struct SymbolsMapKey {
26   MachO::SymbolKind Kind;
27   StringRef Name;
28 
SymbolsMapKeySymbolsMapKey29   SymbolsMapKey(MachO::SymbolKind Kind, StringRef Name)
30       : Kind(Kind), Name(Name) {}
31 };
32 template <> struct DenseMapInfo<SymbolsMapKey> {
33   static inline SymbolsMapKey getEmptyKey() {
34     return SymbolsMapKey(MachO::SymbolKind::GlobalSymbol, StringRef{});
35   }
36 
37   static inline SymbolsMapKey getTombstoneKey() {
38     return SymbolsMapKey(MachO::SymbolKind::ObjectiveCInstanceVariable,
39                          StringRef{});
40   }
41 
42   static unsigned getHashValue(const SymbolsMapKey &Key) {
43     return hash_combine(hash_value(Key.Kind), hash_value(Key.Name));
44   }
45 
46   static bool isEqual(const SymbolsMapKey &LHS, const SymbolsMapKey &RHS) {
47     return std::tie(LHS.Kind, LHS.Name) == std::tie(RHS.Kind, RHS.Name);
48   }
49 };
50 
51 template <typename DerivedT, typename KeyInfoT, typename BucketT>
52 bool operator==(const DenseMapBase<DerivedT, SymbolsMapKey, MachO::Symbol *,
53                                    KeyInfoT, BucketT> &LHS,
54                 const DenseMapBase<DerivedT, SymbolsMapKey, MachO::Symbol *,
55                                    KeyInfoT, BucketT> &RHS) {
56   if (LHS.size() != RHS.size())
57     return false;
58   for (const auto &KV : LHS) {
59     auto I = RHS.find(KV.first);
60     if (I == RHS.end() || *I->second != *KV.second)
61       return false;
62   }
63   return true;
64 }
65 
66 template <typename DerivedT, typename KeyInfoT, typename BucketT>
67 bool operator!=(const DenseMapBase<DerivedT, SymbolsMapKey, MachO::Symbol *,
68                                    KeyInfoT, BucketT> &LHS,
69                 const DenseMapBase<DerivedT, SymbolsMapKey, MachO::Symbol *,
70                                    KeyInfoT, BucketT> &RHS) {
71   return !(LHS == RHS);
72 }
73 
74 namespace MachO {
75 
76 class SymbolSet {
77 private:
78   llvm::BumpPtrAllocator Allocator;
79   StringRef copyString(StringRef String) {
80     if (String.empty())
81       return {};
82     void *Ptr = Allocator.Allocate(String.size(), 1);
83     memcpy(Ptr, String.data(), String.size());
84     return StringRef(reinterpret_cast<const char *>(Ptr), String.size());
85   }
86 
87   using SymbolsMapType = llvm::DenseMap<SymbolsMapKey, Symbol *>;
88   SymbolsMapType Symbols;
89 
90   Symbol *addGlobalImpl(SymbolKind, StringRef Name, SymbolFlags Flags);
91 
92 public:
93   SymbolSet() = default;
94   Symbol *addGlobal(SymbolKind Kind, StringRef Name, SymbolFlags Flags,
95                     const Target &Targ);
96   size_t size() const { return Symbols.size(); }
97 
98   template <typename RangeT, typename ElT = std::remove_reference_t<
99                                  decltype(*std::begin(std::declval<RangeT>()))>>
100   Symbol *addGlobal(SymbolKind Kind, StringRef Name, SymbolFlags Flags,
101                     RangeT &&Targets) {
102     auto *Global = addGlobalImpl(Kind, Name, Flags);
103     for (const auto &Targ : Targets)
104       Global->addTarget(Targ);
105     if (Kind == SymbolKind::ObjectiveCClassEHType)
106       addGlobal(SymbolKind::ObjectiveCClass, Name, Flags, Targets);
107     return Global;
108   }
109 
110   const Symbol *findSymbol(SymbolKind Kind, StringRef Name) const;
111 
112   struct const_symbol_iterator
113       : public iterator_adaptor_base<
114             const_symbol_iterator, SymbolsMapType::const_iterator,
115             std::forward_iterator_tag, const Symbol *, ptrdiff_t,
116             const Symbol *, const Symbol *> {
117     const_symbol_iterator() = default;
118 
119     template <typename U>
120     const_symbol_iterator(U &&u)
121         : iterator_adaptor_base(std::forward<U &&>(u)) {}
122 
123     reference operator*() const { return I->second; }
124     pointer operator->() const { return I->second; }
125   };
126 
127   using const_symbol_range = iterator_range<const_symbol_iterator>;
128 
129   using const_filtered_symbol_iterator =
130       filter_iterator<const_symbol_iterator,
131                       std::function<bool(const Symbol *)>>;
132   using const_filtered_symbol_range =
133       iterator_range<const_filtered_symbol_iterator>;
134 
135   // Range that contains all symbols.
136   const_symbol_range symbols() const {
137     return {Symbols.begin(), Symbols.end()};
138   }
139 
140   // Range that contains all defined and exported symbols.
141   const_filtered_symbol_range exports() const {
142     std::function<bool(const Symbol *)> fn = [](const Symbol *Symbol) {
143       return !Symbol->isUndefined() && !Symbol->isReexported();
144     };
145     return make_filter_range(
146         make_range<const_symbol_iterator>({Symbols.begin()}, {Symbols.end()}),
147         fn);
148   }
149 
150   // Range that contains all reexported symbols.
151   const_filtered_symbol_range reexports() const {
152     std::function<bool(const Symbol *)> fn = [](const Symbol *Symbol) {
153       return Symbol->isReexported();
154     };
155     return make_filter_range(
156         make_range<const_symbol_iterator>({Symbols.begin()}, {Symbols.end()}),
157         fn);
158   }
159 
160   // Range that contains all undefined and exported symbols.
161   const_filtered_symbol_range undefineds() const {
162     std::function<bool(const Symbol *)> fn = [](const Symbol *Symbol) {
163       return Symbol->isUndefined();
164     };
165     return make_filter_range(
166         make_range<const_symbol_iterator>({Symbols.begin()}, {Symbols.end()}),
167         fn);
168   }
169 
170   bool operator==(const SymbolSet &O) const;
171 
172   bool operator!=(const SymbolSet &O) const { return !(Symbols == O.Symbols); }
173 
174   void *allocate(size_t Size, unsigned Align = 8) {
175     return Allocator.Allocate(Size, Align);
176   }
177 };
178 
179 } // namespace MachO
180 } // namespace llvm
181 #endif // LLVM_TEXTAPI_SYMBOLSET_H
182