bolt/deps/llvm-18.1.8/llvm/lib/TextAPI/RecordsSlice.cpp

340 lines
11 KiB
C++
Raw Normal View History

2025-02-14 19:21:04 +01:00
//===- RecordsSlice.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 Records Slice APIs.
//
//===----------------------------------------------------------------------===//
#include "llvm/TextAPI/RecordsSlice.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/TextAPI/Record.h"
#include "llvm/TextAPI/Symbol.h"
#include <utility>
using namespace llvm;
using namespace llvm::MachO;
Record *RecordsSlice::addRecord(StringRef Name, SymbolFlags Flags,
GlobalRecord::Kind GV, RecordLinkage Linkage) {
// Find a specific Record type to capture.
auto [APIName, SymKind] = parseSymbol(Name, Flags);
Name = APIName;
switch (SymKind) {
case SymbolKind::GlobalSymbol:
return addGlobal(Name, Linkage, GV, Flags);
case SymbolKind::ObjectiveCClass:
return addObjCInterface(Name, Linkage);
case SymbolKind::ObjectiveCClassEHType:
return addObjCInterface(Name, Linkage, /*HasEHType=*/true);
case SymbolKind::ObjectiveCInstanceVariable: {
auto [Super, IVar] = Name.split('.');
// Attempt to find super class.
ObjCContainerRecord *Container = findContainer(/*isIVar=*/false, Super);
// If not found, create extension since there is no mapped class symbol.
if (Container == nullptr)
Container = addObjCCategory(Super, {});
return addObjCIVar(Container, IVar, Linkage);
}
}
llvm_unreachable("unexpected symbol kind when adding to Record Slice");
}
ObjCContainerRecord *RecordsSlice::findContainer(bool IsIVar,
StringRef Name) const {
StringRef Super = IsIVar ? Name.split('.').first : Name;
ObjCContainerRecord *Container = findObjCInterface(Super);
// Ivars can only exist with extensions, if they did not come from
// class.
if (Container == nullptr)
Container = findObjCCategory(Super, "");
return Container;
}
template <typename R, typename C = RecordMap<R>, typename K = StringRef>
R *findRecord(K Key, const C &Container) {
const auto *Record = Container.find(Key);
if (Record == Container.end())
return nullptr;
return Record->second.get();
}
GlobalRecord *RecordsSlice::findGlobal(StringRef Name,
GlobalRecord::Kind GV) const {
auto *Record = findRecord<GlobalRecord>(Name, Globals);
if (!Record)
return nullptr;
switch (GV) {
case GlobalRecord::Kind::Variable: {
if (!Record->isVariable())
return nullptr;
break;
}
case GlobalRecord::Kind::Function: {
if (!Record->isFunction())
return nullptr;
break;
}
case GlobalRecord::Kind::Unknown:
return Record;
}
return Record;
}
ObjCInterfaceRecord *RecordsSlice::findObjCInterface(StringRef Name) const {
return findRecord<ObjCInterfaceRecord>(Name, Classes);
}
ObjCCategoryRecord *RecordsSlice::findObjCCategory(StringRef ClassToExtend,
StringRef Category) const {
return findRecord<ObjCCategoryRecord>(std::make_pair(ClassToExtend, Category),
Categories);
}
ObjCIVarRecord *ObjCContainerRecord::findObjCIVar(StringRef IVar) const {
return findRecord<ObjCIVarRecord>(IVar, IVars);
}
ObjCIVarRecord *RecordsSlice::findObjCIVar(bool IsScopedName,
StringRef Name) const {
// If scoped name, the name of the container is known.
if (IsScopedName) {
// IVar does not exist if there is not a container assigned to it.
auto *Container = findContainer(/*IsIVar=*/true, Name);
if (!Container)
return nullptr;
StringRef IVar = Name.substr(Name.find_first_of('.') + 1);
return Container->findObjCIVar(IVar);
}
// Otherwise traverse through containers and attempt to find IVar.
auto getIVar = [Name](auto &Records) -> ObjCIVarRecord * {
for (const auto &[_, Container] : Records) {
if (auto *IVarR = Container->findObjCIVar(Name))
return IVarR;
}
return nullptr;
};
if (auto *IVarRecord = getIVar(Classes))
return IVarRecord;
return getIVar(Categories);
}
GlobalRecord *RecordsSlice::addGlobal(StringRef Name, RecordLinkage Linkage,
GlobalRecord::Kind GV,
SymbolFlags Flags) {
if (GV == GlobalRecord::Kind::Function)
Flags |= SymbolFlags::Text;
else if (GV == GlobalRecord::Kind::Variable)
Flags |= SymbolFlags::Data;
Name = copyString(Name);
auto Result = Globals.insert({Name, nullptr});
if (Result.second)
Result.first->second =
std::make_unique<GlobalRecord>(Name, Linkage, Flags, GV);
else {
updateLinkage(Result.first->second.get(), Linkage);
updateFlags(Result.first->second.get(), Flags);
}
return Result.first->second.get();
}
ObjCInterfaceRecord *RecordsSlice::addObjCInterface(StringRef Name,
RecordLinkage Linkage,
bool HasEHType) {
Name = copyString(Name);
auto Result = Classes.insert({Name, nullptr});
if (Result.second) {
Result.first->second =
std::make_unique<ObjCInterfaceRecord>(Name, Linkage, HasEHType);
} else {
// ObjC classes represent multiple symbols that could have competing
// linkages, in those cases assign the largest one.
if (Linkage >= RecordLinkage::Rexported)
updateLinkage(Result.first->second.get(), Linkage);
}
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});
return Result.second;
}
ObjCCategoryRecord *RecordsSlice::addObjCCategory(StringRef ClassToExtend,
StringRef Category) {
Category = copyString(Category);
// Add owning record first into record slice.
auto Result =
Categories.insert({std::make_pair(ClassToExtend, Category), nullptr});
if (Result.second)
Result.first->second =
std::make_unique<ObjCCategoryRecord>(ClassToExtend, Category);
// Then add reference to it in in the class.
if (auto *ObjCClass = findObjCInterface(ClassToExtend))
ObjCClass->addObjCCategory(Result.first->second.get());
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>(IVar, Linkage);
return Result.first->second.get();
}
ObjCIVarRecord *RecordsSlice::addObjCIVar(ObjCContainerRecord *Container,
StringRef Name,
RecordLinkage Linkage) {
Name = copyString(Name);
ObjCIVarRecord *Record = Container->addObjCIVar(Name, Linkage);
updateLinkage(Record, Linkage);
return Record;
}
StringRef RecordsSlice::copyString(StringRef String) {
if (String.empty())
return {};
if (StringAllocator.identifyObject(String.data()))
return String;
void *Ptr = StringAllocator.Allocate(String.size(), 1);
memcpy(Ptr, String.data(), String.size());
return StringRef(reinterpret_cast<const char *>(Ptr), String.size());
}
RecordsSlice::BinaryAttrs &RecordsSlice::getBinaryAttrs() {
if (!hasBinaryAttrs())
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 (StringRef IN : llvm::drop_begin(InstallNames))
File->addDocument(createInterfaceFile(Slices, IN));
return File;
}