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

Reply via email to