diff options
Diffstat (limited to 'contrib/llvm-project/llvm/lib/TextAPI')
11 files changed, 675 insertions, 145 deletions
diff --git a/contrib/llvm-project/llvm/lib/TextAPI/InterfaceFile.cpp b/contrib/llvm-project/llvm/lib/TextAPI/InterfaceFile.cpp index b7f967aa754e..3689ab919191 100644 --- a/contrib/llvm-project/llvm/lib/TextAPI/InterfaceFile.cpp +++ b/contrib/llvm-project/llvm/lib/TextAPI/InterfaceFile.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "llvm/TextAPI/InterfaceFile.h" +#include "llvm/TextAPI/TextAPIError.h" #include <iomanip> #include <sstream> @@ -47,16 +48,16 @@ void InterfaceFile::addParentUmbrella(const Target &Target_, StringRef Parent) { } void InterfaceFile::addRPath(const Target &InputTarget, StringRef RPath) { - auto Iter = lower_bound(RPaths, InputTarget, - [](const std::pair<Target, std::string> &LHS, - Target RHS) { return LHS.first < RHS; }); + using RPathEntryT = const std::pair<Target, std::string>; + RPathEntryT Entry(InputTarget, RPath); + auto Iter = + lower_bound(RPaths, Entry, + [](RPathEntryT &LHS, RPathEntryT &RHS) { return LHS < RHS; }); - if ((Iter != RPaths.end()) && !(InputTarget < Iter->first)) { - Iter->second = std::string(RPath); + if ((Iter != RPaths.end()) && (*Iter == Entry)) return; - } - RPaths.emplace(Iter, InputTarget, std::string(RPath)); + RPaths.emplace(Iter, Entry); } void InterfaceFile::addTarget(const Target &Target) { @@ -81,6 +82,267 @@ void InterfaceFile::addDocument(std::shared_ptr<InterfaceFile> &&Document) { Documents.insert(Pos, Document); } +void InterfaceFile::inlineLibrary(std::shared_ptr<InterfaceFile> Library, + bool Overwrite) { + auto AddFwk = [&](std::shared_ptr<InterfaceFile> &&Reexport) { + auto It = lower_bound( + Documents, Reexport->getInstallName(), + [](std::shared_ptr<InterfaceFile> &Lhs, const StringRef Rhs) { + return Lhs->getInstallName() < Rhs; + }); + + if (Overwrite && It != Documents.end() && + Reexport->getInstallName() == (*It)->getInstallName()) { + std::replace(Documents.begin(), Documents.end(), *It, + std::move(Reexport)); + return; + } + + if ((It != Documents.end()) && + !(Reexport->getInstallName() < (*It)->getInstallName())) + return; + + Documents.emplace(It, std::move(Reexport)); + }; + for (auto Doc : Library->documents()) + AddFwk(std::move(Doc)); + + Library->Documents.clear(); + AddFwk(std::move(Library)); +} + +Expected<std::unique_ptr<InterfaceFile>> +InterfaceFile::merge(const InterfaceFile *O) const { + // Verify files can be merged. + if (getInstallName() != O->getInstallName()) { + return make_error<StringError>("install names do not match", + inconvertibleErrorCode()); + } + + if (getCurrentVersion() != O->getCurrentVersion()) { + return make_error<StringError>("current versions do not match", + inconvertibleErrorCode()); + } + + if (getCompatibilityVersion() != O->getCompatibilityVersion()) { + return make_error<StringError>("compatibility versions do not match", + inconvertibleErrorCode()); + } + + if ((getSwiftABIVersion() != 0) && (O->getSwiftABIVersion() != 0) && + (getSwiftABIVersion() != O->getSwiftABIVersion())) { + return make_error<StringError>("swift ABI versions do not match", + inconvertibleErrorCode()); + } + + if (isTwoLevelNamespace() != O->isTwoLevelNamespace()) { + return make_error<StringError>("two level namespace flags do not match", + inconvertibleErrorCode()); + } + + if (isApplicationExtensionSafe() != O->isApplicationExtensionSafe()) { + return make_error<StringError>( + "application extension safe flags do not match", + inconvertibleErrorCode()); + } + + std::unique_ptr<InterfaceFile> IF(new InterfaceFile()); + IF->setFileType(std::max(getFileType(), O->getFileType())); + IF->setPath(getPath()); + IF->setInstallName(getInstallName()); + IF->setCurrentVersion(getCurrentVersion()); + IF->setCompatibilityVersion(getCompatibilityVersion()); + + if (getSwiftABIVersion() == 0) + IF->setSwiftABIVersion(O->getSwiftABIVersion()); + else + IF->setSwiftABIVersion(getSwiftABIVersion()); + + IF->setTwoLevelNamespace(isTwoLevelNamespace()); + IF->setApplicationExtensionSafe(isApplicationExtensionSafe()); + + for (const auto &It : umbrellas()) { + if (!It.second.empty()) + IF->addParentUmbrella(It.first, It.second); + } + for (const auto &It : O->umbrellas()) { + if (!It.second.empty()) + IF->addParentUmbrella(It.first, It.second); + } + IF->addTargets(targets()); + IF->addTargets(O->targets()); + + for (const auto &Lib : allowableClients()) + for (const auto &Target : Lib.targets()) + IF->addAllowableClient(Lib.getInstallName(), Target); + + for (const auto &Lib : O->allowableClients()) + for (const auto &Target : Lib.targets()) + IF->addAllowableClient(Lib.getInstallName(), Target); + + for (const auto &Lib : reexportedLibraries()) + for (const auto &Target : Lib.targets()) + IF->addReexportedLibrary(Lib.getInstallName(), Target); + + for (const auto &Lib : O->reexportedLibraries()) + for (const auto &Target : Lib.targets()) + IF->addReexportedLibrary(Lib.getInstallName(), Target); + + for (const auto &[Target, Path] : rpaths()) + IF->addRPath(Target, Path); + for (const auto &[Target, Path] : O->rpaths()) + IF->addRPath(Target, Path); + + for (const auto *Sym : symbols()) { + IF->addSymbol(Sym->getKind(), Sym->getName(), Sym->targets(), + Sym->getFlags()); + } + + for (const auto *Sym : O->symbols()) { + IF->addSymbol(Sym->getKind(), Sym->getName(), Sym->targets(), + Sym->getFlags()); + } + + return std::move(IF); +} + +Expected<std::unique_ptr<InterfaceFile>> +InterfaceFile::remove(Architecture Arch) const { + if (getArchitectures() == Arch) + return make_error<StringError>("cannot remove last architecture slice '" + + getArchitectureName(Arch) + "'", + inconvertibleErrorCode()); + + if (!getArchitectures().has(Arch)) { + bool Found = false; + for (auto &Doc : Documents) { + if (Doc->getArchitectures().has(Arch)) { + Found = true; + break; + } + } + + if (!Found) + return make_error<TextAPIError>(TextAPIErrorCode::NoSuchArchitecture); + } + + std::unique_ptr<InterfaceFile> IF(new InterfaceFile()); + IF->setFileType(getFileType()); + IF->setPath(getPath()); + IF->addTargets(targets(ArchitectureSet::All().clear(Arch))); + IF->setInstallName(getInstallName()); + IF->setCurrentVersion(getCurrentVersion()); + IF->setCompatibilityVersion(getCompatibilityVersion()); + IF->setSwiftABIVersion(getSwiftABIVersion()); + IF->setTwoLevelNamespace(isTwoLevelNamespace()); + IF->setApplicationExtensionSafe(isApplicationExtensionSafe()); + for (const auto &It : umbrellas()) + if (It.first.Arch != Arch) + IF->addParentUmbrella(It.first, It.second); + + for (const auto &Lib : allowableClients()) { + for (const auto &Target : Lib.targets()) + if (Target.Arch != Arch) + IF->addAllowableClient(Lib.getInstallName(), Target); + } + + for (const auto &Lib : reexportedLibraries()) { + for (const auto &Target : Lib.targets()) + if (Target.Arch != Arch) + IF->addReexportedLibrary(Lib.getInstallName(), Target); + } + + for (const auto *Sym : symbols()) { + auto Archs = Sym->getArchitectures(); + Archs.clear(Arch); + if (Archs.empty()) + continue; + + IF->addSymbol(Sym->getKind(), Sym->getName(), Sym->targets(Archs), + Sym->getFlags()); + } + + for (auto &Doc : Documents) { + // Skip the inlined document if the to be removed architecture is the + // only one left. + if (Doc->getArchitectures() == Arch) + continue; + + // If the document doesn't contain the arch, then no work is to be done + // and it can be copied over. + if (!Doc->getArchitectures().has(Arch)) { + auto NewDoc = Doc; + IF->addDocument(std::move(NewDoc)); + continue; + } + + auto Result = Doc->remove(Arch); + if (!Result) + return Result; + + IF->addDocument(std::move(Result.get())); + } + + return std::move(IF); +} + +Expected<std::unique_ptr<InterfaceFile>> +InterfaceFile::extract(Architecture Arch) const { + if (!getArchitectures().has(Arch)) { + return make_error<StringError>("file doesn't have architecture '" + + getArchitectureName(Arch) + "'", + inconvertibleErrorCode()); + } + + std::unique_ptr<InterfaceFile> IF(new InterfaceFile()); + IF->setFileType(getFileType()); + IF->setPath(getPath()); + IF->addTargets(targets(Arch)); + IF->setInstallName(getInstallName()); + IF->setCurrentVersion(getCurrentVersion()); + IF->setCompatibilityVersion(getCompatibilityVersion()); + IF->setSwiftABIVersion(getSwiftABIVersion()); + IF->setTwoLevelNamespace(isTwoLevelNamespace()); + IF->setApplicationExtensionSafe(isApplicationExtensionSafe()); + for (const auto &It : umbrellas()) + if (It.first.Arch == Arch) + IF->addParentUmbrella(It.first, It.second); + + for (const auto &It : rpaths()) + if (It.first.Arch == Arch) + IF->addRPath(It.first, It.second); + + for (const auto &Lib : allowableClients()) + for (const auto &Target : Lib.targets()) + if (Target.Arch == Arch) + IF->addAllowableClient(Lib.getInstallName(), Target); + + for (const auto &Lib : reexportedLibraries()) + for (const auto &Target : Lib.targets()) + if (Target.Arch == Arch) + IF->addReexportedLibrary(Lib.getInstallName(), Target); + + for (const auto *Sym : symbols()) { + if (Sym->hasArchitecture(Arch)) + IF->addSymbol(Sym->getKind(), Sym->getName(), Sym->targets(Arch), + Sym->getFlags()); + } + + for (auto &Doc : Documents) { + // Skip documents that don't have the requested architecture. + if (!Doc->getArchitectures().has(Arch)) + continue; + + auto Result = Doc->extract(Arch); + if (!Result) + return Result; + + IF->addDocument(std::move(Result.get())); + } + + return std::move(IF); +} + static bool isYAMLTextStub(const FileType &Kind) { return (Kind >= FileType::TBD_V1) && (Kind < FileType::TBD_V5); } @@ -99,6 +361,10 @@ bool InterfaceFile::operator==(const InterfaceFile &O) const { return false; if (IsAppExtensionSafe != O.IsAppExtensionSafe) return false; + if (IsOSLibNotForSharedCache != O.IsOSLibNotForSharedCache) + return false; + if (HasSimSupport != O.HasSimSupport) + return false; if (ParentUmbrellas != O.ParentUmbrellas) return false; if (AllowableClients != O.AllowableClients) diff --git a/contrib/llvm-project/llvm/lib/TextAPI/PackedVersion.cpp b/contrib/llvm-project/llvm/lib/TextAPI/PackedVersion.cpp index 22960c33e9ee..4742be79f457 100644 --- a/contrib/llvm-project/llvm/lib/TextAPI/PackedVersion.cpp +++ b/contrib/llvm-project/llvm/lib/TextAPI/PackedVersion.cpp @@ -28,7 +28,7 @@ bool PackedVersion::parse32(StringRef Str) { SmallVector<StringRef, 3> Parts; SplitString(Str, Parts, "."); - if (Parts.size() > 3) + if (Parts.size() > 3 || Parts.empty()) return false; unsigned long long Num; @@ -63,7 +63,7 @@ std::pair<bool, bool> PackedVersion::parse64(StringRef Str) { SmallVector<StringRef, 5> Parts; SplitString(Str, Parts, "."); - if (Parts.size() > 5) + if (Parts.size() > 5 || Parts.empty()) return std::make_pair(false, Truncated); unsigned long long Num; diff --git a/contrib/llvm-project/llvm/lib/TextAPI/Platform.cpp b/contrib/llvm-project/llvm/lib/TextAPI/Platform.cpp index d0575847a876..ed041af40aa5 100644 --- a/contrib/llvm-project/llvm/lib/TextAPI/Platform.cpp +++ b/contrib/llvm-project/llvm/lib/TextAPI/Platform.cpp @@ -62,28 +62,11 @@ PlatformSet mapToPlatformSet(ArrayRef<Triple> Targets) { StringRef getPlatformName(PlatformType Platform) { switch (Platform) { - case PLATFORM_UNKNOWN: - return "unknown"; - case PLATFORM_MACOS: - return "macOS"; - case PLATFORM_IOS: - return "iOS"; - case PLATFORM_TVOS: - return "tvOS"; - case PLATFORM_WATCHOS: - return "watchOS"; - case PLATFORM_BRIDGEOS: - return "bridgeOS"; - case PLATFORM_MACCATALYST: - return "macCatalyst"; - case PLATFORM_IOSSIMULATOR: - return "iOS Simulator"; - case PLATFORM_TVOSSIMULATOR: - return "tvOS Simulator"; - case PLATFORM_WATCHOSSIMULATOR: - return "watchOS Simulator"; - case PLATFORM_DRIVERKIT: - return "DriverKit"; +#define PLATFORM(platform, id, name, build_name, target, tapi_target, \ + marketing) \ + case PLATFORM_##platform: \ + return #marketing; +#include "llvm/BinaryFormat/MachO.def" } llvm_unreachable("Unknown llvm::MachO::PlatformType enum"); } @@ -91,16 +74,10 @@ StringRef getPlatformName(PlatformType Platform) { PlatformType getPlatformFromName(StringRef Name) { return StringSwitch<PlatformType>(Name) .Case("osx", PLATFORM_MACOS) - .Case("macos", PLATFORM_MACOS) - .Case("ios", PLATFORM_IOS) - .Case("tvos", PLATFORM_TVOS) - .Case("watchos", PLATFORM_WATCHOS) - .Case("bridgeos", PLATFORM_BRIDGEOS) - .Case("ios-macabi", PLATFORM_MACCATALYST) - .Case("ios-simulator", PLATFORM_IOSSIMULATOR) - .Case("tvos-simulator", PLATFORM_TVOSSIMULATOR) - .Case("watchos-simulator", PLATFORM_WATCHOSSIMULATOR) - .Case("driverkit", PLATFORM_DRIVERKIT) +#define PLATFORM(platform, id, name, build_name, target, tapi_target, \ + marketing) \ + .Case(#target, PLATFORM_##platform) +#include "llvm/BinaryFormat/MachO.def" .Default(PLATFORM_UNKNOWN); } diff --git a/contrib/llvm-project/llvm/lib/TextAPI/RecordsSlice.cpp b/contrib/llvm-project/llvm/lib/TextAPI/RecordsSlice.cpp new file mode 100644 index 000000000000..a220b255aea3 --- /dev/null +++ b/contrib/llvm-project/llvm/lib/TextAPI/RecordsSlice.cpp @@ -0,0 +1,224 @@ +//===- 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/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); + 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(); +} + +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(); +} + +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); + 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; +} diff --git a/contrib/llvm-project/llvm/lib/TextAPI/Symbol.cpp b/contrib/llvm-project/llvm/lib/TextAPI/Symbol.cpp index 20fa6362716a..fd395436051d 100644 --- a/contrib/llvm-project/llvm/lib/TextAPI/Symbol.cpp +++ b/contrib/llvm-project/llvm/lib/TextAPI/Symbol.cpp @@ -72,5 +72,31 @@ bool Symbol::operator==(const Symbol &O) const { std::tie(O.Name, O.Kind, O.Targets, RHSFlags); } +SimpleSymbol parseSymbol(StringRef SymName, const SymbolFlags Flags) { + if (SymName.starts_with(ObjC1ClassNamePrefix)) + return {SymName.drop_front(ObjC1ClassNamePrefix.size()), + SymbolKind::ObjectiveCClass}; + if (SymName.starts_with(ObjC2ClassNamePrefix)) + return {SymName.drop_front(ObjC2ClassNamePrefix.size()), + SymbolKind::ObjectiveCClass}; + if (SymName.starts_with(ObjC2MetaClassNamePrefix)) + return {SymName.drop_front(ObjC2MetaClassNamePrefix.size()), + SymbolKind::ObjectiveCClass}; + if (SymName.starts_with(ObjC2EHTypePrefix)) { + // When classes without ehtype are used in try/catch blocks + // a weak-defined symbol is exported. In those cases, treat these as a + // global instead. + if ((Flags & SymbolFlags::WeakDefined) == SymbolFlags::WeakDefined) + return {SymName, SymbolKind::GlobalSymbol}; + return {SymName.drop_front(ObjC2EHTypePrefix.size()), + SymbolKind::ObjectiveCClassEHType}; + } + + if (SymName.starts_with(ObjC2IVarPrefix)) + return {SymName.drop_front(ObjC2IVarPrefix.size()), + SymbolKind::ObjectiveCInstanceVariable}; + return {SymName, SymbolKind::GlobalSymbol}; +} + } // end namespace MachO. } // end namespace llvm. diff --git a/contrib/llvm-project/llvm/lib/TextAPI/SymbolSet.cpp b/contrib/llvm-project/llvm/lib/TextAPI/SymbolSet.cpp index 157e13749729..5b9882dadcdf 100644 --- a/contrib/llvm-project/llvm/lib/TextAPI/SymbolSet.cpp +++ b/contrib/llvm-project/llvm/lib/TextAPI/SymbolSet.cpp @@ -29,8 +29,5 @@ Symbol *SymbolSet::addGlobal(SymbolKind Kind, StringRef Name, SymbolFlags Flags, } const Symbol *SymbolSet::findSymbol(SymbolKind Kind, StringRef Name) const { - auto It = Symbols.find({Kind, Name}); - if (It != Symbols.end()) - return It->second; - return nullptr; + return Symbols.lookup({Kind, Name}); } diff --git a/contrib/llvm-project/llvm/lib/TextAPI/Target.cpp b/contrib/llvm-project/llvm/lib/TextAPI/Target.cpp index e20842498331..a50abeeca194 100644 --- a/contrib/llvm-project/llvm/lib/TextAPI/Target.cpp +++ b/contrib/llvm-project/llvm/lib/TextAPI/Target.cpp @@ -21,20 +21,14 @@ Expected<Target> Target::create(StringRef TargetValue) { auto PlatformStr = Result.second; PlatformType Platform; Platform = StringSwitch<PlatformType>(PlatformStr) - .Case("macos", PLATFORM_MACOS) - .Case("ios", PLATFORM_IOS) - .Case("tvos", PLATFORM_TVOS) - .Case("watchos", PLATFORM_WATCHOS) - .Case("bridgeos", PLATFORM_BRIDGEOS) - .Case("maccatalyst", PLATFORM_MACCATALYST) - .Case("ios-simulator", PLATFORM_IOSSIMULATOR) - .Case("tvos-simulator", PLATFORM_TVOSSIMULATOR) - .Case("watchos-simulator", PLATFORM_WATCHOSSIMULATOR) - .Case("driverkit", PLATFORM_DRIVERKIT) +#define PLATFORM(platform, id, name, build_name, target, tapi_target, \ + marketing) \ + .Case(#tapi_target, PLATFORM_##platform) +#include "llvm/BinaryFormat/MachO.def" .Default(PLATFORM_UNKNOWN); if (Platform == PLATFORM_UNKNOWN) { - if (PlatformStr.startswith("<") && PlatformStr.endswith(">")) { + if (PlatformStr.starts_with("<") && PlatformStr.ends_with(">")) { PlatformStr = PlatformStr.drop_front().drop_back(); unsigned long long RawValue; if (!PlatformStr.getAsInteger(10, RawValue)) diff --git a/contrib/llvm-project/llvm/lib/TextAPI/TextAPIError.cpp b/contrib/llvm-project/llvm/lib/TextAPI/TextAPIError.cpp new file mode 100644 index 000000000000..23954a9e3466 --- /dev/null +++ b/contrib/llvm-project/llvm/lib/TextAPI/TextAPIError.cpp @@ -0,0 +1,39 @@ +//===- TextAPIError.cpp - Tapi Error ----------------------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Implements TAPI Error. +/// +//===----------------------------------------------------------------------===// + +#include "llvm/TextAPI/TextAPIError.h" + +using namespace llvm; +using namespace llvm::MachO; + +char TextAPIError::ID = 0; + +void TextAPIError::log(raw_ostream &OS) const { + switch (EC) { + case TextAPIErrorCode::NoSuchArchitecture: + OS << "no such architecture"; + break; + case TextAPIErrorCode::InvalidInputFormat: + OS << "invalid input format"; + break; + default: + llvm_unreachable("unhandled TextAPIErrorCode"); + } + if (!Msg.empty()) + OS << ": " << Msg; + OS << "\n"; +} + +std::error_code TextAPIError::convertToErrorCode() const { + llvm_unreachable("convertToErrorCode is not supported."); +} diff --git a/contrib/llvm-project/llvm/lib/TextAPI/TextStub.cpp b/contrib/llvm-project/llvm/lib/TextAPI/TextStub.cpp index 78de3ebf3f3a..9fa1459e9557 100644 --- a/contrib/llvm-project/llvm/lib/TextAPI/TextStub.cpp +++ b/contrib/llvm-project/llvm/lib/TextAPI/TextStub.cpp @@ -360,6 +360,8 @@ template <> struct ScalarBitSetTraits<TBDFlags> { IO.bitSetCase(Flags, "not_app_extension_safe", TBDFlags::NotApplicationExtensionSafe); IO.bitSetCase(Flags, "installapi", TBDFlags::InstallAPI); + IO.bitSetCase(Flags, "not_for_dyld_shared_cache", + TBDFlags::OSLibNotForSharedCache); } }; @@ -367,39 +369,12 @@ template <> struct ScalarTraits<Target> { static void output(const Target &Value, void *, raw_ostream &OS) { OS << Value.Arch << "-"; switch (Value.Platform) { - default: - OS << "unknown"; - break; - case PLATFORM_MACOS: - OS << "macos"; - break; - case PLATFORM_IOS: - OS << "ios"; - break; - case PLATFORM_TVOS: - OS << "tvos"; - break; - case PLATFORM_WATCHOS: - OS << "watchos"; - break; - case PLATFORM_BRIDGEOS: - OS << "bridgeos"; - break; - case PLATFORM_MACCATALYST: - OS << "maccatalyst"; - break; - case PLATFORM_IOSSIMULATOR: - OS << "ios-simulator"; - break; - case PLATFORM_TVOSSIMULATOR: - OS << "tvos-simulator"; - break; - case PLATFORM_WATCHOSSIMULATOR: - OS << "watchos-simulator"; - break; - case PLATFORM_DRIVERKIT: - OS << "driverkit"; - break; +#define PLATFORM(platform, id, name, build_name, target, tapi_target, \ + marketing) \ + case PLATFORM_##platform: \ + OS << #tapi_target; \ + break; +#include "llvm/BinaryFormat/MachO.def" } } @@ -620,6 +595,11 @@ template <> struct MappingTraits<const InterfaceFile *> { !(Flags & TBDFlags::NotApplicationExtensionSafe)); } + // For older file formats, the segment where the symbol + // comes from is unknown, treat all symbols as Data + // in these cases. + const auto Flags = SymbolFlags::Data; + for (const auto &Section : Exports) { const auto Targets = synthesizeTargets(Section.Architectures, Platforms); @@ -634,33 +614,34 @@ template <> struct MappingTraits<const InterfaceFile *> { for (const auto &Symbol : Section.Symbols) { if (Ctx->FileKind != FileType::TBD_V3 && - Symbol.value.startswith("_OBJC_EHTYPE_$_")) + Symbol.value.starts_with(ObjC2EHTypePrefix)) File->addSymbol(SymbolKind::ObjectiveCClassEHType, - Symbol.value.drop_front(15), Targets); + Symbol.value.drop_front(15), Targets, Flags); else - File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets); + File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets, Flags); } for (auto &Symbol : Section.Classes) { auto Name = Symbol.value; if (Ctx->FileKind != FileType::TBD_V3) Name = Name.drop_front(); - File->addSymbol(SymbolKind::ObjectiveCClass, Name, Targets); + File->addSymbol(SymbolKind::ObjectiveCClass, Name, Targets, Flags); } for (auto &Symbol : Section.ClassEHs) - File->addSymbol(SymbolKind::ObjectiveCClassEHType, Symbol, Targets); + File->addSymbol(SymbolKind::ObjectiveCClassEHType, Symbol, Targets, + Flags); for (auto &Symbol : Section.IVars) { auto Name = Symbol.value; if (Ctx->FileKind != FileType::TBD_V3) Name = Name.drop_front(); - File->addSymbol(SymbolKind::ObjectiveCInstanceVariable, Name, - Targets); + File->addSymbol(SymbolKind::ObjectiveCInstanceVariable, Name, Targets, + Flags); } for (auto &Symbol : Section.WeakDefSymbols) File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets, - SymbolFlags::WeakDefined); + SymbolFlags::WeakDefined | Flags); for (auto &Symbol : Section.TLVSymbols) File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets, - SymbolFlags::ThreadLocalValue); + SymbolFlags::ThreadLocalValue | Flags); } for (const auto &Section : Undefineds) { @@ -668,34 +649,35 @@ template <> struct MappingTraits<const InterfaceFile *> { synthesizeTargets(Section.Architectures, Platforms); for (auto &Symbol : Section.Symbols) { if (Ctx->FileKind != FileType::TBD_V3 && - Symbol.value.startswith("_OBJC_EHTYPE_$_")) + Symbol.value.starts_with(ObjC2EHTypePrefix)) File->addSymbol(SymbolKind::ObjectiveCClassEHType, Symbol.value.drop_front(15), Targets, - SymbolFlags::Undefined); + SymbolFlags::Undefined | Flags); else File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets, - SymbolFlags::Undefined); + SymbolFlags::Undefined | Flags); } for (auto &Symbol : Section.Classes) { auto Name = Symbol.value; if (Ctx->FileKind != FileType::TBD_V3) Name = Name.drop_front(); File->addSymbol(SymbolKind::ObjectiveCClass, Name, Targets, - SymbolFlags::Undefined); + SymbolFlags::Undefined | Flags); } for (auto &Symbol : Section.ClassEHs) File->addSymbol(SymbolKind::ObjectiveCClassEHType, Symbol, Targets, - SymbolFlags::Undefined); + SymbolFlags::Undefined | Flags); for (auto &Symbol : Section.IVars) { auto Name = Symbol.value; if (Ctx->FileKind != FileType::TBD_V3) Name = Name.drop_front(); File->addSymbol(SymbolKind::ObjectiveCInstanceVariable, Name, Targets, - SymbolFlags::Undefined); + SymbolFlags::Undefined | Flags); } for (auto &Symbol : Section.WeakRefSymbols) File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets, - SymbolFlags::Undefined | SymbolFlags::WeakReferenced); + SymbolFlags::Undefined | SymbolFlags::WeakReferenced | + Flags); } return File; @@ -787,7 +769,7 @@ template <> struct MappingTraits<const InterfaceFile *> { NormalizedTBD_V4(IO &IO, const InterfaceFile *&File) { auto Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext()); assert(Ctx); - TBDVersion = Ctx->FileKind >> 1; + TBDVersion = Ctx->FileKind >> 4; Targets.insert(Targets.begin(), File->targets().begin(), File->targets().end()); InstallName = File->getInstallName(); @@ -802,6 +784,9 @@ template <> struct MappingTraits<const InterfaceFile *> { if (!File->isTwoLevelNamespace()) Flags |= TBDFlags::FlatNamespace; + if (File->isOSLibNotForSharedCache()) + Flags |= TBDFlags::OSLibNotForSharedCache; + { std::map<std::string, TargetList> valueToTargetList; for (const auto &it : File->umbrellas()) @@ -892,6 +877,8 @@ template <> struct MappingTraits<const InterfaceFile *> { File->setTwoLevelNamespace(!(Flags & TBDFlags::FlatNamespace)); File->setApplicationExtensionSafe( !(Flags & TBDFlags::NotApplicationExtensionSafe)); + File->setOSLibNotForSharedCache( + (Flags & TBDFlags::OSLibNotForSharedCache)); for (const auto &CurrentSection : AllowableClients) { for (const auto &lib : CurrentSection.Values) @@ -906,7 +893,12 @@ template <> struct MappingTraits<const InterfaceFile *> { } auto handleSymbols = [File](const SectionList &CurrentSections, - SymbolFlags Flag = SymbolFlags::None) { + SymbolFlags InputFlag = SymbolFlags::None) { + // For older file formats, the segment where the symbol + // comes from is unknown, treat all symbols as Data + // in these cases. + const SymbolFlags Flag = InputFlag | SymbolFlags::Data; + for (const auto &CurrentSection : CurrentSections) { for (auto &sym : CurrentSection.Symbols) File->addSymbol(SymbolKind::GlobalSymbol, sym, @@ -924,9 +916,10 @@ template <> struct MappingTraits<const InterfaceFile *> { File->addSymbol(SymbolKind::ObjectiveCInstanceVariable, sym, CurrentSection.Targets, Flag); - SymbolFlags SymFlag = (Flag == SymbolFlags::Undefined) - ? SymbolFlags::WeakReferenced - : SymbolFlags::WeakDefined; + SymbolFlags SymFlag = + ((Flag & SymbolFlags::Undefined) == SymbolFlags::Undefined) + ? SymbolFlags::WeakReferenced + : SymbolFlags::WeakDefined; for (auto &sym : CurrentSection.WeakSymbols) { File->addSymbol(SymbolKind::GlobalSymbol, sym, CurrentSection.Targets, Flag | SymFlag); @@ -1078,38 +1071,35 @@ static void DiagHandler(const SMDiagnostic &Diag, void *Context) { File->ErrorMessage = ("malformed file\n" + Message).str(); } -namespace { - -Expected<FileType> canReadFileType(MemoryBufferRef InputBuffer) { +Expected<FileType> TextAPIReader::canRead(MemoryBufferRef InputBuffer) { auto TAPIFile = InputBuffer.getBuffer().trim(); - if (TAPIFile.startswith("{") && TAPIFile.endswith("}")) + if (TAPIFile.starts_with("{") && TAPIFile.ends_with("}")) return FileType::TBD_V5; - if (!TAPIFile.endswith("...")) + if (!TAPIFile.ends_with("...")) return createStringError(std::errc::not_supported, "unsupported file type"); - if (TAPIFile.startswith("--- !tapi-tbd\n")) + if (TAPIFile.starts_with("--- !tapi-tbd\n")) return FileType::TBD_V4; - if (TAPIFile.startswith("--- !tapi-tbd-v3\n")) + if (TAPIFile.starts_with("--- !tapi-tbd-v3\n")) return FileType::TBD_V3; - if (TAPIFile.startswith("--- !tapi-tbd-v2\n")) + if (TAPIFile.starts_with("--- !tapi-tbd-v2\n")) return FileType::TBD_V2; - if (TAPIFile.startswith("--- !tapi-tbd-v1\n") || - TAPIFile.startswith("---\narchs:")) + if (TAPIFile.starts_with("--- !tapi-tbd-v1\n") || + TAPIFile.starts_with("---\narchs:")) return FileType::TBD_V1; return createStringError(std::errc::not_supported, "unsupported file type"); } -} // namespace Expected<std::unique_ptr<InterfaceFile>> TextAPIReader::get(MemoryBufferRef InputBuffer) { TextAPIContext Ctx; Ctx.Path = std::string(InputBuffer.getBufferIdentifier()); - if (auto FTOrErr = canReadFileType(InputBuffer)) + if (auto FTOrErr = canRead(InputBuffer)) Ctx.FileKind = *FTOrErr; else return FTOrErr.takeError(); @@ -1119,6 +1109,8 @@ TextAPIReader::get(MemoryBufferRef InputBuffer) { auto FileOrErr = getInterfaceFileFromJSON(InputBuffer.getBuffer()); if (!FileOrErr) return FileOrErr.takeError(); + + (*FileOrErr)->setPath(Ctx.Path); return std::move(*FileOrErr); } yaml::Input YAMLIn(InputBuffer.getBuffer(), &Ctx, DiagHandler, &Ctx); @@ -1143,14 +1135,18 @@ TextAPIReader::get(MemoryBufferRef InputBuffer) { } Error TextAPIWriter::writeToStream(raw_ostream &OS, const InterfaceFile &File, - bool Compact) { + const FileType FileKind, bool Compact) { TextAPIContext Ctx; Ctx.Path = std::string(File.getPath()); - Ctx.FileKind = File.getFileType(); + + // Prefer parameter for format if passed, otherwise fallback to the File + // FileType. + Ctx.FileKind = + (FileKind == FileType::Invalid) ? File.getFileType() : FileKind; // Write out in JSON format. if (Ctx.FileKind >= FileType::TBD_V5) { - return serializeInterfaceFileToJSON(OS, File, Compact); + return serializeInterfaceFileToJSON(OS, File, Ctx.FileKind, Compact); } llvm::yaml::Output YAMLOut(OS, &Ctx, /*WrapColumn=*/80); @@ -1158,7 +1154,7 @@ Error TextAPIWriter::writeToStream(raw_ostream &OS, const InterfaceFile &File, std::vector<const InterfaceFile *> Files; Files.emplace_back(&File); - for (auto Document : File.documents()) + for (const auto &Document : File.documents()) Files.emplace_back(Document.get()); // Stream out yaml. diff --git a/contrib/llvm-project/llvm/lib/TextAPI/TextStubCommon.h b/contrib/llvm-project/llvm/lib/TextAPI/TextStubCommon.h index d4dcd3af447a..360910c48d4f 100644 --- a/contrib/llvm-project/llvm/lib/TextAPI/TextStubCommon.h +++ b/contrib/llvm-project/llvm/lib/TextAPI/TextStubCommon.h @@ -28,7 +28,9 @@ enum TBDFlags : unsigned { FlatNamespace = 1U << 0, NotApplicationExtensionSafe = 1U << 1, InstallAPI = 1U << 2, - LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/InstallAPI), + SimulatorSupport = 1U << 3, + OSLibNotForSharedCache = 1U << 4, + LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/OSLibNotForSharedCache), }; // clang-format on @@ -47,7 +49,7 @@ Expected<std::unique_ptr<InterfaceFile>> getInterfaceFileFromJSON(StringRef JSON); Error serializeInterfaceFileToJSON(raw_ostream &OS, const InterfaceFile &File, - bool Compact); + const FileType FileKind, bool Compact); } // namespace MachO namespace yaml { diff --git a/contrib/llvm-project/llvm/lib/TextAPI/TextStubV5.cpp b/contrib/llvm-project/llvm/lib/TextAPI/TextStubV5.cpp index 5b3d69b8d94a..2f82bc03480b 100644 --- a/contrib/llvm-project/llvm/lib/TextAPI/TextStubV5.cpp +++ b/contrib/llvm-project/llvm/lib/TextAPI/TextStubV5.cpp @@ -27,7 +27,7 @@ All library level keys, accept target values and are defaulted if not specified. "target_info": [ # Required: target information { "target": "x86_64-macos", - "min_deployment": "10.14" # Required: minimum OS deployment version + "min_deployment": "10.14" # Optional: minOS defaults to 0 }, { "target": "arm64-macos", @@ -283,17 +283,16 @@ Expected<TargetList> getTargetsSection(const Object *Section) { getRequiredValue<StringRef>(TBDKey::Target, Obj, &Object::getString); if (!TargetStr) return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target)); - auto VersionStr = getRequiredValue<StringRef>(TBDKey::Deployment, Obj, - &Object::getString); - if (!VersionStr) - return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Deployment)); - VersionTuple Version; - if (Version.tryParse(*VersionStr)) - return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Deployment)); auto TargetOrErr = Target::create(*TargetStr); if (!TargetOrErr) return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target)); + + auto VersionStr = Obj->getString(Keys[TBDKey::Deployment]); + VersionTuple Version; + if (VersionStr && Version.tryParse(*VersionStr)) + return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Deployment)); TargetOrErr->MinDeployment = Version; + // Convert to LLVM::Triple to accurately compute minOS + platform + arch // pairing. IFTargets.push_back( @@ -548,11 +547,11 @@ Expected<PackedVersion> getPackedVersion(const Object *File, TBDKey Key) { Expected<TBDFlags> getFlags(const Object *File) { TBDFlags Flags = TBDFlags::None; const Array *Section = File->getArray(Keys[TBDKey::Flags]); - if (!Section) + if (!Section || Section->empty()) return Flags; for (auto &Val : *Section) { - // TODO: Just take first for now. + // FIXME: Flags currently apply to all target triples. const auto *Obj = Val.getAsObject(); if (!Obj) return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Flags)); @@ -564,6 +563,9 @@ Expected<TBDFlags> getFlags(const Object *File) { .Case("flat_namespace", TBDFlags::FlatNamespace) .Case("not_app_extension_safe", TBDFlags::NotApplicationExtensionSafe) + .Case("sim_support", TBDFlags::SimulatorSupport) + .Case("not_for_dyld_shared_cache", + TBDFlags::OSLibNotForSharedCache) .Default(TBDFlags::None); Flags |= TBDFlag; }); @@ -654,6 +656,8 @@ Expected<IFPtr> parseToInterfaceFile(const Object *File) { F->setTwoLevelNamespace(!(Flags & TBDFlags::FlatNamespace)); F->setApplicationExtensionSafe( !(Flags & TBDFlags::NotApplicationExtensionSafe)); + F->setSimulatorSupport((Flags & TBDFlags::SimulatorSupport)); + F->setOSLibNotForSharedCache((Flags & TBDFlags::OSLibNotForSharedCache)); for (auto &T : Targets) F->addTarget(T); for (auto &[Lib, Targets] : Clients) @@ -753,9 +757,9 @@ std::vector<std::string> serializeTargets(const AggregateT Targets, if (Targets.size() == ActiveTargets.size()) return TargetsStr; - llvm::for_each(Targets, [&TargetsStr](const MachO::Target &Target) { + for (const MachO::Target &Target : Targets) TargetsStr.emplace_back(getFormattedStr(Target)); - }); + return TargetsStr; } @@ -763,7 +767,8 @@ Array serializeTargetInfo(const TargetList &ActiveTargets) { Array Targets; for (const auto Targ : ActiveTargets) { Object TargetInfo; - TargetInfo[Keys[TBDKey::Deployment]] = Targ.MinDeployment.getAsString(); + if (!Targ.MinDeployment.empty()) + TargetInfo[Keys[TBDKey::Deployment]] = Targ.MinDeployment.getAsString(); TargetInfo[Keys[TBDKey::Target]] = getFormattedStr(Targ); Targets.emplace_back(std::move(TargetInfo)); } @@ -920,6 +925,10 @@ Array serializeFlags(const InterfaceFile *File) { Flags.emplace_back("flat_namespace"); if (!File->isApplicationExtensionSafe()) Flags.emplace_back("not_app_extension_safe"); + if (File->hasSimulatorSupport()) + Flags.emplace_back("sim_support"); + if (File->isOSLibNotForSharedCache()) + Flags.emplace_back("not_for_dyld_shared_cache"); return serializeScalar(TBDKey::Attributes, std::move(Flags)); } @@ -983,9 +992,8 @@ Expected<Object> serializeIF(const InterfaceFile *File) { return std::move(Library); } -Expected<Object> getJSON(const InterfaceFile *File) { - assert(File->getFileType() == FileType::TBD_V5 && - "unexpected json file format version"); +Expected<Object> getJSON(const InterfaceFile *File, const FileType FileKind) { + assert(FileKind == FileType::TBD_V5 && "unexpected json file format version"); Object Root; auto MainLibOrErr = serializeIF(File); @@ -1009,8 +1017,9 @@ Expected<Object> getJSON(const InterfaceFile *File) { Error MachO::serializeInterfaceFileToJSON(raw_ostream &OS, const InterfaceFile &File, + const FileType FileKind, bool Compact) { - auto TextFile = getJSON(&File); + auto TextFile = getJSON(&File, FileKind); if (!TextFile) return TextFile.takeError(); if (Compact) |