Author: Ebuka Ezike
Date: 2026-02-17T12:55:19Z
New Revision: 47a969ef889c9e244dfb34e6a4c4dbb5bf03ea60

URL: 
https://github.com/llvm/llvm-project/commit/47a969ef889c9e244dfb34e6a4c4dbb5bf03ea60
DIFF: 
https://github.com/llvm/llvm-project/commit/47a969ef889c9e244dfb34e6a4c4dbb5bf03ea60.diff

LOG: [lldb-dap] Refactor variablesReference storage and scope management. 
(#179262)

This commit refactors the Variables class into a
VariableReferenceStorage with variableReferences of different
ReferenceKinds.

The variablesReference is now a uint32_t.
The most significant byte (bits 24 - 31) holds the reference kind and
the remaining 3 bytes (bits 0 -23) holds the actual reference.

We have (at the moment) 3 reference kinds.
Temporary => 0b0000 => 0x00
Permanent => 0b0001 => 0x01
Scope     => 0b0010 => 0x03

The actual variablesReference can be used to get a `VariableStore`.

VariableStore holds variables in a group.
It has two implementations:
- ScopeStore: Holds variables within frame scopes (locals, globals,
registers). This is lazy-loaded and only fetched when variable(s) in the
scope is requested.
- ExpandableValueStore: Holds SBValue and fetches it's variable children
when requested.

ReferenceKindPool:
   The variablesReference created starts from 1 with the mask of the
   Reference kind applied.
   It holds vector of VariableStore of one Referencekind,
   This allows constant lookup of a reference

Example:
```md

| maskedVariablesReference | Mask | variablesReference | RefrenceKind | 
VariableStore |
|--------------------------|------|--------------------|--------------|---------------|
| 20        -> 0x00000014  | 0x00 | 20 -> 0x00000014   | temporary    | 
ValueStore    |
| 268435476 -> 0x01000014  | 0x01 | 20 -> 0x00000014   | permanent    | 
ValueStore    |
| 536870932 -> 0x01000014  | 0x02 | 20 -> 0x00000014   | scope        | 
ScopeStore    |
```

Added: 
    

Modified: 
    lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py
    lldb/tools/lldb-dap/DAP.cpp
    lldb/tools/lldb-dap/DAP.h
    lldb/tools/lldb-dap/DAPForward.h
    lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp
    lldb/tools/lldb-dap/Handler/EvaluateRequestHandler.cpp
    lldb/tools/lldb-dap/Handler/LocationsRequestHandler.cpp
    lldb/tools/lldb-dap/Handler/ScopesRequestHandler.cpp
    lldb/tools/lldb-dap/Handler/SetVariableRequestHandler.cpp
    lldb/tools/lldb-dap/Handler/VariablesRequestHandler.cpp
    lldb/tools/lldb-dap/Protocol/DAPTypes.cpp
    lldb/tools/lldb-dap/Protocol/DAPTypes.h
    lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp
    lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
    lldb/tools/lldb-dap/Protocol/ProtocolTypes.h
    lldb/tools/lldb-dap/ProtocolUtils.cpp
    lldb/tools/lldb-dap/ProtocolUtils.h
    lldb/tools/lldb-dap/SBAPIExtras.h
    lldb/tools/lldb-dap/Variables.cpp
    lldb/tools/lldb-dap/Variables.h
    lldb/unittests/DAP/DAPTypesTest.cpp
    lldb/unittests/DAP/ProtocolRequestsTest.cpp
    lldb/unittests/DAP/ProtocolTypesTest.cpp
    lldb/unittests/DAP/VariablesTest.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py 
b/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py
index 1dbb0143e7a55..10c67a94407e6 100644
--- a/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py
+++ b/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py
@@ -99,6 +99,11 @@ def verify_values(self, verify_dict, actual, 
varref_dict=None, expression=None):
             )
 
     def verify_variables(self, verify_dict, variables, varref_dict=None):
+        self.assertGreaterEqual(
+            len(variables),
+            1,
+            f"No variables to verify, verify_dict={json.dumps(verify_dict, 
indent=4)}",
+        )
         for variable in variables:
             name = variable["name"]
             if not name.startswith("std::"):
@@ -542,6 +547,7 @@ def do_test_scopes_and_evaluate_expansion(self, 
enableAutoVariableSummaries: boo
 
         # Evaluate from known contexts.
         expr_varref_dict = {}
+        permanent_expandable_ref = None
         for context, verify_dict in expandable_expression["context"].items():
             response = self.dap_server.request_evaluate(
                 expandable_expression["name"],
@@ -549,9 +555,15 @@ def do_test_scopes_and_evaluate_expansion(self, 
enableAutoVariableSummaries: boo
                 threadId=None,
                 context=context,
             )
+
+            response_body = response["body"]
+            if context == "repl":  # save the variablesReference
+                self.assertIn("variablesReference", response_body)
+                permanent_expandable_ref = response_body["variablesReference"]
+
             self.verify_values(
                 verify_dict,
-                response["body"],
+                response_body,
                 expr_varref_dict,
                 expandable_expression["name"],
             )
@@ -578,7 +590,7 @@ def do_test_scopes_and_evaluate_expansion(self, 
enableAutoVariableSummaries: boo
         )
         self.continue_to_breakpoints(breakpoint_ids)
 
-        var_ref = expr_varref_dict[expandable_expression["name"]]
+        var_ref = permanent_expandable_ref
         response = self.dap_server.request_variables(var_ref)
         self.verify_variables(
             expandable_expression["children"], response["body"]["variables"]
@@ -598,6 +610,16 @@ def do_test_scopes_and_evaluate_expansion(self, 
enableAutoVariableSummaries: boo
             if scope["name"] == "Registers":
                 self.assertEqual(scope.get("presentationHint"), "registers")
 
+        # Test invalid variablesReference.
+        for wrong_var_ref in (-6000, -1, 4000):
+            response = self.dap_server.request_variables(wrong_var_ref)
+            self.assertFalse(response["success"])
+            error_msg: str = response["body"]["error"]["format"]
+            self.assertTrue(
+                error_msg.startswith("invalid variablesReference"),
+                f"seen error message : {error_msg}",
+            )
+
     def test_scopes_and_evaluate_expansion(self):
         
self.do_test_scopes_and_evaluate_expansion(enableAutoVariableSummaries=False)
 

diff  --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp
index 4110432c4fd00..6d5e175ae29e0 100644
--- a/lldb/tools/lldb-dap/DAP.cpp
+++ b/lldb/tools/lldb-dap/DAP.cpp
@@ -22,6 +22,7 @@
 #include "Protocol/ProtocolTypes.h"
 #include "ProtocolUtils.h"
 #include "Transport.h"
+#include "Variables.h"
 #include "lldb/API/SBBreakpoint.h"
 #include "lldb/API/SBCommandInterpreter.h"
 #include "lldb/API/SBEvent.h"
@@ -125,7 +126,8 @@ llvm::StringRef DAP::debug_adapter_path = "";
 DAP::DAP(Log &log, const ReplMode default_repl_mode,
          std::vector<std::string> pre_init_commands, bool no_lldbinit,
          llvm::StringRef client_name, DAPTransport &transport, MainLoop &loop)
-    : log(log), transport(transport), broadcaster("lldb-dap"),
+    : log(log), transport(transport), reference_storage(log),
+      broadcaster("lldb-dap"),
       progress_event_reporter(
           [&](const ProgressEvent &event) { SendJSON(event.ToJSON()); }),
       repl_mode(default_repl_mode), no_lldbinit(no_lldbinit),

diff  --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h
index 34d6a29b3c110..a164cc484f4be 100644
--- a/lldb/tools/lldb-dap/DAP.h
+++ b/lldb/tools/lldb-dap/DAP.h
@@ -102,7 +102,7 @@ struct DAP final : public DAPTransport::MessageHandler {
   /// The target instance for this DAP session.
   lldb::SBTarget target;
 
-  Variables variables;
+  VariableReferenceStorage reference_storage;
   lldb::SBBroadcaster broadcaster;
   FunctionBreakpointMap function_breakpoints;
   InstructionBreakpointMap instruction_breakpoints;
@@ -379,7 +379,7 @@ struct DAP final : public DAPTransport::MessageHandler {
   protocol::Capabilities GetCustomCapabilities();
 
   /// Debuggee will continue from stopped state.
-  void WillContinue() { variables.Clear(); }
+  void WillContinue() { reference_storage.Clear(); }
 
   /// Poll the process to wait for it to reach the eStateStopped state.
   ///

diff  --git a/lldb/tools/lldb-dap/DAPForward.h 
b/lldb/tools/lldb-dap/DAPForward.h
index e7fbbf669e7ec..05441d093d256 100644
--- a/lldb/tools/lldb-dap/DAPForward.h
+++ b/lldb/tools/lldb-dap/DAPForward.h
@@ -22,6 +22,10 @@ class ResponseHandler;
 class SourceBreakpoint;
 class Watchpoint;
 struct DAP;
+namespace protocol {
+struct var_ref_t;
+} // namespace protocol
+using var_ref_t = protocol::var_ref_t;
 } // namespace lldb_dap
 
 namespace lldb {

diff  --git a/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp 
b/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp
index 245d92c18e59e..0b959a5260d23 100644
--- a/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp
@@ -41,8 +41,11 @@ llvm::Expected<protocol::DataBreakpointInfoResponseBody>
 DataBreakpointInfoRequestHandler::Run(
     const protocol::DataBreakpointInfoArguments &args) const {
   protocol::DataBreakpointInfoResponseBody response;
-  lldb::SBValue variable = dap.variables.FindVariable(
-      args.variablesReference.value_or(0), args.name);
+  const var_ref_t arg_var_ref =
+      args.variablesReference.value_or(var_ref_t(var_ref_t::k_no_child));
+
+  lldb::SBValue variable =
+      dap.reference_storage.FindVariable(arg_var_ref, args.name);
   std::string addr, size;
 
   bool is_data_ok = true;
@@ -61,7 +64,7 @@ DataBreakpointInfoRequestHandler::Run(
       size = llvm::utostr(byte_size);
     }
   } else if (lldb::SBFrame frame = dap.GetLLDBFrame(args.frameId);
-             args.variablesReference.value_or(0) == 0 && frame.IsValid()) {
+             arg_var_ref.Reference() == 0 && frame.IsValid()) {
     lldb::SBValue value = frame.EvaluateExpression(args.name.c_str());
     if (value.GetError().Fail()) {
       lldb::SBError error = value.GetError();

diff  --git a/lldb/tools/lldb-dap/Handler/EvaluateRequestHandler.cpp 
b/lldb/tools/lldb-dap/Handler/EvaluateRequestHandler.cpp
index 44a5be5c17b20..77d9f03554a2a 100644
--- a/lldb/tools/lldb-dap/Handler/EvaluateRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/EvaluateRequestHandler.cpp
@@ -11,6 +11,7 @@
 #include "EventHelper.h"
 #include "JSONUtils.h"
 #include "LLDBUtils.h"
+#include "Protocol/DAPTypes.h"
 #include "Protocol/ProtocolRequests.h"
 #include "Protocol/ProtocolTypes.h"
 #include "RequestHandler.h"
@@ -132,15 +133,16 @@ EvaluateRequestHandler::Run(const EvaluateArguments 
&arguments) const {
   body.type = desc.display_type_name;
 
   if (value.MightHaveChildren() || ValuePointsToCode(value))
-    body.variablesReference =
-        dap.variables.InsertVariable(value, /*is_permanent=*/is_repl_context);
+    body.variablesReference = dap.reference_storage.InsertVariable(
+        value, /*is_permanent=*/is_repl_context);
 
   if (lldb::addr_t addr = value.GetLoadAddress(); addr != LLDB_INVALID_ADDRESS)
     body.memoryReference = EncodeMemoryReference(addr);
 
   if (ValuePointsToCode(value) &&
-      body.variablesReference != LLDB_DAP_INVALID_VAR_REF)
-    body.valueLocationReference = PackLocation(body.variablesReference, true);
+      body.variablesReference.Kind() != eReferenceKindInvalid)
+    body.valueLocationReference =
+        PackLocation(body.variablesReference.AsUInt32(), true);
 
   return body;
 }

diff  --git a/lldb/tools/lldb-dap/Handler/LocationsRequestHandler.cpp 
b/lldb/tools/lldb-dap/Handler/LocationsRequestHandler.cpp
index 923c8b1aefa34..ce4a527009dea 100644
--- a/lldb/tools/lldb-dap/Handler/LocationsRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/LocationsRequestHandler.cpp
@@ -27,7 +27,8 @@ LocationsRequestHandler::Run(const 
protocol::LocationsArguments &args) const {
   // We use the lowest bit to distinguish between value location and 
declaration
   // location
   auto [var_ref, is_value_location] = UnpackLocation(args.locationReference);
-  lldb::SBValue variable = dap.variables.GetVariable(var_ref);
+  lldb::SBValue variable =
+      dap.reference_storage.GetVariable(var_ref_t(var_ref));
   if (!variable.IsValid())
     return llvm::make_error<DAPError>("Invalid variable reference");
 

diff  --git a/lldb/tools/lldb-dap/Handler/ScopesRequestHandler.cpp 
b/lldb/tools/lldb-dap/Handler/ScopesRequestHandler.cpp
index 251711ca62406..3786d583e0e87 100644
--- a/lldb/tools/lldb-dap/Handler/ScopesRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/ScopesRequestHandler.cpp
@@ -37,7 +37,7 @@ ScopesRequestHandler::Run(const ScopesArguments &args) const {
   }
 
   std::vector<protocol::Scope> scopes =
-      dap.variables.CreateScopes(args.frameId, frame);
+      dap.reference_storage.CreateScopes(frame);
 
   return ScopesResponseBody{std::move(scopes)};
 }

diff  --git a/lldb/tools/lldb-dap/Handler/SetVariableRequestHandler.cpp 
b/lldb/tools/lldb-dap/Handler/SetVariableRequestHandler.cpp
index b9ae28d6772ac..fb02d0ada651e 100644
--- a/lldb/tools/lldb-dap/Handler/SetVariableRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/SetVariableRequestHandler.cpp
@@ -9,7 +9,9 @@
 #include "DAP.h"
 #include "EventHelper.h"
 #include "JSONUtils.h"
+#include "Protocol/DAPTypes.h"
 #include "Protocol/ProtocolEvents.h"
+#include "Protocol/ProtocolTypes.h"
 #include "RequestHandler.h"
 
 using namespace lldb_dap::protocol;
@@ -27,9 +29,11 @@ llvm::Expected<SetVariableResponseBody>
 SetVariableRequestHandler::Run(const SetVariableArguments &args) const {
   const auto args_name = llvm::StringRef(args.name);
 
-  if (args.variablesReference == UINT64_MAX) {
+  if (args.variablesReference.Kind() == eReferenceKindInvalid) {
     return llvm::make_error<DAPError>(
-        llvm::formatv("invalid reference {}", args.variablesReference).str(),
+        llvm::formatv("invalid reference {}",
+                      args.variablesReference.AsUInt32())
+            .str(),
         llvm::inconvertibleErrorCode(),
         /*show_user=*/false);
   }
@@ -40,7 +44,7 @@ SetVariableRequestHandler::Run(const SetVariableArguments 
&args) const {
         "cannot change the value of the return value");
 
   lldb::SBValue variable =
-      dap.variables.FindVariable(args.variablesReference, args_name);
+      dap.reference_storage.FindVariable(args.variablesReference, args_name);
 
   if (!variable.IsValid())
     return llvm::make_error<DAPError>("could not find variable in scope");
@@ -61,8 +65,8 @@ SetVariableRequestHandler::Run(const SetVariableArguments 
&args) const {
   // so always insert a new one to get its variablesReference.
   // is_permanent is false because debug console does not support
   // setVariable request.
-  const int64_t new_var_ref =
-      dap.variables.InsertVariable(variable, /*is_permanent=*/false);
+  const var_ref_t new_var_ref =
+      dap.reference_storage.InsertVariable(variable, /*is_permanent=*/false);
   if (variable.MightHaveChildren()) {
     body.variablesReference = new_var_ref;
     if (desc.type_obj.IsArrayType())
@@ -76,7 +80,7 @@ SetVariableRequestHandler::Run(const SetVariableArguments 
&args) const {
     body.memoryReference = addr;
 
   if (ValuePointsToCode(variable))
-    body.valueLocationReference = new_var_ref;
+    body.valueLocationReference = new_var_ref.AsUInt32();
 
   // Also send invalidated event to signal client that some variables
   // (e.g. references) can be changed.

diff  --git a/lldb/tools/lldb-dap/Handler/VariablesRequestHandler.cpp 
b/lldb/tools/lldb-dap/Handler/VariablesRequestHandler.cpp
index ee7cb525d9c29..26719b3a14d4d 100644
--- a/lldb/tools/lldb-dap/Handler/VariablesRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/VariablesRequestHandler.cpp
@@ -7,11 +7,13 @@
 
//===----------------------------------------------------------------------===//
 
 #include "DAP.h"
+#include "DAPError.h"
 #include "EventHelper.h"
 #include "Handler/RequestHandler.h"
-#include "JSONUtils.h"
-#include "ProtocolUtils.h"
+#include "Protocol/DAPTypes.h"
+#include "Protocol/ProtocolRequests.h"
 #include "Variables.h"
+#include "llvm/Support/ErrorExtras.h"
 
 using namespace llvm;
 using namespace lldb_dap::protocol;
@@ -24,150 +26,20 @@ namespace lldb_dap {
 /// indexed children.
 Expected<VariablesResponseBody>
 VariablesRequestHandler::Run(const VariablesArguments &arguments) const {
-  const uint64_t var_ref = arguments.variablesReference;
-  const uint64_t count = arguments.count;
-  const uint64_t start = arguments.start;
-  const bool hex = arguments.format ? arguments.format->hex : false;
-
-  std::vector<Variable> variables;
-
-  std::optional<ScopeData> scope_data = 
dap.variables.GetTopLevelScope(var_ref);
-  if (scope_data) {
-    // variablesReference is one of our scopes, not an actual variable it is
-    // asking for the list of args, locals or globals.
-    int64_t start_idx = 0;
-    int64_t num_children = 0;
-
-    if (scope_data->kind == eScopeKindRegisters) {
-
-      // Change the default format of any pointer sized registers in the first
-      // register set to be the lldb::eFormatAddressInfo so we show the pointer
-      // and resolve what the pointer resolves to. Only change the format if 
the
-      // format was set to the default format or if it was hex as some 
registers
-      // have formats set for them.
-      const uint32_t addr_size = dap.target.GetProcess().GetAddressByteSize();
-      lldb::SBValue reg_set = scope_data->scope.GetValueAtIndex(0);
-      const uint32_t num_regs = reg_set.GetNumChildren();
-      for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx) {
-        lldb::SBValue reg = reg_set.GetChildAtIndex(reg_idx);
-        const lldb::Format format = reg.GetFormat();
-        if (format == lldb::eFormatDefault || format == lldb::eFormatHex) {
-          if (reg.GetByteSize() == addr_size)
-            reg.SetFormat(lldb::eFormatAddressInfo);
-        }
-      }
-    }
-
-    num_children = scope_data->scope.GetSize();
-    if (num_children == 0 && scope_data->kind == eScopeKindLocals) {
-      // Check for an error in the SBValueList that might explain why we don't
-      // have locals. If we have an error display it as the sole value in the
-      // the locals.
-
-      // "error" owns the error string so we must keep it alive as long as we
-      // want to use the returns "const char *"
-      lldb::SBError error = scope_data->scope.GetError();
-      const char *var_err = error.GetCString();
-      if (var_err) {
-        // Create a fake variable named "error" to explain why variables were
-        // not available. This new error will help let users know when there 
was
-        // a problem that kept variables from being available for display and
-        // allow users to fix this issue instead of seeing no variables. The
-        // errors are only set when there is a problem that the user could
-        // fix, so no error will show up when you have no debug info, only when
-        // we do have debug info and something that is fixable can be done.
-        Variable var;
-        var.name = "<error>";
-        var.type = "const char *";
-        var.value = var_err;
-        variables.emplace_back(var);
-      }
-    }
-    const int64_t end_idx = start_idx + ((count == 0) ? num_children : count);
-
-    // We first find out which variable names are duplicated
-    std::map<llvm::StringRef, int> variable_name_counts;
-    for (auto i = start_idx; i < end_idx; ++i) {
-      lldb::SBValue variable = scope_data->scope.GetValueAtIndex(i);
-      if (!variable.IsValid())
-        break;
-      variable_name_counts[GetNonNullVariableName(variable)]++;
-    }
-
-    // Show return value if there is any ( in the local top frame )
-    if (scope_data && scope_data->kind == eScopeKindLocals) {
-      auto process = dap.target.GetProcess();
-      auto selected_thread = process.GetSelectedThread();
-      lldb::SBValue stop_return_value = selected_thread.GetStopReturnValue();
-
-      if (stop_return_value.IsValid() &&
-          (selected_thread.GetSelectedFrame().GetFrameID() == 0)) {
-        auto renamed_return_value = stop_return_value.Clone("(Return Value)");
-        int64_t return_var_ref = 0;
-
-        if (stop_return_value.MightHaveChildren() ||
-            stop_return_value.IsSynthetic()) {
-          return_var_ref = dap.variables.InsertVariable(stop_return_value,
-                                                        
/*is_permanent=*/false);
-        }
-        variables.emplace_back(CreateVariable(
-            renamed_return_value, return_var_ref, hex,
-            dap.configuration.enableAutoVariableSummaries,
-            dap.configuration.enableSyntheticChildDebugging, false));
-      }
-    }
-
-    // Now we construct the result with unique display variable names
-    for (auto i = start_idx; i < end_idx; ++i) {
-      lldb::SBValue variable = scope_data->scope.GetValueAtIndex(i);
-
-      if (!variable.IsValid())
-        break;
-
-      const int64_t frame_var_ref =
-          dap.variables.InsertVariable(variable, /*is_permanent=*/false);
-      variables.emplace_back(CreateVariable(
-          variable, frame_var_ref, hex,
-          dap.configuration.enableAutoVariableSummaries,
-          dap.configuration.enableSyntheticChildDebugging,
-          variable_name_counts[GetNonNullVariableName(variable)] > 1));
-    }
-  } else {
-    // We are expanding a variable that has children, so we will return its
-    // children.
-    lldb::SBValue variable = dap.variables.GetVariable(var_ref);
-    if (variable.IsValid()) {
-      const bool is_permanent =
-          dap.variables.IsPermanentVariableReference(var_ref);
-      auto addChild = [&](lldb::SBValue child,
-                          std::optional<llvm::StringRef> custom_name = {}) {
-        if (!child.IsValid())
-          return;
-        const int64_t child_var_ref =
-            dap.variables.InsertVariable(child, is_permanent);
-        variables.emplace_back(
-            CreateVariable(child, child_var_ref, hex,
-                           dap.configuration.enableAutoVariableSummaries,
-                           dap.configuration.enableSyntheticChildDebugging,
-                           /*is_name_duplicated=*/false, custom_name));
-      };
-      const int64_t num_children = variable.GetNumChildren();
-      const int64_t end_idx = start + ((count == 0) ? num_children : count);
-      int64_t i = start;
-      for (; i < end_idx && i < num_children; ++i)
-        addChild(variable.GetChildAtIndex(i));
-
-      // If we haven't filled the count quota from the request, we insert a new
-      // "[raw]" child that can be used to inspect the raw version of a
-      // synthetic member. That eliminates the need for the user to go to the
-      // debug console and type `frame var <variable> to get these values.
-      if (dap.configuration.enableSyntheticChildDebugging &&
-          variable.IsSynthetic() && i == num_children)
-        addChild(variable.GetNonSyntheticValue(), "[raw]");
-    }
-  }
-
-  return VariablesResponseBody{std::move(variables)};
+  const var_ref_t var_ref = arguments.variablesReference;
+  if (var_ref.Kind() == eReferenceKindInvalid)
+    return llvm::make_error<DAPError>(
+        llvm::formatv("invalid variablesReference: {}.", var_ref.AsUInt32()),
+        /*error_code=*/llvm::inconvertibleErrorCode(), /*show_user=*/false);
+
+  VariableStore *store = dap.reference_storage.GetVariableStore(var_ref);
+  if (!store)
+    return llvm::make_error<DAPError>(
+        llvm::formatv("invalid variablesReference: {}.", var_ref.AsUInt32()),
+        /*error_code=*/llvm::inconvertibleErrorCode(), /*show_user=*/false);
+
+  return VariablesResponseBody{
+      store->GetVariables(dap.reference_storage, dap.configuration, 
arguments)};
 }
 
 } // namespace lldb_dap

diff  --git a/lldb/tools/lldb-dap/Protocol/DAPTypes.cpp 
b/lldb/tools/lldb-dap/Protocol/DAPTypes.cpp
index a14ed9e521f48..ae49b4bfd48e9 100644
--- a/lldb/tools/lldb-dap/Protocol/DAPTypes.cpp
+++ b/lldb/tools/lldb-dap/Protocol/DAPTypes.cpp
@@ -3,8 +3,15 @@
 #include "lldb/lldb-enumerations.h"
 
 using namespace llvm;
-
 namespace lldb_dap::protocol {
+bool fromJSON(const json::Value &E, var_ref_t &Out, json::Path P) {
+  if (auto S = E.getAsInteger()) {
+    Out = var_ref_t(*S);
+    return true;
+  }
+  P.report("expected unsigned integer");
+  return false;
+}
 
 bool fromJSON(const llvm::json::Value &Params, PersistenceData &PD,
               llvm::json::Path P) {

diff  --git a/lldb/tools/lldb-dap/Protocol/DAPTypes.h 
b/lldb/tools/lldb-dap/Protocol/DAPTypes.h
index 23ba93946bdee..4fc0c8db1acc8 100644
--- a/lldb/tools/lldb-dap/Protocol/DAPTypes.h
+++ b/lldb/tools/lldb-dap/Protocol/DAPTypes.h
@@ -1,4 +1,4 @@
-//===-- ProtocolTypes.h 
---------------------------------------------------===//
+//===-- DAPTypes.h ---------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -19,11 +19,80 @@
 #include "lldb/lldb-defines.h"
 #include "lldb/lldb-types.h"
 #include "llvm/Support/JSON.h"
+#include <cstdint>
 #include <optional>
 #include <string>
 
 namespace lldb_dap::protocol {
 
+enum ReferenceKind : uint8_t {
+  eReferenceKindTemporary = 0,
+  eReferenceKindPermanent = 1,
+  eReferenceKindScope = 1 << 1,
+  eReferenceKindInvalid = 0xFF
+};
+
+/// The var_ref_t hold two values, the `ReferenceKind` and the
+/// `variablesReference`.
+struct var_ref_t {
+private:
+  static constexpr uint32_t k_kind_bit_size = sizeof(ReferenceKind) * 8;
+  static constexpr uint32_t k_reference_bit_size =
+      std::numeric_limits<uint32_t>::digits - k_kind_bit_size;
+  static constexpr uint32_t k_reference_bit_mask =
+      (1 << k_reference_bit_size) - 1;
+  static constexpr uint32_t k_kind_mask = 0xFF;
+
+public:
+  static constexpr uint32_t k_invalid_var_ref = UINT32_MAX;
+  static constexpr uint32_t k_no_child = 0;
+
+  explicit constexpr var_ref_t(uint32_t reference, ReferenceKind kind)
+      : reference(reference), kind(kind) {}
+
+  explicit constexpr var_ref_t(uint32_t masked_ref = k_invalid_var_ref)
+      : reference(masked_ref & k_reference_bit_mask),
+        kind((masked_ref >> k_reference_bit_size) & k_kind_mask) {}
+
+  [[nodiscard]] constexpr uint32_t AsUInt32() const {
+    return (kind << k_reference_bit_size) | reference;
+  };
+
+  [[nodiscard]] constexpr ReferenceKind Kind() const {
+    const auto current_kind = static_cast<ReferenceKind>(kind);
+    switch (current_kind) {
+    case eReferenceKindTemporary:
+    case eReferenceKindPermanent:
+    case eReferenceKindScope:
+      return current_kind;
+    default:
+      return eReferenceKindInvalid;
+    }
+  }
+
+  [[nodiscard]] constexpr uint32_t Reference() const { return reference; }
+
+  // We should be able to store at least 8 million variables for each store
+  // type at every stopped state.
+  static constexpr uint32_t k_variables_reference_threshold = 8'000'000;
+  static constexpr uint32_t k_max_variables_references =
+      k_reference_bit_mask - 1;
+  static_assert((k_max_variables_references >
+                 k_variables_reference_threshold) &&
+                "not enough variablesReferences to store 8 million 
variables.");
+
+private:
+  uint32_t reference : k_reference_bit_size;
+  uint32_t kind : k_kind_bit_size;
+};
+static_assert(sizeof(var_ref_t) == sizeof(uint32_t) &&
+              "the size of var_ref_t must be equal to the size of uint32_t.");
+
+bool fromJSON(const llvm::json::Value &, var_ref_t &, llvm::json::Path);
+inline llvm::json::Value toJSON(const var_ref_t &var_ref) {
+  return var_ref.AsUInt32();
+}
+
 /// Data used to help lldb-dap resolve breakpoints persistently across 
diff erent
 /// sessions. This information is especially useful for assembly breakpoints,
 /// because `sourceReference` can change across sessions. For regular source

diff  --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp 
b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp
index a72802a33fc9c..faed1f8c4d574 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp
@@ -405,7 +405,7 @@ json::Value toJSON(const SetVariableResponseBody &SVR) {
 
   if (!SVR.type.empty())
     Body.insert({"type", SVR.type});
-  if (SVR.variablesReference)
+  if (SVR.variablesReference.Reference())
     Body.insert({"variablesReference", SVR.variablesReference});
   if (SVR.namedVariables)
     Body.insert({"namedVariables", SVR.namedVariables});

diff  --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h 
b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
index 91fc2a4db6f57..9bf04757294d6 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
@@ -435,7 +435,7 @@ struct SetVariableArguments {
   /// The reference of the variable container. The `variablesReference` must
   /// have been obtained in the current suspended state. See 'Lifetime of 
Object
   ///  References' in the Overview section for details.
-  uint64_t variablesReference = UINT64_MAX;
+  var_ref_t variablesReference{var_ref_t::k_invalid_var_ref};
 
   /// The name of the variable in the container.
   std::string name;
@@ -466,7 +466,7 @@ struct SetVariableResponseBody {
   /// If this property is included in the response, any `variablesReference`
   /// previously associated with the updated variable, and those of its
   /// children, are no longer valid.
-  uint64_t variablesReference = 0;
+  var_ref_t variablesReference{var_ref_t::k_no_child};
 
   /// The number of named child variables.
   /// The client can use this information to present the variables in a paged
@@ -727,7 +727,7 @@ struct DataBreakpointInfoArguments {
   /// for a child of the container. The `variablesReference` must have been
   /// obtained in the current suspended state.See 'Lifetime of Object
   /// References' in the Overview section for details.
-  std::optional<int64_t> variablesReference;
+  std::optional<var_ref_t> variablesReference;
 
   /// The name of the variable's child to obtain data breakpoint information
   /// for. If `variablesReference` isn't specified, this can be an expression,
@@ -953,7 +953,7 @@ struct VariablesArguments {
   /// The variable for which to retrieve its children. The `variablesReference`
   /// must have been obtained in the current suspended state. See 'Lifetime of
   /// Object References' in the Overview section for details.
-  uint64_t variablesReference;
+  var_ref_t variablesReference{var_ref_t::k_invalid_var_ref};
 
   enum VariablesFilter : unsigned {
     eVariablesFilterBoth = 0,
@@ -1158,7 +1158,7 @@ struct EvaluateResponseBody {
   /// children can be retrieved by passing `variablesReference` to the
   /// `variables` request as long as execution remains suspended. See 'Lifetime
   /// of Object References' in the Overview section for details.
-  int64_t variablesReference = 0;
+  var_ref_t variablesReference{var_ref_t::k_no_child};
 
   /// The number of named child variables.
   /// The client can use this information to present the variables in a paged

diff  --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h 
b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h
index 71046d24c9787..2a23871621cca 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h
@@ -29,7 +29,6 @@
 #include <optional>
 #include <string>
 
-#define LLDB_DAP_INVALID_VAR_REF INT64_MAX
 #define LLDB_DAP_INVALID_SRC_REF 0
 #define LLDB_DAP_INVALID_VALUE_LOC 0
 #define LLDB_DAP_INVALID_STACK_FRAME_ID UINT64_MAX
@@ -464,7 +463,7 @@ struct Scope {
   /// remains suspended. See 'Lifetime of Object References' in the Overview
   /// section for details.
   ////
-  uint64_t variablesReference = LLDB_DAP_INVALID_VAR_REF;
+  var_ref_t variablesReference{var_ref_t::k_invalid_var_ref};
 
   /// The number of named variables in this scope.
   /// The client can use this information to present the variables in a paged 
UI
@@ -963,7 +962,7 @@ struct Variable {
   /// children can be retrieved by passing `variablesReference` to the
   /// `variables` request as long as execution remains suspended. See 'Lifetime
   /// of Object References' in the Overview section for details.
-  uint64_t variablesReference = 0;
+  var_ref_t variablesReference{var_ref_t::k_no_child};
 
   /// The number of named child variables.
   ///

diff  --git a/lldb/tools/lldb-dap/ProtocolUtils.cpp 
b/lldb/tools/lldb-dap/ProtocolUtils.cpp
index af583fdef52fb..d18c040b119da 100644
--- a/lldb/tools/lldb-dap/ProtocolUtils.cpp
+++ b/lldb/tools/lldb-dap/ProtocolUtils.cpp
@@ -239,7 +239,7 @@ CreateExceptionBreakpointFilter(const ExceptionBreakpoint 
&bp) {
   return filter;
 }
 
-Variable CreateVariable(lldb::SBValue v, int64_t var_ref, bool format_hex,
+Variable CreateVariable(lldb::SBValue v, var_ref_t var_ref, bool format_hex,
                         bool auto_variable_summaries,
                         bool synthetic_child_debugging, bool 
is_name_duplicated,
                         std::optional<llvm::StringRef> custom_name) {
@@ -292,10 +292,10 @@ Variable CreateVariable(lldb::SBValue v, int64_t var_ref, 
bool format_hex,
     var.variablesReference = var_ref;
 
   if (v.GetDeclaration().IsValid())
-    var.declarationLocationReference = PackLocation(var_ref, false);
+    var.declarationLocationReference = PackLocation(var_ref.AsUInt32(), false);
 
   if (ValuePointsToCode(v))
-    var.valueLocationReference = PackLocation(var_ref, true);
+    var.valueLocationReference = PackLocation(var_ref.AsUInt32(), true);
 
   if (lldb::addr_t addr = v.GetLoadAddress(); addr != LLDB_INVALID_ADDRESS)
     var.memoryReference = addr;

diff  --git a/lldb/tools/lldb-dap/ProtocolUtils.h 
b/lldb/tools/lldb-dap/ProtocolUtils.h
index 89839f2caad50..376a8d6b7c023 100644
--- a/lldb/tools/lldb-dap/ProtocolUtils.h
+++ b/lldb/tools/lldb-dap/ProtocolUtils.h
@@ -144,7 +144,7 @@ std::string ConvertDebugInfoSizeToString(uint64_t 
debug_size);
 /// \return
 ///     A Variable representing the given value.
 protocol::Variable
-CreateVariable(lldb::SBValue v, int64_t var_ref, bool format_hex,
+CreateVariable(lldb::SBValue v, var_ref_t var_ref, bool format_hex,
                bool auto_variable_summaries, bool synthetic_child_debugging,
                bool is_name_duplicated,
                std::optional<llvm::StringRef> custom_name = {});

diff  --git a/lldb/tools/lldb-dap/SBAPIExtras.h 
b/lldb/tools/lldb-dap/SBAPIExtras.h
index eb59cb08ea4fd..2f7a18d1a3da1 100644
--- a/lldb/tools/lldb-dap/SBAPIExtras.h
+++ b/lldb/tools/lldb-dap/SBAPIExtras.h
@@ -55,6 +55,13 @@ using frame_iter =
 inline frame_iter begin(SBThread T) { return {T, 0}; }
 inline frame_iter end(SBThread T) { return {T, T.GetNumFrames()}; }
 
+/// SBValue value iterators.
+/// @{
+using value_iter = iter<SBValue, SBValue, uint32_t, &SBValue::GetChildAtIndex>;
+inline value_iter begin(SBValue &T) { return {T, 0}; }
+inline value_iter end(SBValue &T) { return {T, T.GetNumChildren()}; }
+/// @}
+
 // llvm::raw_ostream print helpers.
 
 inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, SBStream &stream) {

diff  --git a/lldb/tools/lldb-dap/Variables.cpp 
b/lldb/tools/lldb-dap/Variables.cpp
index 6d49113243799..1f429b087ac0e 100644
--- a/lldb/tools/lldb-dap/Variables.cpp
+++ b/lldb/tools/lldb-dap/Variables.cpp
@@ -7,24 +7,32 @@
 
//===----------------------------------------------------------------------===//
 
 #include "Variables.h"
+#include "DAPLog.h"
 #include "JSONUtils.h"
+#include "Protocol/DAPTypes.h"
+#include "Protocol/ProtocolRequests.h"
 #include "Protocol/ProtocolTypes.h"
+#include "ProtocolUtils.h"
+#include "SBAPIExtras.h"
 #include "lldb/API/SBFrame.h"
+#include "lldb/API/SBProcess.h"
 #include "lldb/API/SBValue.h"
 #include "lldb/API/SBValueList.h"
+#include "llvm/ADT/Sequence.h"
+#include "llvm/Support/ErrorHandling.h"
 #include <cstdint>
 #include <optional>
 #include <vector>
 
 using namespace lldb_dap;
+using namespace lldb_dap::protocol;
 
 namespace lldb_dap {
 
-protocol::Scope CreateScope(const ScopeKind kind, int64_t variablesReference,
-                            int64_t namedVariables, bool expensive) {
+protocol::Scope CreateScope(ScopeKind kind, var_ref_t variablesReference,
+                            bool expensive) {
   protocol::Scope scope;
   scope.variablesReference = variablesReference;
-  scope.namedVariables = namedVariables;
   scope.expensive = expensive;
 
   // TODO: Support "arguments" and "return value" scope.
@@ -51,155 +59,313 @@ protocol::Scope CreateScope(const ScopeKind kind, int64_t 
variablesReference,
   return scope;
 }
 
-std::optional<ScopeData>
-Variables::GetTopLevelScope(int64_t variablesReference) {
-  auto scope_kind_iter = m_scope_kinds.find(variablesReference);
-  if (scope_kind_iter == m_scope_kinds.end())
-    return std::nullopt;
+std::vector<Variable>
+ScopeStore::GetVariables(VariableReferenceStorage &storage,
+                         const Configuration &config,
+                         const VariablesArguments &args) {
+  LoadVariables();
+  if (m_kind == lldb_dap::eScopeKindRegisters)
+    SetRegistersFormat();
 
-  ScopeKind scope_kind = scope_kind_iter->second.first;
-  uint64_t dap_frame_id = scope_kind_iter->second.second;
+  const bool format_hex = args.format ? args.format->hex : false;
+  std::vector<Variable> variables;
+  if (m_kind == eScopeKindLocals)
+    AddReturnValue(storage, config, variables, format_hex);
 
-  auto frame_iter = m_frames.find(dap_frame_id);
-  if (frame_iter == m_frames.end())
-    return std::nullopt;
+  const uint64_t count = args.count;
+  const uint32_t start_idx = 0;
+  const uint32_t num_children = m_children.GetSize();
+  const uint32_t end_idx = start_idx + ((count == 0) ? num_children : count);
 
-  lldb::SBValueList *scope = frame_iter->second.GetScope(scope_kind);
-  if (scope == nullptr)
-    return std::nullopt;
+  // We first find out which variable names are duplicated.
+  std::map<llvm::StringRef, uint32_t> variable_name_counts;
+  for (auto i = start_idx; i < end_idx; ++i) {
+    lldb::SBValue variable = m_children.GetValueAtIndex(i);
+    if (!variable.IsValid())
+      break;
+    variable_name_counts[GetNonNullVariableName(variable)]++;
+  }
 
-  ScopeData scope_data;
-  scope_data.kind = scope_kind;
-  scope_data.scope = *scope;
-  return scope_data;
-}
+  // Now we construct the result with unique display variable names.
+  for (auto i = start_idx; i < end_idx; ++i) {
+    lldb::SBValue variable = m_children.GetValueAtIndex(i);
+
+    if (!variable.IsValid())
+      break;
+
+    const var_ref_t frame_var_ref =
+        storage.InsertVariable(variable, /*is_permanent=*/false);
+    if (LLVM_UNLIKELY(frame_var_ref.AsUInt32() >=
+                      var_ref_t::k_variables_reference_threshold)) {
+      DAP_LOG(storage.log,
+              "warning: scopes variablesReference threshold reached. "
+              "current: {} threshold: {}, maximum {}.",
+              frame_var_ref.AsUInt32(),
+              var_ref_t::k_variables_reference_threshold,
+              var_ref_t::k_max_variables_references);
+    }
 
-void Variables::Clear() {
-  m_referencedvariables.clear();
-  m_scope_kinds.clear();
-  m_frames.clear();
-  m_next_temporary_var_ref = TemporaryVariableStartIndex;
+    if (LLVM_UNLIKELY(frame_var_ref.Kind() == eReferenceKindInvalid))
+      break;
+
+    variables.emplace_back(CreateVariable(
+        variable, frame_var_ref, format_hex, 
config.enableAutoVariableSummaries,
+        config.enableSyntheticChildDebugging,
+        variable_name_counts[GetNonNullVariableName(variable)] > 1));
+  }
+  return variables;
 }
 
-int64_t Variables::GetNewVariableReference(bool is_permanent) {
-  if (is_permanent)
-    return m_next_permanent_var_ref++;
-  return m_next_temporary_var_ref++;
+lldb::SBValue ScopeStore::FindVariable(llvm::StringRef name) {
+  LoadVariables();
+
+  lldb::SBValue variable;
+  const bool is_name_duplicated = name.contains(" @");
+  // variablesReference is one of our scopes, not an actual variable it is
+  // asking for a variable in locals or globals or registers.
+  const uint32_t end_idx = m_children.GetSize();
+  // Searching backward so that we choose the variable in closest scope
+  // among variables of the same name.
+  for (const uint32_t i : llvm::reverse(llvm::seq<uint32_t>(0, end_idx))) {
+    lldb::SBValue curr_variable = m_children.GetValueAtIndex(i);
+    std::string variable_name =
+        CreateUniqueVariableNameForDisplay(curr_variable, is_name_duplicated);
+    if (variable_name == name) {
+      variable = curr_variable;
+      break;
+    }
+  }
+  return variable;
 }
 
-bool Variables::IsPermanentVariableReference(int64_t var_ref) {
-  return var_ref >= PermanentVariableStartIndex;
+void ScopeStore::LoadVariables() {
+  if (m_variables_loaded)
+    return;
+
+  m_variables_loaded = true;
+  switch (m_kind) {
+  case eScopeKindLocals:
+    m_children = m_frame.GetVariables(/*arguments=*/true,
+                                      /*locals=*/true,
+                                      /*statics=*/false,
+                                      /*in_scope_only=*/true);
+    break;
+  case eScopeKindGlobals:
+    m_children = m_frame.GetVariables(/*arguments=*/false,
+                                      /*locals=*/false,
+                                      /*statics=*/true,
+                                      /*in_scope_only=*/true);
+    break;
+  case eScopeKindRegisters:
+    m_children = m_frame.GetRegisters();
+  }
 }
 
-lldb::SBValue Variables::GetVariable(int64_t var_ref) const {
-  if (IsPermanentVariableReference(var_ref)) {
-    auto pos = m_referencedpermanent_variables.find(var_ref);
-    if (pos != m_referencedpermanent_variables.end())
-      return pos->second;
-  } else {
-    auto pos = m_referencedvariables.find(var_ref);
-    if (pos != m_referencedvariables.end())
-      return pos->second;
+void ScopeStore::SetRegistersFormat() {
+  // Change the default format of any pointer sized registers in the first
+  // register set to be the lldb::eFormatAddressInfo so we show the pointer
+  // and resolve what the pointer resolves to. Only change the format if the
+  // format was set to the default format or if it was hex as some registers
+  // have formats set for them.
+  const uint32_t addr_size =
+      m_frame.GetThread().GetProcess().GetAddressByteSize();
+  for (lldb::SBValue reg : m_children.GetValueAtIndex(0)) {
+    const lldb::Format format = reg.GetFormat();
+    if (format == lldb::eFormatDefault || format == lldb::eFormatHex) {
+      if (reg.GetByteSize() == addr_size)
+        reg.SetFormat(lldb::eFormatAddressInfo);
+    }
   }
-  return lldb::SBValue();
 }
 
-int64_t Variables::InsertVariable(lldb::SBValue variable, bool is_permanent) {
-  int64_t var_ref = GetNewVariableReference(is_permanent);
-  if (is_permanent)
-    m_referencedpermanent_variables.insert(std::make_pair(var_ref, variable));
-  else
-    m_referencedvariables.insert(std::make_pair(var_ref, variable));
-  return var_ref;
+void ScopeStore::AddReturnValue(VariableReferenceStorage &storage,
+                                const Configuration &config,
+                                std::vector<Variable> &variables,
+                                bool format_hex) {
+  assert(m_kind == eScopeKindLocals &&
+         "Return Value Should only be in local scope");
+  if (m_children.GetSize() == 0) {
+    // Check for an error in the SBValueList that might explain why we don't
+    // have locals. If we have an error display it as the sole value in the
+    // the locals.
+
+    // "error" owns the error string so we must keep it alive as long as we
+    // want to use the returns "const char *".
+    lldb::SBError error = m_children.GetError();
+    if (const char *var_err = error.GetCString()) {
+      // Create a fake variable named "error" to explain why variables were
+      // not available. This new error will help let users know when there was
+      // a problem that kept variables from being available for display and
+      // allow users to fix this issue instead of seeing no variables. The
+      // errors are only set when there is a problem that the user could
+      // fix, so no error will show up when you have no debug info, only when
+      // we do have debug info and something that is fixable can be done.
+      Variable err_var;
+      err_var.name = "<error>";
+      err_var.type = "const char *";
+      err_var.value = var_err;
+      variables.push_back(std::move(err_var));
+    }
+    return;
+  }
+
+  // Show return value if there is any ( in the local top frame )
+  lldb::SBThread selected_thread = m_frame.GetThread();
+  lldb::SBValue stop_return_value = selected_thread.GetStopReturnValue();
+
+  if (stop_return_value.IsValid() &&
+      (selected_thread.GetSelectedFrame().GetFrameID() == 0)) {
+    auto renamed_return_value = stop_return_value.Clone("(Return Value)");
+    var_ref_t return_var_ref{var_ref_t::k_no_child};
+
+    if (stop_return_value.MightHaveChildren() ||
+        stop_return_value.IsSynthetic()) {
+      return_var_ref = storage.InsertVariable(stop_return_value,
+                                              /*is_permanent=*/false);
+    }
+    variables.emplace_back(
+        CreateVariable(renamed_return_value, return_var_ref, format_hex,
+                       config.enableAutoVariableSummaries,
+                       config.enableSyntheticChildDebugging, false));
+  }
 }
 
-lldb::SBValue Variables::FindVariable(uint64_t variablesReference,
-                                      llvm::StringRef name) {
-  lldb::SBValue variable;
-  if (std::optional<ScopeData> scope_data =
-          GetTopLevelScope(variablesReference)) {
-    bool is_duplicated_variable_name = name.contains(" @");
-    // variablesReference is one of our scopes, not an actual variable it is
-    // asking for a variable in locals or globals or registers
-    int64_t end_idx = scope_data->scope.GetSize();
-    // Searching backward so that we choose the variable in closest scope
-    // among variables of the same name.
-    for (int64_t i = end_idx - 1; i >= 0; --i) {
-      lldb::SBValue curr_variable = scope_data->scope.GetValueAtIndex(i);
-      std::string variable_name = CreateUniqueVariableNameForDisplay(
-          curr_variable, is_duplicated_variable_name);
-      if (variable_name == name) {
-        variable = curr_variable;
-        break;
-      }
+std::vector<Variable>
+ExpandableValueStore::GetVariables(VariableReferenceStorage &storage,
+                                   const Configuration &config,
+                                   const VariablesArguments &args) {
+  const var_ref_t var_ref = args.variablesReference;
+  const uint64_t count = args.count;
+  const uint64_t start = args.start;
+  const bool hex = args.format ? args.format->hex : false;
+
+  lldb::SBValue variable = storage.GetVariable(var_ref);
+  if (!variable)
+    return {};
+
+  // We are expanding a variable that has children, so we will return its
+  // children.
+  std::vector<Variable> variables;
+  const bool is_permanent = var_ref.Kind() == eReferenceKindPermanent;
+  auto addChild = [&](lldb::SBValue child,
+                      std::optional<llvm::StringRef> custom_name = {}) {
+    if (!child.IsValid())
+      return;
+
+    const var_ref_t child_var_ref = storage.InsertVariable(child, 
is_permanent);
+    if (LLVM_UNLIKELY(child_var_ref.AsUInt32() ==
+                      var_ref_t::k_variables_reference_threshold)) {
+      DAP_LOG(storage.log,
+              "warning: {} variablesReference threshold reached. "
+              "current: {} threshold: {}, maximum {}.",
+              (is_permanent ? "permanent" : "temporary"),
+              child_var_ref.AsUInt32(),
+              var_ref_t::k_variables_reference_threshold,
+              var_ref_t::k_max_variables_references);
     }
-  } else {
-    // This is not under the globals or locals scope, so there are no
-    // duplicated names.
-
-    // We have a named item within an actual variable so we need to find it
-    // withing the container variable by name.
-    lldb::SBValue container = GetVariable(variablesReference);
-    variable = container.GetChildMemberWithName(name.data());
-    if (!variable.IsValid()) {
-      if (name.starts_with("[")) {
-        llvm::StringRef index_str(name.drop_front(1));
-        uint64_t index = 0;
-        if (!index_str.consumeInteger(0, index)) {
-          if (index_str == "]")
-            variable = container.GetChildAtIndex(index);
-        }
-      }
+
+    if (LLVM_UNLIKELY(child_var_ref.Kind() == eReferenceKindInvalid)) {
+      DAP_LOG(storage.log,
+              "error: invalid variablesReference created for {} variable {}.",
+              (is_permanent ? "permanent" : "temporary"), variable.GetName());
+      return;
+    }
+
+    variables.emplace_back(CreateVariable(
+        child, child_var_ref, hex, config.enableAutoVariableSummaries,
+        config.enableSyntheticChildDebugging,
+        /*is_name_duplicated=*/false, custom_name));
+  };
+
+  const uint32_t num_children = variable.GetNumChildren();
+  const uint32_t end_idx = start + ((count == 0) ? num_children : count);
+  uint32_t i = start;
+  for (; i < end_idx && i < num_children; ++i)
+    addChild(variable.GetChildAtIndex(i));
+
+  // If we haven't filled the count quota from the request, we insert a new
+  // "[raw]" child that can be used to inspect the raw version of a
+  // synthetic member. That eliminates the need for the user to go to the
+  // debug console and type `frame var <variable> to get these values.
+  if (config.enableSyntheticChildDebugging && variable.IsSynthetic() &&
+      i == num_children)
+    addChild(variable.GetNonSyntheticValue(), "[raw]");
+
+  return variables;
+}
+
+lldb::SBValue ExpandableValueStore::FindVariable(llvm::StringRef name) {
+  lldb::SBValue variable = m_value.GetChildMemberWithName(name.data());
+  if (variable.IsValid())
+    return variable;
+
+  if (name.consume_front('[') && name.consume_back("]")) {
+    uint64_t index = 0;
+    if (!name.consumeInteger(0, index)) {
+      variable = m_value.GetChildAtIndex(index);
     }
   }
   return variable;
 }
 
-lldb::SBValueList *Variables::GetScope(const uint64_t dap_frame_id,
-                                       const ScopeKind kind) {
+lldb::SBValue VariableReferenceStorage::GetVariable(var_ref_t var_ref) {
+  const ReferenceKind kind = var_ref.Kind();
 
-  auto frame = m_frames.find(dap_frame_id);
-  if (frame == m_frames.end()) {
-    return nullptr;
+  if (kind == eReferenceKindTemporary) {
+    if (auto *store = m_temporary_kind_pool.GetVariableStore(var_ref))
+      return store->GetVariable();
   }
 
-  return frame->second.GetScope(kind);
+  if (kind == eReferenceKindPermanent) {
+    if (auto *store = m_permanent_kind_pool.GetVariableStore(var_ref))
+      return store->GetVariable();
+  }
+
+  return {};
 }
 
-std::vector<protocol::Scope>
-Variables::CreateScopes(const uint64_t dap_frame_id, lldb::SBFrame &frame) {
-  auto iter = m_frames.find(dap_frame_id);
-  if (iter == m_frames.end()) {
-    auto locals = frame.GetVariables(/*arguments=*/true,
-                                     /*locals=*/true,
-                                     /*statics=*/false,
-                                     /*in_scope_only=*/true);
-
-    auto globals = frame.GetVariables(/*arguments=*/false,
-                                      /*locals=*/false,
-                                      /*statics=*/true,
-                                      /*in_scope_only=*/true);
+var_ref_t
+VariableReferenceStorage::InsertVariable(const lldb::SBValue &variable,
+                                         bool is_permanent) {
+  if (is_permanent)
+    return m_permanent_kind_pool.Add(variable);
 
-    auto registers = frame.GetRegisters();
+  return m_temporary_kind_pool.Add(variable);
+}
 
-    iter =
-        m_frames.emplace(dap_frame_id, FrameScopes{locals, globals, registers})
-            .first;
-  }
+lldb::SBValue VariableReferenceStorage::FindVariable(var_ref_t var_ref,
+                                                     llvm::StringRef name) {
+  if (VariableStore *store = GetVariableStore(var_ref))
+    return store->FindVariable(name);
 
-  const FrameScopes &frame_scopes = iter->second;
+  return {};
+}
 
-  auto create_scope = [&](ScopeKind kind, uint32_t size) {
-    int64_t ref = GetNewVariableReference(false);
-    m_scope_kinds.try_emplace(ref, kind, dap_frame_id);
-    return CreateScope(kind, ref, size, false);
+std::vector<protocol::Scope>
+VariableReferenceStorage::CreateScopes(lldb::SBFrame &frame) {
+  auto create_scope = [&](ScopeKind kind) {
+    const var_ref_t var_ref = m_scope_kind_pool.Add(kind, frame);
+    const bool is_expensive = kind != eScopeKindLocals;
+    return CreateScope(kind, var_ref, is_expensive);
   };
 
-  return {
-      create_scope(eScopeKindLocals, frame_scopes.locals.GetSize()),
-      create_scope(eScopeKindGlobals, frame_scopes.globals.GetSize()),
-      create_scope(eScopeKindRegisters, frame_scopes.registers.GetSize()),
-  };
+  return {create_scope(eScopeKindLocals), create_scope(eScopeKindGlobals),
+          create_scope(eScopeKindRegisters)};
+}
+
+VariableStore *VariableReferenceStorage::GetVariableStore(var_ref_t var_ref) {
+  const ReferenceKind kind = var_ref.Kind();
+  switch (kind) {
+  case eReferenceKindPermanent:
+    return m_permanent_kind_pool.GetVariableStore(var_ref);
+  case eReferenceKindTemporary:
+    return m_temporary_kind_pool.GetVariableStore(var_ref);
+  case eReferenceKindScope:
+    return m_scope_kind_pool.GetVariableStore(var_ref);
+  default:
+    return nullptr;
+  }
+  llvm_unreachable("Unknown reference kind.");
 }
 
 } // namespace lldb_dap

diff  --git a/lldb/tools/lldb-dap/Variables.h b/lldb/tools/lldb-dap/Variables.h
index 9814cabc7036c..d887648fbc672 100644
--- a/lldb/tools/lldb-dap/Variables.h
+++ b/lldb/tools/lldb-dap/Variables.h
@@ -9,21 +9,25 @@
 #ifndef LLDB_TOOLS_LLDB_DAP_VARIABLES_H
 #define LLDB_TOOLS_LLDB_DAP_VARIABLES_H
 
+#include "DAPForward.h"
+#include "DAPLog.h"
+#include "Protocol/DAPTypes.h"
+#include "Protocol/ProtocolRequests.h"
 #include "Protocol/ProtocolTypes.h"
+#include "lldb/API/SBFrame.h"
 #include "lldb/API/SBValue.h"
 #include "lldb/API/SBValueList.h"
-#include "llvm/ADT/DenseMap.h"
-#include <map>
-#include <optional>
-#include <utility>
+#include "llvm/Support/ErrorHandling.h"
 
 namespace lldb_dap {
+struct VariableReferenceStorage;
 
 enum ScopeKind : unsigned {
   eScopeKindLocals,
   eScopeKindGlobals,
   eScopeKindRegisters
 };
+
 /// Creates a `protocol::Scope` struct.
 ///
 /// \param[in] kind
@@ -32,100 +36,184 @@ enum ScopeKind : unsigned {
 /// \param[in] variablesReference
 ///     The value to place into the "variablesReference" key
 ///
-/// \param[in] namedVariables
-///     The value to place into the "namedVariables" key
-///
 /// \param[in] expensive
 ///     The value to place into the "expensive" key
 ///
 /// \return
 ///     A `protocol::Scope`
-protocol::Scope CreateScope(const ScopeKind kind, int64_t variablesReference,
-                            int64_t namedVariables, bool expensive);
-
-struct ScopeData {
-  ScopeKind kind;
-  lldb::SBValueList scope;
+protocol::Scope CreateScope(ScopeKind kind, var_ref_t variablesReference,
+                            bool expensive);
+
+/// An Interface to get or find specific variables by name.
+class VariableStore {
+public:
+  explicit VariableStore() = default;
+  virtual ~VariableStore() = default;
+
+  virtual std::vector<protocol::Variable>
+  GetVariables(VariableReferenceStorage &storage,
+               const protocol::Configuration &config,
+               const protocol::VariablesArguments &args) = 0;
+  virtual lldb::SBValue FindVariable(llvm::StringRef name) = 0;
+
+  // Not copyable.
+  VariableStore(const VariableStore &) = delete;
+  VariableStore operator=(const VariableStore &) = delete;
+  VariableStore(VariableStore &&) = default;
+  VariableStore &operator=(VariableStore &&) = default;
 };
 
-/// Stores the three scope variable lists for a single stack frame.
-struct FrameScopes {
-  lldb::SBValueList locals;
-  lldb::SBValueList globals;
-  lldb::SBValueList registers;
-
-  /// Returns a pointer to the scope corresponding to the given kind.
-  lldb::SBValueList *GetScope(ScopeKind kind) {
-    switch (kind) {
-    case eScopeKindLocals:
-      return &locals;
-    case eScopeKindGlobals:
-      return &globals;
-    case eScopeKindRegisters:
-      return &registers;
-    }
+/// A Variable store for fetching variables within a specific scope (locals,
+/// globals, or registers) for a given stack frame.
+class ScopeStore final : public VariableStore {
+public:
+  explicit ScopeStore(ScopeKind kind, const lldb::SBFrame &frame)
+      : m_frame(frame), m_kind(kind) {}
 
-    llvm_unreachable("unknown scope kind");
-  }
+  std::vector<protocol::Variable>
+  GetVariables(VariableReferenceStorage &storage,
+               const protocol::Configuration &config,
+               const protocol::VariablesArguments &args) override;
+  lldb::SBValue FindVariable(llvm::StringRef name) override;
+
+private:
+  void LoadVariables();
+  void SetRegistersFormat();
+  void AddReturnValue(VariableReferenceStorage &storage,
+                      const protocol::Configuration &config,
+                      std::vector<protocol::Variable> &variables,
+                      bool format_hex);
+  lldb::SBFrame m_frame;
+  lldb::SBValueList m_children;
+  ScopeKind m_kind;
+  bool m_variables_loaded = false;
 };
 
-struct Variables {
-  /// Check if \p var_ref points to a variable that should persist for the
-  /// entire duration of the debug session, e.g. repl expandable variables
-  static bool IsPermanentVariableReference(int64_t var_ref);
+/// Variable store for expandable values.
+///
+/// Manages children variables of complex types (structs, arrays, pointers,
+/// etc.) that can be expanded in the debugger UI.
+class ExpandableValueStore final : public VariableStore {
+
+public:
+  explicit ExpandableValueStore(const lldb::SBValue &value) : m_value(value) {}
 
+  std::vector<protocol::Variable>
+  GetVariables(VariableReferenceStorage &storage,
+               const protocol::Configuration &config,
+               const protocol::VariablesArguments &args) override;
+  lldb::SBValue FindVariable(llvm::StringRef name) override;
+  [[nodiscard]] lldb::SBValue GetVariable() const { return m_value; };
+
+private:
+  lldb::SBValue m_value;
+};
+
+struct VariableReferenceStorage {
+  explicit VariableReferenceStorage(Log &log) : log(log) {}
   /// \return a new variableReference.
   /// Specify is_permanent as true for variable that should persist entire
   /// debug session.
-  int64_t GetNewVariableReference(bool is_permanent);
+  var_ref_t CreateVariableReference(bool is_permanent);
 
   /// \return the expandable variable corresponding with variableReference
   /// value of \p value.
   /// If \p var_ref is invalid an empty SBValue is returned.
-  lldb::SBValue GetVariable(int64_t var_ref) const;
-
-  lldb::SBValueList *GetScope(const uint64_t dap_frame_id,
-                              const ScopeKind kind);
+  lldb::SBValue GetVariable(var_ref_t var_ref);
 
   /// Insert a new \p variable.
   /// \return variableReference assigned to this expandable variable.
-  int64_t InsertVariable(lldb::SBValue variable, bool is_permanent);
+  var_ref_t InsertVariable(const lldb::SBValue &variable, bool is_permanent);
 
-  std::optional<ScopeData> GetTopLevelScope(int64_t variablesReference);
+  lldb::SBValue FindVariable(var_ref_t var_ref, llvm::StringRef name);
 
-  lldb::SBValue FindVariable(uint64_t variablesReference, llvm::StringRef 
name);
+  std::vector<protocol::Scope> CreateScopes(lldb::SBFrame &frame);
 
-  /// Initialize a frame if it hasn't been already, otherwise do nothing
-  std::vector<protocol::Scope> CreateScopes(const uint64_t dap_frame_id,
-                                            lldb::SBFrame &frame);
+  void Clear() {
+    m_temporary_kind_pool.Clear();
+    m_scope_kind_pool.Clear();
+  }
 
-  /// Clear all scope variables and non-permanent expandable variables.
-  void Clear();
+  VariableStore *GetVariableStore(var_ref_t var_ref);
+  Log &log;
 
 private:
-  /// Variable reference start index of temporary variables.
-  static constexpr int64_t TemporaryVariableStartIndex = 1;
+  /// Template class for managing pools of variable stores.
+  /// All references created starts from zero with the Reference kind mask
+  /// applied, the mask is then removed when fetching a variable store
+  ///
+  /// \tparam VariableStoreType
+  ///     The type of variable store to use.
+  ///
+  /// \tparam ReferenceKind
+  ///     The reference kind created in this pool
+  template <typename VariableStoreType, protocol::ReferenceKind Kind>
+  class ReferenceKindPool {
+
+  public:
+    explicit ReferenceKindPool() = default;
+
+    /// Resets the count to zero and clears the pool,
+    /// disabled for permanent reference kind.
+    template <protocol::ReferenceKind LHS = Kind,
+              protocol::ReferenceKind RHS = protocol::eReferenceKindPermanent>
+    std::enable_if_t<LHS != RHS, void> Clear() {
+      reference_count = 0;
+      m_pool.clear();
+    }
 
-  /// Variable reference start index of permanent expandable variable.
-  static constexpr int64_t PermanentVariableStartIndex = (1ll << 32);
+    VariableStoreType *GetVariableStore(var_ref_t var_ref) {
+      const uint32_t raw_ref = var_ref.Reference();
+
+      if (raw_ref != 0 && raw_ref <= m_pool.size())
+        return &m_pool[raw_ref - 1];
+      return nullptr;
+    }
 
-  int64_t m_next_permanent_var_ref{PermanentVariableStartIndex};
-  int64_t m_next_temporary_var_ref{TemporaryVariableStartIndex};
+    template <typename... Args> var_ref_t Add(Args &&...args) {
+      assert(reference_count == m_pool.size() &&
+             "Current reference_count must be the size of the pool");
+
+      if (LLVM_UNLIKELY(reference_count >=
+                        var_ref_t::k_max_variables_references)) {
+        // We cannot add new variables to the pool;
+        return var_ref_t(var_ref_t::k_invalid_var_ref);
+      }
+
+      m_pool.emplace_back(std::forward<Args>(args)...);
+      const uint32_t raw_ref = NextRawReference();
+      return var_ref_t(raw_ref, Kind);
+    }
 
-  // Variable Reference,                 dap_frame_id
-  std::map<int64_t, std::pair<ScopeKind, uint64_t>> m_scope_kinds;
+    [[nodiscard]] size_t Size() const { return m_pool.size(); }
+
+    // Non copyable and non movable.
+    ReferenceKindPool(const ReferenceKindPool &) = delete;
+    ReferenceKindPool &operator=(const ReferenceKindPool &) = delete;
+    ReferenceKindPool(ReferenceKindPool &&) = delete;
+    ReferenceKindPool &operator=(ReferenceKindPool &&) = delete;
+    ~ReferenceKindPool() = default;
+
+  private:
+    uint32_t NextRawReference() {
+      reference_count++;
+      return reference_count;
+    }
+
+    uint32_t reference_count = 0;
+    std::vector<VariableStoreType> m_pool;
+  };
 
   /// Variables that are alive in this stop state.
   /// Will be cleared when debuggee resumes.
-  llvm::DenseMap<int64_t, lldb::SBValue> m_referencedvariables;
-
+  ReferenceKindPool<ExpandableValueStore, protocol::eReferenceKindTemporary>
+      m_temporary_kind_pool;
   /// Variables that persist across entire debug session.
   /// These are the variables evaluated from debug console REPL.
-  llvm::DenseMap<int64_t, lldb::SBValue> m_referencedpermanent_variables;
-
-  /// Key = dap_frame_id (encodes both thread index ID and frame ID)
-  /// Value = scopes for the frame (locals, globals, registers)
-  std::map<uint64_t, FrameScopes> m_frames;
+  ReferenceKindPool<ExpandableValueStore, protocol::eReferenceKindPermanent>
+      m_permanent_kind_pool;
+  ReferenceKindPool<ScopeStore, protocol::eReferenceKindScope>
+      m_scope_kind_pool;
 };
 
 } // namespace lldb_dap

diff  --git a/lldb/unittests/DAP/DAPTypesTest.cpp 
b/lldb/unittests/DAP/DAPTypesTest.cpp
index f398c54b724a0..0e6cd26abe2eb 100644
--- a/lldb/unittests/DAP/DAPTypesTest.cpp
+++ b/lldb/unittests/DAP/DAPTypesTest.cpp
@@ -58,3 +58,50 @@ TEST(DAPTypesTest, DAPSymbol) {
   EXPECT_EQ(symbol.size, deserialized_symbol->size);
   EXPECT_EQ(symbol.name, deserialized_symbol->name);
 }
+
+TEST(DapTypesTest, DAP_var_ref_t) {
+  // Check the masked ref constructor.
+  const uint32_t scope_masked_var_ref = 0x2000001;
+  const var_ref_t scope_ref(scope_masked_var_ref);
+  EXPECT_EQ(scope_ref.AsUInt32(), scope_masked_var_ref);
+  EXPECT_EQ(scope_ref.Reference(), 1U);
+  EXPECT_EQ(scope_ref.Kind(), eReferenceKindScope);
+
+  const uint32_t temp_masked_var_ref = 0x0000021;
+  const var_ref_t temp_ref(temp_masked_var_ref);
+  EXPECT_EQ(temp_ref.AsUInt32(), temp_masked_var_ref);
+  EXPECT_EQ(temp_ref.Reference(), 0x21U);
+  EXPECT_EQ(temp_ref.Kind(), eReferenceKindTemporary);
+
+  const uint32_t perm_masked_var_ref = 0x1000032;
+  const var_ref_t perm_ref(perm_masked_var_ref);
+  EXPECT_EQ(perm_ref.AsUInt32(), perm_masked_var_ref);
+  EXPECT_EQ(perm_ref.Reference(), 0x32U);
+  EXPECT_EQ(perm_ref.Kind(), eReferenceKindPermanent);
+
+  const var_ref_t invalid_ref{};
+  EXPECT_EQ(invalid_ref.AsUInt32(), var_ref_t::k_invalid_var_ref);
+  EXPECT_EQ(invalid_ref.Kind(), eReferenceKindInvalid);
+
+  // Check unknown reference kind.
+  const uint32_t unknown_masked_var_ref = 0x14000032;
+  const var_ref_t unknown_ref(unknown_masked_var_ref);
+  EXPECT_EQ(unknown_ref.AsUInt32(), unknown_masked_var_ref);
+  EXPECT_EQ(unknown_ref.Reference(), 0x32U);
+  EXPECT_EQ(unknown_ref.Kind(), eReferenceKindInvalid);
+
+  const var_ref_t no_child_ref(var_ref_t::k_no_child);
+  EXPECT_EQ(no_child_ref.AsUInt32(), 0U);
+  EXPECT_EQ(no_child_ref.Reference(), 0U);
+  EXPECT_EQ(no_child_ref.Kind(), eReferenceKindTemporary);
+
+  // Check the refkind constructor.
+  const uint32_t scope2_masked_ref = 0x2000003;
+  const var_ref_t scope_ref2(3, eReferenceKindScope);
+  EXPECT_EQ(scope_ref2.AsUInt32(), scope2_masked_ref);
+  EXPECT_EQ(scope_ref2.Reference(), 3U);
+  EXPECT_EQ(scope_ref2.Kind(), eReferenceKindScope);
+
+  EXPECT_EQ(var_ref_t().AsUInt32(),
+            var_ref_t{var_ref_t::k_invalid_var_ref}.AsUInt32());
+}

diff  --git a/lldb/unittests/DAP/ProtocolRequestsTest.cpp 
b/lldb/unittests/DAP/ProtocolRequestsTest.cpp
index cdc012b448c8f..18ba5cbf58cfd 100644
--- a/lldb/unittests/DAP/ProtocolRequestsTest.cpp
+++ b/lldb/unittests/DAP/ProtocolRequestsTest.cpp
@@ -14,6 +14,7 @@
 
 using namespace llvm;
 using namespace lldb_dap::protocol;
+using namespace lldb_dap;
 using lldb_private::PrettyPrint;
 using llvm::json::parse;
 
@@ -85,7 +86,7 @@ TEST(ProtocolRequestsTest, EvaluateArguments) {
 TEST(ProtocolRequestsTest, EvaluateResponseBody) {
   EvaluateResponseBody body;
   body.result = "hello world";
-  body.variablesReference = 7;
+  body.variablesReference = var_ref_t(7);
 
   // Check required keys.
   Expected<json::Value> expected = parse(R"({
@@ -99,7 +100,7 @@ TEST(ProtocolRequestsTest, EvaluateResponseBody) {
   // Check optional keys.
   body.result = "'abc'";
   body.type = "string";
-  body.variablesReference = 42;
+  body.variablesReference = var_ref_t(42);
   body.namedVariables = 1;
   body.indexedVariables = 2;
   body.memoryReference = "0x123";

diff  --git a/lldb/unittests/DAP/ProtocolTypesTest.cpp 
b/lldb/unittests/DAP/ProtocolTypesTest.cpp
index 88af97248febc..863fd3c4fe3a3 100644
--- a/lldb/unittests/DAP/ProtocolTypesTest.cpp
+++ b/lldb/unittests/DAP/ProtocolTypesTest.cpp
@@ -291,7 +291,7 @@ TEST(ProtocolTypesTest, Scope) {
   Scope scope;
   scope.name = "Locals";
   scope.presentationHint = Scope::eScopePresentationHintLocals;
-  scope.variablesReference = 1;
+  scope.variablesReference = var_ref_t(1);
   scope.namedVariables = 2;
   scope.indexedVariables = std::nullopt;
   scope.expensive = false;
@@ -311,7 +311,8 @@ TEST(ProtocolTypesTest, Scope) {
   ASSERT_THAT_EXPECTED(deserialized_scope, llvm::Succeeded());
   EXPECT_EQ(scope.name, deserialized_scope->name);
   EXPECT_EQ(scope.presentationHint, deserialized_scope->presentationHint);
-  EXPECT_EQ(scope.variablesReference, deserialized_scope->variablesReference);
+  EXPECT_EQ(scope.variablesReference.AsUInt32(),
+            deserialized_scope->variablesReference.AsUInt32());
   EXPECT_EQ(scope.namedVariables, deserialized_scope->namedVariables);
   EXPECT_EQ(scope.indexedVariables, deserialized_scope->indexedVariables);
   EXPECT_EQ(scope.expensive, deserialized_scope->expensive);
@@ -909,7 +910,7 @@ TEST(ProtocolTypesTest, VariablePresentationHint) {
 TEST(ProtocolTypesTest, Variable) {
   Variable var;
   var.name = "var1";
-  var.variablesReference = 42;
+  var.variablesReference = var_ref_t(42);
   var.value = "value";
   var.type = "type";
 
@@ -954,7 +955,7 @@ TEST(ProtocolTypesTest, VariablesArguments) {
     }
   })");
   ASSERT_THAT_EXPECTED(expected, llvm::Succeeded());
-  EXPECT_EQ(expected->variablesReference, 42u);
+  EXPECT_EQ(expected->variablesReference.AsUInt32(), 42U);
   EXPECT_EQ(expected->filter, VariablesArguments::eVariablesFilterIndexed);
   EXPECT_EQ(expected->start, 10u);
   EXPECT_EQ(expected->count, 5u);
@@ -973,12 +974,12 @@ TEST(ProtocolTypesTest, VariablesArguments) {
 TEST(ProtocolTypesTest, VariablesResponseBody) {
   Variable var1;
   var1.name = "var1";
-  var1.variablesReference = 42;
+  var1.variablesReference = var_ref_t(42);
   var1.value = "<var1-value>";
 
   Variable var2;
   var2.name = "var2";
-  var2.variablesReference = 3;
+  var2.variablesReference = var_ref_t(3);
   var2.value = "<var2-value>";
 
   VariablesResponseBody response{{var1, var2}};
@@ -1113,7 +1114,7 @@ TEST(ProtocolTypesTest, DataBreakpointInfoArguments) {
   })");
   ASSERT_THAT_EXPECTED(expected, llvm::Succeeded());
   EXPECT_EQ(expected->name, "data");
-  EXPECT_EQ(expected->variablesReference, 8);
+  EXPECT_EQ(expected->variablesReference->AsUInt32(), 8U);
   EXPECT_EQ(expected->frameId, 9u);
   EXPECT_EQ(expected->bytes, 10);
   EXPECT_EQ(expected->asAddress, false);

diff  --git a/lldb/unittests/DAP/VariablesTest.cpp 
b/lldb/unittests/DAP/VariablesTest.cpp
index c7ffe42202090..10dd567a4ecca 100644
--- a/lldb/unittests/DAP/VariablesTest.cpp
+++ b/lldb/unittests/DAP/VariablesTest.cpp
@@ -7,18 +7,26 @@
 
//===----------------------------------------------------------------------===//
 
 #include "Variables.h"
+#include "DAPLog.h"
+#include "Protocol/DAPTypes.h"
 #include "Protocol/ProtocolTypes.h"
 #include "lldb/API/SBFrame.h"
 #include "lldb/API/SBValue.h"
-#include "lldb/API/SBValueList.h"
 #include "gtest/gtest.h"
 
 using namespace lldb_dap;
+using namespace lldb_dap::protocol;
 
 class VariablesTest : public ::testing::Test {
+
+public:
+  VariablesTest() : log(llvm::nulls(), mutex), vars(log) {}
+
 protected:
   enum : bool { Permanent = true, Temporary = false };
-  Variables vars;
+  Log::Mutex mutex;
+  Log log;
+  VariableReferenceStorage vars;
 
   static const protocol::Scope *
   FindScope(const std::vector<protocol::Scope> &scopes, llvm::StringRef name) {
@@ -31,20 +39,19 @@ class VariablesTest : public ::testing::Test {
 };
 
 TEST_F(VariablesTest, GetNewVariableReference_UniqueAndRanges) {
-  const int64_t temp1 = vars.GetNewVariableReference(Temporary);
-  const int64_t temp2 = vars.GetNewVariableReference(Temporary);
-  const int64_t perm1 = vars.GetNewVariableReference(Permanent);
-  const int64_t perm2 = vars.GetNewVariableReference(Permanent);
-
-  EXPECT_NE(temp1, temp2);
-  EXPECT_NE(perm1, perm2);
-  EXPECT_LT(temp1, perm1);
-  EXPECT_LT(temp2, perm1);
+  const var_ref_t temp1 = vars.InsertVariable(lldb::SBValue(), Temporary);
+  const var_ref_t temp2 = vars.InsertVariable(lldb::SBValue(), Temporary);
+  const var_ref_t perm1 = vars.InsertVariable(lldb::SBValue(), Permanent);
+  const var_ref_t perm2 = vars.InsertVariable(lldb::SBValue(), Permanent);
+  EXPECT_NE(temp1.AsUInt32(), temp2.AsUInt32());
+  EXPECT_NE(perm1.AsUInt32(), perm2.AsUInt32());
+  EXPECT_LT(temp1.AsUInt32(), perm1.AsUInt32());
+  EXPECT_LT(temp2.AsUInt32(), perm1.AsUInt32());
 }
 
 TEST_F(VariablesTest, InsertAndGetVariable_Temporary) {
   lldb::SBValue dummy;
-  const int64_t ref = vars.InsertVariable(dummy, Temporary);
+  const var_ref_t ref = vars.InsertVariable(dummy, Temporary);
   lldb::SBValue out = vars.GetVariable(ref);
 
   EXPECT_EQ(out.IsValid(), dummy.IsValid());
@@ -52,35 +59,34 @@ TEST_F(VariablesTest, InsertAndGetVariable_Temporary) {
 
 TEST_F(VariablesTest, InsertAndGetVariable_Permanent) {
   lldb::SBValue dummy;
-  const int64_t ref = vars.InsertVariable(dummy, Permanent);
+  const var_ref_t ref = vars.InsertVariable(dummy, Permanent);
   lldb::SBValue out = vars.GetVariable(ref);
 
   EXPECT_EQ(out.IsValid(), dummy.IsValid());
 }
 
 TEST_F(VariablesTest, IsPermanentVariableReference) {
-  const int64_t perm = vars.GetNewVariableReference(Permanent);
-  const int64_t temp = vars.GetNewVariableReference(Temporary);
+  const var_ref_t perm = vars.InsertVariable(lldb::SBValue(), Permanent);
+  const var_ref_t temp = vars.InsertVariable(lldb::SBValue(), Temporary);
 
-  EXPECT_TRUE(Variables::IsPermanentVariableReference(perm));
-  EXPECT_FALSE(Variables::IsPermanentVariableReference(temp));
+  EXPECT_EQ(perm.Kind(), eReferenceKindPermanent);
+  EXPECT_EQ(temp.Kind(), eReferenceKindTemporary);
 }
 
 TEST_F(VariablesTest, Clear_RemovesTemporaryKeepsPermanent) {
   lldb::SBValue dummy;
-  const int64_t temp = vars.InsertVariable(dummy, Temporary);
-  const int64_t perm = vars.InsertVariable(dummy, Permanent);
+  const var_ref_t temp = vars.InsertVariable(dummy, Temporary);
+  const var_ref_t perm = vars.InsertVariable(dummy, Permanent);
   vars.Clear();
 
   EXPECT_FALSE(vars.GetVariable(temp).IsValid());
   EXPECT_EQ(vars.GetVariable(perm).IsValid(), dummy.IsValid());
 }
 
-TEST_F(VariablesTest, GetTopLevelScope_ReturnsCorrectScope) {
+TEST_F(VariablesTest, VariablesStore) {
   lldb::SBFrame frame;
-  uint32_t frame_id = 0;
 
-  std::vector<protocol::Scope> scopes = vars.CreateScopes(frame_id, frame);
+  std::vector<protocol::Scope> scopes = vars.CreateScopes(frame);
 
   const protocol::Scope *locals_scope = FindScope(scopes, "Locals");
   const protocol::Scope *globals_scope = FindScope(scopes, "Globals");
@@ -90,27 +96,30 @@ TEST_F(VariablesTest, GetTopLevelScope_ReturnsCorrectScope) 
{
   ASSERT_NE(globals_scope, nullptr);
   ASSERT_NE(registers_scope, nullptr);
 
-  auto locals_data = vars.GetTopLevelScope(locals_scope->variablesReference);
-  auto globals_data = vars.GetTopLevelScope(globals_scope->variablesReference);
-  auto registers_data =
-      vars.GetTopLevelScope(registers_scope->variablesReference);
+  auto *locals_store = vars.GetVariableStore(locals_scope->variablesReference);
+  auto *globals_store =
+      vars.GetVariableStore(globals_scope->variablesReference);
+  auto *registers_store =
+      vars.GetVariableStore(registers_scope->variablesReference);
 
-  ASSERT_TRUE(locals_data.has_value());
-  ASSERT_TRUE(globals_data.has_value());
-  ASSERT_TRUE(registers_data.has_value());
+  ASSERT_NE(locals_store, nullptr);
+  ASSERT_NE(globals_store, nullptr);
+  ASSERT_NE(registers_store, nullptr);
 
-  EXPECT_EQ(locals_data->kind, eScopeKindLocals);
-  EXPECT_EQ(globals_data->kind, eScopeKindGlobals);
-  EXPECT_EQ(registers_data->kind, eScopeKindRegisters);
+  const var_ref_t local_ref = locals_scope->variablesReference;
+  const var_ref_t global_ref = globals_scope->variablesReference;
+  const var_ref_t register_ref = registers_scope->variablesReference;
+  ASSERT_EQ(global_ref.Kind(), eReferenceKindScope);
+  ASSERT_EQ(local_ref.Kind(), eReferenceKindScope);
+  ASSERT_EQ(register_ref.Kind(), eReferenceKindScope);
 
-  EXPECT_FALSE(vars.GetTopLevelScope(9999).has_value());
+  EXPECT_EQ(vars.GetVariableStore(var_ref_t(9999)), nullptr);
 }
 
 TEST_F(VariablesTest, FindVariable_LocalsByName) {
   lldb::SBFrame frame;
-  uint32_t frame_id = 0;
 
-  std::vector<protocol::Scope> scopes = vars.CreateScopes(frame_id, frame);
+  std::vector<protocol::Scope> scopes = vars.CreateScopes(frame);
 
   const protocol::Scope *locals_scope = FindScope(scopes, "Locals");
   ASSERT_NE(locals_scope, nullptr);


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

Reply via email to