Skip to content

Commit 4824a88

Browse files
committed
[clang][deps] Serialize JSON without creating intermediate objects (llvm#111734)
The dependency scanner uses the `llvm::json` library for outputting the dependency information. Until now, it created an in-memory representation of the dependency graph using the `llvm::json::Object` hierarchy. This not only creates unnecessary copies of the data, but also forces lexicographical ordering of attributes in the output, both of which I'd like to avoid. This patch adopts the `llvm::json::OStream` API instead and reorders the attribute printing logic such that the existing lexicographical ordering is preserved (for now). (cherry picked from commit c55d68f)
1 parent 96a972f commit 4824a88

File tree

1 file changed

+112
-90
lines changed

1 file changed

+112
-90
lines changed

clang/tools/clang-scan-deps/ClangScanDeps.cpp

Lines changed: 112 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -585,38 +585,46 @@ static bool useCAS() {
585585
return InMemoryCAS || !OnDiskCASPath.empty() || outputFormatRequiresCAS();
586586
}
587587

588-
static llvm::json::Array toJSONSorted(const llvm::StringSet<> &Set) {
589-
std::vector<llvm::StringRef> Strings;
590-
for (auto &&I : Set)
591-
Strings.push_back(I.getKey());
588+
template <typename Container>
589+
static auto toJSONStrings(llvm::json::OStream &JOS, Container &&Strings) {
590+
return [&JOS, Strings = std::forward<Container>(Strings)] {
591+
for (StringRef Str : Strings)
592+
JOS.value(Str);
593+
};
594+
}
595+
596+
static auto toJSONSorted(llvm::json::OStream &JOS,
597+
const llvm::StringSet<> &Set) {
598+
SmallVector<StringRef> Strings(Set.keys());
592599
llvm::sort(Strings);
593-
return llvm::json::Array(Strings);
600+
return toJSONStrings(JOS, std::move(Strings));
594601
}
595602

596603
// Technically, we don't need to sort the dependency list to get determinism.
597604
// Leaving these be will simply preserve the import order.
598-
static llvm::json::Array toJSONSorted(std::vector<ModuleID> V) {
605+
static auto toJSONSorted(llvm::json::OStream &JOS, std::vector<ModuleID> V) {
599606
llvm::sort(V);
600-
601-
llvm::json::Array Ret;
602-
for (const ModuleID &MID : V)
603-
Ret.push_back(llvm::json::Object(
604-
{{"module-name", MID.ModuleName}, {"context-hash", MID.ContextHash}}));
605-
return Ret;
607+
return [&JOS, V = std::move(V)] {
608+
for (const ModuleID &MID : V)
609+
JOS.object([&] {
610+
JOS.attribute("context-hash", StringRef(MID.ContextHash));
611+
JOS.attribute("module-name", StringRef(MID.ModuleName));
612+
});
613+
};
606614
}
607615

608-
static llvm::json::Array
609-
toJSONSorted(llvm::SmallVector<Module::LinkLibrary, 2> &LinkLibs) {
610-
llvm::sort(LinkLibs, [](const Module::LinkLibrary &lhs,
611-
const Module::LinkLibrary &rhs) {
612-
return lhs.Library < rhs.Library;
616+
static auto toJSONSorted(llvm::json::OStream &JOS,
617+
SmallVector<Module::LinkLibrary, 2> LinkLibs) {
618+
llvm::sort(LinkLibs, [](const auto &LHS, const auto &RHS) {
619+
return LHS.Library < RHS.Library;
613620
});
614-
615-
llvm::json::Array Ret;
616-
for (const Module::LinkLibrary &LL : LinkLibs)
617-
Ret.push_back(llvm::json::Object(
618-
{{"link-name", LL.Library}, {"isFramework", LL.IsFramework}}));
619-
return Ret;
621+
return [&JOS, LinkLibs = std::move(LinkLibs)] {
622+
for (const auto &LL : LinkLibs)
623+
JOS.object([&] {
624+
JOS.attribute("isFramework", LL.IsFramework);
625+
JOS.attribute("link-name", StringRef(LL.Library));
626+
});
627+
};
620628
}
621629

622630
// Thread safe.
@@ -707,76 +715,90 @@ class FullDeps {
707715
ModuleIDs.push_back(M.first);
708716
llvm::sort(ModuleIDs);
709717

710-
using namespace llvm::json;
711-
712-
Array OutModules;
713-
for (auto &&ModID : ModuleIDs) {
714-
auto &MD = Modules[ModID];
715-
Object O{
716-
{"name", MD.ID.ModuleName},
717-
{"context-hash", MD.ID.ContextHash},
718-
{"file-deps", toJSONSorted(MD.FileDeps)},
719-
{"clang-module-deps", toJSONSorted(MD.ClangModuleDeps)},
720-
{"clang-modulemap-file", MD.ClangModuleMapFile},
721-
{"command-line", MD.getBuildArguments()},
722-
{"link-libraries", toJSONSorted(MD.LinkLibraries)},
723-
};
724-
if (MD.ModuleCacheKey)
725-
O.try_emplace("cache-key", MD.ModuleCacheKey);
726-
if (MD.CASFileSystemRootID)
727-
O.try_emplace("casfs-root-id", MD.CASFileSystemRootID->toString());
728-
if (MD.IncludeTreeID)
729-
O.try_emplace("cas-include-tree-id", MD.IncludeTreeID);
730-
OutModules.push_back(std::move(O));
731-
}
732-
733-
Array TUs;
734-
for (auto &&I : Inputs) {
735-
Array Commands;
736-
if (I.DriverCommandLine.empty()) {
737-
for (const auto &Cmd : I.Commands) {
738-
Object O{
739-
{"input-file", I.FileName},
740-
{"clang-context-hash", I.ContextHash},
741-
{"file-deps", I.FileDeps},
742-
{"clang-module-deps", toJSONSorted(I.ModuleDeps)},
743-
{"executable", Cmd.Executable},
744-
{"command-line", Cmd.Arguments},
745-
};
746-
if (Cmd.TUCacheKey)
747-
O.try_emplace("cache-key", Cmd.TUCacheKey);
748-
if (I.CASFileSystemRootID)
749-
O.try_emplace("casfs-root-id", I.CASFileSystemRootID);
750-
if (I.IncludeTreeID)
751-
O.try_emplace("cas-include-tree-id", I.IncludeTreeID);
752-
Commands.push_back(std::move(O));
718+
llvm::json::OStream JOS(OS, /*IndentSize=*/2);
719+
720+
JOS.object([&] {
721+
JOS.attributeArray("modules", [&] {
722+
for (auto &&ModID : ModuleIDs) {
723+
auto &MD = Modules[ModID];
724+
JOS.object([&] {
725+
if (MD.ModuleCacheKey)
726+
JOS.attribute("cache-key", StringRef(*MD.ModuleCacheKey));
727+
if (MD.IncludeTreeID)
728+
JOS.attribute("cas-include-tree-id",
729+
StringRef(*MD.IncludeTreeID));
730+
if (MD.CASFileSystemRootID)
731+
JOS.attribute("casfs-root-id",
732+
StringRef(MD.CASFileSystemRootID->toString()));
733+
734+
JOS.attributeArray("clang-module-deps",
735+
toJSONSorted(JOS, MD.ClangModuleDeps));
736+
JOS.attribute("clang-modulemap-file",
737+
StringRef(MD.ClangModuleMapFile));
738+
JOS.attributeArray("command-line",
739+
toJSONStrings(JOS, MD.getBuildArguments()));
740+
JOS.attribute("context-hash", StringRef(MD.ID.ContextHash));
741+
JOS.attributeArray("file-deps", toJSONSorted(JOS, MD.FileDeps));
742+
JOS.attributeArray("link-libraries",
743+
toJSONSorted(JOS, MD.LinkLibraries));
744+
JOS.attribute("name", StringRef(MD.ID.ModuleName));
745+
});
753746
}
754-
} else {
755-
Object O{
756-
{"input-file", I.FileName},
757-
{"clang-context-hash", I.ContextHash},
758-
{"file-deps", I.FileDeps},
759-
{"clang-module-deps", toJSONSorted(I.ModuleDeps)},
760-
{"executable", "clang"},
761-
{"command-line", I.DriverCommandLine},
762-
};
763-
if (I.CASFileSystemRootID)
764-
O.try_emplace("casfs-root-id", I.CASFileSystemRootID);
765-
if (I.IncludeTreeID)
766-
O.try_emplace("cas-include-tree-id", I.IncludeTreeID);
767-
Commands.push_back(std::move(O));
768-
}
769-
TUs.push_back(Object{
770-
{"commands", std::move(Commands)},
771747
});
772-
}
773-
774-
Object Output{
775-
{"modules", std::move(OutModules)},
776-
{"translation-units", std::move(TUs)},
777-
};
778748

779-
OS << llvm::formatv("{0:2}\n", Value(std::move(Output)));
749+
JOS.attributeArray("translation-units", [&] {
750+
for (auto &&I : Inputs) {
751+
JOS.object([&] {
752+
JOS.attributeArray("commands", [&] {
753+
if (I.DriverCommandLine.empty()) {
754+
for (const auto &Cmd : I.Commands) {
755+
JOS.object([&] {
756+
if (Cmd.TUCacheKey)
757+
JOS.attribute("cache-key", StringRef(*Cmd.TUCacheKey));
758+
if (I.IncludeTreeID)
759+
JOS.attribute("cas-include-tree-id",
760+
StringRef(*I.IncludeTreeID));
761+
if (I.CASFileSystemRootID)
762+
JOS.attribute("casfs-root-id",
763+
StringRef(*I.CASFileSystemRootID));
764+
765+
JOS.attribute("clang-context-hash",
766+
StringRef(I.ContextHash));
767+
JOS.attributeArray("clang-module-deps",
768+
toJSONSorted(JOS, I.ModuleDeps));
769+
JOS.attributeArray("command-line",
770+
toJSONStrings(JOS, Cmd.Arguments));
771+
JOS.attribute("executable", StringRef(Cmd.Executable));
772+
JOS.attributeArray("file-deps",
773+
toJSONStrings(JOS, I.FileDeps));
774+
JOS.attribute("input-file", StringRef(I.FileName));
775+
});
776+
}
777+
} else {
778+
JOS.object([&] {
779+
if (I.CASFileSystemRootID)
780+
JOS.attribute("casfs-root-id",
781+
StringRef(*I.CASFileSystemRootID));
782+
if (I.IncludeTreeID)
783+
JOS.attribute("cas-include-tree-id",
784+
StringRef(*I.IncludeTreeID));
785+
786+
JOS.attribute("clang-context-hash", StringRef(I.ContextHash));
787+
JOS.attributeArray("clang-module-deps",
788+
toJSONSorted(JOS, I.ModuleDeps));
789+
JOS.attributeArray("command-line",
790+
toJSONStrings(JOS, I.DriverCommandLine));
791+
JOS.attribute("executable", "clang");
792+
JOS.attributeArray("file-deps",
793+
toJSONStrings(JOS, I.FileDeps));
794+
JOS.attribute("input-file", StringRef(I.FileName));
795+
});
796+
}
797+
});
798+
});
799+
}
800+
});
801+
});
780802
}
781803

782804
private:

0 commit comments

Comments
 (0)