aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/TextAPI
diff options
context:
space:
mode:
authorCyndy Ishida <cyndy_ishida@apple.com>2023-12-20 08:47:10 -0800
committerGitHub <noreply@github.com>2023-12-20 08:47:10 -0800
commit5ea15fab19eb005c6032ea453c7a01ae32269336 (patch)
treecb886ce71496c46e52dba158137169baab0f9a2a /llvm/lib/TextAPI
parent8bbeed05c4da832a2abf532fee8665c0d6576cbc (diff)
downloadllvm-5ea15fab19eb005c6032ea453c7a01ae32269336.zip
llvm-5ea15fab19eb005c6032ea453c7a01ae32269336.tar.gz
llvm-5ea15fab19eb005c6032ea453c7a01ae32269336.tar.bz2
[TextAPI] Add support to convert RecordSlices -> InterfaceFile (#75007)
Introduce RecordVisitor. This is used for different clients that want to extract information out of RecordSlice types. The first and immediate use case is for serializing symbol information into TBD files.
Diffstat (limited to 'llvm/lib/TextAPI')
-rw-r--r--llvm/lib/TextAPI/BinaryReader/DylibReader.cpp10
-rw-r--r--llvm/lib/TextAPI/CMakeLists.txt1
-rw-r--r--llvm/lib/TextAPI/RecordVisitor.cpp65
-rw-r--r--llvm/lib/TextAPI/RecordsSlice.cpp120
4 files changed, 194 insertions, 2 deletions
diff --git a/llvm/lib/TextAPI/BinaryReader/DylibReader.cpp b/llvm/lib/TextAPI/BinaryReader/DylibReader.cpp
index b01130c..40b57b5 100644
--- a/llvm/lib/TextAPI/BinaryReader/DylibReader.cpp
+++ b/llvm/lib/TextAPI/BinaryReader/DylibReader.cpp
@@ -417,3 +417,13 @@ Expected<Records> DylibReader::readFile(MemoryBufferRef Buffer,
return make_error<TextAPIError>(TextAPIErrorCode::EmptyResults);
return Results;
}
+
+Expected<std::unique_ptr<InterfaceFile>>
+DylibReader::get(MemoryBufferRef Buffer) {
+ ParseOption Options;
+ auto SlicesOrErr = readFile(Buffer, Options);
+ if (!SlicesOrErr)
+ return SlicesOrErr.takeError();
+
+ return convertToInterfaceFile(*SlicesOrErr);
+}
diff --git a/llvm/lib/TextAPI/CMakeLists.txt b/llvm/lib/TextAPI/CMakeLists.txt
index 75fc92f..2017a1ad 100644
--- a/llvm/lib/TextAPI/CMakeLists.txt
+++ b/llvm/lib/TextAPI/CMakeLists.txt
@@ -6,6 +6,7 @@ add_llvm_component_library(LLVMTextAPI
PackedVersion.cpp
Platform.cpp
RecordsSlice.cpp
+ RecordVisitor.cpp
Symbol.cpp
SymbolSet.cpp
Target.cpp
diff --git a/llvm/lib/TextAPI/RecordVisitor.cpp b/llvm/lib/TextAPI/RecordVisitor.cpp
new file mode 100644
index 0000000..cee04e6
--- /dev/null
+++ b/llvm/lib/TextAPI/RecordVisitor.cpp
@@ -0,0 +1,65 @@
+//===- RecordVisitor.cpp --------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// Implements the TAPI Record Visitor.
+///
+//===----------------------------------------------------------------------===//
+
+#include "llvm/TextAPI/RecordVisitor.h"
+
+using namespace llvm;
+using namespace llvm::MachO;
+
+RecordVisitor::~RecordVisitor() {}
+void RecordVisitor::visitObjCInterface(const ObjCInterfaceRecord &) {}
+void RecordVisitor::visitObjCCategory(const ObjCCategoryRecord &) {}
+
+static bool shouldSkipRecord(const Record &R, const bool RecordUndefs) {
+ if (R.isExported())
+ return false;
+
+ // Skip non exported symbols unless for flat namespace libraries.
+ return !(RecordUndefs && R.isUndefined());
+}
+
+void SymbolConverter::visitGlobal(const GlobalRecord &GR) {
+ auto [SymName, SymKind] = parseSymbol(GR.getName(), GR.getFlags());
+ if (shouldSkipRecord(GR, RecordUndefs))
+ return;
+ Symbols->addGlobal(SymKind, SymName, GR.getFlags(), Targ);
+}
+
+void SymbolConverter::addIVars(const ArrayRef<ObjCIVarRecord *> IVars,
+ StringRef ContainerName) {
+ for (auto *IV : IVars) {
+ if (shouldSkipRecord(*IV, RecordUndefs))
+ continue;
+ std::string Name =
+ ObjCIVarRecord::createScopedName(ContainerName, IV->getName());
+ Symbols->addGlobal(SymbolKind::ObjectiveCInstanceVariable, Name,
+ IV->getFlags(), Targ);
+ }
+}
+
+void SymbolConverter::visitObjCInterface(const ObjCInterfaceRecord &ObjCR) {
+ if (!shouldSkipRecord(ObjCR, RecordUndefs)) {
+ Symbols->addGlobal(SymbolKind::ObjectiveCClass, ObjCR.getName(),
+ ObjCR.getFlags(), Targ);
+ if (ObjCR.hasExceptionAttribute())
+ Symbols->addGlobal(SymbolKind::ObjectiveCClassEHType, ObjCR.getName(),
+ ObjCR.getFlags(), Targ);
+ }
+
+ addIVars(ObjCR.getObjCIVars(), ObjCR.getName());
+ for (const auto *Cat : ObjCR.getObjCCategories())
+ addIVars(Cat->getObjCIVars(), ObjCR.getName());
+}
+
+void SymbolConverter::visitObjCCategory(const ObjCCategoryRecord &Cat) {
+ addIVars(Cat.getObjCIVars(), Cat.getName());
+}
diff --git a/llvm/lib/TextAPI/RecordsSlice.cpp b/llvm/lib/TextAPI/RecordsSlice.cpp
index a220b25..7ceffc7 100644
--- a/llvm/lib/TextAPI/RecordsSlice.cpp
+++ b/llvm/lib/TextAPI/RecordsSlice.cpp
@@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/TextAPI/RecordsSlice.h"
+#include "llvm/ADT/SetVector.h"
#include "llvm/TextAPI/Record.h"
#include "llvm/TextAPI/Symbol.h"
#include <utility>
@@ -142,8 +143,10 @@ GlobalRecord *RecordsSlice::addGlobal(StringRef Name, RecordLinkage Linkage,
if (Result.second)
Result.first->second =
std::make_unique<GlobalRecord>(Name, Linkage, Flags, GV);
- else
+ else {
updateLinkage(Result.first->second.get(), Linkage);
+ updateFlags(Result.first->second.get(), Flags);
+ }
return Result.first->second.get();
}
@@ -164,6 +167,19 @@ ObjCInterfaceRecord *RecordsSlice::addObjCInterface(StringRef Name,
return Result.first->second.get();
}
+SymbolFlags Record::mergeFlags(SymbolFlags Flags, RecordLinkage Linkage) {
+ // Add Linkage properties into Flags.
+ switch (Linkage) {
+ case RecordLinkage::Rexported:
+ Flags |= SymbolFlags::Rexported;
+ return Flags;
+ case RecordLinkage::Undefined:
+ Flags |= SymbolFlags::Undefined;
+ return Flags;
+ default:
+ return Flags;
+ }
+}
bool ObjCInterfaceRecord::addObjCCategory(ObjCCategoryRecord *Record) {
auto Result = Categories.insert({Name, Record});
@@ -188,11 +204,26 @@ ObjCCategoryRecord *RecordsSlice::addObjCCategory(StringRef ClassToExtend,
return Result.first->second.get();
}
+std::vector<ObjCIVarRecord *> ObjCContainerRecord::getObjCIVars() const {
+ std::vector<ObjCIVarRecord *> Records;
+ llvm::for_each(IVars,
+ [&](auto &Record) { Records.push_back(Record.second.get()); });
+ return Records;
+}
+
+std::vector<ObjCCategoryRecord *>
+ObjCInterfaceRecord::getObjCCategories() const {
+ std::vector<ObjCCategoryRecord *> Records;
+ llvm::for_each(Categories,
+ [&](auto &Record) { Records.push_back(Record.second); });
+ return Records;
+}
+
ObjCIVarRecord *ObjCContainerRecord::addObjCIVar(StringRef IVar,
RecordLinkage Linkage) {
auto Result = IVars.insert({IVar, nullptr});
if (Result.second)
- Result.first->second = std::make_unique<ObjCIVarRecord>(Name, Linkage);
+ Result.first->second = std::make_unique<ObjCIVarRecord>(IVar, Linkage);
return Result.first->second.get();
}
@@ -222,3 +253,88 @@ RecordsSlice::BinaryAttrs &RecordsSlice::getBinaryAttrs() {
BA = std::make_unique<BinaryAttrs>();
return *BA;
}
+
+void RecordsSlice::visit(RecordVisitor &V) const {
+ for (auto &G : Globals)
+ V.visitGlobal(*G.second);
+ for (auto &C : Classes)
+ V.visitObjCInterface(*C.second);
+ for (auto &Cat : Categories)
+ V.visitObjCCategory(*Cat.second);
+}
+
+static std::unique_ptr<InterfaceFile>
+createInterfaceFile(const Records &Slices, StringRef InstallName) {
+ // Pickup symbols first.
+ auto Symbols = std::make_unique<SymbolSet>();
+ for (auto &S : Slices) {
+ if (S->empty())
+ continue;
+ auto &BA = S->getBinaryAttrs();
+ if (BA.InstallName != InstallName)
+ continue;
+
+ SymbolConverter Converter(Symbols.get(), S->getTarget(),
+ !BA.TwoLevelNamespace);
+ S->visit(Converter);
+ }
+
+ auto File = std::make_unique<InterfaceFile>(std::move(Symbols));
+ File->setInstallName(InstallName);
+ // Assign other attributes.
+ for (auto &S : Slices) {
+ if (S->empty())
+ continue;
+ auto &BA = S->getBinaryAttrs();
+ if (BA.InstallName != InstallName)
+ continue;
+ const Target &Targ = S->getTarget();
+ File->addTarget(Targ);
+ if (File->getFileType() == FileType::Invalid)
+ File->setFileType(BA.File);
+ if (BA.AppExtensionSafe && !File->isApplicationExtensionSafe())
+ File->setApplicationExtensionSafe();
+ if (BA.TwoLevelNamespace && !File->isTwoLevelNamespace())
+ File->setTwoLevelNamespace();
+ if (BA.OSLibNotForSharedCache && !File->isOSLibNotForSharedCache())
+ File->setOSLibNotForSharedCache();
+ if (File->getCurrentVersion().empty())
+ File->setCurrentVersion(BA.CurrentVersion);
+ if (File->getCompatibilityVersion().empty())
+ File->setCompatibilityVersion(BA.CompatVersion);
+ if (File->getSwiftABIVersion() == 0)
+ File->setSwiftABIVersion(BA.SwiftABI);
+ if (File->getPath().empty())
+ File->setPath(BA.Path);
+ if (!BA.ParentUmbrella.empty())
+ File->addParentUmbrella(Targ, BA.ParentUmbrella);
+ for (const auto &Client : BA.AllowableClients)
+ File->addAllowableClient(Client, Targ);
+ for (const auto &Lib : BA.RexportedLibraries)
+ File->addReexportedLibrary(Lib, Targ);
+ }
+
+ return File;
+}
+
+std::unique_ptr<InterfaceFile>
+llvm::MachO::convertToInterfaceFile(const Records &Slices) {
+ std::unique_ptr<InterfaceFile> File;
+ if (Slices.empty())
+ return File;
+
+ SetVector<StringRef> InstallNames;
+ for (auto &S : Slices) {
+ auto Name = S->getBinaryAttrs().InstallName;
+ if (Name.empty())
+ continue;
+ InstallNames.insert(Name);
+ }
+
+ File = createInterfaceFile(Slices, *InstallNames.begin());
+ for (auto it = std::next(InstallNames.begin()); it != InstallNames.end();
+ ++it)
+ File->addDocument(createInterfaceFile(Slices, *it));
+
+ return File;
+}