brintos

brintos / llvm-project-archived public Read only

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