Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/TextAPI/RecordsSlice.cpp
35262 views
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
13
#include "llvm/TextAPI/RecordsSlice.h"
14
#include "llvm/ADT/SetVector.h"
15
#include "llvm/TextAPI/InterfaceFile.h"
16
#include "llvm/TextAPI/Record.h"
17
#include "llvm/TextAPI/Symbol.h"
18
#include <utility>
19
20
using namespace llvm;
21
using namespace llvm::MachO;
22
23
Record *RecordsSlice::addRecord(StringRef Name, SymbolFlags Flags,
24
GlobalRecord::Kind GV, RecordLinkage Linkage) {
25
// Find a specific Record type to capture.
26
auto [APIName, SymKind, InterfaceType] = parseSymbol(Name);
27
Name = APIName;
28
switch (SymKind) {
29
case EncodeKind::GlobalSymbol:
30
return addGlobal(Name, Linkage, GV, Flags);
31
case EncodeKind::ObjectiveCClass:
32
return addObjCInterface(Name, Linkage, InterfaceType);
33
case EncodeKind::ObjectiveCClassEHType: {
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.
37
if ((Flags & SymbolFlags::WeakDefined) == SymbolFlags::WeakDefined)
38
updateFlags(Rec, SymbolFlags::WeakDefined);
39
return Rec;
40
}
41
case EncodeKind::ObjectiveCInstanceVariable: {
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
55
ObjCContainerRecord *RecordsSlice::findContainer(bool IsIVar,
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
66
template <typename R, typename C = RecordMap<R>, typename K = StringRef>
67
R *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
74
GlobalRecord *RecordsSlice::findGlobal(StringRef Name,
75
GlobalRecord::Kind GV) const {
76
auto *Record = findRecord<GlobalRecord>(Name, Globals);
77
if (!Record)
78
return nullptr;
79
80
switch (GV) {
81
case GlobalRecord::Kind::Variable: {
82
if (!Record->isVariable())
83
return nullptr;
84
break;
85
}
86
case GlobalRecord::Kind::Function: {
87
if (!Record->isFunction())
88
return nullptr;
89
break;
90
}
91
case GlobalRecord::Kind::Unknown:
92
return Record;
93
}
94
95
return Record;
96
}
97
98
RecordLinkage
99
ObjCInterfaceRecord::getLinkageForSymbol(ObjCIFSymbolKind CurrType) const {
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
114
void ObjCInterfaceRecord::updateLinkageForSymbols(ObjCIFSymbolKind SymType,
115
RecordLinkage Link) {
116
if ((SymType & ObjCIFSymbolKind::Class) == ObjCIFSymbolKind::Class)
117
Linkages.Class = std::max(Link, Linkages.Class);
118
if ((SymType & ObjCIFSymbolKind::MetaClass) == ObjCIFSymbolKind::MetaClass)
119
Linkages.MetaClass = std::max(Link, Linkages.MetaClass);
120
if ((SymType & ObjCIFSymbolKind::EHType) == ObjCIFSymbolKind::EHType)
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
131
ObjCInterfaceRecord *RecordsSlice::findObjCInterface(StringRef Name) const {
132
return findRecord<ObjCInterfaceRecord>(Name, Classes);
133
}
134
135
ObjCCategoryRecord *RecordsSlice::findObjCCategory(StringRef ClassToExtend,
136
StringRef Category) const {
137
return findRecord<ObjCCategoryRecord>(std::make_pair(ClassToExtend, Category),
138
Categories);
139
}
140
141
ObjCIVarRecord *ObjCContainerRecord::findObjCIVar(StringRef IVar) const {
142
return findRecord<ObjCIVarRecord>(IVar, IVars);
143
}
144
145
ObjCIVarRecord *RecordsSlice::findObjCIVar(bool IsScopedName,
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
173
GlobalRecord *RecordsSlice::addGlobal(StringRef Name, RecordLinkage Linkage,
174
GlobalRecord::Kind GV, SymbolFlags Flags,
175
bool Inlined) {
176
if (GV == GlobalRecord::Kind::Function)
177
Flags |= SymbolFlags::Text;
178
else if (GV == GlobalRecord::Kind::Variable)
179
Flags |= SymbolFlags::Data;
180
181
Name = copyString(Name);
182
auto Result = Globals.insert({Name, nullptr});
183
if (Result.second)
184
Result.first->second =
185
std::make_unique<GlobalRecord>(Name, Linkage, Flags, GV, Inlined);
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
193
ObjCInterfaceRecord *RecordsSlice::addObjCInterface(StringRef Name,
194
RecordLinkage Linkage,
195
ObjCIFSymbolKind SymType) {
196
Name = copyString(Name);
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
206
SymbolFlags Record::mergeFlags(SymbolFlags Flags, RecordLinkage Linkage) {
207
// Add Linkage properties into Flags.
208
switch (Linkage) {
209
case RecordLinkage::Rexported:
210
Flags |= SymbolFlags::Rexported;
211
return Flags;
212
case RecordLinkage::Undefined:
213
Flags |= SymbolFlags::Undefined;
214
return Flags;
215
default:
216
return Flags;
217
}
218
}
219
220
bool ObjCInterfaceRecord::addObjCCategory(ObjCCategoryRecord *Record) {
221
auto Result = Categories.insert({Name, Record});
222
return Result.second;
223
}
224
225
ObjCCategoryRecord *RecordsSlice::addObjCCategory(StringRef ClassToExtend,
226
StringRef Category) {
227
Category = copyString(Category);
228
ClassToExtend = copyString(ClassToExtend);
229
230
// Add owning record first into record slice.
231
auto Result =
232
Categories.insert({std::make_pair(ClassToExtend, Category), nullptr});
233
if (Result.second)
234
Result.first->second =
235
std::make_unique<ObjCCategoryRecord>(ClassToExtend, Category);
236
237
// Then add reference to it in in the class.
238
if (auto *ObjCClass = findObjCInterface(ClassToExtend))
239
ObjCClass->addObjCCategory(Result.first->second.get());
240
241
return Result.first->second.get();
242
}
243
244
std::vector<ObjCIVarRecord *> ObjCContainerRecord::getObjCIVars() const {
245
std::vector<ObjCIVarRecord *> Records;
246
llvm::for_each(IVars,
247
[&](auto &Record) { Records.push_back(Record.second.get()); });
248
return Records;
249
}
250
251
std::vector<ObjCCategoryRecord *>
252
ObjCInterfaceRecord::getObjCCategories() const {
253
std::vector<ObjCCategoryRecord *> Records;
254
llvm::for_each(Categories,
255
[&](auto &Record) { Records.push_back(Record.second); });
256
return Records;
257
}
258
259
ObjCIVarRecord *ObjCContainerRecord::addObjCIVar(StringRef IVar,
260
RecordLinkage Linkage) {
261
auto Result = IVars.insert({IVar, nullptr});
262
if (Result.second)
263
Result.first->second = std::make_unique<ObjCIVarRecord>(IVar, Linkage);
264
return Result.first->second.get();
265
}
266
267
ObjCIVarRecord *RecordsSlice::addObjCIVar(ObjCContainerRecord *Container,
268
StringRef Name,
269
RecordLinkage Linkage) {
270
Name = copyString(Name);
271
ObjCIVarRecord *Record = Container->addObjCIVar(Name, Linkage);
272
updateLinkage(Record, Linkage);
273
return Record;
274
}
275
276
StringRef RecordsSlice::copyString(StringRef String) {
277
if (String.empty())
278
return {};
279
280
if (StringAllocator.identifyObject(String.data()))
281
return String;
282
283
void *Ptr = StringAllocator.Allocate(String.size(), 1);
284
memcpy(Ptr, String.data(), String.size());
285
return StringRef(reinterpret_cast<const char *>(Ptr), String.size());
286
}
287
288
RecordsSlice::BinaryAttrs &RecordsSlice::getBinaryAttrs() {
289
if (!hasBinaryAttrs())
290
BA = std::make_unique<BinaryAttrs>();
291
return *BA;
292
}
293
294
void RecordsSlice::visit(RecordVisitor &V) const {
295
for (auto &G : Globals)
296
V.visitGlobal(*G.second);
297
for (auto &C : Classes)
298
V.visitObjCInterface(*C.second);
299
for (auto &Cat : Categories)
300
V.visitObjCCategory(*Cat.second);
301
}
302
303
static std::unique_ptr<InterfaceFile>
304
createInterfaceFile(const Records &Slices, StringRef InstallName) {
305
// Pickup symbols first.
306
auto Symbols = std::make_unique<SymbolSet>();
307
for (auto &S : Slices) {
308
if (S->empty())
309
continue;
310
auto &BA = S->getBinaryAttrs();
311
if (BA.InstallName != InstallName)
312
continue;
313
314
SymbolConverter Converter(Symbols.get(), S->getTarget(),
315
!BA.TwoLevelNamespace);
316
S->visit(Converter);
317
}
318
319
auto File = std::make_unique<InterfaceFile>(std::move(Symbols));
320
File->setInstallName(InstallName);
321
// Assign other attributes.
322
for (auto &S : Slices) {
323
if (S->empty())
324
continue;
325
auto &BA = S->getBinaryAttrs();
326
if (BA.InstallName != InstallName)
327
continue;
328
const Target &Targ = S->getTarget();
329
File->addTarget(Targ);
330
File->setFromBinaryAttrs(BA, Targ);
331
}
332
333
return File;
334
}
335
336
std::unique_ptr<InterfaceFile>
337
llvm::MachO::convertToInterfaceFile(const Records &Slices) {
338
std::unique_ptr<InterfaceFile> File;
339
if (Slices.empty())
340
return File;
341
342
SetVector<StringRef> InstallNames;
343
for (auto &S : Slices) {
344
auto Name = S->getBinaryAttrs().InstallName;
345
if (Name.empty())
346
continue;
347
InstallNames.insert(Name);
348
}
349
350
File = createInterfaceFile(Slices, *InstallNames.begin());
351
for (StringRef IN : llvm::drop_begin(InstallNames))
352
File->addDocument(createInterfaceFile(Slices, IN));
353
354
return File;
355
}
356
357