Path: blob/main/contrib/llvm-project/llvm/lib/TextAPI/RecordsSlice.cpp
35262 views
//===- RecordsSlice.cpp --------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// Implements the Records Slice APIs.9//10//===----------------------------------------------------------------------===//1112#include "llvm/TextAPI/RecordsSlice.h"13#include "llvm/ADT/SetVector.h"14#include "llvm/TextAPI/InterfaceFile.h"15#include "llvm/TextAPI/Record.h"16#include "llvm/TextAPI/Symbol.h"17#include <utility>1819using namespace llvm;20using namespace llvm::MachO;2122Record *RecordsSlice::addRecord(StringRef Name, SymbolFlags Flags,23GlobalRecord::Kind GV, RecordLinkage Linkage) {24// Find a specific Record type to capture.25auto [APIName, SymKind, InterfaceType] = parseSymbol(Name);26Name = APIName;27switch (SymKind) {28case EncodeKind::GlobalSymbol:29return addGlobal(Name, Linkage, GV, Flags);30case EncodeKind::ObjectiveCClass:31return addObjCInterface(Name, Linkage, InterfaceType);32case EncodeKind::ObjectiveCClassEHType: {33ObjCInterfaceRecord *Rec = addObjCInterface(Name, Linkage, InterfaceType);34// When classes without ehtype are used in try/catch blocks35// a weak-defined symbol is exported.36if ((Flags & SymbolFlags::WeakDefined) == SymbolFlags::WeakDefined)37updateFlags(Rec, SymbolFlags::WeakDefined);38return Rec;39}40case EncodeKind::ObjectiveCInstanceVariable: {41auto [Super, IVar] = Name.split('.');42// Attempt to find super class.43ObjCContainerRecord *Container = findContainer(/*isIVar=*/false, Super);44// If not found, create extension since there is no mapped class symbol.45if (Container == nullptr)46Container = addObjCCategory(Super, {});47return addObjCIVar(Container, IVar, Linkage);48}49}5051llvm_unreachable("unexpected symbol kind when adding to Record Slice");52}5354ObjCContainerRecord *RecordsSlice::findContainer(bool IsIVar,55StringRef Name) const {56StringRef Super = IsIVar ? Name.split('.').first : Name;57ObjCContainerRecord *Container = findObjCInterface(Super);58// Ivars can only exist with extensions, if they did not come from59// class.60if (Container == nullptr)61Container = findObjCCategory(Super, "");62return Container;63}6465template <typename R, typename C = RecordMap<R>, typename K = StringRef>66R *findRecord(K Key, const C &Container) {67const auto *Record = Container.find(Key);68if (Record == Container.end())69return nullptr;70return Record->second.get();71}7273GlobalRecord *RecordsSlice::findGlobal(StringRef Name,74GlobalRecord::Kind GV) const {75auto *Record = findRecord<GlobalRecord>(Name, Globals);76if (!Record)77return nullptr;7879switch (GV) {80case GlobalRecord::Kind::Variable: {81if (!Record->isVariable())82return nullptr;83break;84}85case GlobalRecord::Kind::Function: {86if (!Record->isFunction())87return nullptr;88break;89}90case GlobalRecord::Kind::Unknown:91return Record;92}9394return Record;95}9697RecordLinkage98ObjCInterfaceRecord::getLinkageForSymbol(ObjCIFSymbolKind CurrType) const {99assert(CurrType <= ObjCIFSymbolKind::EHType &&100"expected single ObjCIFSymbolKind enum value");101if (CurrType == ObjCIFSymbolKind::Class)102return Linkages.Class;103104if (CurrType == ObjCIFSymbolKind::MetaClass)105return Linkages.MetaClass;106107if (CurrType == ObjCIFSymbolKind::EHType)108return Linkages.EHType;109110llvm_unreachable("unexpected ObjCIFSymbolKind");111}112113void ObjCInterfaceRecord::updateLinkageForSymbols(ObjCIFSymbolKind SymType,114RecordLinkage Link) {115if ((SymType & ObjCIFSymbolKind::Class) == ObjCIFSymbolKind::Class)116Linkages.Class = std::max(Link, Linkages.Class);117if ((SymType & ObjCIFSymbolKind::MetaClass) == ObjCIFSymbolKind::MetaClass)118Linkages.MetaClass = std::max(Link, Linkages.MetaClass);119if ((SymType & ObjCIFSymbolKind::EHType) == ObjCIFSymbolKind::EHType)120Linkages.EHType = std::max(Link, Linkages.EHType);121122// Obj-C Classes represent multiple symbols that could have competing123// linkages, in this case assign the largest one, when querying the linkage of124// the record itself. This allows visitors pick whether they want to account125// for complete symbol information.126Linkage =127std::max(Linkages.Class, std::max(Linkages.MetaClass, Linkages.EHType));128}129130ObjCInterfaceRecord *RecordsSlice::findObjCInterface(StringRef Name) const {131return findRecord<ObjCInterfaceRecord>(Name, Classes);132}133134ObjCCategoryRecord *RecordsSlice::findObjCCategory(StringRef ClassToExtend,135StringRef Category) const {136return findRecord<ObjCCategoryRecord>(std::make_pair(ClassToExtend, Category),137Categories);138}139140ObjCIVarRecord *ObjCContainerRecord::findObjCIVar(StringRef IVar) const {141return findRecord<ObjCIVarRecord>(IVar, IVars);142}143144ObjCIVarRecord *RecordsSlice::findObjCIVar(bool IsScopedName,145StringRef Name) const {146// If scoped name, the name of the container is known.147if (IsScopedName) {148// IVar does not exist if there is not a container assigned to it.149auto *Container = findContainer(/*IsIVar=*/true, Name);150if (!Container)151return nullptr;152153StringRef IVar = Name.substr(Name.find_first_of('.') + 1);154return Container->findObjCIVar(IVar);155}156157// Otherwise traverse through containers and attempt to find IVar.158auto getIVar = [Name](auto &Records) -> ObjCIVarRecord * {159for (const auto &[_, Container] : Records) {160if (auto *IVarR = Container->findObjCIVar(Name))161return IVarR;162}163return nullptr;164};165166if (auto *IVarRecord = getIVar(Classes))167return IVarRecord;168169return getIVar(Categories);170}171172GlobalRecord *RecordsSlice::addGlobal(StringRef Name, RecordLinkage Linkage,173GlobalRecord::Kind GV, SymbolFlags Flags,174bool Inlined) {175if (GV == GlobalRecord::Kind::Function)176Flags |= SymbolFlags::Text;177else if (GV == GlobalRecord::Kind::Variable)178Flags |= SymbolFlags::Data;179180Name = copyString(Name);181auto Result = Globals.insert({Name, nullptr});182if (Result.second)183Result.first->second =184std::make_unique<GlobalRecord>(Name, Linkage, Flags, GV, Inlined);185else {186updateLinkage(Result.first->second.get(), Linkage);187updateFlags(Result.first->second.get(), Flags);188}189return Result.first->second.get();190}191192ObjCInterfaceRecord *RecordsSlice::addObjCInterface(StringRef Name,193RecordLinkage Linkage,194ObjCIFSymbolKind SymType) {195Name = copyString(Name);196auto Result = Classes.insert({Name, nullptr});197if (Result.second)198Result.first->second =199std::make_unique<ObjCInterfaceRecord>(Name, Linkage, SymType);200else201Result.first->second->updateLinkageForSymbols(SymType, Linkage);202return Result.first->second.get();203}204205SymbolFlags Record::mergeFlags(SymbolFlags Flags, RecordLinkage Linkage) {206// Add Linkage properties into Flags.207switch (Linkage) {208case RecordLinkage::Rexported:209Flags |= SymbolFlags::Rexported;210return Flags;211case RecordLinkage::Undefined:212Flags |= SymbolFlags::Undefined;213return Flags;214default:215return Flags;216}217}218219bool ObjCInterfaceRecord::addObjCCategory(ObjCCategoryRecord *Record) {220auto Result = Categories.insert({Name, Record});221return Result.second;222}223224ObjCCategoryRecord *RecordsSlice::addObjCCategory(StringRef ClassToExtend,225StringRef Category) {226Category = copyString(Category);227ClassToExtend = copyString(ClassToExtend);228229// Add owning record first into record slice.230auto Result =231Categories.insert({std::make_pair(ClassToExtend, Category), nullptr});232if (Result.second)233Result.first->second =234std::make_unique<ObjCCategoryRecord>(ClassToExtend, Category);235236// Then add reference to it in in the class.237if (auto *ObjCClass = findObjCInterface(ClassToExtend))238ObjCClass->addObjCCategory(Result.first->second.get());239240return Result.first->second.get();241}242243std::vector<ObjCIVarRecord *> ObjCContainerRecord::getObjCIVars() const {244std::vector<ObjCIVarRecord *> Records;245llvm::for_each(IVars,246[&](auto &Record) { Records.push_back(Record.second.get()); });247return Records;248}249250std::vector<ObjCCategoryRecord *>251ObjCInterfaceRecord::getObjCCategories() const {252std::vector<ObjCCategoryRecord *> Records;253llvm::for_each(Categories,254[&](auto &Record) { Records.push_back(Record.second); });255return Records;256}257258ObjCIVarRecord *ObjCContainerRecord::addObjCIVar(StringRef IVar,259RecordLinkage Linkage) {260auto Result = IVars.insert({IVar, nullptr});261if (Result.second)262Result.first->second = std::make_unique<ObjCIVarRecord>(IVar, Linkage);263return Result.first->second.get();264}265266ObjCIVarRecord *RecordsSlice::addObjCIVar(ObjCContainerRecord *Container,267StringRef Name,268RecordLinkage Linkage) {269Name = copyString(Name);270ObjCIVarRecord *Record = Container->addObjCIVar(Name, Linkage);271updateLinkage(Record, Linkage);272return Record;273}274275StringRef RecordsSlice::copyString(StringRef String) {276if (String.empty())277return {};278279if (StringAllocator.identifyObject(String.data()))280return String;281282void *Ptr = StringAllocator.Allocate(String.size(), 1);283memcpy(Ptr, String.data(), String.size());284return StringRef(reinterpret_cast<const char *>(Ptr), String.size());285}286287RecordsSlice::BinaryAttrs &RecordsSlice::getBinaryAttrs() {288if (!hasBinaryAttrs())289BA = std::make_unique<BinaryAttrs>();290return *BA;291}292293void RecordsSlice::visit(RecordVisitor &V) const {294for (auto &G : Globals)295V.visitGlobal(*G.second);296for (auto &C : Classes)297V.visitObjCInterface(*C.second);298for (auto &Cat : Categories)299V.visitObjCCategory(*Cat.second);300}301302static std::unique_ptr<InterfaceFile>303createInterfaceFile(const Records &Slices, StringRef InstallName) {304// Pickup symbols first.305auto Symbols = std::make_unique<SymbolSet>();306for (auto &S : Slices) {307if (S->empty())308continue;309auto &BA = S->getBinaryAttrs();310if (BA.InstallName != InstallName)311continue;312313SymbolConverter Converter(Symbols.get(), S->getTarget(),314!BA.TwoLevelNamespace);315S->visit(Converter);316}317318auto File = std::make_unique<InterfaceFile>(std::move(Symbols));319File->setInstallName(InstallName);320// Assign other attributes.321for (auto &S : Slices) {322if (S->empty())323continue;324auto &BA = S->getBinaryAttrs();325if (BA.InstallName != InstallName)326continue;327const Target &Targ = S->getTarget();328File->addTarget(Targ);329File->setFromBinaryAttrs(BA, Targ);330}331332return File;333}334335std::unique_ptr<InterfaceFile>336llvm::MachO::convertToInterfaceFile(const Records &Slices) {337std::unique_ptr<InterfaceFile> File;338if (Slices.empty())339return File;340341SetVector<StringRef> InstallNames;342for (auto &S : Slices) {343auto Name = S->getBinaryAttrs().InstallName;344if (Name.empty())345continue;346InstallNames.insert(Name);347}348349File = createInterfaceFile(Slices, *InstallNames.begin());350for (StringRef IN : llvm::drop_begin(InstallNames))351File->addDocument(createInterfaceFile(Slices, IN));352353return File;354}355356357