https://github.com/zixu-w updated https://github.com/llvm/llvm-project/pull/171230
>From cef7f9c203022471a7a3c8c2995688af521a3d5c Mon Sep 17 00:00:00 2001 From: Zixu Wang <[email protected]> Date: Mon, 8 Dec 2025 15:21:23 -0800 Subject: [PATCH] [Support][JSON] Use `std::map` for object storage `llvm::DenseMap` is not suitable for the key-value `Storage` inside `llvm::json::Object`. Use `std::map` instead to optimize memory usage. `llvm::DenseMap` is optimized for mapping small keys and values (pointers), and it pre-allocates 64 buckets by default. `llvm::json::ObjectKey` is 24 bytes in size, and `llvm::json::Value` is 40 bytes. Currently, the JSON parser allocates 4KB of memory for each JSON object. In practice, most JSON objects contain only a handful of fields, and likely to have lists of many small objects. This is a significant waste of memory. --- clang-tools-extra/clang-doc/JSONGenerator.cpp | 2 +- clang/lib/Basic/DarwinSDKInfo.cpp | 10 +++++----- clang/tools/clang-installapi/Options.cpp | 4 ++-- clang/unittests/Basic/SarifTest.cpp | 2 +- llvm/include/llvm/Support/JSON.h | 10 +++++----- llvm/lib/Support/JSON.cpp | 4 ++-- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/clang-tools-extra/clang-doc/JSONGenerator.cpp b/clang-tools-extra/clang-doc/JSONGenerator.cpp index 97c599a3f605c..8be1a27c27c70 100644 --- a/clang-tools-extra/clang-doc/JSONGenerator.cpp +++ b/clang-tools-extra/clang-doc/JSONGenerator.cpp @@ -94,7 +94,7 @@ static void insertComment(Object &Description, json::Value &Comment, Description[Key] = std::move(CommentsArray); Description["Has" + Key.str()] = true; } else { - DescriptionIt->getSecond().getAsArray()->push_back(Comment); + DescriptionIt->second.getAsArray()->push_back(Comment); } } diff --git a/clang/lib/Basic/DarwinSDKInfo.cpp b/clang/lib/Basic/DarwinSDKInfo.cpp index 6bcfb9d598377..82cb5d774363d 100644 --- a/clang/lib/Basic/DarwinSDKInfo.cpp +++ b/clang/lib/Basic/DarwinSDKInfo.cpp @@ -25,7 +25,7 @@ std::optional<VersionTuple> DarwinSDKInfo::RelatedTargetVersionMapping::map( return MaximumValue; auto KV = Mapping.find(Key.normalize()); if (KV != Mapping.end()) - return KV->getSecond(); + return KV->second; // If no exact entry found, try just the major key version. Only do so when // a minor version number is present, to avoid recursing indefinitely into // the major-only check. @@ -43,10 +43,10 @@ DarwinSDKInfo::RelatedTargetVersionMapping::parseJSON( VersionTuple MinValue = Min; llvm::DenseMap<VersionTuple, VersionTuple> Mapping; for (const auto &KV : Obj) { - if (auto Val = KV.getSecond().getAsString()) { + if (auto Val = KV.second.getAsString()) { llvm::VersionTuple KeyVersion; llvm::VersionTuple ValueVersion; - if (KeyVersion.tryParse(KV.getFirst()) || ValueVersion.tryParse(*Val)) + if (KeyVersion.tryParse(KV.first) || ValueVersion.tryParse(*Val)) return std::nullopt; Mapping[KeyVersion.normalize()] = ValueVersion; if (KeyVersion < Min) @@ -113,12 +113,12 @@ DarwinSDKInfo::parseDarwinSDKSettingsJSON(const llvm::json::Object *Obj) { // FIXME: Generalize this out beyond iOS-deriving targets. // Look for ios_<targetos> version mapping for targets that derive from ios. for (const auto &KV : *VM) { - auto Pair = StringRef(KV.getFirst()).split("_"); + auto Pair = StringRef(KV.first).split("_"); if (Pair.first.compare_insensitive("ios") == 0) { llvm::Triple TT(llvm::Twine("--") + Pair.second.lower()); if (TT.getOS() != llvm::Triple::UnknownOS) { auto Mapping = RelatedTargetVersionMapping::parseJSON( - *KV.getSecond().getAsObject(), *MaximumDeploymentVersion); + *KV.second.getAsObject(), *MaximumDeploymentVersion); if (Mapping) VersionMappings[OSEnvPair(llvm::Triple::IOS, llvm::Triple::UnknownEnvironment, diff --git a/clang/tools/clang-installapi/Options.cpp b/clang/tools/clang-installapi/Options.cpp index f484d6f33ad8f..1151f65af4dce 100644 --- a/clang/tools/clang-installapi/Options.cpp +++ b/clang/tools/clang-installapi/Options.cpp @@ -84,8 +84,8 @@ getArgListFromJSON(const StringRef Input, llvm::opt::OptTable *Table, return llvm::opt::InputArgList(); for (const auto &KV : *Root) { - const Array *ArgList = KV.getSecond().getAsArray(); - std::string Label = "-X" + KV.getFirst().str(); + const Array *ArgList = KV.second.getAsArray(); + std::string Label = "-X" + KV.first.str(); if (!ArgList) return make_error<TextAPIError>(TextAPIErrorCode::InvalidInputFormat); for (auto Arg : *ArgList) { diff --git a/clang/unittests/Basic/SarifTest.cpp b/clang/unittests/Basic/SarifTest.cpp index 089b6cb01ded8..40c8ad4f749a9 100644 --- a/clang/unittests/Basic/SarifTest.cpp +++ b/clang/unittests/Basic/SarifTest.cpp @@ -83,7 +83,7 @@ TEST_F(SarifDocumentWriterTest, canCreateEmptyDocument) { const llvm::json::Object &EmptyDoc = Writer.createDocument(); std::vector<StringRef> Keys(EmptyDoc.size()); std::transform(EmptyDoc.begin(), EmptyDoc.end(), Keys.begin(), - [](auto Item) { return Item.getFirst(); }); + [](auto Item) { return Item.first; }); // THEN: ASSERT_THAT(Keys, testing::UnorderedElementsAre("$schema", "version")); diff --git a/llvm/include/llvm/Support/JSON.h b/llvm/include/llvm/Support/JSON.h index a58332c912942..a34570fffa5ae 100644 --- a/llvm/include/llvm/Support/JSON.h +++ b/llvm/include/llvm/Support/JSON.h @@ -94,9 +94,9 @@ class Value; template <typename T> Value toJSON(const std::optional<T> &Opt); /// An Object is a JSON object, which maps strings to heterogenous JSON values. -/// It simulates DenseMap<ObjectKey, Value>. ObjectKey is a maybe-owned string. +/// ObjectKey is a maybe-owned string. class Object { - using Storage = DenseMap<ObjectKey, Value, llvm::DenseMapInfo<StringRef>>; + using Storage = std::map<ObjectKey, Value>; Storage M; public: @@ -133,8 +133,8 @@ class Object { bool erase(StringRef K); void erase(iterator I) { M.erase(I); } - iterator find(StringRef K) { return M.find_as(K); } - const_iterator find(StringRef K) const { return M.find_as(K); } + iterator find(const ObjectKey &K) { return M.find(K); } + const_iterator find(const ObjectKey &K) const { return M.find(K); } // operator[] acts as if Value was default-constructible as null. LLVM_ABI Value &operator[](const ObjectKey &K); LLVM_ABI Value &operator[](ObjectKey &&K); @@ -649,7 +649,7 @@ inline Object::Object(std::initializer_list<KV> Properties) { for (const auto &P : Properties) { auto R = try_emplace(P.K, nullptr); if (R.second) - R.first->getSecond().moveFrom(std::move(P.V)); + R.first->second.moveFrom(std::move(P.V)); } } inline std::pair<Object::iterator, bool> Object::insert(KV E) { diff --git a/llvm/lib/Support/JSON.cpp b/llvm/lib/Support/JSON.cpp index 4652c0740dc4d..ab46a8eca3188 100644 --- a/llvm/lib/Support/JSON.cpp +++ b/llvm/lib/Support/JSON.cpp @@ -22,10 +22,10 @@ namespace llvm { namespace json { Value &Object::operator[](const ObjectKey &K) { - return try_emplace(K, nullptr).first->getSecond(); + return try_emplace(K, nullptr).first->second; } Value &Object::operator[](ObjectKey &&K) { - return try_emplace(std::move(K), nullptr).first->getSecond(); + return try_emplace(std::move(K), nullptr).first->second; } Value *Object::get(StringRef K) { auto I = find(K); _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
