[Lldb-commits] [lldb] [lldb] Introduce formatter bytecode version 2 ABI (PR #228589)

Adrian Prantl via lldb-commits lldb-commits at lists.llvm.org
Fri Oct 2 14:53:52 PDT 2026


================
@@ -238,30 +240,40 @@ This is followed by one or more dictionary values that immediately follow each o
 - Length of the program (ULEB128)
 - The program bytecode
 
+### Calling conventions
+
+A record's version number (see [Embedding](#embedding)) also determines the calling convention of its methods. This includes how `self` (`this`) is represented.
+
+In **version 1** (legacy), `self` is a combination of the data stack after `@init` and `@update` run. Nothing constrains what shape `self` ends up in, it can be zero, one, or many values.
+
+In **version 2**, the runtime owns `self`, a `Dictionary` that starts out empty. The runtime passes the same `Dictionary` as the first argument to every method except `@summary`, followed by that method's own arguments (if any). Methods may modify `self` in place, and do not return it. The runtime keeps a reference, to ensure modifications are visible to subsequent method calls.
+
 The possible function signatures are:
 
 ```{eval-rst}
-=========  ========================= ==============================
-Signature    Mnemonic                Stack Effect
----------  ------------------------- ------------------------------
-  0x00      ``@summary``              ``(Object -> String)``
-  0x01      ``@init``                 ``(Object -> Object+)``
-  0x02      ``@get_num_children``     ``(Object+ -> UInt)``
-  0x03      ``@get_child_index``      ``(Object+ String -> UInt)``
-  0x04      ``@get_child_at_index``   ``(Object+ UInt -> Object)``
-  0x05      ``@get_value``            ``(Object+ -> String)``
-  0x06      ``@update``               ``(Object+ -> Object+)``
-=========  ========================= ==============================
+=========  ========================= ==============================================  ==============================================
+Signature    Mnemonic                Stack Effect (version 1)                       Stack Effect (version 2)
+---------  ------------------------- ----------------------------------------------  ----------------------------------------------
+  0x00      ``@summary``              ``(Object -> String)``                          ``(Object -> String)``
+  0x01      ``@init``                 ``(Object -> Object+)``                         ``(Dictionary Object -> )``
+  0x02      ``@get_num_children``     ``(Object+ -> UInt)``                           ``(Dictionary -> Integer)``
+  0x03      ``@get_child_index``      ``(Object+ String -> UInt)``                    ``(Dictionary String -> Integer)``
+  0x04      ``@get_child_at_index``   ``(Object+ UInt -> Object)``                    ``(Dictionary Integer -> Object)``
+  0x05      ``@get_value``            ``(Object+ -> String)``                         ``(Dictionary -> String)``
+  0x06      ``@update``               ``(Object+ -> Object+ [Integer])``              ``(Dictionary -> Integer)``
+=========  ========================= ==============================================  ==============================================
 ```
 
-If not specified, the init function defaults to an empty function that just passes the Object along. Its results may be cached and allow common prep work to be done for an Object that can be reused by subsequent calls to the other methods. This way subsequent calls to `@get_child_at_index` can avoid recomputing shared information, for example.
+The `@init` method must only be used for one time setup work. Any computation that needs to be reperformed should happen in `@update`. If not specified, initialization will save the given Object to the `self` dictionary using the idiomatic key `"valobj"`.
+
+The `@update` method performs computation that may change over the course of a value's lifetime, such as interpreting a value's state, and (re)computing children. The return value is an `Integer`, where 1 means the previously computed children can be reused, and 0 means they must be refetched.
 
 While it is more efficient to store multiple programs per type key, this is not a requirement. LLDB will merge all entries. If there are conflicts the result is undefined.
 
 ### Execution model
 
-Execution begins at the first byte in the program. The program counter of the virtual machine starts at offset 0 of the bytecode and may never move outside the range of the program as defined in the header. The data stack starts with one Object or the result of the `@init` function (`Object+` in the table above).
+Execution begins at the first byte in the program. The program counter of the virtual machine starts at offset 0 of the bytecode and may never move outside the range of the program as defined in the header. The data stack starts with the method's arguments, as listed in the signature table in [Calling conventions](#calling-conventions).
 
 ### Error handling
 
-In version 1 errors are unrecoverable, the entire expression will fail if any kind of error is encountered.
+In versions 1 and 2, errors are unrecoverable, the entire expression will fail if any kind of error is encountered.
----------------
adrian-prantl wrote:

At the end add:

## Changes in version 2

https://github.com/llvm/llvm-project/pull/228589


More information about the lldb-commits mailing list