Path: blob/main/contrib/llvm-project/llvm/lib/TextAPI/TextStub.cpp
35262 views
//===- TextStub.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 text stub file reader/writer.9//10//===----------------------------------------------------------------------===//1112#include "TextAPIContext.h"13#include "TextStubCommon.h"14#include "llvm/ADT/BitmaskEnum.h"15#include "llvm/ADT/SmallString.h"16#include "llvm/ADT/StringRef.h"17#include "llvm/Support/Allocator.h"18#include "llvm/Support/SourceMgr.h"19#include "llvm/Support/YAMLTraits.h"20#include "llvm/Support/raw_ostream.h"21#include "llvm/TextAPI/Architecture.h"22#include "llvm/TextAPI/ArchitectureSet.h"23#include "llvm/TextAPI/InterfaceFile.h"24#include "llvm/TextAPI/PackedVersion.h"25#include "llvm/TextAPI/TextAPIReader.h"26#include "llvm/TextAPI/TextAPIWriter.h"27#include <algorithm>28#include <set>2930// clang-format off31/*3233YAML Format specification.3435The TBD v1 format only support two level address libraries and is per36definition application extension safe.3738--- # the tag !tapi-tbd-v1 is optional and39# shouldn't be emitted to support older linker.40archs: [ armv7, armv7s, arm64 ] # the list of architecture slices that are41# supported by this file.42platform: ios # Specifies the platform (macosx, ios, etc)43install-name: /u/l/libfoo.dylib #44current-version: 1.2.3 # Optional: defaults to 1.045compatibility-version: 1.0 # Optional: defaults to 1.046swift-version: 0 # Optional: defaults to 047objc-constraint: none # Optional: defaults to none48exports: # List of export sections49...5051Each export section is defined as following:5253- archs: [ arm64 ] # the list of architecture slices54allowed-clients: [ client ] # Optional: List of clients55re-exports: [ ] # Optional: List of re-exports56symbols: [ _sym ] # Optional: List of symbols57objc-classes: [] # Optional: List of Objective-C classes58objc-ivars: [] # Optional: List of Objective C Instance59# Variables60weak-def-symbols: [] # Optional: List of weak defined symbols61thread-local-symbols: [] # Optional: List of thread local symbols62*/6364/*6566YAML Format specification.6768--- !tapi-tbd-v269archs: [ armv7, armv7s, arm64 ] # the list of architecture slices that are70# supported by this file.71uuids: [ armv7:... ] # Optional: List of architecture and UUID pairs.72platform: ios # Specifies the platform (macosx, ios, etc)73flags: [] # Optional:74install-name: /u/l/libfoo.dylib #75current-version: 1.2.3 # Optional: defaults to 1.076compatibility-version: 1.0 # Optional: defaults to 1.077swift-version: 0 # Optional: defaults to 078objc-constraint: retain_release # Optional: defaults to retain_release79parent-umbrella: # Optional:80exports: # List of export sections81...82undefineds: # List of undefineds sections83...8485Each export section is defined as following:8687- archs: [ arm64 ] # the list of architecture slices88allowed-clients: [ client ] # Optional: List of clients89re-exports: [ ] # Optional: List of re-exports90symbols: [ _sym ] # Optional: List of symbols91objc-classes: [] # Optional: List of Objective-C classes92objc-ivars: [] # Optional: List of Objective C Instance93# Variables94weak-def-symbols: [] # Optional: List of weak defined symbols95thread-local-symbols: [] # Optional: List of thread local symbols9697Each undefineds section is defined as following:98- archs: [ arm64 ] # the list of architecture slices99symbols: [ _sym ] # Optional: List of symbols100objc-classes: [] # Optional: List of Objective-C classes101objc-ivars: [] # Optional: List of Objective C Instance Variables102weak-ref-symbols: [] # Optional: List of weak defined symbols103*/104105/*106107YAML Format specification.108109--- !tapi-tbd-v3110archs: [ armv7, armv7s, arm64 ] # the list of architecture slices that are111# supported by this file.112uuids: [ armv7:... ] # Optional: List of architecture and UUID pairs.113platform: ios # Specifies the platform (macosx, ios, etc)114flags: [] # Optional:115install-name: /u/l/libfoo.dylib #116current-version: 1.2.3 # Optional: defaults to 1.0117compatibility-version: 1.0 # Optional: defaults to 1.0118swift-abi-version: 0 # Optional: defaults to 0119objc-constraint: retain_release # Optional: defaults to retain_release120parent-umbrella: # Optional:121exports: # List of export sections122...123undefineds: # List of undefineds sections124...125126Each export section is defined as following:127128- archs: [ arm64 ] # the list of architecture slices129allowed-clients: [ client ] # Optional: List of clients130re-exports: [ ] # Optional: List of re-exports131symbols: [ _sym ] # Optional: List of symbols132objc-classes: [] # Optional: List of Objective-C classes133objc-eh-types: [] # Optional: List of Objective-C classes134# with EH135objc-ivars: [] # Optional: List of Objective C Instance136# Variables137weak-def-symbols: [] # Optional: List of weak defined symbols138thread-local-symbols: [] # Optional: List of thread local symbols139140Each undefineds section is defined as following:141- archs: [ arm64 ] # the list of architecture slices142symbols: [ _sym ] # Optional: List of symbols143objc-classes: [] # Optional: List of Objective-C classes144objc-eh-types: [] # Optional: List of Objective-C classes145# with EH146objc-ivars: [] # Optional: List of Objective C Instance Variables147weak-ref-symbols: [] # Optional: List of weak defined symbols148*/149150/*151152YAML Format specification.153154--- !tapi-tbd155tbd-version: 4 # The tbd version for format156targets: [ armv7-ios, x86_64-maccatalyst ] # The list of applicable tapi supported target triples157uuids: # Optional: List of target and UUID pairs.158- target: armv7-ios159value: ...160- target: x86_64-maccatalyst161value: ...162flags: [] # Optional:163install-name: /u/l/libfoo.dylib #164current-version: 1.2.3 # Optional: defaults to 1.0165compatibility-version: 1.0 # Optional: defaults to 1.0166swift-abi-version: 0 # Optional: defaults to 0167parent-umbrella: # Optional:168allowable-clients:169- targets: [ armv7-ios ] # Optional:170clients: [ clientA ]171exports: # List of export sections172...173re-exports: # List of reexport sections174...175undefineds: # List of undefineds sections176...177178Each export and reexport section is defined as following:179180- targets: [ arm64-macos ] # The list of target triples associated with symbols181symbols: [ _symA ] # Optional: List of symbols182objc-classes: [] # Optional: List of Objective-C classes183objc-eh-types: [] # Optional: List of Objective-C classes184# with EH185objc-ivars: [] # Optional: List of Objective C Instance186# Variables187weak-symbols: [] # Optional: List of weak defined symbols188thread-local-symbols: [] # Optional: List of thread local symbols189- targets: [ arm64-macos, x86_64-maccatalyst ] # Optional: Targets for applicable additional symbols190symbols: [ _symB ] # Optional: List of symbols191192Each undefineds section is defined as following:193- targets: [ arm64-macos ] # The list of target triples associated with symbols194symbols: [ _symC ] # Optional: List of symbols195objc-classes: [] # Optional: List of Objective-C classes196objc-eh-types: [] # Optional: List of Objective-C classes197# with EH198objc-ivars: [] # Optional: List of Objective C Instance Variables199weak-symbols: [] # Optional: List of weak defined symbols200*/201// clang-format on202203using namespace llvm;204using namespace llvm::yaml;205using namespace llvm::MachO;206207namespace {208struct ExportSection {209std::vector<Architecture> Architectures;210std::vector<FlowStringRef> AllowableClients;211std::vector<FlowStringRef> ReexportedLibraries;212std::vector<FlowStringRef> Symbols;213std::vector<FlowStringRef> Classes;214std::vector<FlowStringRef> ClassEHs;215std::vector<FlowStringRef> IVars;216std::vector<FlowStringRef> WeakDefSymbols;217std::vector<FlowStringRef> TLVSymbols;218};219220struct UndefinedSection {221std::vector<Architecture> Architectures;222std::vector<FlowStringRef> Symbols;223std::vector<FlowStringRef> Classes;224std::vector<FlowStringRef> ClassEHs;225std::vector<FlowStringRef> IVars;226std::vector<FlowStringRef> WeakRefSymbols;227};228229// Sections for direct target mapping in TBDv4230struct SymbolSection {231TargetList Targets;232std::vector<FlowStringRef> Symbols;233std::vector<FlowStringRef> Classes;234std::vector<FlowStringRef> ClassEHs;235std::vector<FlowStringRef> Ivars;236std::vector<FlowStringRef> WeakSymbols;237std::vector<FlowStringRef> TlvSymbols;238};239240struct MetadataSection {241enum Option { Clients, Libraries };242std::vector<Target> Targets;243std::vector<FlowStringRef> Values;244};245246struct UmbrellaSection {247std::vector<Target> Targets;248std::string Umbrella;249};250251// UUID's for TBDv4 are mapped to target not arch252struct UUIDv4 {253Target TargetID;254std::string Value;255256UUIDv4() = default;257UUIDv4(const Target &TargetID, const std::string &Value)258: TargetID(TargetID), Value(Value) {}259};260} // end anonymous namespace.261262LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(Architecture)263LLVM_YAML_IS_SEQUENCE_VECTOR(ExportSection)264LLVM_YAML_IS_SEQUENCE_VECTOR(UndefinedSection)265// Specific to TBDv4266LLVM_YAML_IS_SEQUENCE_VECTOR(SymbolSection)267LLVM_YAML_IS_SEQUENCE_VECTOR(MetadataSection)268LLVM_YAML_IS_SEQUENCE_VECTOR(UmbrellaSection)269LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(Target)270LLVM_YAML_IS_SEQUENCE_VECTOR(UUIDv4)271272namespace llvm {273namespace yaml {274275template <> struct MappingTraits<ExportSection> {276static void mapping(IO &IO, ExportSection &Section) {277const auto *Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext());278assert((!Ctx || Ctx->FileKind != FileType::Invalid) &&279"File type is not set in YAML context");280281IO.mapRequired("archs", Section.Architectures);282if (Ctx->FileKind == FileType::TBD_V1)283IO.mapOptional("allowed-clients", Section.AllowableClients);284else285IO.mapOptional("allowable-clients", Section.AllowableClients);286IO.mapOptional("re-exports", Section.ReexportedLibraries);287IO.mapOptional("symbols", Section.Symbols);288IO.mapOptional("objc-classes", Section.Classes);289if (Ctx->FileKind == FileType::TBD_V3)290IO.mapOptional("objc-eh-types", Section.ClassEHs);291IO.mapOptional("objc-ivars", Section.IVars);292IO.mapOptional("weak-def-symbols", Section.WeakDefSymbols);293IO.mapOptional("thread-local-symbols", Section.TLVSymbols);294}295};296297template <> struct MappingTraits<UndefinedSection> {298static void mapping(IO &IO, UndefinedSection &Section) {299const auto *Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext());300assert((!Ctx || Ctx->FileKind != FileType::Invalid) &&301"File type is not set in YAML context");302303IO.mapRequired("archs", Section.Architectures);304IO.mapOptional("symbols", Section.Symbols);305IO.mapOptional("objc-classes", Section.Classes);306if (Ctx->FileKind == FileType::TBD_V3)307IO.mapOptional("objc-eh-types", Section.ClassEHs);308IO.mapOptional("objc-ivars", Section.IVars);309IO.mapOptional("weak-ref-symbols", Section.WeakRefSymbols);310}311};312313template <> struct MappingTraits<SymbolSection> {314static void mapping(IO &IO, SymbolSection &Section) {315IO.mapRequired("targets", Section.Targets);316IO.mapOptional("symbols", Section.Symbols);317IO.mapOptional("objc-classes", Section.Classes);318IO.mapOptional("objc-eh-types", Section.ClassEHs);319IO.mapOptional("objc-ivars", Section.Ivars);320IO.mapOptional("weak-symbols", Section.WeakSymbols);321IO.mapOptional("thread-local-symbols", Section.TlvSymbols);322}323};324325template <> struct MappingTraits<UmbrellaSection> {326static void mapping(IO &IO, UmbrellaSection &Section) {327IO.mapRequired("targets", Section.Targets);328IO.mapRequired("umbrella", Section.Umbrella);329}330};331332template <> struct MappingTraits<UUIDv4> {333static void mapping(IO &IO, UUIDv4 &UUID) {334IO.mapRequired("target", UUID.TargetID);335IO.mapRequired("value", UUID.Value);336}337};338339template <>340struct MappingContextTraits<MetadataSection, MetadataSection::Option> {341static void mapping(IO &IO, MetadataSection &Section,342MetadataSection::Option &OptionKind) {343IO.mapRequired("targets", Section.Targets);344switch (OptionKind) {345case MetadataSection::Option::Clients:346IO.mapRequired("clients", Section.Values);347return;348case MetadataSection::Option::Libraries:349IO.mapRequired("libraries", Section.Values);350return;351}352llvm_unreachable("unexpected option for metadata");353}354};355356template <> struct ScalarBitSetTraits<TBDFlags> {357static void bitset(IO &IO, TBDFlags &Flags) {358IO.bitSetCase(Flags, "flat_namespace", TBDFlags::FlatNamespace);359IO.bitSetCase(Flags, "not_app_extension_safe",360TBDFlags::NotApplicationExtensionSafe);361IO.bitSetCase(Flags, "installapi", TBDFlags::InstallAPI);362IO.bitSetCase(Flags, "not_for_dyld_shared_cache",363TBDFlags::OSLibNotForSharedCache);364}365};366367template <> struct ScalarTraits<Target> {368static void output(const Target &Value, void *, raw_ostream &OS) {369OS << Value.Arch << "-";370switch (Value.Platform) {371#define PLATFORM(platform, id, name, build_name, target, tapi_target, \372marketing) \373case PLATFORM_##platform: \374OS << #tapi_target; \375break;376#include "llvm/BinaryFormat/MachO.def"377}378}379380static StringRef input(StringRef Scalar, void *, Target &Value) {381auto Result = Target::create(Scalar);382if (!Result) {383consumeError(Result.takeError());384return "unparsable target";385}386387Value = *Result;388if (Value.Arch == AK_unknown)389return "unknown architecture";390if (Value.Platform == PLATFORM_UNKNOWN)391return "unknown platform";392393return {};394}395396static QuotingType mustQuote(StringRef) { return QuotingType::None; }397};398399template <> struct MappingTraits<const InterfaceFile *> {400struct NormalizedTBD {401explicit NormalizedTBD(IO &IO) {}402NormalizedTBD(IO &IO, const InterfaceFile *&File) {403Architectures = File->getArchitectures();404Platforms = File->getPlatforms();405InstallName = File->getInstallName();406CurrentVersion = PackedVersion(File->getCurrentVersion());407CompatibilityVersion = PackedVersion(File->getCompatibilityVersion());408SwiftABIVersion = File->getSwiftABIVersion();409ObjCConstraint = File->getObjCConstraint();410411Flags = TBDFlags::None;412if (!File->isApplicationExtensionSafe())413Flags |= TBDFlags::NotApplicationExtensionSafe;414415if (!File->isTwoLevelNamespace())416Flags |= TBDFlags::FlatNamespace;417418if (!File->umbrellas().empty())419ParentUmbrella = File->umbrellas().begin()->second;420421std::set<ArchitectureSet> ArchSet;422for (const auto &Library : File->allowableClients())423ArchSet.insert(Library.getArchitectures());424425for (const auto &Library : File->reexportedLibraries())426ArchSet.insert(Library.getArchitectures());427428std::map<const Symbol *, ArchitectureSet> SymbolToArchSet;429for (const auto *Symbol : File->symbols()) {430auto Architectures = Symbol->getArchitectures();431SymbolToArchSet[Symbol] = Architectures;432ArchSet.insert(Architectures);433}434435for (auto Architectures : ArchSet) {436ExportSection Section;437Section.Architectures = Architectures;438439for (const auto &Library : File->allowableClients())440if (Library.getArchitectures() == Architectures)441Section.AllowableClients.emplace_back(Library.getInstallName());442443for (const auto &Library : File->reexportedLibraries())444if (Library.getArchitectures() == Architectures)445Section.ReexportedLibraries.emplace_back(Library.getInstallName());446447for (const auto &SymArch : SymbolToArchSet) {448if (SymArch.second != Architectures)449continue;450451const auto *Symbol = SymArch.first;452switch (Symbol->getKind()) {453case EncodeKind::GlobalSymbol:454if (Symbol->isWeakDefined())455Section.WeakDefSymbols.emplace_back(Symbol->getName());456else if (Symbol->isThreadLocalValue())457Section.TLVSymbols.emplace_back(Symbol->getName());458else459Section.Symbols.emplace_back(Symbol->getName());460break;461case EncodeKind::ObjectiveCClass:462if (File->getFileType() != FileType::TBD_V3)463Section.Classes.emplace_back(464copyString("_" + Symbol->getName().str()));465else466Section.Classes.emplace_back(Symbol->getName());467break;468case EncodeKind::ObjectiveCClassEHType:469if (File->getFileType() != FileType::TBD_V3)470Section.Symbols.emplace_back(471copyString("_OBJC_EHTYPE_$_" + Symbol->getName().str()));472else473Section.ClassEHs.emplace_back(Symbol->getName());474break;475case EncodeKind::ObjectiveCInstanceVariable:476if (File->getFileType() != FileType::TBD_V3)477Section.IVars.emplace_back(478copyString("_" + Symbol->getName().str()));479else480Section.IVars.emplace_back(Symbol->getName());481break;482}483}484llvm::sort(Section.Symbols);485llvm::sort(Section.Classes);486llvm::sort(Section.ClassEHs);487llvm::sort(Section.IVars);488llvm::sort(Section.WeakDefSymbols);489llvm::sort(Section.TLVSymbols);490Exports.emplace_back(std::move(Section));491}492493ArchSet.clear();494SymbolToArchSet.clear();495496for (const auto *Symbol : File->undefineds()) {497auto Architectures = Symbol->getArchitectures();498SymbolToArchSet[Symbol] = Architectures;499ArchSet.insert(Architectures);500}501502for (auto Architectures : ArchSet) {503UndefinedSection Section;504Section.Architectures = Architectures;505506for (const auto &SymArch : SymbolToArchSet) {507if (SymArch.second != Architectures)508continue;509510const auto *Symbol = SymArch.first;511switch (Symbol->getKind()) {512case EncodeKind::GlobalSymbol:513if (Symbol->isWeakReferenced())514Section.WeakRefSymbols.emplace_back(Symbol->getName());515else516Section.Symbols.emplace_back(Symbol->getName());517break;518case EncodeKind::ObjectiveCClass:519if (File->getFileType() != FileType::TBD_V3)520Section.Classes.emplace_back(521copyString("_" + Symbol->getName().str()));522else523Section.Classes.emplace_back(Symbol->getName());524break;525case EncodeKind::ObjectiveCClassEHType:526if (File->getFileType() != FileType::TBD_V3)527Section.Symbols.emplace_back(528copyString("_OBJC_EHTYPE_$_" + Symbol->getName().str()));529else530Section.ClassEHs.emplace_back(Symbol->getName());531break;532case EncodeKind::ObjectiveCInstanceVariable:533if (File->getFileType() != FileType::TBD_V3)534Section.IVars.emplace_back(535copyString("_" + Symbol->getName().str()));536else537Section.IVars.emplace_back(Symbol->getName());538break;539}540}541llvm::sort(Section.Symbols);542llvm::sort(Section.Classes);543llvm::sort(Section.ClassEHs);544llvm::sort(Section.IVars);545llvm::sort(Section.WeakRefSymbols);546Undefineds.emplace_back(std::move(Section));547}548}549550// TBD v1 - TBD v3 files only support one platform and several551// architectures. It is possible to have more than one platform for TBD v3552// files, but the architectures don't apply to all553// platforms, specifically to filter out the i386 slice from554// platform macCatalyst.555TargetList synthesizeTargets(ArchitectureSet Architectures,556const PlatformSet &Platforms) {557TargetList Targets;558559for (auto Platform : Platforms) {560Platform = mapToPlatformType(Platform, Architectures.hasX86());561562for (const auto &&Architecture : Architectures) {563if ((Architecture == AK_i386) && (Platform == PLATFORM_MACCATALYST))564continue;565566Targets.emplace_back(Architecture, Platform);567}568}569return Targets;570}571572const InterfaceFile *denormalize(IO &IO) {573auto Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext());574assert(Ctx);575576auto *File = new InterfaceFile;577File->setPath(Ctx->Path);578File->setFileType(Ctx->FileKind);579File->addTargets(synthesizeTargets(Architectures, Platforms));580File->setInstallName(InstallName);581File->setCurrentVersion(CurrentVersion);582File->setCompatibilityVersion(CompatibilityVersion);583File->setSwiftABIVersion(SwiftABIVersion);584File->setObjCConstraint(ObjCConstraint);585for (const auto &Target : File->targets())586File->addParentUmbrella(Target, ParentUmbrella);587588if (Ctx->FileKind == FileType::TBD_V1) {589File->setTwoLevelNamespace();590File->setApplicationExtensionSafe();591} else {592File->setTwoLevelNamespace(!(Flags & TBDFlags::FlatNamespace));593File->setApplicationExtensionSafe(594!(Flags & TBDFlags::NotApplicationExtensionSafe));595}596597// For older file formats, the segment where the symbol598// comes from is unknown, treat all symbols as Data599// in these cases.600const auto Flags = SymbolFlags::Data;601602for (const auto &Section : Exports) {603const auto Targets =604synthesizeTargets(Section.Architectures, Platforms);605606for (const auto &Lib : Section.AllowableClients)607for (const auto &Target : Targets)608File->addAllowableClient(Lib, Target);609610for (const auto &Lib : Section.ReexportedLibraries)611for (const auto &Target : Targets)612File->addReexportedLibrary(Lib, Target);613614for (const auto &Symbol : Section.Symbols) {615if (Ctx->FileKind != FileType::TBD_V3 &&616Symbol.value.starts_with(ObjC2EHTypePrefix))617File->addSymbol(EncodeKind::ObjectiveCClassEHType,618Symbol.value.drop_front(15), Targets, Flags);619else620File->addSymbol(EncodeKind::GlobalSymbol, Symbol, Targets, Flags);621}622for (auto &Symbol : Section.Classes) {623auto Name = Symbol.value;624if (Ctx->FileKind != FileType::TBD_V3)625Name = Name.drop_front();626File->addSymbol(EncodeKind::ObjectiveCClass, Name, Targets, Flags);627}628for (auto &Symbol : Section.ClassEHs)629File->addSymbol(EncodeKind::ObjectiveCClassEHType, Symbol, Targets,630Flags);631for (auto &Symbol : Section.IVars) {632auto Name = Symbol.value;633if (Ctx->FileKind != FileType::TBD_V3)634Name = Name.drop_front();635File->addSymbol(EncodeKind::ObjectiveCInstanceVariable, Name, Targets,636Flags);637}638for (auto &Symbol : Section.WeakDefSymbols)639File->addSymbol(EncodeKind::GlobalSymbol, Symbol, Targets,640SymbolFlags::WeakDefined | Flags);641for (auto &Symbol : Section.TLVSymbols)642File->addSymbol(EncodeKind::GlobalSymbol, Symbol, Targets,643SymbolFlags::ThreadLocalValue | Flags);644}645646for (const auto &Section : Undefineds) {647const auto Targets =648synthesizeTargets(Section.Architectures, Platforms);649for (auto &Symbol : Section.Symbols) {650if (Ctx->FileKind != FileType::TBD_V3 &&651Symbol.value.starts_with(ObjC2EHTypePrefix))652File->addSymbol(EncodeKind::ObjectiveCClassEHType,653Symbol.value.drop_front(15), Targets,654SymbolFlags::Undefined | Flags);655else656File->addSymbol(EncodeKind::GlobalSymbol, Symbol, Targets,657SymbolFlags::Undefined | Flags);658}659for (auto &Symbol : Section.Classes) {660auto Name = Symbol.value;661if (Ctx->FileKind != FileType::TBD_V3)662Name = Name.drop_front();663File->addSymbol(EncodeKind::ObjectiveCClass, Name, Targets,664SymbolFlags::Undefined | Flags);665}666for (auto &Symbol : Section.ClassEHs)667File->addSymbol(EncodeKind::ObjectiveCClassEHType, Symbol, Targets,668SymbolFlags::Undefined | Flags);669for (auto &Symbol : Section.IVars) {670auto Name = Symbol.value;671if (Ctx->FileKind != FileType::TBD_V3)672Name = Name.drop_front();673File->addSymbol(EncodeKind::ObjectiveCInstanceVariable, Name, Targets,674SymbolFlags::Undefined | Flags);675}676for (auto &Symbol : Section.WeakRefSymbols)677File->addSymbol(EncodeKind::GlobalSymbol, Symbol, Targets,678SymbolFlags::Undefined | SymbolFlags::WeakReferenced |679Flags);680}681682return File;683}684685llvm::BumpPtrAllocator Allocator;686StringRef copyString(StringRef String) {687if (String.empty())688return {};689690void *Ptr = Allocator.Allocate(String.size(), 1);691memcpy(Ptr, String.data(), String.size());692return StringRef(reinterpret_cast<const char *>(Ptr), String.size());693}694695std::vector<Architecture> Architectures;696std::vector<UUID> UUIDs;697PlatformSet Platforms;698StringRef InstallName;699PackedVersion CurrentVersion;700PackedVersion CompatibilityVersion;701SwiftVersion SwiftABIVersion{0};702ObjCConstraintType ObjCConstraint{ObjCConstraintType::None};703TBDFlags Flags{TBDFlags::None};704StringRef ParentUmbrella;705std::vector<ExportSection> Exports;706std::vector<UndefinedSection> Undefineds;707};708709static void setFileTypeForInput(TextAPIContext *Ctx, IO &IO) {710if (IO.mapTag("!tapi-tbd", false))711Ctx->FileKind = FileType::TBD_V4;712else if (IO.mapTag("!tapi-tbd-v3", false))713Ctx->FileKind = FileType::TBD_V3;714else if (IO.mapTag("!tapi-tbd-v2", false))715Ctx->FileKind = FileType::TBD_V2;716else if (IO.mapTag("!tapi-tbd-v1", false) ||717IO.mapTag("tag:yaml.org,2002:map", false))718Ctx->FileKind = FileType::TBD_V1;719else {720Ctx->FileKind = FileType::Invalid;721return;722}723}724725static void mapping(IO &IO, const InterfaceFile *&File) {726auto *Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext());727assert((!Ctx || !IO.outputting() ||728(Ctx && Ctx->FileKind != FileType::Invalid)) &&729"File type is not set in YAML context");730731if (!IO.outputting()) {732setFileTypeForInput(Ctx, IO);733switch (Ctx->FileKind) {734default:735break;736case FileType::TBD_V4:737mapKeysToValuesV4(IO, File);738return;739case FileType::Invalid:740IO.setError("unsupported file type");741return;742}743} else {744// Set file type when writing.745switch (Ctx->FileKind) {746default:747llvm_unreachable("unexpected file type");748case FileType::TBD_V4:749mapKeysToValuesV4(IO, File);750return;751case FileType::TBD_V3:752IO.mapTag("!tapi-tbd-v3", true);753break;754case FileType::TBD_V2:755IO.mapTag("!tapi-tbd-v2", true);756break;757case FileType::TBD_V1:758// Don't write the tag into the .tbd file for TBD v1759break;760}761}762mapKeysToValues(Ctx->FileKind, IO, File);763}764765using SectionList = std::vector<SymbolSection>;766struct NormalizedTBD_V4 {767explicit NormalizedTBD_V4(IO &IO) {}768NormalizedTBD_V4(IO &IO, const InterfaceFile *&File) {769auto Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext());770assert(Ctx);771TBDVersion = Ctx->FileKind >> 4;772Targets.insert(Targets.begin(), File->targets().begin(),773File->targets().end());774InstallName = File->getInstallName();775CurrentVersion = File->getCurrentVersion();776CompatibilityVersion = File->getCompatibilityVersion();777SwiftABIVersion = File->getSwiftABIVersion();778779Flags = TBDFlags::None;780if (!File->isApplicationExtensionSafe())781Flags |= TBDFlags::NotApplicationExtensionSafe;782783if (!File->isTwoLevelNamespace())784Flags |= TBDFlags::FlatNamespace;785786if (File->isOSLibNotForSharedCache())787Flags |= TBDFlags::OSLibNotForSharedCache;788789{790std::map<std::string, TargetList> valueToTargetList;791for (const auto &it : File->umbrellas())792valueToTargetList[it.second].emplace_back(it.first);793794for (const auto &it : valueToTargetList) {795UmbrellaSection CurrentSection;796CurrentSection.Targets.insert(CurrentSection.Targets.begin(),797it.second.begin(), it.second.end());798CurrentSection.Umbrella = it.first;799ParentUmbrellas.emplace_back(std::move(CurrentSection));800}801}802803assignTargetsToLibrary(File->allowableClients(), AllowableClients);804assignTargetsToLibrary(File->reexportedLibraries(), ReexportedLibraries);805806auto handleSymbols =807[](SectionList &CurrentSections,808InterfaceFile::const_filtered_symbol_range Symbols) {809std::set<TargetList> TargetSet;810std::map<const Symbol *, TargetList> SymbolToTargetList;811for (const auto *Symbol : Symbols) {812TargetList Targets(Symbol->targets());813SymbolToTargetList[Symbol] = Targets;814TargetSet.emplace(std::move(Targets));815}816for (const auto &TargetIDs : TargetSet) {817SymbolSection CurrentSection;818CurrentSection.Targets.insert(CurrentSection.Targets.begin(),819TargetIDs.begin(), TargetIDs.end());820821for (const auto &IT : SymbolToTargetList) {822if (IT.second != TargetIDs)823continue;824825const auto *Symbol = IT.first;826switch (Symbol->getKind()) {827case EncodeKind::GlobalSymbol:828if (Symbol->isWeakDefined())829CurrentSection.WeakSymbols.emplace_back(Symbol->getName());830else if (Symbol->isThreadLocalValue())831CurrentSection.TlvSymbols.emplace_back(Symbol->getName());832else833CurrentSection.Symbols.emplace_back(Symbol->getName());834break;835case EncodeKind::ObjectiveCClass:836CurrentSection.Classes.emplace_back(Symbol->getName());837break;838case EncodeKind::ObjectiveCClassEHType:839CurrentSection.ClassEHs.emplace_back(Symbol->getName());840break;841case EncodeKind::ObjectiveCInstanceVariable:842CurrentSection.Ivars.emplace_back(Symbol->getName());843break;844}845}846sort(CurrentSection.Symbols);847sort(CurrentSection.Classes);848sort(CurrentSection.ClassEHs);849sort(CurrentSection.Ivars);850sort(CurrentSection.WeakSymbols);851sort(CurrentSection.TlvSymbols);852CurrentSections.emplace_back(std::move(CurrentSection));853}854};855856handleSymbols(Exports, File->exports());857handleSymbols(Reexports, File->reexports());858handleSymbols(Undefineds, File->undefineds());859}860861const InterfaceFile *denormalize(IO &IO) {862auto Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext());863assert(Ctx);864865auto *File = new InterfaceFile;866File->setPath(Ctx->Path);867File->setFileType(Ctx->FileKind);868File->addTargets(Targets);869File->setInstallName(InstallName);870File->setCurrentVersion(CurrentVersion);871File->setCompatibilityVersion(CompatibilityVersion);872File->setSwiftABIVersion(SwiftABIVersion);873for (const auto &CurrentSection : ParentUmbrellas)874for (const auto &target : CurrentSection.Targets)875File->addParentUmbrella(target, CurrentSection.Umbrella);876File->setTwoLevelNamespace(!(Flags & TBDFlags::FlatNamespace));877File->setApplicationExtensionSafe(878!(Flags & TBDFlags::NotApplicationExtensionSafe));879File->setOSLibNotForSharedCache(880(Flags & TBDFlags::OSLibNotForSharedCache));881882for (const auto &CurrentSection : AllowableClients) {883for (const auto &lib : CurrentSection.Values)884for (const auto &Target : CurrentSection.Targets)885File->addAllowableClient(lib, Target);886}887888for (const auto &CurrentSection : ReexportedLibraries) {889for (const auto &Lib : CurrentSection.Values)890for (const auto &Target : CurrentSection.Targets)891File->addReexportedLibrary(Lib, Target);892}893894auto handleSymbols = [File](const SectionList &CurrentSections,895SymbolFlags InputFlag = SymbolFlags::None) {896// For older file formats, the segment where the symbol897// comes from is unknown, treat all symbols as Data898// in these cases.899const SymbolFlags Flag = InputFlag | SymbolFlags::Data;900901for (const auto &CurrentSection : CurrentSections) {902for (auto &sym : CurrentSection.Symbols)903File->addSymbol(EncodeKind::GlobalSymbol, sym,904CurrentSection.Targets, Flag);905906for (auto &sym : CurrentSection.Classes)907File->addSymbol(EncodeKind::ObjectiveCClass, sym,908CurrentSection.Targets, Flag);909910for (auto &sym : CurrentSection.ClassEHs)911File->addSymbol(EncodeKind::ObjectiveCClassEHType, sym,912CurrentSection.Targets, Flag);913914for (auto &sym : CurrentSection.Ivars)915File->addSymbol(EncodeKind::ObjectiveCInstanceVariable, sym,916CurrentSection.Targets, Flag);917918SymbolFlags SymFlag =919((Flag & SymbolFlags::Undefined) == SymbolFlags::Undefined)920? SymbolFlags::WeakReferenced921: SymbolFlags::WeakDefined;922for (auto &sym : CurrentSection.WeakSymbols) {923File->addSymbol(EncodeKind::GlobalSymbol, sym,924CurrentSection.Targets, Flag | SymFlag);925}926927for (auto &sym : CurrentSection.TlvSymbols)928File->addSymbol(EncodeKind::GlobalSymbol, sym,929CurrentSection.Targets,930Flag | SymbolFlags::ThreadLocalValue);931}932};933934handleSymbols(Exports);935handleSymbols(Reexports, SymbolFlags::Rexported);936handleSymbols(Undefineds, SymbolFlags::Undefined);937938return File;939}940941unsigned TBDVersion;942std::vector<UUIDv4> UUIDs;943TargetList Targets;944StringRef InstallName;945PackedVersion CurrentVersion;946PackedVersion CompatibilityVersion;947SwiftVersion SwiftABIVersion{0};948std::vector<MetadataSection> AllowableClients;949std::vector<MetadataSection> ReexportedLibraries;950TBDFlags Flags{TBDFlags::None};951std::vector<UmbrellaSection> ParentUmbrellas;952SectionList Exports;953SectionList Reexports;954SectionList Undefineds;955956private:957void assignTargetsToLibrary(const std::vector<InterfaceFileRef> &Libraries,958std::vector<MetadataSection> &Section) {959std::set<TargetList> targetSet;960std::map<const InterfaceFileRef *, TargetList> valueToTargetList;961for (const auto &library : Libraries) {962TargetList targets(library.targets());963valueToTargetList[&library] = targets;964targetSet.emplace(std::move(targets));965}966967for (const auto &targets : targetSet) {968MetadataSection CurrentSection;969CurrentSection.Targets.insert(CurrentSection.Targets.begin(),970targets.begin(), targets.end());971972for (const auto &it : valueToTargetList) {973if (it.second != targets)974continue;975976CurrentSection.Values.emplace_back(it.first->getInstallName());977}978llvm::sort(CurrentSection.Values);979Section.emplace_back(std::move(CurrentSection));980}981}982};983984static void mapKeysToValues(FileType FileKind, IO &IO,985const InterfaceFile *&File) {986MappingNormalization<NormalizedTBD, const InterfaceFile *> Keys(IO, File);987std::vector<UUID> EmptyUUID;988IO.mapRequired("archs", Keys->Architectures);989if (FileKind != FileType::TBD_V1)990IO.mapOptional("uuids", EmptyUUID);991IO.mapRequired("platform", Keys->Platforms);992if (FileKind != FileType::TBD_V1)993IO.mapOptional("flags", Keys->Flags, TBDFlags::None);994IO.mapRequired("install-name", Keys->InstallName);995IO.mapOptional("current-version", Keys->CurrentVersion,996PackedVersion(1, 0, 0));997IO.mapOptional("compatibility-version", Keys->CompatibilityVersion,998PackedVersion(1, 0, 0));999if (FileKind != FileType::TBD_V3)1000IO.mapOptional("swift-version", Keys->SwiftABIVersion, SwiftVersion(0));1001else1002IO.mapOptional("swift-abi-version", Keys->SwiftABIVersion,1003SwiftVersion(0));1004IO.mapOptional("objc-constraint", Keys->ObjCConstraint,1005(FileKind == FileType::TBD_V1)1006? ObjCConstraintType::None1007: ObjCConstraintType::Retain_Release);1008if (FileKind != FileType::TBD_V1)1009IO.mapOptional("parent-umbrella", Keys->ParentUmbrella, StringRef());1010IO.mapOptional("exports", Keys->Exports);1011if (FileKind != FileType::TBD_V1)1012IO.mapOptional("undefineds", Keys->Undefineds);1013}10141015static void mapKeysToValuesV4(IO &IO, const InterfaceFile *&File) {1016MappingNormalization<NormalizedTBD_V4, const InterfaceFile *> Keys(IO,1017File);1018std::vector<UUIDv4> EmptyUUID;1019IO.mapTag("!tapi-tbd", true);1020IO.mapRequired("tbd-version", Keys->TBDVersion);1021IO.mapRequired("targets", Keys->Targets);1022IO.mapOptional("uuids", EmptyUUID);1023IO.mapOptional("flags", Keys->Flags, TBDFlags::None);1024IO.mapRequired("install-name", Keys->InstallName);1025IO.mapOptional("current-version", Keys->CurrentVersion,1026PackedVersion(1, 0, 0));1027IO.mapOptional("compatibility-version", Keys->CompatibilityVersion,1028PackedVersion(1, 0, 0));1029IO.mapOptional("swift-abi-version", Keys->SwiftABIVersion, SwiftVersion(0));1030IO.mapOptional("parent-umbrella", Keys->ParentUmbrellas);1031auto OptionKind = MetadataSection::Option::Clients;1032IO.mapOptionalWithContext("allowable-clients", Keys->AllowableClients,1033OptionKind);1034OptionKind = MetadataSection::Option::Libraries;1035IO.mapOptionalWithContext("reexported-libraries", Keys->ReexportedLibraries,1036OptionKind);1037IO.mapOptional("exports", Keys->Exports);1038IO.mapOptional("reexports", Keys->Reexports);1039IO.mapOptional("undefineds", Keys->Undefineds);1040}1041};10421043template <>1044struct DocumentListTraits<std::vector<const MachO::InterfaceFile *>> {1045static size_t size(IO &IO, std::vector<const MachO::InterfaceFile *> &Seq) {1046return Seq.size();1047}1048static const InterfaceFile *&1049element(IO &IO, std::vector<const InterfaceFile *> &Seq, size_t Index) {1050if (Index >= Seq.size())1051Seq.resize(Index + 1);1052return Seq[Index];1053}1054};10551056} // end namespace yaml.1057} // namespace llvm10581059static void DiagHandler(const SMDiagnostic &Diag, void *Context) {1060auto *File = static_cast<TextAPIContext *>(Context);1061SmallString<1024> Message;1062raw_svector_ostream S(Message);10631064SMDiagnostic NewDiag(*Diag.getSourceMgr(), Diag.getLoc(), File->Path,1065Diag.getLineNo(), Diag.getColumnNo(), Diag.getKind(),1066Diag.getMessage(), Diag.getLineContents(),1067Diag.getRanges(), Diag.getFixIts());10681069NewDiag.print(nullptr, S);1070File->ErrorMessage = ("malformed file\n" + Message).str();1071}10721073Expected<FileType> TextAPIReader::canRead(MemoryBufferRef InputBuffer) {1074auto TAPIFile = InputBuffer.getBuffer().trim();1075if (TAPIFile.starts_with("{") && TAPIFile.ends_with("}"))1076return FileType::TBD_V5;10771078if (!TAPIFile.ends_with("..."))1079return createStringError(std::errc::not_supported, "unsupported file type");10801081if (TAPIFile.starts_with("--- !tapi-tbd"))1082return FileType::TBD_V4;10831084if (TAPIFile.starts_with("--- !tapi-tbd-v3"))1085return FileType::TBD_V3;10861087if (TAPIFile.starts_with("--- !tapi-tbd-v2"))1088return FileType::TBD_V2;10891090if (TAPIFile.starts_with("--- !tapi-tbd-v1") ||1091TAPIFile.starts_with("---\narchs:"))1092return FileType::TBD_V1;10931094return createStringError(std::errc::not_supported, "unsupported file type");1095}10961097Expected<std::unique_ptr<InterfaceFile>>1098TextAPIReader::get(MemoryBufferRef InputBuffer) {1099TextAPIContext Ctx;1100Ctx.Path = std::string(InputBuffer.getBufferIdentifier());1101if (auto FTOrErr = canRead(InputBuffer))1102Ctx.FileKind = *FTOrErr;1103else1104return FTOrErr.takeError();11051106// Handle JSON Format.1107if (Ctx.FileKind >= FileType::TBD_V5) {1108auto FileOrErr = getInterfaceFileFromJSON(InputBuffer.getBuffer());1109if (!FileOrErr)1110return FileOrErr.takeError();11111112(*FileOrErr)->setPath(Ctx.Path);1113return std::move(*FileOrErr);1114}1115yaml::Input YAMLIn(InputBuffer.getBuffer(), &Ctx, DiagHandler, &Ctx);11161117// Fill vector with interface file objects created by parsing the YAML file.1118std::vector<const InterfaceFile *> Files;1119YAMLIn >> Files;11201121// YAMLIn dynamically allocates for Interface file and in case of error,1122// memory leak will occur unless wrapped around unique_ptr1123auto File = std::unique_ptr<InterfaceFile>(1124const_cast<InterfaceFile *>(Files.front()));11251126for (const InterfaceFile *FI : llvm::drop_begin(Files))1127File->addDocument(1128std::shared_ptr<InterfaceFile>(const_cast<InterfaceFile *>(FI)));11291130if (YAMLIn.error())1131return make_error<StringError>(Ctx.ErrorMessage, YAMLIn.error());11321133return std::move(File);1134}11351136Error TextAPIWriter::writeToStream(raw_ostream &OS, const InterfaceFile &File,1137const FileType FileKind, bool Compact) {1138TextAPIContext Ctx;1139Ctx.Path = std::string(File.getPath());11401141// Prefer parameter for format if passed, otherwise fallback to the File1142// FileType.1143Ctx.FileKind =1144(FileKind == FileType::Invalid) ? File.getFileType() : FileKind;11451146// Write out in JSON format.1147if (Ctx.FileKind >= FileType::TBD_V5) {1148return serializeInterfaceFileToJSON(OS, File, Ctx.FileKind, Compact);1149}11501151llvm::yaml::Output YAMLOut(OS, &Ctx, /*WrapColumn=*/80);11521153std::vector<const InterfaceFile *> Files;1154Files.emplace_back(&File);11551156for (const auto &Document : File.documents())1157Files.emplace_back(Document.get());11581159// Stream out yaml.1160YAMLOut << Files;11611162return Error::success();1163}116411651166