https://github.com/kastiglione updated 
https://github.com/llvm/llvm-project/pull/181199

>From 40eabae47e330e17a5e1419919f786d4840654ff Mon Sep 17 00:00:00 2001
From: Dave Lee <[email protected]>
Date: Thu, 12 Feb 2026 10:29:20 -0800
Subject: [PATCH 1/3] [lldb] Enable caching for
 BytecodeSyntheticChildren::FrontEnd::Update

---
 lldb/source/DataFormatters/TypeSynthetic.cpp  | 34 ++++++++++++++++++-
 .../TestBytecodeSynthetic.py                  | 21 +++++++++++-
 .../bytecode-synthetic/main.cpp               |  5 ++-
 3 files changed, 57 insertions(+), 3 deletions(-)

diff --git a/lldb/source/DataFormatters/TypeSynthetic.cpp 
b/lldb/source/DataFormatters/TypeSynthetic.cpp
index 10655cdca6f05..32d035eb8a90b 100644
--- a/lldb/source/DataFormatters/TypeSynthetic.cpp
+++ b/lldb/source/DataFormatters/TypeSynthetic.cpp
@@ -22,6 +22,7 @@
 #include "lldb/Utility/StreamString.h"
 #include "llvm/Support/Error.h"
 #include <cstdint>
+#include <optional>
 
 using namespace lldb;
 using namespace lldb_private;
@@ -291,10 +292,41 @@ lldb::ChildCacheState 
BytecodeSyntheticChildren::FrontEnd::Update() {
     return ChildCacheState::eRefetch;
   }
 
+  // If the top of the stack is a 0 or 1, that value is popped of the stack and
+  // treated as a return value of eRefetch or eReuse respectively. If the top 
of
+  // the stack is any other value, it stays on the stack and becomes part of
+  // `self`.
+  //
+  // This dynamic logic can lead to errors for synthetic formatter authors.
+  // Consider the case where an `update` implementation places the number of
+  // children last on the stack. LLDB will _sometimes_ (but not always) consume
+  // that value as a ChildCacheState value. This would cause downstream 
problems
+  // in `num_children`, because the count won't be on the stack.
+  //
+  // Bytecode authors are encouraged to explicitly push a ChildCacheState value
+  // on to the stack.
+  std::optional<ChildCacheState> cache_state = std::nullopt;
+  const FormatterBytecode::DataStackElement &top = data.back();
+  if (auto *u = std::get_if<uint64_t>(&top))
+    if (*u == 0 || *u == 1)
+      cache_state = static_cast<ChildCacheState>(*u);
+  if (auto *i = std::get_if<int64_t>(&top))
+    if (*i == 0 || *i == 1)
+      cache_state = static_cast<ChildCacheState>(*i);
+
+  if (cache_state) {
+    data.pop_back();
+    if (cache_state == ChildCacheState::eReuse)
+      LLDB_LOG(GetLog(LLDBLog::DataFormatters),
+               "Bytecode formatter returned eReuse from `update` (type: `{0}`, 
"
+               "name: `{1}`)",
+               m_backend.GetDisplayTypeName(), m_backend.GetName());
+  }
+
   if (data.size() > 0)
     m_self = std::move(data);
 
-  return ChildCacheState::eRefetch;
+  return cache_state.value_or(ChildCacheState::eRefetch);
 }
 
 llvm::Expected<uint32_t>
diff --git 
a/lldb/test/API/functionalities/data-formatter/bytecode-synthetic/TestBytecodeSynthetic.py
 
b/lldb/test/API/functionalities/data-formatter/bytecode-synthetic/TestBytecodeSynthetic.py
index c5c2811c59439..cd4be83ad8563 100644
--- 
a/lldb/test/API/functionalities/data-formatter/bytecode-synthetic/TestBytecodeSynthetic.py
+++ 
b/lldb/test/API/functionalities/data-formatter/bytecode-synthetic/TestBytecodeSynthetic.py
@@ -5,8 +5,9 @@
 
 
 class TestCase(TestBase):
+
     @skipUnlessDarwin
-    def test(self):
+    def test_synthetic(self):
         self.build()
         if self.TraceOn():
             self.expect("log enable -v lldb formatters")
@@ -21,3 +22,21 @@ def test(self):
         self.assertEqual(account.child[0].name, "username")
 
         self.expect("v acc", matching=False, substrs=["password"])
+
+    @skipUnlessDarwin
+    def test_update_reuse(self):
+        self.build()
+
+        log = self.getBuildArtifact("formatter.log")
+        self.runCmd(f"log enable lldb formatters -f {log}")
+
+        _, _, thread, _ = lldbutil.run_to_source_breakpoint(
+            self, "break here", lldb.SBFileSpec("main.cpp")
+        )
+
+        frame = thread.selected_frame
+        account = frame.var("acc")
+        self.assertEqual(account.num_children, 1)
+
+        self.filecheck(f"platform shell cat {log}", __file__)
+        # CHECK: Bytecode formatter returned eReuse from `update` (type: 
`Account`, name: `acc`)
diff --git 
a/lldb/test/API/functionalities/data-formatter/bytecode-synthetic/main.cpp 
b/lldb/test/API/functionalities/data-formatter/bytecode-synthetic/main.cpp
index 3e6ae77bbca83..051e44c937bed 100644
--- a/lldb/test/API/functionalities/data-formatter/bytecode-synthetic/main.cpp
+++ b/lldb/test/API/functionalities/data-formatter/bytecode-synthetic/main.cpp
@@ -16,10 +16,13 @@ int main(int argc, char **argv) {
 __attribute__((used, section("__DATA_CONST,__lldbformatters"))) unsigned char
     _Account_synthetic[] =
         "\x01"                      // version
-        "\x15"                      // remaining record size
+        "\x19"                      // remaining record size
         "\x07"                      // type name size
         "Account"                   // type name
         "\x00"                      // flags
+        "\x06"                      // sig_update
+        "\x02"                      // program size
+        "\x20\x01"                  // `return eReuse`
         "\x02"                      // sig_get_num_children
         "\x02"                      // program size
         "\x20\x01"                  // `return 1`

>From 8b2f81906d427b2399f0db9a5bd5ecd34f6c9e35 Mon Sep 17 00:00:00 2001
From: Dave Lee <[email protected]>
Date: Thu, 12 Feb 2026 10:33:26 -0800
Subject: [PATCH 2/3] python formatting

---
 .../data-formatter/bytecode-synthetic/TestBytecodeSynthetic.py   | 1 -
 1 file changed, 1 deletion(-)

diff --git 
a/lldb/test/API/functionalities/data-formatter/bytecode-synthetic/TestBytecodeSynthetic.py
 
b/lldb/test/API/functionalities/data-formatter/bytecode-synthetic/TestBytecodeSynthetic.py
index cd4be83ad8563..a90415a02f99e 100644
--- 
a/lldb/test/API/functionalities/data-formatter/bytecode-synthetic/TestBytecodeSynthetic.py
+++ 
b/lldb/test/API/functionalities/data-formatter/bytecode-synthetic/TestBytecodeSynthetic.py
@@ -5,7 +5,6 @@
 
 
 class TestCase(TestBase):
-
     @skipUnlessDarwin
     def test_synthetic(self):
         self.build()

>From e5f73b34d3e3e297b2e7195fa791ffd8087cf2fd Mon Sep 17 00:00:00 2001
From: Dave Lee <[email protected]>
Date: Tue, 17 Feb 2026 17:58:26 -0800
Subject: [PATCH 3/3] Always return eReuse from Update()

---
 lldb/source/DataFormatters/TypeSynthetic.cpp  | 36 ++-----------------
 .../TestBytecodeSynthetic.py                  | 20 +----------
 .../bytecode-synthetic/main.cpp               |  5 +--
 3 files changed, 5 insertions(+), 56 deletions(-)

diff --git a/lldb/source/DataFormatters/TypeSynthetic.cpp 
b/lldb/source/DataFormatters/TypeSynthetic.cpp
index 32d035eb8a90b..7409dbf572d16 100644
--- a/lldb/source/DataFormatters/TypeSynthetic.cpp
+++ b/lldb/source/DataFormatters/TypeSynthetic.cpp
@@ -22,7 +22,6 @@
 #include "lldb/Utility/StreamString.h"
 #include "llvm/Support/Error.h"
 #include <cstdint>
-#include <optional>
 
 using namespace lldb;
 using namespace lldb_private;
@@ -292,41 +291,12 @@ lldb::ChildCacheState 
BytecodeSyntheticChildren::FrontEnd::Update() {
     return ChildCacheState::eRefetch;
   }
 
-  // If the top of the stack is a 0 or 1, that value is popped of the stack and
-  // treated as a return value of eRefetch or eReuse respectively. If the top 
of
-  // the stack is any other value, it stays on the stack and becomes part of
-  // `self`.
-  //
-  // This dynamic logic can lead to errors for synthetic formatter authors.
-  // Consider the case where an `update` implementation places the number of
-  // children last on the stack. LLDB will _sometimes_ (but not always) consume
-  // that value as a ChildCacheState value. This would cause downstream 
problems
-  // in `num_children`, because the count won't be on the stack.
-  //
-  // Bytecode authors are encouraged to explicitly push a ChildCacheState value
-  // on to the stack.
-  std::optional<ChildCacheState> cache_state = std::nullopt;
-  const FormatterBytecode::DataStackElement &top = data.back();
-  if (auto *u = std::get_if<uint64_t>(&top))
-    if (*u == 0 || *u == 1)
-      cache_state = static_cast<ChildCacheState>(*u);
-  if (auto *i = std::get_if<int64_t>(&top))
-    if (*i == 0 || *i == 1)
-      cache_state = static_cast<ChildCacheState>(*i);
-
-  if (cache_state) {
-    data.pop_back();
-    if (cache_state == ChildCacheState::eReuse)
-      LLDB_LOG(GetLog(LLDBLog::DataFormatters),
-               "Bytecode formatter returned eReuse from `update` (type: `{0}`, 
"
-               "name: `{1}`)",
-               m_backend.GetDisplayTypeName(), m_backend.GetName());
-  }
-
   if (data.size() > 0)
     m_self = std::move(data);
 
-  return cache_state.value_or(ChildCacheState::eRefetch);
+  // At this time it is assumed that synthetic bytecode formatters can always
+  // reuse the work performed in `update`.
+  return ChildCacheState::eReuse;
 }
 
 llvm::Expected<uint32_t>
diff --git 
a/lldb/test/API/functionalities/data-formatter/bytecode-synthetic/TestBytecodeSynthetic.py
 
b/lldb/test/API/functionalities/data-formatter/bytecode-synthetic/TestBytecodeSynthetic.py
index a90415a02f99e..c5c2811c59439 100644
--- 
a/lldb/test/API/functionalities/data-formatter/bytecode-synthetic/TestBytecodeSynthetic.py
+++ 
b/lldb/test/API/functionalities/data-formatter/bytecode-synthetic/TestBytecodeSynthetic.py
@@ -6,7 +6,7 @@
 
 class TestCase(TestBase):
     @skipUnlessDarwin
-    def test_synthetic(self):
+    def test(self):
         self.build()
         if self.TraceOn():
             self.expect("log enable -v lldb formatters")
@@ -21,21 +21,3 @@ def test_synthetic(self):
         self.assertEqual(account.child[0].name, "username")
 
         self.expect("v acc", matching=False, substrs=["password"])
-
-    @skipUnlessDarwin
-    def test_update_reuse(self):
-        self.build()
-
-        log = self.getBuildArtifact("formatter.log")
-        self.runCmd(f"log enable lldb formatters -f {log}")
-
-        _, _, thread, _ = lldbutil.run_to_source_breakpoint(
-            self, "break here", lldb.SBFileSpec("main.cpp")
-        )
-
-        frame = thread.selected_frame
-        account = frame.var("acc")
-        self.assertEqual(account.num_children, 1)
-
-        self.filecheck(f"platform shell cat {log}", __file__)
-        # CHECK: Bytecode formatter returned eReuse from `update` (type: 
`Account`, name: `acc`)
diff --git 
a/lldb/test/API/functionalities/data-formatter/bytecode-synthetic/main.cpp 
b/lldb/test/API/functionalities/data-formatter/bytecode-synthetic/main.cpp
index 051e44c937bed..3e6ae77bbca83 100644
--- a/lldb/test/API/functionalities/data-formatter/bytecode-synthetic/main.cpp
+++ b/lldb/test/API/functionalities/data-formatter/bytecode-synthetic/main.cpp
@@ -16,13 +16,10 @@ int main(int argc, char **argv) {
 __attribute__((used, section("__DATA_CONST,__lldbformatters"))) unsigned char
     _Account_synthetic[] =
         "\x01"                      // version
-        "\x19"                      // remaining record size
+        "\x15"                      // remaining record size
         "\x07"                      // type name size
         "Account"                   // type name
         "\x00"                      // flags
-        "\x06"                      // sig_update
-        "\x02"                      // program size
-        "\x20\x01"                  // `return eReuse`
         "\x02"                      // sig_get_num_children
         "\x02"                      // program size
         "\x20\x01"                  // `return 1`

_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to