LLVM 19.0.0git
RecordsSlice.cpp
Go to the documentation of this file.
1//===- RecordsSlice.cpp --------------------------------------------------===//
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// Implements the Records Slice APIs.
10//
11//===----------------------------------------------------------------------===//
12
14#include "llvm/ADT/SetVector.h"
16#include "llvm/TextAPI/Record.h"
17#include "llvm/TextAPI/Symbol.h"
18#include <utility>
19
20using namespace llvm;
21using namespace llvm::MachO;
22
25 // Find a specific Record type to capture.
26 auto [APIName, SymKind, InterfaceType] = parseSymbol(Name);
27 Name = APIName;
28 switch (SymKind) {
30 return addGlobal(Name, Linkage, GV, Flags);
32 return addObjCInterface(Name, Linkage, InterfaceType);
34 ObjCInterfaceRecord *Rec = addObjCInterface(Name, Linkage, InterfaceType);
35 // When classes without ehtype are used in try/catch blocks
36 // a weak-defined symbol is exported.
38 updateFlags(Rec, SymbolFlags::WeakDefined);
39 return Rec;
40 }
42 auto [Super, IVar] = Name.split('.');
43 // Attempt to find super class.
44 ObjCContainerRecord *Container = findContainer(/*isIVar=*/false, Super);
45 // If not found, create extension since there is no mapped class symbol.
46 if (Container == nullptr)
47 Container = addObjCCategory(Super, {});
48 return addObjCIVar(Container, IVar, Linkage);
49 }
50 }
51
52 llvm_unreachable("unexpected symbol kind when adding to Record Slice");
53}
54
56 StringRef Name) const {
57 StringRef Super = IsIVar ? Name.split('.').first : Name;
58 ObjCContainerRecord *Container = findObjCInterface(Super);
59 // Ivars can only exist with extensions, if they did not come from
60 // class.
61 if (Container == nullptr)
62 Container = findObjCCategory(Super, "");
63 return Container;
64}
65
66template <typename R, typename C = RecordMap<R>, typename K = StringRef>
67R *findRecord(K Key, const C &Container) {
68 const auto *Record = Container.find(Key);
69 if (Record == Container.end())
70 return nullptr;
71 return Record->second.get();
72}
73
75 GlobalRecord::Kind GV) const {
76 auto *Record = findRecord<GlobalRecord>(Name, Globals);
77 if (!Record)
78 return nullptr;
79
80 switch (GV) {
82 if (!Record->isVariable())
83 return nullptr;
84 break;
85 }
87 if (!Record->isFunction())
88 return nullptr;
89 break;
90 }
92 return Record;
93 }
94
95 return Record;
96}
97
100 assert(CurrType <= ObjCIFSymbolKind::EHType &&
101 "expected single ObjCIFSymbolKind enum value");
102 if (CurrType == ObjCIFSymbolKind::Class)
103 return Linkages.Class;
104
105 if (CurrType == ObjCIFSymbolKind::MetaClass)
106 return Linkages.MetaClass;
107
108 if (CurrType == ObjCIFSymbolKind::EHType)
109 return Linkages.EHType;
110
111 llvm_unreachable("unexpected ObjCIFSymbolKind");
112}
113
115 RecordLinkage Link) {
117 Linkages.Class = std::max(Link, Linkages.Class);
119 Linkages.MetaClass = std::max(Link, Linkages.MetaClass);
121 Linkages.EHType = std::max(Link, Linkages.EHType);
122
123 // Obj-C Classes represent multiple symbols that could have competing
124 // linkages, in this case assign the largest one, when querying the linkage of
125 // the record itself. This allows visitors pick whether they want to account
126 // for complete symbol information.
127 Linkage =
128 std::max(Linkages.Class, std::max(Linkages.MetaClass, Linkages.EHType));
129}
130
132 return findRecord<ObjCInterfaceRecord>(Name, Classes);
133}
134
136 StringRef Category) const {
137 return findRecord<ObjCCategoryRecord>(std::make_pair(ClassToExtend, Category),
138 Categories);
139}
140
142 return findRecord<ObjCIVarRecord>(IVar, IVars);
143}
144
146 StringRef Name) const {
147 // If scoped name, the name of the container is known.
148 if (IsScopedName) {
149 // IVar does not exist if there is not a container assigned to it.
150 auto *Container = findContainer(/*IsIVar=*/true, Name);
151 if (!Container)
152 return nullptr;
153
154 StringRef IVar = Name.substr(Name.find_first_of('.') + 1);
155 return Container->findObjCIVar(IVar);
156 }
157
158 // Otherwise traverse through containers and attempt to find IVar.
159 auto getIVar = [Name](auto &Records) -> ObjCIVarRecord * {
160 for (const auto &[_, Container] : Records) {
161 if (auto *IVarR = Container->findObjCIVar(Name))
162 return IVarR;
163 }
164 return nullptr;
165 };
166
167 if (auto *IVarRecord = getIVar(Classes))
168 return IVarRecord;
169
170 return getIVar(Categories);
171}
172
175 SymbolFlags Flags) {
177 Flags |= SymbolFlags::Text;
178 else if (GV == GlobalRecord::Kind::Variable)
179 Flags |= SymbolFlags::Data;
180
182 auto Result = Globals.insert({Name, nullptr});
183 if (Result.second)
184 Result.first->second =
185 std::make_unique<GlobalRecord>(Name, Linkage, Flags, GV);
186 else {
187 updateLinkage(Result.first->second.get(), Linkage);
188 updateFlags(Result.first->second.get(), Flags);
189 }
190 return Result.first->second.get();
191}
192
194 RecordLinkage Linkage,
195 ObjCIFSymbolKind SymType) {
197 auto Result = Classes.insert({Name, nullptr});
198 if (Result.second)
199 Result.first->second =
200 std::make_unique<ObjCInterfaceRecord>(Name, Linkage, SymType);
201 else
202 Result.first->second->updateLinkageForSymbols(SymType, Linkage);
203 return Result.first->second.get();
204}
205
206SymbolFlags Record::mergeFlags(SymbolFlags Flags, RecordLinkage Linkage) {
207 // Add Linkage properties into Flags.
208 switch (Linkage) {
211 return Flags;
214 return Flags;
215 default:
216 return Flags;
217 }
218}
219
221 auto Result = Categories.insert({Name, Record});
222 return Result.second;
223}
224
226 StringRef Category) {
227 Category = copyString(Category);
228
229 // Add owning record first into record slice.
230 auto Result =
231 Categories.insert({std::make_pair(ClassToExtend, Category), nullptr});
232 if (Result.second)
233 Result.first->second =
234 std::make_unique<ObjCCategoryRecord>(ClassToExtend, Category);
235
236 // Then add reference to it in in the class.
237 if (auto *ObjCClass = findObjCInterface(ClassToExtend))
238 ObjCClass->addObjCCategory(Result.first->second.get());
239
240 return Result.first->second.get();
241}
242
243std::vector<ObjCIVarRecord *> ObjCContainerRecord::getObjCIVars() const {
244 std::vector<ObjCIVarRecord *> Records;
245 llvm::for_each(IVars,
246 [&](auto &Record) { Records.push_back(Record.second.get()); });
247 return Records;
248}
249
250std::vector<ObjCCategoryRecord *>
252 std::vector<ObjCCategoryRecord *> Records;
253 llvm::for_each(Categories,
254 [&](auto &Record) { Records.push_back(Record.second); });
255 return Records;
256}
257
259 RecordLinkage Linkage) {
260 auto Result = IVars.insert({IVar, nullptr});
261 if (Result.second)
262 Result.first->second = std::make_unique<ObjCIVarRecord>(IVar, Linkage);
263 return Result.first->second.get();
264}
265
268 RecordLinkage Linkage) {
270 ObjCIVarRecord *Record = Container->addObjCIVar(Name, Linkage);
271 updateLinkage(Record, Linkage);
272 return Record;
273}
274
276 if (String.empty())
277 return {};
278
279 if (StringAllocator.identifyObject(String.data()))
280 return String;
281
282 void *Ptr = StringAllocator.Allocate(String.size(), 1);
283 memcpy(Ptr, String.data(), String.size());
284 return StringRef(reinterpret_cast<const char *>(Ptr), String.size());
285}
286
288 if (!hasBinaryAttrs())
289 BA = std::make_unique<BinaryAttrs>();
290 return *BA;
291}
292
294 for (auto &G : Globals)
295 V.visitGlobal(*G.second);
296 for (auto &C : Classes)
297 V.visitObjCInterface(*C.second);
298 for (auto &Cat : Categories)
299 V.visitObjCCategory(*Cat.second);
300}
301
302static std::unique_ptr<InterfaceFile>
303createInterfaceFile(const Records &Slices, StringRef InstallName) {
304 // Pickup symbols first.
305 auto Symbols = std::make_unique<SymbolSet>();
306 for (auto &S : Slices) {
307 if (S->empty())
308 continue;
309 auto &BA = S->getBinaryAttrs();
310 if (BA.InstallName != InstallName)
311 continue;
312
313 SymbolConverter Converter(Symbols.get(), S->getTarget(),
314 !BA.TwoLevelNamespace);
315 S->visit(Converter);
316 }
317
318 auto File = std::make_unique<InterfaceFile>(std::move(Symbols));
319 File->setInstallName(InstallName);
320 // Assign other attributes.
321 for (auto &S : Slices) {
322 if (S->empty())
323 continue;
324 auto &BA = S->getBinaryAttrs();
325 if (BA.InstallName != InstallName)
326 continue;
327 const Target &Targ = S->getTarget();
328 File->addTarget(Targ);
329 File->setFromBinaryAttrs(BA, Targ);
330 }
331
332 return File;
333}
334
335std::unique_ptr<InterfaceFile>
337 std::unique_ptr<InterfaceFile> File;
338 if (Slices.empty())
339 return File;
340
341 SetVector<StringRef> InstallNames;
342 for (auto &S : Slices) {
343 auto Name = S->getBinaryAttrs().InstallName;
344 if (Name.empty())
345 continue;
346 InstallNames.insert(Name);
347 }
348
349 File = createInterfaceFile(Slices, *InstallNames.begin());
350 for (StringRef IN : llvm::drop_begin(InstallNames))
351 File->addDocument(createInterfaceFile(Slices, IN));
352
353 return File;
354}
std::string Name
Early If Converter
#define _
#define G(x, y, z)
Definition: MD5.cpp:56
static std::unique_ptr< InterfaceFile > createInterfaceFile(const Records &Slices, StringRef InstallName)
R * findRecord(K Key, const C &Container)
Implements the TAPI Record Collection Type.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file implements a set that has insertion order iteration characteristics.
Implements the TAPI Record Types.
std::optional< int64_t > identifyObject(const void *Ptr)
Definition: Allocator.h:232
LLVM_ATTRIBUTE_RETURNS_NONNULL void * Allocate(size_t Size, Align Alignment)
Allocate space at the specified alignment.
Definition: Allocator.h:148
ObjCIVarRecord * addObjCIVar(StringRef IVar, RecordLinkage Linkage)
ObjCIVarRecord * findObjCIVar(StringRef IVar) const
std::vector< ObjCIVarRecord * > getObjCIVars() const
RecordLinkage getLinkageForSymbol(ObjCIFSymbolKind CurrType) const
std::vector< ObjCCategoryRecord * > getObjCCategories() const
bool addObjCCategory(ObjCCategoryRecord *Record)
void updateLinkageForSymbols(ObjCIFSymbolKind SymType, RecordLinkage Link)
Base class for any usage of traversing over collected Records.
Definition: RecordVisitor.h:23
Define Record.
Definition: Record.h:50
RecordLinkage Linkage
Definition: Record.h:90
StringRef Name
Definition: Record.h:89
SymbolFlags Flags
Definition: Record.h:91
GlobalRecord * addGlobal(StringRef Name, RecordLinkage Linkage, GlobalRecord::Kind GV, SymbolFlags Flags=SymbolFlags::None)
Add non-ObjC global record.
StringRef copyString(StringRef String)
Store any strings owned by RecordSlice into allocator and return back reference to that.
ObjCIVarRecord * findObjCIVar(bool IsScopedName, StringRef Name) const
Find ObjC instance variable.
ObjCCategoryRecord * addObjCCategory(StringRef ClassToExtend, StringRef Category)
Add ObjC Category record.
ObjCInterfaceRecord * addObjCInterface(StringRef Name, RecordLinkage Linkage, ObjCIFSymbolKind SymType)
Add ObjC Class record.
ObjCContainerRecord * findContainer(bool IsIVar, StringRef Name) const
Find ObjC Container.
ObjCIVarRecord * addObjCIVar(ObjCContainerRecord *Container, StringRef Name, RecordLinkage Linkage)
Add ObjC IVar record.
GlobalRecord * findGlobal(StringRef Name, GlobalRecord::Kind GV=GlobalRecord::Kind::Unknown) const
Find non-objc global.
ObjCCategoryRecord * findObjCCategory(StringRef ClassToExtend, StringRef Category) const
Find ObjC Category.
BinaryAttrs & getBinaryAttrs()
Return reference to BinaryAttrs.
ObjCInterfaceRecord * findObjCInterface(StringRef Name) const
Find ObjC Class.
Record * addRecord(StringRef Name, SymbolFlags Flags, GlobalRecord::Kind GV=GlobalRecord::Kind::Unknown, RecordLinkage Linkage=RecordLinkage::Unknown)
Add unspecified record to slice.
void visit(RecordVisitor &V) const
Specialized RecordVisitor for collecting exported symbols and undefined symbols if RecordSlice being ...
Definition: RecordVisitor.h:35
A vector that has set insertion semantics.
Definition: SetVector.h:57
iterator begin()
Get an iterator to the beginning of the SetVector.
Definition: SetVector.h:103
bool insert(const value_type &X)
Insert a new element into the SetVector.
Definition: SetVector.h:162
bool empty() const
Definition: SmallVector.h:94
void push_back(const T &Elt)
Definition: SmallVector.h:426
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1209
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
Target - Wrapper for Target specific information.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ C
The default llvm calling convention, compatible with C.
Definition: CallingConv.h:34
RecordLinkage
Definition: Record.h:31
std::unique_ptr< InterfaceFile > convertToInterfaceFile(const Records &Slices)
ObjCIFSymbolKind
ObjC Interface symbol mappings.
Definition: Symbol.h:69
@ EHType
Is OBJC_EHTYPE* symbol.
@ Class
Is OBJC_CLASS* symbol.
@ MetaClass
Is OBJC_METACLASS* symbol.
SimpleSymbol parseSymbol(StringRef SymName)
Get symbol classification by parsing the name of a symbol.
Definition: Symbol.cpp:75
llvm::SmallVector< std::shared_ptr< RecordsSlice >, 4 > Records
Definition: RecordsSlice.h:193
SymbolFlags
Symbol flags.
Definition: Symbol.h:24
@ WeakDefined
Weak defined symbol.
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
Definition: STLExtras.h:329
UnaryFunction for_each(R &&Range, UnaryFunction F)
Provide wrappers to std::for_each which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1724