Path: blob/main/contrib/llvm-project/llvm/lib/TextAPI/TextStubV5.cpp
35262 views
//===- TextStubV5.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 Text Stub JSON mappings.9//10//===----------------------------------------------------------------------===//11#include "TextStubCommon.h"12#include "llvm/ADT/StringSwitch.h"13#include "llvm/Support/JSON.h"14#include <utility>1516// clang-format off17/*1819JSON Format specification.2021All library level keys, accept target values and are defaulted if not specified.2223{24"tapi_tbd_version": 5, # Required: TBD version for all documents in file25"main_library": { # Required: top level library26"target_info": [ # Required: target information27{28"target": "x86_64-macos",29"min_deployment": "10.14" # Optional: minOS defaults to 030},31{32"target": "arm64-macos",33"min_deployment": "10.14"34},35{36"target": "arm64-maccatalyst",37"min_deployment": "12.1"38}],39"flags":[{"attributes": ["flat_namespace"]}], # Optional:40"install_names":[{"name":"/S/L/F/Foo.fwk/Foo"}], # Required: library install name41"current_versions":[{"version": "1.2"}], # Optional: defaults to 142"compatibility_versions":[{ "version": "1.1"}], # Optional: defaults to 143"rpaths": [ # Optional:44{45"targets": ["x86_64-macos"], # Optional: defaults to targets in `target-info`46"paths": ["@executable_path/.../Frameworks"]47}],48"parent_umbrellas": [{"umbrella": "System"}],49"allowable_clients": [{"clients": ["ClientA"]}],50"reexported_libraries": [{"names": ["/u/l/l/foo.dylib"]}],51"exported_symbols": [{ # List of export symbols section52"targets": ["x86_64-macos", "arm64-macos"], # Optional: defaults to targets in `target-info`53"text": { # List of Text segment symbols54"global": [ "_func" ],55"weak": [],56"thread_local": []57},58"data": { ... }, # List of Data segment symbols59}],60"reexported_symbols": [{ ... }], # List of reexported symbols section61"undefined_symbols": [{ ... }] # List of undefined symbols section62},63"libraries": [ # Optional: Array of inlined libraries64{...}, {...}, {...}65]66}67*/68// clang-format on6970using namespace llvm;71using namespace llvm::json;72using namespace llvm::MachO;7374namespace {75struct JSONSymbol {76EncodeKind Kind;77std::string Name;78SymbolFlags Flags;79};8081using AttrToTargets = std::map<std::string, TargetList>;82using TargetsToSymbols =83SmallVector<std::pair<TargetList, std::vector<JSONSymbol>>>;8485enum TBDKey : size_t {86TBDVersion = 0U,87MainLibrary,88Documents,89TargetInfo,90Targets,91Target,92Deployment,93Flags,94Attributes,95InstallName,96CurrentVersion,97CompatibilityVersion,98Version,99SwiftABI,100ABI,101ParentUmbrella,102Umbrella,103AllowableClients,104Clients,105ReexportLibs,106Names,107Name,108Exports,109Reexports,110Undefineds,111Data,112Text,113Weak,114ThreadLocal,115Globals,116ObjCClass,117ObjCEHType,118ObjCIvar,119RPath,120Paths,121};122123std::array<StringRef, 64> Keys = {124"tapi_tbd_version",125"main_library",126"libraries",127"target_info",128"targets",129"target",130"min_deployment",131"flags",132"attributes",133"install_names",134"current_versions",135"compatibility_versions",136"version",137"swift_abi",138"abi",139"parent_umbrellas",140"umbrella",141"allowable_clients",142"clients",143"reexported_libraries",144"names",145"name",146"exported_symbols",147"reexported_symbols",148"undefined_symbols",149"data",150"text",151"weak",152"thread_local",153"global",154"objc_class",155"objc_eh_type",156"objc_ivar",157"rpaths",158"paths",159};160161static llvm::SmallString<128> getParseErrorMsg(TBDKey Key) {162return {"invalid ", Keys[Key], " section"};163}164165static llvm::SmallString<128> getSerializeErrorMsg(TBDKey Key) {166return {"missing ", Keys[Key], " information"};167}168169class JSONStubError : public llvm::ErrorInfo<llvm::json::ParseError> {170public:171JSONStubError(Twine ErrMsg) : Message(ErrMsg.str()) {}172173void log(llvm::raw_ostream &OS) const override { OS << Message << "\n"; }174std::error_code convertToErrorCode() const override {175return llvm::inconvertibleErrorCode();176}177178private:179std::string Message;180};181182template <typename JsonT, typename StubT = JsonT>183Expected<StubT> getRequiredValue(184TBDKey Key, const Object *Obj,185std::function<std::optional<JsonT>(const Object *, StringRef)> GetValue,186std::function<std::optional<StubT>(JsonT)> Validate = nullptr) {187std::optional<JsonT> Val = GetValue(Obj, Keys[Key]);188if (!Val)189return make_error<JSONStubError>(getParseErrorMsg(Key));190191if (Validate == nullptr)192return static_cast<StubT>(*Val);193194std::optional<StubT> Result = Validate(*Val);195if (!Result.has_value())196return make_error<JSONStubError>(getParseErrorMsg(Key));197return Result.value();198}199200template <typename JsonT, typename StubT = JsonT>201Expected<StubT> getRequiredValue(202TBDKey Key, const Object *Obj,203std::function<std::optional<JsonT>(const Object *, StringRef)> const204GetValue,205StubT DefaultValue, function_ref<std::optional<StubT>(JsonT)> Validate) {206std::optional<JsonT> Val = GetValue(Obj, Keys[Key]);207if (!Val)208return DefaultValue;209210std::optional<StubT> Result;211Result = Validate(*Val);212if (!Result.has_value())213return make_error<JSONStubError>(getParseErrorMsg(Key));214return Result.value();215}216217Error collectFromArray(TBDKey Key, const Object *Obj,218function_ref<void(StringRef)> Append,219bool IsRequired = false) {220const auto *Values = Obj->getArray(Keys[Key]);221if (!Values) {222if (IsRequired)223return make_error<JSONStubError>(getParseErrorMsg(Key));224return Error::success();225}226227for (const Value &Val : *Values) {228auto ValStr = Val.getAsString();229if (!ValStr.has_value())230return make_error<JSONStubError>(getParseErrorMsg(Key));231Append(ValStr.value());232}233234return Error::success();235}236237namespace StubParser {238239Expected<FileType> getVersion(const Object *File) {240auto VersionOrErr = getRequiredValue<int64_t, FileType>(241TBDKey::TBDVersion, File, &Object::getInteger,242[](int64_t Val) -> std::optional<FileType> {243unsigned Result = Val;244if (Result != 5)245return std::nullopt;246return FileType::TBD_V5;247});248249if (!VersionOrErr)250return VersionOrErr.takeError();251return *VersionOrErr;252}253254Expected<TargetList> getTargets(const Object *Section) {255const auto *Targets = Section->getArray(Keys[TBDKey::Targets]);256if (!Targets)257return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Targets));258259TargetList IFTargets;260for (const Value &JSONTarget : *Targets) {261auto TargetStr = JSONTarget.getAsString();262if (!TargetStr.has_value())263return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));264auto TargetOrErr = Target::create(TargetStr.value());265if (!TargetOrErr)266return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));267IFTargets.push_back(*TargetOrErr);268}269return std::move(IFTargets);270}271272Expected<TargetList> getTargetsSection(const Object *Section) {273const Array *Targets = Section->getArray(Keys[TBDKey::TargetInfo]);274if (!Targets)275return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Targets));276277TargetList IFTargets;278for (const Value &JSONTarget : *Targets) {279const auto *Obj = JSONTarget.getAsObject();280if (!Obj)281return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));282auto TargetStr =283getRequiredValue<StringRef>(TBDKey::Target, Obj, &Object::getString);284if (!TargetStr)285return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));286auto TargetOrErr = Target::create(*TargetStr);287if (!TargetOrErr)288return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));289290auto VersionStr = Obj->getString(Keys[TBDKey::Deployment]);291VersionTuple Version;292if (VersionStr && Version.tryParse(*VersionStr))293return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Deployment));294TargetOrErr->MinDeployment = Version;295296// Convert to LLVM::Triple to accurately compute minOS + platform + arch297// pairing.298IFTargets.push_back(299MachO::Target(Triple(getTargetTripleName(*TargetOrErr))));300}301return std::move(IFTargets);302}303304Error collectSymbolsFromSegment(const Object *Segment, TargetsToSymbols &Result,305SymbolFlags SectionFlag) {306auto Err = collectFromArray(307TBDKey::Globals, Segment, [&Result, &SectionFlag](StringRef Name) {308JSONSymbol Sym = {EncodeKind::GlobalSymbol, Name.str(), SectionFlag};309Result.back().second.emplace_back(Sym);310});311if (Err)312return Err;313314Err = collectFromArray(315TBDKey::ObjCClass, Segment, [&Result, &SectionFlag](StringRef Name) {316JSONSymbol Sym = {EncodeKind::ObjectiveCClass, Name.str(), SectionFlag};317Result.back().second.emplace_back(Sym);318});319if (Err)320return Err;321322Err = collectFromArray(TBDKey::ObjCEHType, Segment,323[&Result, &SectionFlag](StringRef Name) {324JSONSymbol Sym = {EncodeKind::ObjectiveCClassEHType,325Name.str(), SectionFlag};326Result.back().second.emplace_back(Sym);327});328if (Err)329return Err;330331Err = collectFromArray(332TBDKey::ObjCIvar, Segment, [&Result, &SectionFlag](StringRef Name) {333JSONSymbol Sym = {EncodeKind::ObjectiveCInstanceVariable, Name.str(),334SectionFlag};335Result.back().second.emplace_back(Sym);336});337if (Err)338return Err;339340SymbolFlags WeakFlag =341SectionFlag |342(((SectionFlag & SymbolFlags::Undefined) == SymbolFlags::Undefined)343? SymbolFlags::WeakReferenced344: SymbolFlags::WeakDefined);345Err = collectFromArray(346TBDKey::Weak, Segment, [&Result, WeakFlag](StringRef Name) {347JSONSymbol Sym = {EncodeKind::GlobalSymbol, Name.str(), WeakFlag};348Result.back().second.emplace_back(Sym);349});350if (Err)351return Err;352353Err = collectFromArray(354TBDKey::ThreadLocal, Segment, [&Result, SectionFlag](StringRef Name) {355JSONSymbol Sym = {EncodeKind::GlobalSymbol, Name.str(),356SymbolFlags::ThreadLocalValue | SectionFlag};357Result.back().second.emplace_back(Sym);358});359if (Err)360return Err;361362return Error::success();363}364365Expected<StringRef> getNameSection(const Object *File) {366const Array *Section = File->getArray(Keys[TBDKey::InstallName]);367if (!Section)368return make_error<JSONStubError>(getParseErrorMsg(TBDKey::InstallName));369370assert(!Section->empty() && "unexpected missing install name");371// TODO: Just take first for now.372const auto *Obj = Section->front().getAsObject();373if (!Obj)374return make_error<JSONStubError>(getParseErrorMsg(TBDKey::InstallName));375376return getRequiredValue<StringRef>(TBDKey::Name, Obj, &Object::getString);377}378379Expected<TargetsToSymbols> getSymbolSection(const Object *File, TBDKey Key,380TargetList &Targets) {381382const Array *Section = File->getArray(Keys[Key]);383if (!Section)384return TargetsToSymbols();385386SymbolFlags SectionFlag;387switch (Key) {388case TBDKey::Reexports:389SectionFlag = SymbolFlags::Rexported;390break;391case TBDKey::Undefineds:392SectionFlag = SymbolFlags::Undefined;393break;394default:395SectionFlag = SymbolFlags::None;396break;397};398399TargetsToSymbols Result;400TargetList MappedTargets;401for (auto Val : *Section) {402auto *Obj = Val.getAsObject();403if (!Obj)404continue;405406auto TargetsOrErr = getTargets(Obj);407if (!TargetsOrErr) {408MappedTargets = Targets;409consumeError(TargetsOrErr.takeError());410} else {411MappedTargets = *TargetsOrErr;412}413Result.emplace_back(414std::make_pair(std::move(MappedTargets), std::vector<JSONSymbol>()));415416auto *DataSection = Obj->getObject(Keys[TBDKey::Data]);417auto *TextSection = Obj->getObject(Keys[TBDKey::Text]);418// There should be at least one valid section.419if (!DataSection && !TextSection)420return make_error<JSONStubError>(getParseErrorMsg(Key));421422if (DataSection) {423auto Err = collectSymbolsFromSegment(DataSection, Result,424SectionFlag | SymbolFlags::Data);425if (Err)426return std::move(Err);427}428if (TextSection) {429auto Err = collectSymbolsFromSegment(TextSection, Result,430SectionFlag | SymbolFlags::Text);431if (Err)432return std::move(Err);433}434}435436return std::move(Result);437}438439Expected<AttrToTargets> getLibSection(const Object *File, TBDKey Key,440TBDKey SubKey,441const TargetList &Targets) {442auto *Section = File->getArray(Keys[Key]);443if (!Section)444return AttrToTargets();445446AttrToTargets Result;447TargetList MappedTargets;448for (auto Val : *Section) {449auto *Obj = Val.getAsObject();450if (!Obj)451continue;452453auto TargetsOrErr = getTargets(Obj);454if (!TargetsOrErr) {455MappedTargets = Targets;456consumeError(TargetsOrErr.takeError());457} else {458MappedTargets = *TargetsOrErr;459}460auto Err =461collectFromArray(SubKey, Obj, [&Result, &MappedTargets](StringRef Key) {462Result[Key.str()] = MappedTargets;463});464if (Err)465return std::move(Err);466}467468return std::move(Result);469}470471Expected<AttrToTargets> getUmbrellaSection(const Object *File,472const TargetList &Targets) {473const auto *Umbrella = File->getArray(Keys[TBDKey::ParentUmbrella]);474if (!Umbrella)475return AttrToTargets();476477AttrToTargets Result;478TargetList MappedTargets;479for (auto Val : *Umbrella) {480auto *Obj = Val.getAsObject();481if (!Obj)482return make_error<JSONStubError>(483getParseErrorMsg(TBDKey::ParentUmbrella));484485// Get Targets section.486auto TargetsOrErr = getTargets(Obj);487if (!TargetsOrErr) {488MappedTargets = Targets;489consumeError(TargetsOrErr.takeError());490} else {491MappedTargets = *TargetsOrErr;492}493494auto UmbrellaOrErr =495getRequiredValue<StringRef>(TBDKey::Umbrella, Obj, &Object::getString);496if (!UmbrellaOrErr)497return UmbrellaOrErr.takeError();498Result[UmbrellaOrErr->str()] = Targets;499}500return std::move(Result);501}502503Expected<uint8_t> getSwiftVersion(const Object *File) {504const Array *Versions = File->getArray(Keys[TBDKey::SwiftABI]);505if (!Versions)506return 0;507508for (const auto &Val : *Versions) {509const auto *Obj = Val.getAsObject();510if (!Obj)511return make_error<JSONStubError>(getParseErrorMsg(TBDKey::SwiftABI));512513// TODO: Take first for now.514return getRequiredValue<int64_t, uint8_t>(TBDKey::ABI, Obj,515&Object::getInteger);516}517518return 0;519}520521Expected<PackedVersion> getPackedVersion(const Object *File, TBDKey Key) {522const Array *Versions = File->getArray(Keys[Key]);523if (!Versions)524return PackedVersion(1, 0, 0);525526for (const auto &Val : *Versions) {527const auto *Obj = Val.getAsObject();528if (!Obj)529return make_error<JSONStubError>(getParseErrorMsg(Key));530531auto ValidatePV = [](StringRef Version) -> std::optional<PackedVersion> {532PackedVersion PV;533auto [success, truncated] = PV.parse64(Version);534if (!success || truncated)535return std::nullopt;536return PV;537};538// TODO: Take first for now.539return getRequiredValue<StringRef, PackedVersion>(540TBDKey::Version, Obj, &Object::getString, PackedVersion(1, 0, 0),541ValidatePV);542}543544return PackedVersion(1, 0, 0);545}546547Expected<TBDFlags> getFlags(const Object *File) {548TBDFlags Flags = TBDFlags::None;549const Array *Section = File->getArray(Keys[TBDKey::Flags]);550if (!Section || Section->empty())551return Flags;552553for (auto &Val : *Section) {554// FIXME: Flags currently apply to all target triples.555const auto *Obj = Val.getAsObject();556if (!Obj)557return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Flags));558559auto FlagsOrErr =560collectFromArray(TBDKey::Attributes, Obj, [&Flags](StringRef Flag) {561TBDFlags TBDFlag =562StringSwitch<TBDFlags>(Flag)563.Case("flat_namespace", TBDFlags::FlatNamespace)564.Case("not_app_extension_safe",565TBDFlags::NotApplicationExtensionSafe)566.Case("sim_support", TBDFlags::SimulatorSupport)567.Case("not_for_dyld_shared_cache",568TBDFlags::OSLibNotForSharedCache)569.Default(TBDFlags::None);570Flags |= TBDFlag;571});572573if (FlagsOrErr)574return std::move(FlagsOrErr);575576return Flags;577}578579return Flags;580}581582using IFPtr = std::unique_ptr<InterfaceFile>;583Expected<IFPtr> parseToInterfaceFile(const Object *File) {584auto TargetsOrErr = getTargetsSection(File);585if (!TargetsOrErr)586return TargetsOrErr.takeError();587TargetList Targets = *TargetsOrErr;588589auto NameOrErr = getNameSection(File);590if (!NameOrErr)591return NameOrErr.takeError();592StringRef Name = *NameOrErr;593594auto CurrVersionOrErr = getPackedVersion(File, TBDKey::CurrentVersion);595if (!CurrVersionOrErr)596return CurrVersionOrErr.takeError();597PackedVersion CurrVersion = *CurrVersionOrErr;598599auto CompVersionOrErr = getPackedVersion(File, TBDKey::CompatibilityVersion);600if (!CompVersionOrErr)601return CompVersionOrErr.takeError();602PackedVersion CompVersion = *CompVersionOrErr;603604auto SwiftABIOrErr = getSwiftVersion(File);605if (!SwiftABIOrErr)606return SwiftABIOrErr.takeError();607uint8_t SwiftABI = *SwiftABIOrErr;608609auto FlagsOrErr = getFlags(File);610if (!FlagsOrErr)611return FlagsOrErr.takeError();612TBDFlags Flags = *FlagsOrErr;613614auto UmbrellasOrErr = getUmbrellaSection(File, Targets);615if (!UmbrellasOrErr)616return UmbrellasOrErr.takeError();617AttrToTargets Umbrellas = *UmbrellasOrErr;618619auto ClientsOrErr =620getLibSection(File, TBDKey::AllowableClients, TBDKey::Clients, Targets);621if (!ClientsOrErr)622return ClientsOrErr.takeError();623AttrToTargets Clients = *ClientsOrErr;624625auto RLOrErr =626getLibSection(File, TBDKey::ReexportLibs, TBDKey::Names, Targets);627if (!RLOrErr)628return RLOrErr.takeError();629AttrToTargets ReexportLibs = std::move(*RLOrErr);630631auto RPathsOrErr = getLibSection(File, TBDKey::RPath, TBDKey::Paths, Targets);632if (!RPathsOrErr)633return RPathsOrErr.takeError();634AttrToTargets RPaths = std::move(*RPathsOrErr);635636auto ExportsOrErr = getSymbolSection(File, TBDKey::Exports, Targets);637if (!ExportsOrErr)638return ExportsOrErr.takeError();639TargetsToSymbols Exports = std::move(*ExportsOrErr);640641auto ReexportsOrErr = getSymbolSection(File, TBDKey::Reexports, Targets);642if (!ReexportsOrErr)643return ReexportsOrErr.takeError();644TargetsToSymbols Reexports = std::move(*ReexportsOrErr);645646auto UndefinedsOrErr = getSymbolSection(File, TBDKey::Undefineds, Targets);647if (!UndefinedsOrErr)648return UndefinedsOrErr.takeError();649TargetsToSymbols Undefineds = std::move(*UndefinedsOrErr);650651IFPtr F(new InterfaceFile);652F->setInstallName(Name);653F->setCurrentVersion(CurrVersion);654F->setCompatibilityVersion(CompVersion);655F->setSwiftABIVersion(SwiftABI);656F->setTwoLevelNamespace(!(Flags & TBDFlags::FlatNamespace));657F->setApplicationExtensionSafe(658!(Flags & TBDFlags::NotApplicationExtensionSafe));659F->setSimulatorSupport((Flags & TBDFlags::SimulatorSupport));660F->setOSLibNotForSharedCache((Flags & TBDFlags::OSLibNotForSharedCache));661for (auto &T : Targets)662F->addTarget(T);663for (auto &[Lib, Targets] : Clients)664for (auto Target : Targets)665F->addAllowableClient(Lib, Target);666for (auto &[Lib, Targets] : ReexportLibs)667for (auto Target : Targets)668F->addReexportedLibrary(Lib, Target);669for (auto &[Lib, Targets] : Umbrellas)670for (auto Target : Targets)671F->addParentUmbrella(Target, Lib);672for (auto &[Path, Targets] : RPaths)673for (auto Target : Targets)674F->addRPath(Path, Target);675for (auto &[Targets, Symbols] : Exports)676for (auto &Sym : Symbols)677F->addSymbol(Sym.Kind, Sym.Name, Targets, Sym.Flags);678for (auto &[Targets, Symbols] : Reexports)679for (auto &Sym : Symbols)680F->addSymbol(Sym.Kind, Sym.Name, Targets, Sym.Flags);681for (auto &[Targets, Symbols] : Undefineds)682for (auto &Sym : Symbols)683F->addSymbol(Sym.Kind, Sym.Name, Targets, Sym.Flags);684685return std::move(F);686}687688Expected<std::vector<IFPtr>> getInlinedLibs(const Object *File) {689std::vector<IFPtr> IFs;690const Array *Files = File->getArray(Keys[TBDKey::Documents]);691if (!Files)692return std::move(IFs);693694for (auto Lib : *Files) {695auto IFOrErr = parseToInterfaceFile(Lib.getAsObject());696if (!IFOrErr)697return IFOrErr.takeError();698auto IF = std::move(*IFOrErr);699IFs.emplace_back(std::move(IF));700}701return std::move(IFs);702}703704} // namespace StubParser705} // namespace706707Expected<std::unique_ptr<InterfaceFile>>708MachO::getInterfaceFileFromJSON(StringRef JSON) {709auto ValOrErr = parse(JSON);710if (!ValOrErr)711return ValOrErr.takeError();712713auto *Root = ValOrErr->getAsObject();714auto VersionOrErr = StubParser::getVersion(Root);715if (!VersionOrErr)716return VersionOrErr.takeError();717FileType Version = *VersionOrErr;718719Object *MainLib = Root->getObject(Keys[TBDKey::MainLibrary]);720auto IFOrErr = StubParser::parseToInterfaceFile(MainLib);721if (!IFOrErr)722return IFOrErr.takeError();723(*IFOrErr)->setFileType(Version);724std::unique_ptr<InterfaceFile> IF(std::move(*IFOrErr));725726auto IFsOrErr = StubParser::getInlinedLibs(Root);727if (!IFsOrErr)728return IFsOrErr.takeError();729for (auto &File : *IFsOrErr) {730File->setFileType(Version);731IF->addDocument(std::shared_ptr<InterfaceFile>(std::move(File)));732}733return std::move(IF);734}735736namespace {737738template <typename ContainerT = Array>739bool insertNonEmptyValues(Object &Obj, TBDKey Key, ContainerT &&Contents) {740if (Contents.empty())741return false;742Obj[Keys[Key]] = std::move(Contents);743return true;744}745746std::string getFormattedStr(const MachO::Target &Targ) {747std::string PlatformStr = Targ.Platform == PLATFORM_MACCATALYST748? "maccatalyst"749: getOSAndEnvironmentName(Targ.Platform);750return (getArchitectureName(Targ.Arch) + "-" + PlatformStr).str();751}752753template <typename AggregateT>754std::vector<std::string> serializeTargets(const AggregateT Targets,755const TargetList &ActiveTargets) {756std::vector<std::string> TargetsStr;757if (Targets.size() == ActiveTargets.size())758return TargetsStr;759760for (const MachO::Target &Target : Targets)761TargetsStr.emplace_back(getFormattedStr(Target));762763return TargetsStr;764}765766Array serializeTargetInfo(const TargetList &ActiveTargets) {767Array Targets;768for (const auto Targ : ActiveTargets) {769Object TargetInfo;770if (!Targ.MinDeployment.empty())771TargetInfo[Keys[TBDKey::Deployment]] = Targ.MinDeployment.getAsString();772TargetInfo[Keys[TBDKey::Target]] = getFormattedStr(Targ);773Targets.emplace_back(std::move(TargetInfo));774}775return Targets;776}777778template <typename ValueT, typename EntryT = ValueT>779Array serializeScalar(TBDKey Key, ValueT Value, ValueT Default = ValueT()) {780if (Value == Default)781return {};782Array Container;783Object ScalarObj({Object::KV({Keys[Key], EntryT(Value)})});784785Container.emplace_back(std::move(ScalarObj));786return Container;787}788789using TargetsToValuesMap =790std::map<std::vector<std::string>, std::vector<std::string>>;791792template <typename AggregateT = TargetsToValuesMap>793Array serializeAttrToTargets(AggregateT &Entries, TBDKey Key) {794Array Container;795for (const auto &[Targets, Values] : Entries) {796Object Obj;797insertNonEmptyValues(Obj, TBDKey::Targets, std::move(Targets));798Obj[Keys[Key]] = Values;799Container.emplace_back(std::move(Obj));800}801return Container;802}803804template <typename ValueT = std::string,805typename AggregateT = std::vector<std::pair<MachO::Target, ValueT>>>806Array serializeField(TBDKey Key, const AggregateT &Values,807const TargetList &ActiveTargets, bool IsArray = true) {808std::map<ValueT, std::set<MachO::Target>> Entries;809for (const auto &[Target, Val] : Values)810Entries[Val].insert(Target);811812if (!IsArray) {813std::map<std::vector<std::string>, std::string> FinalEntries;814for (const auto &[Val, Targets] : Entries)815FinalEntries[serializeTargets(Targets, ActiveTargets)] = Val;816return serializeAttrToTargets(FinalEntries, Key);817}818819TargetsToValuesMap FinalEntries;820for (const auto &[Val, Targets] : Entries)821FinalEntries[serializeTargets(Targets, ActiveTargets)].emplace_back(Val);822return serializeAttrToTargets(FinalEntries, Key);823}824825Array serializeField(TBDKey Key, const std::vector<InterfaceFileRef> &Values,826const TargetList &ActiveTargets) {827TargetsToValuesMap FinalEntries;828for (const auto &Ref : Values) {829TargetList Targets{Ref.targets().begin(), Ref.targets().end()};830FinalEntries[serializeTargets(Targets, ActiveTargets)].emplace_back(831Ref.getInstallName());832}833return serializeAttrToTargets(FinalEntries, Key);834}835836struct SymbolFields {837struct SymbolTypes {838std::vector<StringRef> Weaks;839std::vector<StringRef> Globals;840std::vector<StringRef> TLV;841std::vector<StringRef> ObjCClasses;842std::vector<StringRef> IVars;843std::vector<StringRef> EHTypes;844845bool empty() const {846return Weaks.empty() && Globals.empty() && TLV.empty() &&847ObjCClasses.empty() && IVars.empty() && EHTypes.empty();848}849};850SymbolTypes Data;851SymbolTypes Text;852};853854Array serializeSymbols(InterfaceFile::const_filtered_symbol_range Symbols,855const TargetList &ActiveTargets) {856auto AssignForSymbolType = [](SymbolFields::SymbolTypes &Assignment,857const Symbol *Sym) {858switch (Sym->getKind()) {859case EncodeKind::ObjectiveCClass:860Assignment.ObjCClasses.emplace_back(Sym->getName());861return;862case EncodeKind::ObjectiveCClassEHType:863Assignment.EHTypes.emplace_back(Sym->getName());864return;865case EncodeKind::ObjectiveCInstanceVariable:866Assignment.IVars.emplace_back(Sym->getName());867return;868case EncodeKind::GlobalSymbol: {869if (Sym->isWeakReferenced() || Sym->isWeakDefined())870Assignment.Weaks.emplace_back(Sym->getName());871else if (Sym->isThreadLocalValue())872Assignment.TLV.emplace_back(Sym->getName());873else874Assignment.Globals.emplace_back(Sym->getName());875return;876}877}878};879880std::map<std::vector<std::string>, SymbolFields> Entries;881for (const auto *Sym : Symbols) {882std::set<MachO::Target> Targets{Sym->targets().begin(),883Sym->targets().end()};884auto JSONTargets = serializeTargets(Targets, ActiveTargets);885if (Sym->isData())886AssignForSymbolType(Entries[std::move(JSONTargets)].Data, Sym);887else if (Sym->isText())888AssignForSymbolType(Entries[std::move(JSONTargets)].Text, Sym);889else890llvm_unreachable("unexpected symbol type");891}892893auto InsertSymbolsToJSON = [](Object &SymSection, TBDKey SegmentKey,894SymbolFields::SymbolTypes &SymField) {895if (SymField.empty())896return;897Object Segment;898insertNonEmptyValues(Segment, TBDKey::Globals, std::move(SymField.Globals));899insertNonEmptyValues(Segment, TBDKey::ThreadLocal, std::move(SymField.TLV));900insertNonEmptyValues(Segment, TBDKey::Weak, std::move(SymField.Weaks));901insertNonEmptyValues(Segment, TBDKey::ObjCClass,902std::move(SymField.ObjCClasses));903insertNonEmptyValues(Segment, TBDKey::ObjCEHType,904std::move(SymField.EHTypes));905insertNonEmptyValues(Segment, TBDKey::ObjCIvar, std::move(SymField.IVars));906insertNonEmptyValues(SymSection, SegmentKey, std::move(Segment));907};908909Array SymbolSection;910for (auto &[Targets, Fields] : Entries) {911Object AllSyms;912insertNonEmptyValues(AllSyms, TBDKey::Targets, std::move(Targets));913InsertSymbolsToJSON(AllSyms, TBDKey::Data, Fields.Data);914InsertSymbolsToJSON(AllSyms, TBDKey::Text, Fields.Text);915SymbolSection.emplace_back(std::move(AllSyms));916}917918return SymbolSection;919}920921Array serializeFlags(const InterfaceFile *File) {922// TODO: Give all Targets the same flags for now.923Array Flags;924if (!File->isTwoLevelNamespace())925Flags.emplace_back("flat_namespace");926if (!File->isApplicationExtensionSafe())927Flags.emplace_back("not_app_extension_safe");928if (File->hasSimulatorSupport())929Flags.emplace_back("sim_support");930if (File->isOSLibNotForSharedCache())931Flags.emplace_back("not_for_dyld_shared_cache");932return serializeScalar(TBDKey::Attributes, std::move(Flags));933}934935Expected<Object> serializeIF(const InterfaceFile *File) {936Object Library;937938// Handle required keys.939TargetList ActiveTargets{File->targets().begin(), File->targets().end()};940if (!insertNonEmptyValues(Library, TBDKey::TargetInfo,941serializeTargetInfo(ActiveTargets)))942return make_error<JSONStubError>(getSerializeErrorMsg(TBDKey::TargetInfo));943944Array Name = serializeScalar<StringRef>(TBDKey::Name, File->getInstallName());945if (!insertNonEmptyValues(Library, TBDKey::InstallName, std::move(Name)))946return make_error<JSONStubError>(getSerializeErrorMsg(TBDKey::InstallName));947948// Handle optional keys.949Array Flags = serializeFlags(File);950insertNonEmptyValues(Library, TBDKey::Flags, std::move(Flags));951952Array CurrentV = serializeScalar<PackedVersion, std::string>(953TBDKey::Version, File->getCurrentVersion(), PackedVersion(1, 0, 0));954insertNonEmptyValues(Library, TBDKey::CurrentVersion, std::move(CurrentV));955956Array CompatV = serializeScalar<PackedVersion, std::string>(957TBDKey::Version, File->getCompatibilityVersion(), PackedVersion(1, 0, 0));958insertNonEmptyValues(Library, TBDKey::CompatibilityVersion,959std::move(CompatV));960961Array SwiftABI = serializeScalar<uint8_t, int64_t>(962TBDKey::ABI, File->getSwiftABIVersion(), 0u);963insertNonEmptyValues(Library, TBDKey::SwiftABI, std::move(SwiftABI));964965Array RPaths = serializeField(TBDKey::Paths, File->rpaths(), ActiveTargets);966insertNonEmptyValues(Library, TBDKey::RPath, std::move(RPaths));967968Array Umbrellas = serializeField(TBDKey::Umbrella, File->umbrellas(),969ActiveTargets, /*IsArray=*/false);970insertNonEmptyValues(Library, TBDKey::ParentUmbrella, std::move(Umbrellas));971972Array Clients =973serializeField(TBDKey::Clients, File->allowableClients(), ActiveTargets);974insertNonEmptyValues(Library, TBDKey::AllowableClients, std::move(Clients));975976Array ReexportLibs =977serializeField(TBDKey::Names, File->reexportedLibraries(), ActiveTargets);978insertNonEmptyValues(Library, TBDKey::ReexportLibs, std::move(ReexportLibs));979980// Handle symbols.981Array Exports = serializeSymbols(File->exports(), ActiveTargets);982insertNonEmptyValues(Library, TBDKey::Exports, std::move(Exports));983984Array Reexports = serializeSymbols(File->reexports(), ActiveTargets);985insertNonEmptyValues(Library, TBDKey::Reexports, std::move(Reexports));986987if (!File->isTwoLevelNamespace()) {988Array Undefineds = serializeSymbols(File->undefineds(), ActiveTargets);989insertNonEmptyValues(Library, TBDKey::Undefineds, std::move(Undefineds));990}991992return std::move(Library);993}994995Expected<Object> getJSON(const InterfaceFile *File, const FileType FileKind) {996assert(FileKind == FileType::TBD_V5 && "unexpected json file format version");997Object Root;998999auto MainLibOrErr = serializeIF(File);1000if (!MainLibOrErr)1001return MainLibOrErr;1002Root[Keys[TBDKey::MainLibrary]] = std::move(*MainLibOrErr);1003Array Documents;1004for (const auto &Doc : File->documents()) {1005auto LibOrErr = serializeIF(Doc.get());1006if (!LibOrErr)1007return LibOrErr;1008Documents.emplace_back(std::move(*LibOrErr));1009}10101011Root[Keys[TBDKey::TBDVersion]] = 5;1012insertNonEmptyValues(Root, TBDKey::Documents, std::move(Documents));1013return std::move(Root);1014}10151016} // namespace10171018Error MachO::serializeInterfaceFileToJSON(raw_ostream &OS,1019const InterfaceFile &File,1020const FileType FileKind,1021bool Compact) {1022auto TextFile = getJSON(&File, FileKind);1023if (!TextFile)1024return TextFile.takeError();1025if (Compact)1026OS << formatv("{0}", Value(std::move(*TextFile))) << "\n";1027else1028OS << formatv("{0:2}", Value(std::move(*TextFile))) << "\n";1029return Error::success();1030}103110321033