1c9157d92SDimitry Andric //===- RecordsSlice.cpp --------------------------------------------------===//
2c9157d92SDimitry Andric //
3c9157d92SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4c9157d92SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5c9157d92SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6c9157d92SDimitry Andric //
7c9157d92SDimitry Andric //===----------------------------------------------------------------------===//
8c9157d92SDimitry Andric //
9c9157d92SDimitry Andric // Implements the Records Slice APIs.
10c9157d92SDimitry Andric //
11c9157d92SDimitry Andric //===----------------------------------------------------------------------===//
12c9157d92SDimitry Andric
13c9157d92SDimitry Andric #include "llvm/TextAPI/RecordsSlice.h"
14e710425bSDimitry Andric #include "llvm/ADT/SetVector.h"
15c9157d92SDimitry Andric #include "llvm/TextAPI/Record.h"
16c9157d92SDimitry Andric #include "llvm/TextAPI/Symbol.h"
17c9157d92SDimitry Andric #include <utility>
18c9157d92SDimitry Andric
19c9157d92SDimitry Andric using namespace llvm;
20c9157d92SDimitry Andric using namespace llvm::MachO;
21c9157d92SDimitry Andric
addRecord(StringRef Name,SymbolFlags Flags,GlobalRecord::Kind GV,RecordLinkage Linkage)22c9157d92SDimitry Andric Record *RecordsSlice::addRecord(StringRef Name, SymbolFlags Flags,
23c9157d92SDimitry Andric GlobalRecord::Kind GV, RecordLinkage Linkage) {
24c9157d92SDimitry Andric // Find a specific Record type to capture.
25c9157d92SDimitry Andric auto [APIName, SymKind] = parseSymbol(Name, Flags);
26c9157d92SDimitry Andric Name = APIName;
27c9157d92SDimitry Andric switch (SymKind) {
28c9157d92SDimitry Andric case SymbolKind::GlobalSymbol:
29c9157d92SDimitry Andric return addGlobal(Name, Linkage, GV, Flags);
30c9157d92SDimitry Andric case SymbolKind::ObjectiveCClass:
31c9157d92SDimitry Andric return addObjCInterface(Name, Linkage);
32c9157d92SDimitry Andric case SymbolKind::ObjectiveCClassEHType:
33c9157d92SDimitry Andric return addObjCInterface(Name, Linkage, /*HasEHType=*/true);
34c9157d92SDimitry Andric case SymbolKind::ObjectiveCInstanceVariable: {
35c9157d92SDimitry Andric auto [Super, IVar] = Name.split('.');
36c9157d92SDimitry Andric // Attempt to find super class.
37c9157d92SDimitry Andric ObjCContainerRecord *Container = findContainer(/*isIVar=*/false, Super);
38c9157d92SDimitry Andric // If not found, create extension since there is no mapped class symbol.
39c9157d92SDimitry Andric if (Container == nullptr)
40c9157d92SDimitry Andric Container = addObjCCategory(Super, {});
41c9157d92SDimitry Andric return addObjCIVar(Container, IVar, Linkage);
42c9157d92SDimitry Andric }
43c9157d92SDimitry Andric }
44c9157d92SDimitry Andric
45c9157d92SDimitry Andric llvm_unreachable("unexpected symbol kind when adding to Record Slice");
46c9157d92SDimitry Andric }
47c9157d92SDimitry Andric
findContainer(bool IsIVar,StringRef Name) const48c9157d92SDimitry Andric ObjCContainerRecord *RecordsSlice::findContainer(bool IsIVar,
49c9157d92SDimitry Andric StringRef Name) const {
50c9157d92SDimitry Andric StringRef Super = IsIVar ? Name.split('.').first : Name;
51c9157d92SDimitry Andric ObjCContainerRecord *Container = findObjCInterface(Super);
52c9157d92SDimitry Andric // Ivars can only exist with extensions, if they did not come from
53c9157d92SDimitry Andric // class.
54c9157d92SDimitry Andric if (Container == nullptr)
55c9157d92SDimitry Andric Container = findObjCCategory(Super, "");
56c9157d92SDimitry Andric return Container;
57c9157d92SDimitry Andric }
58c9157d92SDimitry Andric
59c9157d92SDimitry Andric template <typename R, typename C = RecordMap<R>, typename K = StringRef>
findRecord(K Key,const C & Container)60c9157d92SDimitry Andric R *findRecord(K Key, const C &Container) {
61c9157d92SDimitry Andric const auto *Record = Container.find(Key);
62c9157d92SDimitry Andric if (Record == Container.end())
63c9157d92SDimitry Andric return nullptr;
64c9157d92SDimitry Andric return Record->second.get();
65c9157d92SDimitry Andric }
66c9157d92SDimitry Andric
findGlobal(StringRef Name,GlobalRecord::Kind GV) const67c9157d92SDimitry Andric GlobalRecord *RecordsSlice::findGlobal(StringRef Name,
68c9157d92SDimitry Andric GlobalRecord::Kind GV) const {
69c9157d92SDimitry Andric auto *Record = findRecord<GlobalRecord>(Name, Globals);
70c9157d92SDimitry Andric if (!Record)
71c9157d92SDimitry Andric return nullptr;
72c9157d92SDimitry Andric
73c9157d92SDimitry Andric switch (GV) {
74c9157d92SDimitry Andric case GlobalRecord::Kind::Variable: {
75c9157d92SDimitry Andric if (!Record->isVariable())
76c9157d92SDimitry Andric return nullptr;
77c9157d92SDimitry Andric break;
78c9157d92SDimitry Andric }
79c9157d92SDimitry Andric case GlobalRecord::Kind::Function: {
80c9157d92SDimitry Andric if (!Record->isFunction())
81c9157d92SDimitry Andric return nullptr;
82c9157d92SDimitry Andric break;
83c9157d92SDimitry Andric }
84c9157d92SDimitry Andric case GlobalRecord::Kind::Unknown:
85c9157d92SDimitry Andric return Record;
86c9157d92SDimitry Andric }
87c9157d92SDimitry Andric
88c9157d92SDimitry Andric return Record;
89c9157d92SDimitry Andric }
90c9157d92SDimitry Andric
findObjCInterface(StringRef Name) const91c9157d92SDimitry Andric ObjCInterfaceRecord *RecordsSlice::findObjCInterface(StringRef Name) const {
92c9157d92SDimitry Andric return findRecord<ObjCInterfaceRecord>(Name, Classes);
93c9157d92SDimitry Andric }
94c9157d92SDimitry Andric
findObjCCategory(StringRef ClassToExtend,StringRef Category) const95c9157d92SDimitry Andric ObjCCategoryRecord *RecordsSlice::findObjCCategory(StringRef ClassToExtend,
96c9157d92SDimitry Andric StringRef Category) const {
97c9157d92SDimitry Andric return findRecord<ObjCCategoryRecord>(std::make_pair(ClassToExtend, Category),
98c9157d92SDimitry Andric Categories);
99c9157d92SDimitry Andric }
100c9157d92SDimitry Andric
findObjCIVar(StringRef IVar) const101c9157d92SDimitry Andric ObjCIVarRecord *ObjCContainerRecord::findObjCIVar(StringRef IVar) const {
102c9157d92SDimitry Andric return findRecord<ObjCIVarRecord>(IVar, IVars);
103c9157d92SDimitry Andric }
104c9157d92SDimitry Andric
findObjCIVar(bool IsScopedName,StringRef Name) const105c9157d92SDimitry Andric ObjCIVarRecord *RecordsSlice::findObjCIVar(bool IsScopedName,
106c9157d92SDimitry Andric StringRef Name) const {
107c9157d92SDimitry Andric // If scoped name, the name of the container is known.
108c9157d92SDimitry Andric if (IsScopedName) {
109c9157d92SDimitry Andric // IVar does not exist if there is not a container assigned to it.
110c9157d92SDimitry Andric auto *Container = findContainer(/*IsIVar=*/true, Name);
111c9157d92SDimitry Andric if (!Container)
112c9157d92SDimitry Andric return nullptr;
113c9157d92SDimitry Andric
114c9157d92SDimitry Andric StringRef IVar = Name.substr(Name.find_first_of('.') + 1);
115c9157d92SDimitry Andric return Container->findObjCIVar(IVar);
116c9157d92SDimitry Andric }
117c9157d92SDimitry Andric
118c9157d92SDimitry Andric // Otherwise traverse through containers and attempt to find IVar.
119c9157d92SDimitry Andric auto getIVar = [Name](auto &Records) -> ObjCIVarRecord * {
120c9157d92SDimitry Andric for (const auto &[_, Container] : Records) {
121c9157d92SDimitry Andric if (auto *IVarR = Container->findObjCIVar(Name))
122c9157d92SDimitry Andric return IVarR;
123c9157d92SDimitry Andric }
124c9157d92SDimitry Andric return nullptr;
125c9157d92SDimitry Andric };
126c9157d92SDimitry Andric
127c9157d92SDimitry Andric if (auto *IVarRecord = getIVar(Classes))
128c9157d92SDimitry Andric return IVarRecord;
129c9157d92SDimitry Andric
130c9157d92SDimitry Andric return getIVar(Categories);
131c9157d92SDimitry Andric }
132c9157d92SDimitry Andric
addGlobal(StringRef Name,RecordLinkage Linkage,GlobalRecord::Kind GV,SymbolFlags Flags)133c9157d92SDimitry Andric GlobalRecord *RecordsSlice::addGlobal(StringRef Name, RecordLinkage Linkage,
134c9157d92SDimitry Andric GlobalRecord::Kind GV,
135c9157d92SDimitry Andric SymbolFlags Flags) {
136c9157d92SDimitry Andric if (GV == GlobalRecord::Kind::Function)
137c9157d92SDimitry Andric Flags |= SymbolFlags::Text;
138c9157d92SDimitry Andric else if (GV == GlobalRecord::Kind::Variable)
139c9157d92SDimitry Andric Flags |= SymbolFlags::Data;
140c9157d92SDimitry Andric
141c9157d92SDimitry Andric Name = copyString(Name);
142c9157d92SDimitry Andric auto Result = Globals.insert({Name, nullptr});
143c9157d92SDimitry Andric if (Result.second)
144c9157d92SDimitry Andric Result.first->second =
145c9157d92SDimitry Andric std::make_unique<GlobalRecord>(Name, Linkage, Flags, GV);
146e710425bSDimitry Andric else {
147c9157d92SDimitry Andric updateLinkage(Result.first->second.get(), Linkage);
148e710425bSDimitry Andric updateFlags(Result.first->second.get(), Flags);
149e710425bSDimitry Andric }
150c9157d92SDimitry Andric return Result.first->second.get();
151c9157d92SDimitry Andric }
152c9157d92SDimitry Andric
addObjCInterface(StringRef Name,RecordLinkage Linkage,bool HasEHType)153c9157d92SDimitry Andric ObjCInterfaceRecord *RecordsSlice::addObjCInterface(StringRef Name,
154c9157d92SDimitry Andric RecordLinkage Linkage,
155c9157d92SDimitry Andric bool HasEHType) {
156c9157d92SDimitry Andric Name = copyString(Name);
157c9157d92SDimitry Andric auto Result = Classes.insert({Name, nullptr});
158c9157d92SDimitry Andric if (Result.second) {
159c9157d92SDimitry Andric Result.first->second =
160c9157d92SDimitry Andric std::make_unique<ObjCInterfaceRecord>(Name, Linkage, HasEHType);
161c9157d92SDimitry Andric } else {
162c9157d92SDimitry Andric // ObjC classes represent multiple symbols that could have competing
163c9157d92SDimitry Andric // linkages, in those cases assign the largest one.
164c9157d92SDimitry Andric if (Linkage >= RecordLinkage::Rexported)
165c9157d92SDimitry Andric updateLinkage(Result.first->second.get(), Linkage);
166c9157d92SDimitry Andric }
167c9157d92SDimitry Andric
168c9157d92SDimitry Andric return Result.first->second.get();
169c9157d92SDimitry Andric }
mergeFlags(SymbolFlags Flags,RecordLinkage Linkage)170e710425bSDimitry Andric SymbolFlags Record::mergeFlags(SymbolFlags Flags, RecordLinkage Linkage) {
171e710425bSDimitry Andric // Add Linkage properties into Flags.
172e710425bSDimitry Andric switch (Linkage) {
173e710425bSDimitry Andric case RecordLinkage::Rexported:
174e710425bSDimitry Andric Flags |= SymbolFlags::Rexported;
175e710425bSDimitry Andric return Flags;
176e710425bSDimitry Andric case RecordLinkage::Undefined:
177e710425bSDimitry Andric Flags |= SymbolFlags::Undefined;
178e710425bSDimitry Andric return Flags;
179e710425bSDimitry Andric default:
180e710425bSDimitry Andric return Flags;
181e710425bSDimitry Andric }
182e710425bSDimitry Andric }
183c9157d92SDimitry Andric
addObjCCategory(ObjCCategoryRecord * Record)184c9157d92SDimitry Andric bool ObjCInterfaceRecord::addObjCCategory(ObjCCategoryRecord *Record) {
185c9157d92SDimitry Andric auto Result = Categories.insert({Name, Record});
186c9157d92SDimitry Andric return Result.second;
187c9157d92SDimitry Andric }
188c9157d92SDimitry Andric
addObjCCategory(StringRef ClassToExtend,StringRef Category)189c9157d92SDimitry Andric ObjCCategoryRecord *RecordsSlice::addObjCCategory(StringRef ClassToExtend,
190c9157d92SDimitry Andric StringRef Category) {
191c9157d92SDimitry Andric Category = copyString(Category);
192c9157d92SDimitry Andric
193c9157d92SDimitry Andric // Add owning record first into record slice.
194c9157d92SDimitry Andric auto Result =
195c9157d92SDimitry Andric Categories.insert({std::make_pair(ClassToExtend, Category), nullptr});
196c9157d92SDimitry Andric if (Result.second)
197c9157d92SDimitry Andric Result.first->second =
198c9157d92SDimitry Andric std::make_unique<ObjCCategoryRecord>(ClassToExtend, Category);
199c9157d92SDimitry Andric
200c9157d92SDimitry Andric // Then add reference to it in in the class.
201c9157d92SDimitry Andric if (auto *ObjCClass = findObjCInterface(ClassToExtend))
202c9157d92SDimitry Andric ObjCClass->addObjCCategory(Result.first->second.get());
203c9157d92SDimitry Andric
204c9157d92SDimitry Andric return Result.first->second.get();
205c9157d92SDimitry Andric }
206c9157d92SDimitry Andric
getObjCIVars() const207e710425bSDimitry Andric std::vector<ObjCIVarRecord *> ObjCContainerRecord::getObjCIVars() const {
208e710425bSDimitry Andric std::vector<ObjCIVarRecord *> Records;
209e710425bSDimitry Andric llvm::for_each(IVars,
210e710425bSDimitry Andric [&](auto &Record) { Records.push_back(Record.second.get()); });
211e710425bSDimitry Andric return Records;
212e710425bSDimitry Andric }
213e710425bSDimitry Andric
214e710425bSDimitry Andric std::vector<ObjCCategoryRecord *>
getObjCCategories() const215e710425bSDimitry Andric ObjCInterfaceRecord::getObjCCategories() const {
216e710425bSDimitry Andric std::vector<ObjCCategoryRecord *> Records;
217e710425bSDimitry Andric llvm::for_each(Categories,
218e710425bSDimitry Andric [&](auto &Record) { Records.push_back(Record.second); });
219e710425bSDimitry Andric return Records;
220e710425bSDimitry Andric }
221e710425bSDimitry Andric
addObjCIVar(StringRef IVar,RecordLinkage Linkage)222c9157d92SDimitry Andric ObjCIVarRecord *ObjCContainerRecord::addObjCIVar(StringRef IVar,
223c9157d92SDimitry Andric RecordLinkage Linkage) {
224c9157d92SDimitry Andric auto Result = IVars.insert({IVar, nullptr});
225c9157d92SDimitry Andric if (Result.second)
226e710425bSDimitry Andric Result.first->second = std::make_unique<ObjCIVarRecord>(IVar, Linkage);
227c9157d92SDimitry Andric return Result.first->second.get();
228c9157d92SDimitry Andric }
229c9157d92SDimitry Andric
addObjCIVar(ObjCContainerRecord * Container,StringRef Name,RecordLinkage Linkage)230c9157d92SDimitry Andric ObjCIVarRecord *RecordsSlice::addObjCIVar(ObjCContainerRecord *Container,
231c9157d92SDimitry Andric StringRef Name,
232c9157d92SDimitry Andric RecordLinkage Linkage) {
233c9157d92SDimitry Andric Name = copyString(Name);
234c9157d92SDimitry Andric ObjCIVarRecord *Record = Container->addObjCIVar(Name, Linkage);
235c9157d92SDimitry Andric updateLinkage(Record, Linkage);
236c9157d92SDimitry Andric return Record;
237c9157d92SDimitry Andric }
238c9157d92SDimitry Andric
copyString(StringRef String)239c9157d92SDimitry Andric StringRef RecordsSlice::copyString(StringRef String) {
240c9157d92SDimitry Andric if (String.empty())
241c9157d92SDimitry Andric return {};
242c9157d92SDimitry Andric
243c9157d92SDimitry Andric if (StringAllocator.identifyObject(String.data()))
244c9157d92SDimitry Andric return String;
245c9157d92SDimitry Andric
246c9157d92SDimitry Andric void *Ptr = StringAllocator.Allocate(String.size(), 1);
247c9157d92SDimitry Andric memcpy(Ptr, String.data(), String.size());
248c9157d92SDimitry Andric return StringRef(reinterpret_cast<const char *>(Ptr), String.size());
249c9157d92SDimitry Andric }
250c9157d92SDimitry Andric
getBinaryAttrs()251c9157d92SDimitry Andric RecordsSlice::BinaryAttrs &RecordsSlice::getBinaryAttrs() {
252c9157d92SDimitry Andric if (!hasBinaryAttrs())
253c9157d92SDimitry Andric BA = std::make_unique<BinaryAttrs>();
254c9157d92SDimitry Andric return *BA;
255c9157d92SDimitry Andric }
256e710425bSDimitry Andric
visit(RecordVisitor & V) const257e710425bSDimitry Andric void RecordsSlice::visit(RecordVisitor &V) const {
258e710425bSDimitry Andric for (auto &G : Globals)
259e710425bSDimitry Andric V.visitGlobal(*G.second);
260e710425bSDimitry Andric for (auto &C : Classes)
261e710425bSDimitry Andric V.visitObjCInterface(*C.second);
262e710425bSDimitry Andric for (auto &Cat : Categories)
263e710425bSDimitry Andric V.visitObjCCategory(*Cat.second);
264e710425bSDimitry Andric }
265e710425bSDimitry Andric
266e710425bSDimitry Andric static std::unique_ptr<InterfaceFile>
createInterfaceFile(const Records & Slices,StringRef InstallName)267e710425bSDimitry Andric createInterfaceFile(const Records &Slices, StringRef InstallName) {
268e710425bSDimitry Andric // Pickup symbols first.
269e710425bSDimitry Andric auto Symbols = std::make_unique<SymbolSet>();
270e710425bSDimitry Andric for (auto &S : Slices) {
271e710425bSDimitry Andric if (S->empty())
272e710425bSDimitry Andric continue;
273e710425bSDimitry Andric auto &BA = S->getBinaryAttrs();
274e710425bSDimitry Andric if (BA.InstallName != InstallName)
275e710425bSDimitry Andric continue;
276e710425bSDimitry Andric
277e710425bSDimitry Andric SymbolConverter Converter(Symbols.get(), S->getTarget(),
278e710425bSDimitry Andric !BA.TwoLevelNamespace);
279e710425bSDimitry Andric S->visit(Converter);
280e710425bSDimitry Andric }
281e710425bSDimitry Andric
282e710425bSDimitry Andric auto File = std::make_unique<InterfaceFile>(std::move(Symbols));
283e710425bSDimitry Andric File->setInstallName(InstallName);
284e710425bSDimitry Andric // Assign other attributes.
285e710425bSDimitry Andric for (auto &S : Slices) {
286e710425bSDimitry Andric if (S->empty())
287e710425bSDimitry Andric continue;
288e710425bSDimitry Andric auto &BA = S->getBinaryAttrs();
289e710425bSDimitry Andric if (BA.InstallName != InstallName)
290e710425bSDimitry Andric continue;
291e710425bSDimitry Andric const Target &Targ = S->getTarget();
292e710425bSDimitry Andric File->addTarget(Targ);
293e710425bSDimitry Andric if (File->getFileType() == FileType::Invalid)
294e710425bSDimitry Andric File->setFileType(BA.File);
295e710425bSDimitry Andric if (BA.AppExtensionSafe && !File->isApplicationExtensionSafe())
296e710425bSDimitry Andric File->setApplicationExtensionSafe();
297e710425bSDimitry Andric if (BA.TwoLevelNamespace && !File->isTwoLevelNamespace())
298e710425bSDimitry Andric File->setTwoLevelNamespace();
299e710425bSDimitry Andric if (BA.OSLibNotForSharedCache && !File->isOSLibNotForSharedCache())
300e710425bSDimitry Andric File->setOSLibNotForSharedCache();
301e710425bSDimitry Andric if (File->getCurrentVersion().empty())
302e710425bSDimitry Andric File->setCurrentVersion(BA.CurrentVersion);
303e710425bSDimitry Andric if (File->getCompatibilityVersion().empty())
304e710425bSDimitry Andric File->setCompatibilityVersion(BA.CompatVersion);
305e710425bSDimitry Andric if (File->getSwiftABIVersion() == 0)
306e710425bSDimitry Andric File->setSwiftABIVersion(BA.SwiftABI);
307e710425bSDimitry Andric if (File->getPath().empty())
308e710425bSDimitry Andric File->setPath(BA.Path);
309e710425bSDimitry Andric if (!BA.ParentUmbrella.empty())
310e710425bSDimitry Andric File->addParentUmbrella(Targ, BA.ParentUmbrella);
311e710425bSDimitry Andric for (const auto &Client : BA.AllowableClients)
312e710425bSDimitry Andric File->addAllowableClient(Client, Targ);
313e710425bSDimitry Andric for (const auto &Lib : BA.RexportedLibraries)
314e710425bSDimitry Andric File->addReexportedLibrary(Lib, Targ);
315e710425bSDimitry Andric }
316e710425bSDimitry Andric
317e710425bSDimitry Andric return File;
318e710425bSDimitry Andric }
319e710425bSDimitry Andric
320e710425bSDimitry Andric std::unique_ptr<InterfaceFile>
convertToInterfaceFile(const Records & Slices)321e710425bSDimitry Andric llvm::MachO::convertToInterfaceFile(const Records &Slices) {
322e710425bSDimitry Andric std::unique_ptr<InterfaceFile> File;
323e710425bSDimitry Andric if (Slices.empty())
324e710425bSDimitry Andric return File;
325e710425bSDimitry Andric
326e710425bSDimitry Andric SetVector<StringRef> InstallNames;
327e710425bSDimitry Andric for (auto &S : Slices) {
328e710425bSDimitry Andric auto Name = S->getBinaryAttrs().InstallName;
329e710425bSDimitry Andric if (Name.empty())
330e710425bSDimitry Andric continue;
331e710425bSDimitry Andric InstallNames.insert(Name);
332e710425bSDimitry Andric }
333e710425bSDimitry Andric
334e710425bSDimitry Andric File = createInterfaceFile(Slices, *InstallNames.begin());
335*a58f00eaSDimitry Andric for (StringRef IN : llvm::drop_begin(InstallNames))
336*a58f00eaSDimitry Andric File->addDocument(createInterfaceFile(Slices, IN));
337e710425bSDimitry Andric
338e710425bSDimitry Andric return File;
339e710425bSDimitry Andric }
340