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