brintos

brintos / llvm-project-archived public Read only

0
0
Text · 34.7 KiB · f268751 Raw
1084 lines · cpp
1//===- TextStubV5.cpp -----------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// Implements Text Stub JSON mappings.10//11//===----------------------------------------------------------------------===//12#include "TextStubCommon.h"13#include "llvm/ADT/StringSwitch.h"14#include "llvm/Support/JSON.h"15#include <utility>16 17// clang-format off18/*19 20JSON Format specification.21 22All library level keys, accept target values and are defaulted if not specified. 23 24{25"tapi_tbd_version": 5,                            # Required: TBD version for all documents in file26"main_library": {                                 # Required: top level library27  "target_info": [                                # Required: target information 28    {29      "target": "x86_64-macos",30      "min_deployment": "10.14"                   # Optional: minOS defaults to 031    },32    {33      "target": "arm64-macos",34      "min_deployment": "10.14"35    },36    {37      "target": "arm64-maccatalyst",38      "min_deployment": "12.1"39    }],40  "flags":[{"attributes": ["flat_namespace"]}],     # Optional:41  "install_names":[{"name":"/S/L/F/Foo.fwk/Foo"}],  # Required: library install name 42  "current_versions":[{"version": "1.2"}],          # Optional: defaults to 143  "compatibility_versions":[{ "version": "1.1"}],   # Optional: defaults to 144  "rpaths": [                                       # Optional: 45    {46      "targets": ["x86_64-macos"],                  # Optional: defaults to targets in `target-info`47      "paths": ["@executable_path/.../Frameworks"]48    }],49  "parent_umbrellas": [{"umbrella": "System"}],50  "allowable_clients": [{"clients": ["ClientA"]}],51  "reexported_libraries": [{"names": ["/u/l/l/foo.dylib"]}],52  "exported_symbols": [{                            # List of export symbols section53      "targets": ["x86_64-macos", "arm64-macos"],   # Optional: defaults to targets in `target-info`54        "text": {                                   # List of Text segment symbols 55          "global": [ "_func" ],56          "weak": [],57          "thread_local": []58        },59        "data": { ... },                            # List of Data segment symbols60   }],61  "reexported_symbols": [{  ... }],                 # List of reexported symbols section62  "undefined_symbols": [{ ... }]                    # List of undefined symbols section63},64"libraries": [                                      # Optional: Array of inlined libraries65  {...}, {...}, {...}66]67}68*/69// clang-format on70 71using namespace llvm;72using namespace llvm::json;73using namespace llvm::MachO;74 75namespace {76struct JSONSymbol {77  EncodeKind Kind;78  std::string Name;79  SymbolFlags Flags;80};81 82using AttrToTargets = std::map<std::string, TargetList>;83using TargetsToSymbols =84    SmallVector<std::pair<TargetList, std::vector<JSONSymbol>>>;85 86/// Wrapper over a vector for handling textstub attributes, mapped to target87/// triples, that require insertion order to be intact in the resulting \c88/// InterfaceFile.89class InOrderAttrToTargets {90  using EntryT = std::pair<std::string, TargetList>;91 92public:93  void insert(EntryT &&Entry) {94    auto &Element = get(Entry.first);95    Element.second = Entry.second;96  }97 98  const EntryT *begin() { return Container.begin(); }99  const EntryT *end() { return Container.end(); }100 101private:102  EntryT &get(std::string &Key) {103    auto *It = find_if(Container,104                       [&Key](EntryT &Input) { return Input.first == Key; });105    if (It != Container.end())106      return *It;107    Container.push_back(EntryT(Key, {}));108    return Container.back();109  }110  llvm::SmallVector<EntryT> Container;111};112 113enum TBDKey : size_t {114  TBDVersion = 0U,115  MainLibrary,116  Documents,117  TargetInfo,118  Targets,119  Target,120  Deployment,121  Flags,122  Attributes,123  InstallName,124  CurrentVersion,125  CompatibilityVersion,126  Version,127  SwiftABI,128  ABI,129  ParentUmbrella,130  Umbrella,131  AllowableClients,132  Clients,133  ReexportLibs,134  Names,135  Name,136  Exports,137  Reexports,138  Undefineds,139  Data,140  Text,141  Weak,142  ThreadLocal,143  Globals,144  ObjCClass,145  ObjCEHType,146  ObjCIvar,147  RPath,148  Paths,149};150 151std::array<StringRef, 64> Keys = {152    "tapi_tbd_version",153    "main_library",154    "libraries",155    "target_info",156    "targets",157    "target",158    "min_deployment",159    "flags",160    "attributes",161    "install_names",162    "current_versions",163    "compatibility_versions",164    "version",165    "swift_abi",166    "abi",167    "parent_umbrellas",168    "umbrella",169    "allowable_clients",170    "clients",171    "reexported_libraries",172    "names",173    "name",174    "exported_symbols",175    "reexported_symbols",176    "undefined_symbols",177    "data",178    "text",179    "weak",180    "thread_local",181    "global",182    "objc_class",183    "objc_eh_type",184    "objc_ivar",185    "rpaths",186    "paths",187};188 189static llvm::SmallString<128> getParseErrorMsg(TBDKey Key) {190  return {"invalid ", Keys[Key], " section"};191}192 193static llvm::SmallString<128> getSerializeErrorMsg(TBDKey Key) {194  return {"missing ", Keys[Key], " information"};195}196 197class JSONStubError : public llvm::ErrorInfo<llvm::json::ParseError> {198public:199  JSONStubError(Twine ErrMsg) : Message(ErrMsg.str()) {}200 201  void log(llvm::raw_ostream &OS) const override { OS << Message << "\n"; }202  std::error_code convertToErrorCode() const override {203    return llvm::inconvertibleErrorCode();204  }205 206private:207  std::string Message;208};209 210template <typename JsonT, typename StubT = JsonT>211Expected<StubT> getRequiredValue(212    TBDKey Key, const Object *Obj,213    std::function<std::optional<JsonT>(const Object *, StringRef)> GetValue,214    std::function<std::optional<StubT>(JsonT)> Validate = nullptr) {215  std::optional<JsonT> Val = GetValue(Obj, Keys[Key]);216  if (!Val)217    return make_error<JSONStubError>(getParseErrorMsg(Key));218 219  if (Validate == nullptr)220    return static_cast<StubT>(*Val);221 222  std::optional<StubT> Result = Validate(*Val);223  if (!Result.has_value())224    return make_error<JSONStubError>(getParseErrorMsg(Key));225  return Result.value();226}227 228template <typename JsonT, typename StubT = JsonT>229Expected<StubT> getRequiredValue(230    TBDKey Key, const Object *Obj,231    std::function<std::optional<JsonT>(const Object *, StringRef)> const232        GetValue,233    StubT DefaultValue, function_ref<std::optional<StubT>(JsonT)> Validate) {234  std::optional<JsonT> Val = GetValue(Obj, Keys[Key]);235  if (!Val)236    return DefaultValue;237 238  std::optional<StubT> Result;239  Result = Validate(*Val);240  if (!Result.has_value())241    return make_error<JSONStubError>(getParseErrorMsg(Key));242  return Result.value();243}244 245Error collectFromArray(TBDKey Key, const Object *Obj,246                       function_ref<void(StringRef)> Append,247                       bool IsRequired = false) {248  const auto *Values = Obj->getArray(Keys[Key]);249  if (!Values) {250    if (IsRequired)251      return make_error<JSONStubError>(getParseErrorMsg(Key));252    return Error::success();253  }254 255  for (const Value &Val : *Values) {256    auto ValStr = Val.getAsString();257    if (!ValStr.has_value())258      return make_error<JSONStubError>(getParseErrorMsg(Key));259    Append(ValStr.value());260  }261 262  return Error::success();263}264 265namespace StubParser {266 267Expected<FileType> getVersion(const Object *File) {268  auto VersionOrErr = getRequiredValue<int64_t, FileType>(269      TBDKey::TBDVersion, File, &Object::getInteger,270      [](int64_t Val) -> std::optional<FileType> {271        unsigned Result = Val;272        if (Result != 5)273          return std::nullopt;274        return FileType::TBD_V5;275      });276 277  if (!VersionOrErr)278    return VersionOrErr.takeError();279  return *VersionOrErr;280}281 282Expected<TargetList> getTargets(const Object *Section) {283  const auto *Targets = Section->getArray(Keys[TBDKey::Targets]);284  if (!Targets)285    return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Targets));286 287  TargetList IFTargets;288  for (const Value &JSONTarget : *Targets) {289    auto TargetStr = JSONTarget.getAsString();290    if (!TargetStr.has_value())291      return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));292    auto TargetOrErr = Target::create(TargetStr.value());293    if (!TargetOrErr)294      return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));295    IFTargets.push_back(*TargetOrErr);296  }297  return std::move(IFTargets);298}299 300Expected<TargetList> getTargetsSection(const Object *Section) {301  const Array *Targets = Section->getArray(Keys[TBDKey::TargetInfo]);302  if (!Targets)303    return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Targets));304 305  TargetList IFTargets;306  for (const Value &JSONTarget : *Targets) {307    const auto *Obj = JSONTarget.getAsObject();308    if (!Obj)309      return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));310    auto TargetStr =311        getRequiredValue<StringRef>(TBDKey::Target, Obj, &Object::getString);312    if (!TargetStr)313      return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));314    auto TargetOrErr = Target::create(*TargetStr);315    if (!TargetOrErr)316      return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));317 318    auto VersionStr = Obj->getString(Keys[TBDKey::Deployment]);319    VersionTuple Version;320    if (VersionStr && Version.tryParse(*VersionStr))321      return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Deployment));322    TargetOrErr->MinDeployment = Version;323 324    // Convert to LLVM::Triple to accurately compute minOS + platform + arch325    // pairing.326    IFTargets.push_back(327        MachO::Target(Triple(getTargetTripleName(*TargetOrErr))));328  }329  return std::move(IFTargets);330}331 332Error collectSymbolsFromSegment(const Object *Segment, TargetsToSymbols &Result,333                                SymbolFlags SectionFlag) {334  auto Err = collectFromArray(335      TBDKey::Globals, Segment, [&Result, &SectionFlag](StringRef Name) {336        JSONSymbol Sym = {EncodeKind::GlobalSymbol, Name.str(), SectionFlag};337        Result.back().second.emplace_back(Sym);338      });339  if (Err)340    return Err;341 342  Err = collectFromArray(343      TBDKey::ObjCClass, Segment, [&Result, &SectionFlag](StringRef Name) {344        JSONSymbol Sym = {EncodeKind::ObjectiveCClass, Name.str(), SectionFlag};345        Result.back().second.emplace_back(Sym);346      });347  if (Err)348    return Err;349 350  Err = collectFromArray(TBDKey::ObjCEHType, Segment,351                         [&Result, &SectionFlag](StringRef Name) {352                           JSONSymbol Sym = {EncodeKind::ObjectiveCClassEHType,353                                             Name.str(), SectionFlag};354                           Result.back().second.emplace_back(Sym);355                         });356  if (Err)357    return Err;358 359  Err = collectFromArray(360      TBDKey::ObjCIvar, Segment, [&Result, &SectionFlag](StringRef Name) {361        JSONSymbol Sym = {EncodeKind::ObjectiveCInstanceVariable, Name.str(),362                          SectionFlag};363        Result.back().second.emplace_back(Sym);364      });365  if (Err)366    return Err;367 368  SymbolFlags WeakFlag =369      SectionFlag |370      (((SectionFlag & SymbolFlags::Undefined) == SymbolFlags::Undefined)371           ? SymbolFlags::WeakReferenced372           : SymbolFlags::WeakDefined);373  Err = collectFromArray(374      TBDKey::Weak, Segment, [&Result, WeakFlag](StringRef Name) {375        JSONSymbol Sym = {EncodeKind::GlobalSymbol, Name.str(), WeakFlag};376        Result.back().second.emplace_back(Sym);377      });378  if (Err)379    return Err;380 381  Err = collectFromArray(382      TBDKey::ThreadLocal, Segment, [&Result, SectionFlag](StringRef Name) {383        JSONSymbol Sym = {EncodeKind::GlobalSymbol, Name.str(),384                          SymbolFlags::ThreadLocalValue | SectionFlag};385        Result.back().second.emplace_back(Sym);386      });387  if (Err)388    return Err;389 390  return Error::success();391}392 393Expected<StringRef> getNameSection(const Object *File) {394  const Array *Section = File->getArray(Keys[TBDKey::InstallName]);395  if (!Section)396    return make_error<JSONStubError>(getParseErrorMsg(TBDKey::InstallName));397 398  assert(!Section->empty() && "unexpected missing install name");399  // TODO: Just take first for now.400  const auto *Obj = Section->front().getAsObject();401  if (!Obj)402    return make_error<JSONStubError>(getParseErrorMsg(TBDKey::InstallName));403 404  return getRequiredValue<StringRef>(TBDKey::Name, Obj, &Object::getString);405}406 407Expected<TargetsToSymbols> getSymbolSection(const Object *File, TBDKey Key,408                                            TargetList &Targets) {409 410  const Array *Section = File->getArray(Keys[Key]);411  if (!Section)412    return TargetsToSymbols();413 414  SymbolFlags SectionFlag;415  switch (Key) {416  case TBDKey::Reexports:417    SectionFlag = SymbolFlags::Rexported;418    break;419  case TBDKey::Undefineds:420    SectionFlag = SymbolFlags::Undefined;421    break;422  default:423    SectionFlag = SymbolFlags::None;424    break;425  };426 427  TargetsToSymbols Result;428  TargetList MappedTargets;429  for (auto Val : *Section) {430    auto *Obj = Val.getAsObject();431    if (!Obj)432      continue;433 434    auto TargetsOrErr = getTargets(Obj);435    if (!TargetsOrErr) {436      MappedTargets = Targets;437      consumeError(TargetsOrErr.takeError());438    } else {439      MappedTargets = *TargetsOrErr;440    }441    Result.emplace_back(442        std::make_pair(std::move(MappedTargets), std::vector<JSONSymbol>()));443 444    auto *DataSection = Obj->getObject(Keys[TBDKey::Data]);445    auto *TextSection = Obj->getObject(Keys[TBDKey::Text]);446    // There should be at least one valid section.447    if (!DataSection && !TextSection)448      return make_error<JSONStubError>(getParseErrorMsg(Key));449 450    if (DataSection) {451      auto Err = collectSymbolsFromSegment(DataSection, Result,452                                           SectionFlag | SymbolFlags::Data);453      if (Err)454        return std::move(Err);455    }456    if (TextSection) {457      auto Err = collectSymbolsFromSegment(TextSection, Result,458                                           SectionFlag | SymbolFlags::Text);459      if (Err)460        return std::move(Err);461    }462  }463 464  return std::move(Result);465}466 467template <typename ReturnT = AttrToTargets>468Expected<ReturnT> getLibSection(const Object *File, TBDKey Key, TBDKey SubKey,469                                const TargetList &Targets) {470  auto *Section = File->getArray(Keys[Key]);471  if (!Section)472    return ReturnT();473 474  ReturnT Result;475  TargetList MappedTargets;476  for (auto Val : *Section) {477    auto *Obj = Val.getAsObject();478    if (!Obj)479      continue;480 481    auto TargetsOrErr = getTargets(Obj);482    if (!TargetsOrErr) {483      MappedTargets = Targets;484      consumeError(TargetsOrErr.takeError());485    } else {486      MappedTargets = *TargetsOrErr;487    }488    auto Err =489        collectFromArray(SubKey, Obj, [&Result, &MappedTargets](StringRef Key) {490          Result.insert({Key.str(), MappedTargets});491        });492    if (Err)493      return std::move(Err);494  }495 496  return std::move(Result);497}498 499Expected<AttrToTargets> getUmbrellaSection(const Object *File,500                                           const TargetList &Targets) {501  const auto *Umbrella = File->getArray(Keys[TBDKey::ParentUmbrella]);502  if (!Umbrella)503    return AttrToTargets();504 505  AttrToTargets Result;506  TargetList MappedTargets;507  for (auto Val : *Umbrella) {508    auto *Obj = Val.getAsObject();509    if (!Obj)510      return make_error<JSONStubError>(511          getParseErrorMsg(TBDKey::ParentUmbrella));512 513    // Get Targets section.514    auto TargetsOrErr = getTargets(Obj);515    if (!TargetsOrErr) {516      MappedTargets = Targets;517      consumeError(TargetsOrErr.takeError());518    } else {519      MappedTargets = *TargetsOrErr;520    }521 522    auto UmbrellaOrErr =523        getRequiredValue<StringRef>(TBDKey::Umbrella, Obj, &Object::getString);524    if (!UmbrellaOrErr)525      return UmbrellaOrErr.takeError();526    Result[UmbrellaOrErr->str()] = Targets;527  }528  return std::move(Result);529}530 531Expected<uint8_t> getSwiftVersion(const Object *File) {532  const Array *Versions = File->getArray(Keys[TBDKey::SwiftABI]);533  if (!Versions)534    return 0;535 536  for (const auto &Val : *Versions) {537    const auto *Obj = Val.getAsObject();538    if (!Obj)539      return make_error<JSONStubError>(getParseErrorMsg(TBDKey::SwiftABI));540 541    // TODO: Take first for now.542    return getRequiredValue<int64_t, uint8_t>(TBDKey::ABI, Obj,543                                              &Object::getInteger);544  }545 546  return 0;547}548 549Expected<PackedVersion> getPackedVersion(const Object *File, TBDKey Key) {550  const Array *Versions = File->getArray(Keys[Key]);551  if (!Versions)552    return PackedVersion(1, 0, 0);553 554  for (const auto &Val : *Versions) {555    const auto *Obj = Val.getAsObject();556    if (!Obj)557      return make_error<JSONStubError>(getParseErrorMsg(Key));558 559    auto ValidatePV = [](StringRef Version) -> std::optional<PackedVersion> {560      PackedVersion PV;561      auto [success, truncated] = PV.parse64(Version);562      if (!success || truncated)563        return std::nullopt;564      return PV;565    };566    // TODO: Take first for now.567    return getRequiredValue<StringRef, PackedVersion>(568        TBDKey::Version, Obj, &Object::getString, PackedVersion(1, 0, 0),569        ValidatePV);570  }571 572  return PackedVersion(1, 0, 0);573}574 575Expected<TBDFlags> getFlags(const Object *File) {576  TBDFlags Flags = TBDFlags::None;577  const Array *Section = File->getArray(Keys[TBDKey::Flags]);578  if (!Section || Section->empty())579    return Flags;580 581  for (auto &Val : *Section) {582    // FIXME: Flags currently apply to all target triples.583    const auto *Obj = Val.getAsObject();584    if (!Obj)585      return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Flags));586 587    auto FlagsOrErr =588        collectFromArray(TBDKey::Attributes, Obj, [&Flags](StringRef Flag) {589          TBDFlags TBDFlag =590              StringSwitch<TBDFlags>(Flag)591                  .Case("flat_namespace", TBDFlags::FlatNamespace)592                  .Case("not_app_extension_safe",593                        TBDFlags::NotApplicationExtensionSafe)594                  .Case("sim_support", TBDFlags::SimulatorSupport)595                  .Case("not_for_dyld_shared_cache",596                        TBDFlags::OSLibNotForSharedCache)597                  .Default(TBDFlags::None);598          Flags |= TBDFlag;599        });600 601    if (FlagsOrErr)602      return std::move(FlagsOrErr);603 604    return Flags;605  }606 607  return Flags;608}609 610using IFPtr = std::unique_ptr<InterfaceFile>;611Expected<IFPtr> parseToInterfaceFile(const Object *File) {612  auto TargetsOrErr = getTargetsSection(File);613  if (!TargetsOrErr)614    return TargetsOrErr.takeError();615  TargetList Targets = *TargetsOrErr;616 617  auto NameOrErr = getNameSection(File);618  if (!NameOrErr)619    return NameOrErr.takeError();620  StringRef Name = *NameOrErr;621 622  auto CurrVersionOrErr = getPackedVersion(File, TBDKey::CurrentVersion);623  if (!CurrVersionOrErr)624    return CurrVersionOrErr.takeError();625  PackedVersion CurrVersion = *CurrVersionOrErr;626 627  auto CompVersionOrErr = getPackedVersion(File, TBDKey::CompatibilityVersion);628  if (!CompVersionOrErr)629    return CompVersionOrErr.takeError();630  PackedVersion CompVersion = *CompVersionOrErr;631 632  auto SwiftABIOrErr = getSwiftVersion(File);633  if (!SwiftABIOrErr)634    return SwiftABIOrErr.takeError();635  uint8_t SwiftABI = *SwiftABIOrErr;636 637  auto FlagsOrErr = getFlags(File);638  if (!FlagsOrErr)639    return FlagsOrErr.takeError();640  TBDFlags Flags = *FlagsOrErr;641 642  auto UmbrellasOrErr = getUmbrellaSection(File, Targets);643  if (!UmbrellasOrErr)644    return UmbrellasOrErr.takeError();645  AttrToTargets Umbrellas = *UmbrellasOrErr;646 647  auto ClientsOrErr =648      getLibSection(File, TBDKey::AllowableClients, TBDKey::Clients, Targets);649  if (!ClientsOrErr)650    return ClientsOrErr.takeError();651  AttrToTargets Clients = *ClientsOrErr;652 653  auto RLOrErr =654      getLibSection(File, TBDKey::ReexportLibs, TBDKey::Names, Targets);655  if (!RLOrErr)656    return RLOrErr.takeError();657  AttrToTargets ReexportLibs = std::move(*RLOrErr);658 659  auto RPathsOrErr = getLibSection<InOrderAttrToTargets>(660      File, TBDKey::RPath, TBDKey::Paths, Targets);661  if (!RPathsOrErr)662    return RPathsOrErr.takeError();663  InOrderAttrToTargets RPaths = std::move(*RPathsOrErr);664 665  auto ExportsOrErr = getSymbolSection(File, TBDKey::Exports, Targets);666  if (!ExportsOrErr)667    return ExportsOrErr.takeError();668  TargetsToSymbols Exports = std::move(*ExportsOrErr);669 670  auto ReexportsOrErr = getSymbolSection(File, TBDKey::Reexports, Targets);671  if (!ReexportsOrErr)672    return ReexportsOrErr.takeError();673  TargetsToSymbols Reexports = std::move(*ReexportsOrErr);674 675  auto UndefinedsOrErr = getSymbolSection(File, TBDKey::Undefineds, Targets);676  if (!UndefinedsOrErr)677    return UndefinedsOrErr.takeError();678  TargetsToSymbols Undefineds = std::move(*UndefinedsOrErr);679 680  IFPtr F(new InterfaceFile);681  F->setInstallName(Name);682  F->setCurrentVersion(CurrVersion);683  F->setCompatibilityVersion(CompVersion);684  F->setSwiftABIVersion(SwiftABI);685  F->setTwoLevelNamespace(!(Flags & TBDFlags::FlatNamespace));686  F->setApplicationExtensionSafe(687      !(Flags & TBDFlags::NotApplicationExtensionSafe));688  F->setSimulatorSupport((Flags & TBDFlags::SimulatorSupport));689  F->setOSLibNotForSharedCache((Flags & TBDFlags::OSLibNotForSharedCache));690  for (auto &T : Targets)691    F->addTarget(T);692  for (auto &[Lib, Targets] : Clients)693    for (auto Target : Targets)694      F->addAllowableClient(Lib, Target);695  for (auto &[Lib, Targets] : ReexportLibs)696    for (auto Target : Targets)697      F->addReexportedLibrary(Lib, Target);698  for (auto &[Lib, Targets] : Umbrellas)699    for (auto Target : Targets)700      F->addParentUmbrella(Target, Lib);701  for (auto &[Path, Targets] : RPaths)702    for (auto Target : Targets)703      F->addRPath(Path, Target);704  for (auto &[Targets, Symbols] : Exports)705    for (auto &Sym : Symbols)706      F->addSymbol(Sym.Kind, Sym.Name, Targets, Sym.Flags);707  for (auto &[Targets, Symbols] : Reexports)708    for (auto &Sym : Symbols)709      F->addSymbol(Sym.Kind, Sym.Name, Targets, Sym.Flags);710  for (auto &[Targets, Symbols] : Undefineds)711    for (auto &Sym : Symbols)712      F->addSymbol(Sym.Kind, Sym.Name, Targets, Sym.Flags);713 714  return std::move(F);715}716 717Expected<std::vector<IFPtr>> getInlinedLibs(const Object *File) {718  std::vector<IFPtr> IFs;719  const Array *Files = File->getArray(Keys[TBDKey::Documents]);720  if (!Files)721    return std::move(IFs);722 723  for (auto Lib : *Files) {724    auto IFOrErr = parseToInterfaceFile(Lib.getAsObject());725    if (!IFOrErr)726      return IFOrErr.takeError();727    auto IF = std::move(*IFOrErr);728    IFs.emplace_back(std::move(IF));729  }730  return std::move(IFs);731}732 733} // namespace StubParser734} // namespace735 736Expected<std::unique_ptr<InterfaceFile>>737MachO::getInterfaceFileFromJSON(StringRef JSON) {738  auto ValOrErr = parse(JSON);739  if (!ValOrErr)740    return ValOrErr.takeError();741 742  auto *Root = ValOrErr->getAsObject();743  auto VersionOrErr = StubParser::getVersion(Root);744  if (!VersionOrErr)745    return VersionOrErr.takeError();746  FileType Version = *VersionOrErr;747 748  Object *MainLib = Root->getObject(Keys[TBDKey::MainLibrary]);749  auto IFOrErr = StubParser::parseToInterfaceFile(MainLib);750  if (!IFOrErr)751    return IFOrErr.takeError();752  (*IFOrErr)->setFileType(Version);753  std::unique_ptr<InterfaceFile> IF(std::move(*IFOrErr));754 755  auto IFsOrErr = StubParser::getInlinedLibs(Root);756  if (!IFsOrErr)757    return IFsOrErr.takeError();758  for (auto &File : *IFsOrErr) {759    File->setFileType(Version);760    IF->addDocument(std::shared_ptr<InterfaceFile>(std::move(File)));761  }762  return std::move(IF);763}764 765namespace {766 767template <typename ContainerT = Array>768bool insertNonEmptyValues(Object &Obj, TBDKey Key, ContainerT &&Contents) {769  if (Contents.empty())770    return false;771  Obj[Keys[Key]] = std::move(Contents);772  return true;773}774 775std::string getFormattedStr(const MachO::Target &Targ) {776  std::string PlatformStr = Targ.Platform == PLATFORM_MACCATALYST777                                ? "maccatalyst"778                                : getOSAndEnvironmentName(Targ.Platform);779  return (getArchitectureName(Targ.Arch) + "-" + PlatformStr).str();780}781 782template <typename AggregateT>783std::vector<std::string> serializeTargets(const AggregateT Targets,784                                          const TargetList &ActiveTargets) {785  std::vector<std::string> TargetsStr;786  if (Targets.size() == ActiveTargets.size())787    return TargetsStr;788 789  for (const MachO::Target &Target : Targets)790    TargetsStr.emplace_back(getFormattedStr(Target));791 792  return TargetsStr;793}794 795Array serializeTargetInfo(const TargetList &ActiveTargets) {796  Array Targets;797  for (const auto Targ : ActiveTargets) {798    Object TargetInfo;799    if (!Targ.MinDeployment.empty())800      TargetInfo[Keys[TBDKey::Deployment]] = Targ.MinDeployment.getAsString();801    TargetInfo[Keys[TBDKey::Target]] = getFormattedStr(Targ);802    Targets.emplace_back(std::move(TargetInfo));803  }804  return Targets;805}806 807template <typename ValueT, typename EntryT = ValueT>808Array serializeScalar(TBDKey Key, ValueT Value, ValueT Default = ValueT()) {809  if (Value == Default)810    return {};811  Array Container;812  Object ScalarObj({Object::KV({Keys[Key], EntryT(Value)})});813 814  Container.emplace_back(std::move(ScalarObj));815  return Container;816}817 818using TargetsToValuesMap =819    std::map<std::vector<std::string>, std::vector<std::string>>;820 821template <typename AggregateT = TargetsToValuesMap>822Array serializeAttrToTargets(AggregateT &Entries, TBDKey Key) {823  Array Container;824  for (const auto &[Targets, Values] : Entries) {825    Object Obj;826    insertNonEmptyValues(Obj, TBDKey::Targets, std::move(Targets));827    Obj[Keys[Key]] = Values;828    Container.emplace_back(std::move(Obj));829  }830  return Container;831}832 833/// When there is no significance in order, the common case, serialize all834/// attributes in a stable order.835template <typename ValueT = std::string,836          typename AggregateT = std::vector<std::pair<MachO::Target, ValueT>>>837Array serializeField(TBDKey Key, const AggregateT &Values,838                     const TargetList &ActiveTargets, bool IsArray = true) {839  std::map<ValueT, std::set<MachO::Target>> Entries;840  for (const auto &[Target, Val] : Values)841    Entries[Val].insert(Target);842 843  if (!IsArray) {844    std::map<std::vector<std::string>, std::string> FinalEntries;845    for (const auto &[Val, Targets] : Entries)846      FinalEntries[serializeTargets(Targets, ActiveTargets)] = Val;847    return serializeAttrToTargets(FinalEntries, Key);848  }849 850  TargetsToValuesMap FinalEntries;851  for (const auto &[Val, Targets] : Entries)852    FinalEntries[serializeTargets(Targets, ActiveTargets)].emplace_back(Val);853  return serializeAttrToTargets(FinalEntries, Key);854}855 856Array serializeField(TBDKey Key, const std::vector<InterfaceFileRef> &Values,857                     const TargetList &ActiveTargets) {858  TargetsToValuesMap FinalEntries;859  for (const auto &Ref : Values) {860    TargetList Targets{Ref.targets().begin(), Ref.targets().end()};861    FinalEntries[serializeTargets(Targets, ActiveTargets)].emplace_back(862        Ref.getInstallName());863  }864  return serializeAttrToTargets(FinalEntries, Key);865}866 867template <868    typename AggregateT = std::vector<std::pair<MachO::Target, std::string>>>869Array serializeFieldInInsertionOrder(TBDKey Key, const AggregateT &Values,870                                     const TargetList &ActiveTargets) {871  MapVector<StringRef, std::set<MachO::Target>> Entries;872  for (const auto &[Target, Val] : Values)873    Entries[Val].insert(Target);874 875  TargetsToValuesMap FinalEntries;876  for (const auto &[Val, Targets] : Entries)877    FinalEntries[serializeTargets(Targets, ActiveTargets)].emplace_back(878        Val.str());879  return serializeAttrToTargets(FinalEntries, Key);880}881 882struct SymbolFields {883  struct SymbolTypes {884    std::vector<StringRef> Weaks;885    std::vector<StringRef> Globals;886    std::vector<StringRef> TLV;887    std::vector<StringRef> ObjCClasses;888    std::vector<StringRef> IVars;889    std::vector<StringRef> EHTypes;890 891    bool empty() const {892      return Weaks.empty() && Globals.empty() && TLV.empty() &&893             ObjCClasses.empty() && IVars.empty() && EHTypes.empty();894    }895  };896  SymbolTypes Data;897  SymbolTypes Text;898};899 900Array serializeSymbols(InterfaceFile::const_filtered_symbol_range Symbols,901                       const TargetList &ActiveTargets) {902  auto AssignForSymbolType = [](SymbolFields::SymbolTypes &Assignment,903                                const Symbol *Sym) {904    switch (Sym->getKind()) {905    case EncodeKind::ObjectiveCClass:906      Assignment.ObjCClasses.emplace_back(Sym->getName());907      return;908    case EncodeKind::ObjectiveCClassEHType:909      Assignment.EHTypes.emplace_back(Sym->getName());910      return;911    case EncodeKind::ObjectiveCInstanceVariable:912      Assignment.IVars.emplace_back(Sym->getName());913      return;914    case EncodeKind::GlobalSymbol: {915      if (Sym->isWeakReferenced() || Sym->isWeakDefined())916        Assignment.Weaks.emplace_back(Sym->getName());917      else if (Sym->isThreadLocalValue())918        Assignment.TLV.emplace_back(Sym->getName());919      else920        Assignment.Globals.emplace_back(Sym->getName());921      return;922    }923    }924  };925 926  std::map<std::vector<std::string>, SymbolFields> Entries;927  for (const auto *Sym : Symbols) {928    std::set<MachO::Target> Targets{Sym->targets().begin(),929                                    Sym->targets().end()};930    auto JSONTargets = serializeTargets(Targets, ActiveTargets);931    if (Sym->isData())932      AssignForSymbolType(Entries[std::move(JSONTargets)].Data, Sym);933    else if (Sym->isText())934      AssignForSymbolType(Entries[std::move(JSONTargets)].Text, Sym);935    else936      llvm_unreachable("unexpected symbol type");937  }938 939  auto InsertSymbolsToJSON = [](Object &SymSection, TBDKey SegmentKey,940                                SymbolFields::SymbolTypes &SymField) {941    if (SymField.empty())942      return;943    llvm::sort(SymField.Globals);944    llvm::sort(SymField.TLV);945    llvm::sort(SymField.Weaks);946    llvm::sort(SymField.ObjCClasses);947    llvm::sort(SymField.EHTypes);948    llvm::sort(SymField.IVars);949    Object Segment;950    insertNonEmptyValues(Segment, TBDKey::Globals, std::move(SymField.Globals));951    insertNonEmptyValues(Segment, TBDKey::ThreadLocal, std::move(SymField.TLV));952    insertNonEmptyValues(Segment, TBDKey::Weak, std::move(SymField.Weaks));953    insertNonEmptyValues(Segment, TBDKey::ObjCClass,954                         std::move(SymField.ObjCClasses));955    insertNonEmptyValues(Segment, TBDKey::ObjCEHType,956                         std::move(SymField.EHTypes));957    insertNonEmptyValues(Segment, TBDKey::ObjCIvar, std::move(SymField.IVars));958    insertNonEmptyValues(SymSection, SegmentKey, std::move(Segment));959  };960 961  Array SymbolSection;962  for (auto &[Targets, Fields] : Entries) {963    Object AllSyms;964    insertNonEmptyValues(AllSyms, TBDKey::Targets, std::move(Targets));965    InsertSymbolsToJSON(AllSyms, TBDKey::Data, Fields.Data);966    InsertSymbolsToJSON(AllSyms, TBDKey::Text, Fields.Text);967    SymbolSection.emplace_back(std::move(AllSyms));968  }969 970  return SymbolSection;971}972 973Array serializeFlags(const InterfaceFile *File) {974  // TODO: Give all Targets the same flags for now.975  Array Flags;976  if (!File->isTwoLevelNamespace())977    Flags.emplace_back("flat_namespace");978  if (!File->isApplicationExtensionSafe())979    Flags.emplace_back("not_app_extension_safe");980  if (File->hasSimulatorSupport())981    Flags.emplace_back("sim_support");982  if (File->isOSLibNotForSharedCache())983    Flags.emplace_back("not_for_dyld_shared_cache");984  return serializeScalar(TBDKey::Attributes, std::move(Flags));985}986 987Expected<Object> serializeIF(const InterfaceFile *File) {988  Object Library;989 990  // Handle required keys.991  TargetList ActiveTargets{File->targets().begin(), File->targets().end()};992  if (!insertNonEmptyValues(Library, TBDKey::TargetInfo,993                            serializeTargetInfo(ActiveTargets)))994    return make_error<JSONStubError>(getSerializeErrorMsg(TBDKey::TargetInfo));995 996  Array Name = serializeScalar<StringRef>(TBDKey::Name, File->getInstallName());997  if (!insertNonEmptyValues(Library, TBDKey::InstallName, std::move(Name)))998    return make_error<JSONStubError>(getSerializeErrorMsg(TBDKey::InstallName));999 1000  // Handle optional keys.1001  Array Flags = serializeFlags(File);1002  insertNonEmptyValues(Library, TBDKey::Flags, std::move(Flags));1003 1004  Array CurrentV = serializeScalar<PackedVersion, std::string>(1005      TBDKey::Version, File->getCurrentVersion(), PackedVersion(1, 0, 0));1006  insertNonEmptyValues(Library, TBDKey::CurrentVersion, std::move(CurrentV));1007 1008  Array CompatV = serializeScalar<PackedVersion, std::string>(1009      TBDKey::Version, File->getCompatibilityVersion(), PackedVersion(1, 0, 0));1010  insertNonEmptyValues(Library, TBDKey::CompatibilityVersion,1011                       std::move(CompatV));1012 1013  Array SwiftABI = serializeScalar<uint8_t, int64_t>(1014      TBDKey::ABI, File->getSwiftABIVersion(), 0u);1015  insertNonEmptyValues(Library, TBDKey::SwiftABI, std::move(SwiftABI));1016 1017  Array RPaths = serializeFieldInInsertionOrder(TBDKey::Paths, File->rpaths(),1018                                                ActiveTargets);1019  insertNonEmptyValues(Library, TBDKey::RPath, std::move(RPaths));1020 1021  Array Umbrellas = serializeField(TBDKey::Umbrella, File->umbrellas(),1022                                   ActiveTargets, /*IsArray=*/false);1023  insertNonEmptyValues(Library, TBDKey::ParentUmbrella, std::move(Umbrellas));1024 1025  Array Clients =1026      serializeField(TBDKey::Clients, File->allowableClients(), ActiveTargets);1027  insertNonEmptyValues(Library, TBDKey::AllowableClients, std::move(Clients));1028 1029  Array ReexportLibs =1030      serializeField(TBDKey::Names, File->reexportedLibraries(), ActiveTargets);1031  insertNonEmptyValues(Library, TBDKey::ReexportLibs, std::move(ReexportLibs));1032 1033  // Handle symbols.1034  Array Exports = serializeSymbols(File->exports(), ActiveTargets);1035  insertNonEmptyValues(Library, TBDKey::Exports, std::move(Exports));1036 1037  Array Reexports = serializeSymbols(File->reexports(), ActiveTargets);1038  insertNonEmptyValues(Library, TBDKey::Reexports, std::move(Reexports));1039 1040  if (!File->isTwoLevelNamespace()) {1041    Array Undefineds = serializeSymbols(File->undefineds(), ActiveTargets);1042    insertNonEmptyValues(Library, TBDKey::Undefineds, std::move(Undefineds));1043  }1044 1045  return std::move(Library);1046}1047 1048Expected<Object> getJSON(const InterfaceFile *File, const FileType FileKind) {1049  assert(FileKind == FileType::TBD_V5 && "unexpected json file format version");1050  Object Root;1051 1052  auto MainLibOrErr = serializeIF(File);1053  if (!MainLibOrErr)1054    return MainLibOrErr;1055  Root[Keys[TBDKey::MainLibrary]] = std::move(*MainLibOrErr);1056  Array Documents;1057  for (const auto &Doc : File->documents()) {1058    auto LibOrErr = serializeIF(Doc.get());1059    if (!LibOrErr)1060      return LibOrErr;1061    Documents.emplace_back(std::move(*LibOrErr));1062  }1063 1064  Root[Keys[TBDKey::TBDVersion]] = 5;1065  insertNonEmptyValues(Root, TBDKey::Documents, std::move(Documents));1066  return std::move(Root);1067}1068 1069} // namespace1070 1071Error MachO::serializeInterfaceFileToJSON(raw_ostream &OS,1072                                          const InterfaceFile &File,1073                                          const FileType FileKind,1074                                          bool Compact) {1075  auto TextFile = getJSON(&File, FileKind);1076  if (!TextFile)1077    return TextFile.takeError();1078  if (Compact)1079    OS << formatv("{0}", Value(std::move(*TextFile))) << "\n";1080  else1081    OS << formatv("{0:2}", Value(std::move(*TextFile))) << "\n";1082  return Error::success();1083}1084