[RISCV] Refactor predicates for rvv intrinsic patterns.
[llvm-project.git] / llvm / lib / TextAPI / TextStubV5.cpp
blobade4c867fa49d47430a39b98075023eee7a4d94f
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-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Implements Text Stub JSON mappings.
11 //===----------------------------------------------------------------------===//
12 #include "TextStubCommon.h"
13 #include "llvm/ADT/StringSwitch.h"
14 #include "llvm/Support/JSON.h"
15 #include <utility>
17 // clang-format off
20 JSON Format specification.
22 All library level keys, accept target values and are defaulted if not specified.
25 "tapi_tbd_version": 5, # Required: TBD version for all documents in file
26 "main_library": { # Required: top level library
27 "target_info": [ # Required: target information
29 "target": "x86_64-macos",
30 "min_deployment": "10.14" # Required: minimum OS deployment version
33 "target": "arm64-macos",
34 "min_deployment": "10.14"
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 1
43 "compatibility_versions":[{ "version": "1.1"}], # Optional: defaults to 1
44 "rpaths": [ # Optional:
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 section
53 "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": []
59 "data": { ... }, # List of Data segment symbols
60 }],
61 "reexported_symbols": [{ ... }], # List of reexported symbols section
62 "undefined_symbols": [{ ... }] # List of undefined symbols section
64 "libraries": [ # Optional: Array of inlined libraries
65 {...}, {...}, {...}
69 // clang-format on
71 using namespace llvm;
72 using namespace llvm::json;
73 using namespace llvm::MachO;
75 struct JSONSymbol {
76 SymbolKind Kind;
77 std::string Name;
78 SymbolFlags Flags;
81 using AttrToTargets = std::map<std::string, TargetList>;
82 using TargetsToSymbols =
83 SmallVector<std::pair<TargetList, std::vector<JSONSymbol>>>;
85 enum TBDKey : size_t {
86 TBDVersion = 0U,
87 MainLibrary,
88 Documents,
89 TargetInfo,
90 Targets,
91 Target,
92 Deployment,
93 Flags,
94 Attributes,
95 InstallName,
96 CurrentVersion,
97 CompatibilityVersion,
98 Version,
99 SwiftABI,
100 ABI,
101 ParentUmbrella,
102 Umbrella,
103 AllowableClients,
104 Clients,
105 ReexportLibs,
106 Names,
107 Name,
108 Exports,
109 Reexports,
110 Undefineds,
111 Data,
112 Text,
113 Weak,
114 ThreadLocal,
115 Globals,
116 ObjCClass,
117 ObjCEHType,
118 ObjCIvar,
119 RPath,
120 Paths,
123 std::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",
161 static llvm::SmallString<128> getParseErrorMsg(TBDKey Key) {
162 return {"invalid ", Keys[Key], " section"};
165 static llvm::SmallString<128> getSerializeErrorMsg(TBDKey Key) {
166 return {"missing ", Keys[Key], " information"};
169 class JSONStubError : public llvm::ErrorInfo<llvm::json::ParseError> {
170 public:
171 JSONStubError(Twine ErrMsg) : Message(ErrMsg.str()) {}
173 void log(llvm::raw_ostream &OS) const override { OS << Message << "\n"; }
174 std::error_code convertToErrorCode() const override {
175 return llvm::inconvertibleErrorCode();
178 private:
179 std::string Message;
182 template <typename JsonT, typename StubT = JsonT>
183 Expected<StubT> getRequiredValue(
184 TBDKey Key, const Object *Obj,
185 std::function<std::optional<JsonT>(const Object *, StringRef)> GetValue,
186 std::function<std::optional<StubT>(JsonT)> Validate = nullptr) {
187 std::optional<JsonT> Val = GetValue(Obj, Keys[Key]);
188 if (!Val)
189 return make_error<JSONStubError>(getParseErrorMsg(Key));
191 if (Validate == nullptr)
192 return static_cast<StubT>(*Val);
194 std::optional<StubT> Result = Validate(*Val);
195 if (!Result.has_value())
196 return make_error<JSONStubError>(getParseErrorMsg(Key));
197 return Result.value();
200 template <typename JsonT, typename StubT = JsonT>
201 Expected<StubT> getRequiredValue(
202 TBDKey Key, const Object *Obj,
203 std::function<std::optional<JsonT>(const Object *, StringRef)> GetValue,
204 StubT DefaultValue, std::function<std::optional<StubT>(JsonT)> Validate) {
205 std::optional<JsonT> Val = GetValue(Obj, Keys[Key]);
206 if (!Val)
207 return DefaultValue;
209 std::optional<StubT> Result;
210 Result = Validate(*Val);
211 if (!Result.has_value())
212 return make_error<JSONStubError>(getParseErrorMsg(Key));
213 return Result.value();
216 Error collectFromArray(TBDKey Key, const Object *Obj,
217 std::function<void(StringRef)> Append,
218 bool IsRequired = false) {
219 const auto *Values = Obj->getArray(Keys[Key]);
220 if (!Values) {
221 if (IsRequired)
222 return make_error<JSONStubError>(getParseErrorMsg(Key));
223 return Error::success();
226 for (const Value &Val : *Values) {
227 auto ValStr = Val.getAsString();
228 if (!ValStr.has_value())
229 return make_error<JSONStubError>(getParseErrorMsg(Key));
230 Append(ValStr.value());
233 return Error::success();
236 namespace StubParser {
238 Expected<FileType> getVersion(const Object *File) {
239 auto VersionOrErr = getRequiredValue<int64_t, FileType>(
240 TBDKey::TBDVersion, File, &Object::getInteger,
241 [](int64_t Val) -> std::optional<FileType> {
242 unsigned Result = Val;
243 if (Result != 5)
244 return std::nullopt;
245 return FileType::TBD_V5;
248 if (!VersionOrErr)
249 return VersionOrErr.takeError();
250 return *VersionOrErr;
253 Expected<TargetList> getTargets(const Object *Section) {
254 const auto *Targets = Section->getArray(Keys[TBDKey::Targets]);
255 if (!Targets)
256 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Targets));
258 TargetList IFTargets;
259 for (const Value &JSONTarget : *Targets) {
260 auto TargetStr = JSONTarget.getAsString();
261 if (!TargetStr.has_value())
262 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));
263 auto TargetOrErr = Target::create(TargetStr.value());
264 if (!TargetOrErr)
265 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));
266 IFTargets.push_back(*TargetOrErr);
268 return std::move(IFTargets);
271 Expected<TargetList> getTargetsSection(const Object *Section) {
272 const Array *Targets = Section->getArray(Keys[TBDKey::TargetInfo]);
273 if (!Targets)
274 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Targets));
276 TargetList IFTargets;
277 for (const Value &JSONTarget : *Targets) {
278 const auto *Obj = JSONTarget.getAsObject();
279 if (!Obj)
280 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));
281 auto TargetStr =
282 getRequiredValue<StringRef>(TBDKey::Target, Obj, &Object::getString);
283 if (!TargetStr)
284 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));
285 auto VersionStr = getRequiredValue<StringRef>(TBDKey::Deployment, Obj,
286 &Object::getString);
287 if (!VersionStr)
288 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Deployment));
289 VersionTuple Version;
290 if (Version.tryParse(*VersionStr))
291 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Deployment));
292 auto TargetOrErr = Target::create(*TargetStr);
293 if (!TargetOrErr)
294 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));
295 TargetOrErr->MinDeployment = Version;
296 // Convert to LLVM::Triple to accurately compute minOS + platform + arch
297 // pairing.
298 IFTargets.push_back(
299 MachO::Target(Triple(getTargetTripleName(*TargetOrErr))));
301 return std::move(IFTargets);
304 Error collectSymbolsFromSegment(const Object *Segment, TargetsToSymbols &Result,
305 SymbolFlags SectionFlag) {
306 auto Err = collectFromArray(
307 TBDKey::Globals, Segment, [&Result, &SectionFlag](StringRef Name) {
308 JSONSymbol Sym = {SymbolKind::GlobalSymbol, Name.str(), SectionFlag};
309 Result.back().second.emplace_back(Sym);
311 if (Err)
312 return Err;
314 Err = collectFromArray(
315 TBDKey::ObjCClass, Segment, [&Result, &SectionFlag](StringRef Name) {
316 JSONSymbol Sym = {SymbolKind::ObjectiveCClass, Name.str(), SectionFlag};
317 Result.back().second.emplace_back(Sym);
319 if (Err)
320 return Err;
322 Err = collectFromArray(TBDKey::ObjCEHType, Segment,
323 [&Result, &SectionFlag](StringRef Name) {
324 JSONSymbol Sym = {SymbolKind::ObjectiveCClassEHType,
325 Name.str(), SectionFlag};
326 Result.back().second.emplace_back(Sym);
328 if (Err)
329 return Err;
331 Err = collectFromArray(
332 TBDKey::ObjCIvar, Segment, [&Result, &SectionFlag](StringRef Name) {
333 JSONSymbol Sym = {SymbolKind::ObjectiveCInstanceVariable, Name.str(),
334 SectionFlag};
335 Result.back().second.emplace_back(Sym);
337 if (Err)
338 return Err;
340 SymbolFlags WeakFlag =
341 SectionFlag |
342 (((SectionFlag & SymbolFlags::Undefined) == SymbolFlags::Undefined)
343 ? SymbolFlags::WeakReferenced
344 : SymbolFlags::WeakDefined);
345 Err = collectFromArray(
346 TBDKey::Weak, Segment, [&Result, WeakFlag](StringRef Name) {
347 JSONSymbol Sym = {SymbolKind::GlobalSymbol, Name.str(), WeakFlag};
348 Result.back().second.emplace_back(Sym);
350 if (Err)
351 return Err;
353 Err = collectFromArray(
354 TBDKey::ThreadLocal, Segment, [&Result, SectionFlag](StringRef Name) {
355 JSONSymbol Sym = {SymbolKind::GlobalSymbol, Name.str(),
356 SymbolFlags::ThreadLocalValue | SectionFlag};
357 Result.back().second.emplace_back(Sym);
359 if (Err)
360 return Err;
362 return Error::success();
365 Expected<StringRef> getNameSection(const Object *File) {
366 const Array *Section = File->getArray(Keys[TBDKey::InstallName]);
367 if (!Section)
368 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::InstallName));
370 assert(!Section->empty() && "unexpected missing install name");
371 // TODO: Just take first for now.
372 const auto *Obj = Section->front().getAsObject();
373 if (!Obj)
374 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::InstallName));
376 return getRequiredValue<StringRef>(TBDKey::Name, Obj, &Object::getString);
379 Expected<TargetsToSymbols> getSymbolSection(const Object *File, TBDKey Key,
380 TargetList &Targets) {
382 const Array *Section = File->getArray(Keys[Key]);
383 if (!Section)
384 return TargetsToSymbols();
386 SymbolFlags SectionFlag;
387 switch (Key) {
388 case TBDKey::Reexports:
389 SectionFlag = SymbolFlags::Rexported;
390 break;
391 case TBDKey::Undefineds:
392 SectionFlag = SymbolFlags::Undefined;
393 break;
394 default:
395 SectionFlag = SymbolFlags::None;
396 break;
399 TargetsToSymbols Result;
400 TargetList MappedTargets;
401 for (auto Val : *Section) {
402 auto *Obj = Val.getAsObject();
403 if (!Obj)
404 continue;
406 auto TargetsOrErr = getTargets(Obj);
407 if (!TargetsOrErr) {
408 MappedTargets = Targets;
409 consumeError(TargetsOrErr.takeError());
410 } else {
411 MappedTargets = *TargetsOrErr;
413 Result.emplace_back(
414 std::make_pair(std::move(MappedTargets), std::vector<JSONSymbol>()));
416 auto *DataSection = Obj->getObject(Keys[TBDKey::Data]);
417 auto *TextSection = Obj->getObject(Keys[TBDKey::Text]);
418 // There should be at least one valid section.
419 if (!DataSection && !TextSection)
420 return make_error<JSONStubError>(getParseErrorMsg(Key));
422 if (DataSection) {
423 auto Err = collectSymbolsFromSegment(DataSection, Result,
424 SectionFlag | SymbolFlags::Data);
425 if (Err)
426 return std::move(Err);
428 if (TextSection) {
429 auto Err = collectSymbolsFromSegment(TextSection, Result,
430 SectionFlag | SymbolFlags::Text);
431 if (Err)
432 return std::move(Err);
436 return std::move(Result);
439 Expected<AttrToTargets> getLibSection(const Object *File, TBDKey Key,
440 TBDKey SubKey,
441 const TargetList &Targets) {
442 auto *Section = File->getArray(Keys[Key]);
443 if (!Section)
444 return AttrToTargets();
446 AttrToTargets Result;
447 TargetList MappedTargets;
448 for (auto Val : *Section) {
449 auto *Obj = Val.getAsObject();
450 if (!Obj)
451 continue;
453 auto TargetsOrErr = getTargets(Obj);
454 if (!TargetsOrErr) {
455 MappedTargets = Targets;
456 consumeError(TargetsOrErr.takeError());
457 } else {
458 MappedTargets = *TargetsOrErr;
460 auto Err =
461 collectFromArray(SubKey, Obj, [&Result, &MappedTargets](StringRef Key) {
462 Result[Key.str()] = MappedTargets;
464 if (Err)
465 return std::move(Err);
468 return std::move(Result);
471 Expected<AttrToTargets> getUmbrellaSection(const Object *File,
472 const TargetList &Targets) {
473 const auto *Umbrella = File->getArray(Keys[TBDKey::ParentUmbrella]);
474 if (!Umbrella)
475 return AttrToTargets();
477 AttrToTargets Result;
478 TargetList MappedTargets;
479 for (auto Val : *Umbrella) {
480 auto *Obj = Val.getAsObject();
481 if (!Obj)
482 return make_error<JSONStubError>(
483 getParseErrorMsg(TBDKey::ParentUmbrella));
485 // Get Targets section.
486 auto TargetsOrErr = getTargets(Obj);
487 if (!TargetsOrErr) {
488 MappedTargets = Targets;
489 consumeError(TargetsOrErr.takeError());
490 } else {
491 MappedTargets = *TargetsOrErr;
494 auto UmbrellaOrErr =
495 getRequiredValue<StringRef>(TBDKey::Umbrella, Obj, &Object::getString);
496 if (!UmbrellaOrErr)
497 return UmbrellaOrErr.takeError();
498 Result[UmbrellaOrErr->str()] = Targets;
500 return std::move(Result);
503 Expected<uint8_t> getSwiftVersion(const Object *File) {
504 const Array *Versions = File->getArray(Keys[TBDKey::SwiftABI]);
505 if (!Versions)
506 return 0;
508 for (const auto &Val : *Versions) {
509 const auto *Obj = Val.getAsObject();
510 if (!Obj)
511 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::SwiftABI));
513 // TODO: Take first for now.
514 return getRequiredValue<int64_t, uint8_t>(TBDKey::ABI, Obj,
515 &Object::getInteger);
518 return 0;
521 Expected<PackedVersion> getPackedVersion(const Object *File, TBDKey Key) {
522 const Array *Versions = File->getArray(Keys[Key]);
523 if (!Versions)
524 return PackedVersion(1, 0, 0);
526 for (const auto &Val : *Versions) {
527 const auto *Obj = Val.getAsObject();
528 if (!Obj)
529 return make_error<JSONStubError>(getParseErrorMsg(Key));
531 auto ValidatePV = [](StringRef Version) -> std::optional<PackedVersion> {
532 PackedVersion PV;
533 auto [success, truncated] = PV.parse64(Version);
534 if (!success || truncated)
535 return std::nullopt;
536 return PV;
538 // TODO: Take first for now.
539 return getRequiredValue<StringRef, PackedVersion>(
540 TBDKey::Version, Obj, &Object::getString, PackedVersion(1, 0, 0),
541 ValidatePV);
544 return PackedVersion(1, 0, 0);
547 Expected<TBDFlags> getFlags(const Object *File) {
548 TBDFlags Flags = TBDFlags::None;
549 const Array *Section = File->getArray(Keys[TBDKey::Flags]);
550 if (!Section)
551 return Flags;
553 for (auto &Val : *Section) {
554 // TODO: Just take first for now.
555 const auto *Obj = Val.getAsObject();
556 if (!Obj)
557 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Flags));
559 auto FlagsOrErr =
560 collectFromArray(TBDKey::Attributes, Obj, [&Flags](StringRef Flag) {
561 TBDFlags TBDFlag =
562 StringSwitch<TBDFlags>(Flag)
563 .Case("flat_namespace", TBDFlags::FlatNamespace)
564 .Case("not_app_extension_safe",
565 TBDFlags::NotApplicationExtensionSafe)
566 .Default(TBDFlags::None);
567 Flags |= TBDFlag;
570 if (FlagsOrErr)
571 return std::move(FlagsOrErr);
573 return Flags;
576 return Flags;
579 using IFPtr = std::unique_ptr<InterfaceFile>;
580 Expected<IFPtr> parseToInterfaceFile(const Object *File) {
581 auto TargetsOrErr = getTargetsSection(File);
582 if (!TargetsOrErr)
583 return TargetsOrErr.takeError();
584 TargetList Targets = *TargetsOrErr;
586 auto NameOrErr = getNameSection(File);
587 if (!NameOrErr)
588 return NameOrErr.takeError();
589 StringRef Name = *NameOrErr;
591 auto CurrVersionOrErr = getPackedVersion(File, TBDKey::CurrentVersion);
592 if (!CurrVersionOrErr)
593 return CurrVersionOrErr.takeError();
594 PackedVersion CurrVersion = *CurrVersionOrErr;
596 auto CompVersionOrErr = getPackedVersion(File, TBDKey::CompatibilityVersion);
597 if (!CompVersionOrErr)
598 return CompVersionOrErr.takeError();
599 PackedVersion CompVersion = *CompVersionOrErr;
601 auto SwiftABIOrErr = getSwiftVersion(File);
602 if (!SwiftABIOrErr)
603 return SwiftABIOrErr.takeError();
604 uint8_t SwiftABI = *SwiftABIOrErr;
606 auto FlagsOrErr = getFlags(File);
607 if (!FlagsOrErr)
608 return FlagsOrErr.takeError();
609 TBDFlags Flags = *FlagsOrErr;
611 auto UmbrellasOrErr = getUmbrellaSection(File, Targets);
612 if (!UmbrellasOrErr)
613 return UmbrellasOrErr.takeError();
614 AttrToTargets Umbrellas = *UmbrellasOrErr;
616 auto ClientsOrErr =
617 getLibSection(File, TBDKey::AllowableClients, TBDKey::Clients, Targets);
618 if (!ClientsOrErr)
619 return ClientsOrErr.takeError();
620 AttrToTargets Clients = *ClientsOrErr;
622 auto RLOrErr =
623 getLibSection(File, TBDKey::ReexportLibs, TBDKey::Names, Targets);
624 if (!RLOrErr)
625 return RLOrErr.takeError();
626 AttrToTargets ReexportLibs = std::move(*RLOrErr);
628 auto RPathsOrErr = getLibSection(File, TBDKey::RPath, TBDKey::Paths, Targets);
629 if (!RPathsOrErr)
630 return RPathsOrErr.takeError();
631 AttrToTargets RPaths = std::move(*RPathsOrErr);
633 auto ExportsOrErr = getSymbolSection(File, TBDKey::Exports, Targets);
634 if (!ExportsOrErr)
635 return ExportsOrErr.takeError();
636 TargetsToSymbols Exports = std::move(*ExportsOrErr);
638 auto ReexportsOrErr = getSymbolSection(File, TBDKey::Reexports, Targets);
639 if (!ReexportsOrErr)
640 return ReexportsOrErr.takeError();
641 TargetsToSymbols Reexports = std::move(*ReexportsOrErr);
643 auto UndefinedsOrErr = getSymbolSection(File, TBDKey::Undefineds, Targets);
644 if (!UndefinedsOrErr)
645 return UndefinedsOrErr.takeError();
646 TargetsToSymbols Undefineds = std::move(*UndefinedsOrErr);
648 IFPtr F(new InterfaceFile);
649 F->setInstallName(Name);
650 F->setCurrentVersion(CurrVersion);
651 F->setCompatibilityVersion(CompVersion);
652 F->setSwiftABIVersion(SwiftABI);
653 F->setTwoLevelNamespace(!(Flags & TBDFlags::FlatNamespace));
654 F->setApplicationExtensionSafe(
655 !(Flags & TBDFlags::NotApplicationExtensionSafe));
656 for (auto &T : Targets)
657 F->addTarget(T);
658 for (auto &[Lib, Targets] : Clients)
659 for (auto Target : Targets)
660 F->addAllowableClient(Lib, Target);
661 for (auto &[Lib, Targets] : ReexportLibs)
662 for (auto Target : Targets)
663 F->addReexportedLibrary(Lib, Target);
664 for (auto &[Lib, Targets] : Umbrellas)
665 for (auto Target : Targets)
666 F->addParentUmbrella(Target, Lib);
667 for (auto &[Path, Targets] : RPaths)
668 for (auto Target : Targets)
669 F->addRPath(Target, Path);
670 for (auto &[Targets, Symbols] : Exports)
671 for (auto &Sym : Symbols)
672 F->addSymbol(Sym.Kind, Sym.Name, Targets, Sym.Flags);
673 for (auto &[Targets, Symbols] : Reexports)
674 for (auto &Sym : Symbols)
675 F->addSymbol(Sym.Kind, Sym.Name, Targets, Sym.Flags);
676 for (auto &[Targets, Symbols] : Undefineds)
677 for (auto &Sym : Symbols)
678 F->addSymbol(Sym.Kind, Sym.Name, Targets, Sym.Flags);
680 return std::move(F);
683 Expected<std::vector<IFPtr>> getInlinedLibs(const Object *File) {
684 std::vector<IFPtr> IFs;
685 const Array *Files = File->getArray(Keys[TBDKey::Documents]);
686 if (!Files)
687 return std::move(IFs);
689 for (auto Lib : *Files) {
690 auto IFOrErr = parseToInterfaceFile(Lib.getAsObject());
691 if (!IFOrErr)
692 return IFOrErr.takeError();
693 auto IF = std::move(*IFOrErr);
694 IFs.emplace_back(std::move(IF));
696 return std::move(IFs);
699 } // namespace StubParser
701 Expected<std::unique_ptr<InterfaceFile>>
702 MachO::getInterfaceFileFromJSON(StringRef JSON) {
703 auto ValOrErr = parse(JSON);
704 if (!ValOrErr)
705 return ValOrErr.takeError();
707 auto *Root = ValOrErr->getAsObject();
708 auto VersionOrErr = StubParser::getVersion(Root);
709 if (!VersionOrErr)
710 return VersionOrErr.takeError();
711 FileType Version = *VersionOrErr;
713 Object *MainLib = Root->getObject(Keys[TBDKey::MainLibrary]);
714 auto IFOrErr = StubParser::parseToInterfaceFile(MainLib);
715 if (!IFOrErr)
716 return IFOrErr.takeError();
717 (*IFOrErr)->setFileType(Version);
718 std::unique_ptr<InterfaceFile> IF(std::move(*IFOrErr));
720 auto IFsOrErr = StubParser::getInlinedLibs(Root);
721 if (!IFsOrErr)
722 return IFsOrErr.takeError();
723 for (auto &File : *IFsOrErr) {
724 File->setFileType(Version);
725 IF->addDocument(std::shared_ptr<InterfaceFile>(std::move(File)));
727 return std::move(IF);
730 namespace {
732 template <typename ContainerT = Array>
733 bool insertNonEmptyValues(Object &Obj, TBDKey Key, ContainerT &&Contents) {
734 if (Contents.empty())
735 return false;
736 Obj[Keys[Key]] = std::move(Contents);
737 return true;
740 std::string getFormattedStr(const MachO::Target &Targ) {
741 std::string PlatformStr = Targ.Platform == PLATFORM_MACCATALYST
742 ? "maccatalyst"
743 : getOSAndEnvironmentName(Targ.Platform);
744 return (getArchitectureName(Targ.Arch) + "-" + PlatformStr).str();
747 template <typename AggregateT>
748 std::vector<std::string> serializeTargets(const AggregateT Targets,
749 const TargetList &ActiveTargets) {
750 std::vector<std::string> TargetsStr;
751 if (Targets.size() == ActiveTargets.size())
752 return TargetsStr;
754 llvm::for_each(Targets, [&TargetsStr](const MachO::Target &Target) {
755 TargetsStr.emplace_back(getFormattedStr(Target));
757 return TargetsStr;
760 Array serializeTargetInfo(const TargetList &ActiveTargets) {
761 Array Targets;
762 for (const auto Targ : ActiveTargets) {
763 Object TargetInfo;
764 TargetInfo[Keys[TBDKey::Deployment]] = Targ.MinDeployment.getAsString();
765 TargetInfo[Keys[TBDKey::Target]] = getFormattedStr(Targ);
766 Targets.emplace_back(std::move(TargetInfo));
768 return Targets;
771 template <typename ValueT, typename EntryT = ValueT>
772 Array serializeScalar(TBDKey Key, ValueT Value, ValueT Default = ValueT()) {
773 if (Value == Default)
774 return {};
775 Array Container;
776 Object ScalarObj({Object::KV({Keys[Key], EntryT(Value)})});
778 Container.emplace_back(std::move(ScalarObj));
779 return Container;
782 using TargetsToValuesMap =
783 std::map<std::vector<std::string>, std::vector<std::string>>;
785 template <typename AggregateT = TargetsToValuesMap>
786 Array serializeAttrToTargets(AggregateT &Entries, TBDKey Key) {
787 Array Container;
788 for (const auto &[Targets, Values] : Entries) {
789 Object Obj;
790 insertNonEmptyValues(Obj, TBDKey::Targets, std::move(Targets));
791 Obj[Keys[Key]] = Values;
792 Container.emplace_back(std::move(Obj));
794 return Container;
797 template <typename ValueT = std::string,
798 typename AggregateT = std::vector<std::pair<MachO::Target, ValueT>>>
799 Array serializeField(TBDKey Key, const AggregateT &Values,
800 const TargetList &ActiveTargets, bool IsArray = true) {
801 std::map<ValueT, std::set<MachO::Target>> Entries;
802 for (const auto &[Target, Val] : Values)
803 Entries[Val].insert(Target);
805 if (!IsArray) {
806 std::map<std::vector<std::string>, std::string> FinalEntries;
807 for (const auto &[Val, Targets] : Entries)
808 FinalEntries[serializeTargets(Targets, ActiveTargets)] = Val;
809 return serializeAttrToTargets(FinalEntries, Key);
812 TargetsToValuesMap FinalEntries;
813 for (const auto &[Val, Targets] : Entries)
814 FinalEntries[serializeTargets(Targets, ActiveTargets)].emplace_back(Val);
815 return serializeAttrToTargets(FinalEntries, Key);
818 Array serializeField(TBDKey Key, const std::vector<InterfaceFileRef> &Values,
819 const TargetList &ActiveTargets) {
820 TargetsToValuesMap FinalEntries;
821 for (const auto &Ref : Values) {
822 TargetList Targets{Ref.targets().begin(), Ref.targets().end()};
823 FinalEntries[serializeTargets(Targets, ActiveTargets)].emplace_back(
824 Ref.getInstallName());
826 return serializeAttrToTargets(FinalEntries, Key);
829 struct SymbolFields {
830 struct SymbolTypes {
831 std::vector<StringRef> Weaks;
832 std::vector<StringRef> Globals;
833 std::vector<StringRef> TLV;
834 std::vector<StringRef> ObjCClasses;
835 std::vector<StringRef> IVars;
836 std::vector<StringRef> EHTypes;
838 bool empty() const {
839 return Weaks.empty() && Globals.empty() && TLV.empty() &&
840 ObjCClasses.empty() && IVars.empty() && EHTypes.empty();
843 SymbolTypes Data;
844 SymbolTypes Text;
847 Array serializeSymbols(InterfaceFile::const_filtered_symbol_range Symbols,
848 const TargetList &ActiveTargets) {
849 auto AssignForSymbolType = [](SymbolFields::SymbolTypes &Assignment,
850 const Symbol *Sym) {
851 switch (Sym->getKind()) {
852 case SymbolKind::ObjectiveCClass:
853 Assignment.ObjCClasses.emplace_back(Sym->getName());
854 return;
855 case SymbolKind::ObjectiveCClassEHType:
856 Assignment.EHTypes.emplace_back(Sym->getName());
857 return;
858 case SymbolKind::ObjectiveCInstanceVariable:
859 Assignment.IVars.emplace_back(Sym->getName());
860 return;
861 case SymbolKind::GlobalSymbol: {
862 if (Sym->isWeakReferenced() || Sym->isWeakDefined())
863 Assignment.Weaks.emplace_back(Sym->getName());
864 else if (Sym->isThreadLocalValue())
865 Assignment.TLV.emplace_back(Sym->getName());
866 else
867 Assignment.Globals.emplace_back(Sym->getName());
868 return;
873 std::map<std::vector<std::string>, SymbolFields> Entries;
874 for (const auto *Sym : Symbols) {
875 std::set<MachO::Target> Targets{Sym->targets().begin(),
876 Sym->targets().end()};
877 auto JSONTargets = serializeTargets(Targets, ActiveTargets);
878 if (Sym->isData())
879 AssignForSymbolType(Entries[std::move(JSONTargets)].Data, Sym);
880 else if (Sym->isText())
881 AssignForSymbolType(Entries[std::move(JSONTargets)].Text, Sym);
882 else
883 llvm_unreachable("unexpected symbol type");
886 auto InsertSymbolsToJSON = [](Object &SymSection, TBDKey SegmentKey,
887 SymbolFields::SymbolTypes &SymField) {
888 if (SymField.empty())
889 return;
890 Object Segment;
891 insertNonEmptyValues(Segment, TBDKey::Globals, std::move(SymField.Globals));
892 insertNonEmptyValues(Segment, TBDKey::ThreadLocal, std::move(SymField.TLV));
893 insertNonEmptyValues(Segment, TBDKey::Weak, std::move(SymField.Weaks));
894 insertNonEmptyValues(Segment, TBDKey::ObjCClass,
895 std::move(SymField.ObjCClasses));
896 insertNonEmptyValues(Segment, TBDKey::ObjCEHType,
897 std::move(SymField.EHTypes));
898 insertNonEmptyValues(Segment, TBDKey::ObjCIvar, std::move(SymField.IVars));
899 insertNonEmptyValues(SymSection, SegmentKey, std::move(Segment));
902 Array SymbolSection;
903 for (auto &[Targets, Fields] : Entries) {
904 Object AllSyms;
905 insertNonEmptyValues(AllSyms, TBDKey::Targets, std::move(Targets));
906 InsertSymbolsToJSON(AllSyms, TBDKey::Data, Fields.Data);
907 InsertSymbolsToJSON(AllSyms, TBDKey::Text, Fields.Text);
908 SymbolSection.emplace_back(std::move(AllSyms));
911 return SymbolSection;
914 Array serializeFlags(const InterfaceFile *File) {
915 // TODO: Give all Targets the same flags for now.
916 Array Flags;
917 if (!File->isTwoLevelNamespace())
918 Flags.emplace_back("flat_namespace");
919 if (!File->isApplicationExtensionSafe())
920 Flags.emplace_back("not_app_extension_safe");
921 return serializeScalar(TBDKey::Attributes, std::move(Flags));
924 Expected<Object> serializeIF(const InterfaceFile *File) {
925 Object Library;
927 // Handle required keys.
928 TargetList ActiveTargets{File->targets().begin(), File->targets().end()};
929 if (!insertNonEmptyValues(Library, TBDKey::TargetInfo,
930 serializeTargetInfo(ActiveTargets)))
931 return make_error<JSONStubError>(getSerializeErrorMsg(TBDKey::TargetInfo));
933 Array Name = serializeScalar<StringRef>(TBDKey::Name, File->getInstallName());
934 if (!insertNonEmptyValues(Library, TBDKey::InstallName, std::move(Name)))
935 return make_error<JSONStubError>(getSerializeErrorMsg(TBDKey::InstallName));
937 // Handle optional keys.
938 Array Flags = serializeFlags(File);
939 insertNonEmptyValues(Library, TBDKey::Flags, std::move(Flags));
941 Array CurrentV = serializeScalar<PackedVersion, std::string>(
942 TBDKey::Version, File->getCurrentVersion(), PackedVersion(1, 0, 0));
943 insertNonEmptyValues(Library, TBDKey::CurrentVersion, std::move(CurrentV));
945 Array CompatV = serializeScalar<PackedVersion, std::string>(
946 TBDKey::Version, File->getCompatibilityVersion(), PackedVersion(1, 0, 0));
947 insertNonEmptyValues(Library, TBDKey::CompatibilityVersion,
948 std::move(CompatV));
950 Array SwiftABI = serializeScalar<uint8_t, int64_t>(
951 TBDKey::ABI, File->getSwiftABIVersion(), 0u);
952 insertNonEmptyValues(Library, TBDKey::SwiftABI, std::move(SwiftABI));
954 Array RPaths = serializeField(TBDKey::Paths, File->rpaths(), ActiveTargets);
955 insertNonEmptyValues(Library, TBDKey::RPath, std::move(RPaths));
957 Array Umbrellas = serializeField(TBDKey::Umbrella, File->umbrellas(),
958 ActiveTargets, /*IsArray=*/false);
959 insertNonEmptyValues(Library, TBDKey::ParentUmbrella, std::move(Umbrellas));
961 Array Clients =
962 serializeField(TBDKey::Clients, File->allowableClients(), ActiveTargets);
963 insertNonEmptyValues(Library, TBDKey::AllowableClients, std::move(Clients));
965 Array ReexportLibs =
966 serializeField(TBDKey::Names, File->reexportedLibraries(), ActiveTargets);
967 insertNonEmptyValues(Library, TBDKey::ReexportLibs, std::move(ReexportLibs));
969 // Handle symbols.
970 Array Exports = serializeSymbols(File->exports(), ActiveTargets);
971 insertNonEmptyValues(Library, TBDKey::Exports, std::move(Exports));
973 Array Reexports = serializeSymbols(File->reexports(), ActiveTargets);
974 insertNonEmptyValues(Library, TBDKey::Reexports, std::move(Reexports));
976 if (!File->isTwoLevelNamespace()) {
977 Array Undefineds = serializeSymbols(File->undefineds(), ActiveTargets);
978 insertNonEmptyValues(Library, TBDKey::Undefineds, std::move(Undefineds));
981 return std::move(Library);
984 Expected<Object> getJSON(const InterfaceFile *File) {
985 assert(File->getFileType() == FileType::TBD_V5 &&
986 "unexpected json file format version");
987 Object Root;
989 auto MainLibOrErr = serializeIF(File);
990 if (!MainLibOrErr)
991 return MainLibOrErr;
992 Root[Keys[TBDKey::MainLibrary]] = std::move(*MainLibOrErr);
993 Array Documents;
994 for (const auto &Doc : File->documents()) {
995 auto LibOrErr = serializeIF(Doc.get());
996 if (!LibOrErr)
997 return LibOrErr;
998 Documents.emplace_back(std::move(*LibOrErr));
1001 Root[Keys[TBDKey::TBDVersion]] = 5;
1002 insertNonEmptyValues(Root, TBDKey::Documents, std::move(Documents));
1003 return std::move(Root);
1006 } // namespace
1008 Error MachO::serializeInterfaceFileToJSON(raw_ostream &OS,
1009 const InterfaceFile &File,
1010 bool Compact) {
1011 auto TextFile = getJSON(&File);
1012 if (!TextFile)
1013 return TextFile.takeError();
1014 if (Compact)
1015 OS << formatv("{0}", Value(std::move(*TextFile))) << "\n";
1016 else
1017 OS << formatv("{0:2}", Value(std::move(*TextFile))) << "\n";
1018 return Error::success();