================
@@ -32,100 +40,240 @@ 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);
+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;
 
-struct ScopeData {
-  ScopeKind kind;
-  lldb::SBValueList scope;
+  // 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 : 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) final;
+  lldb::SBValue FindVariable(llvm::StringRef name) final;
+
+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 {
+/// 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 : 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) final;
+  lldb::SBValue FindVariable(llvm::StringRef name) final;
+  [[nodiscard]] lldb::SBValue GetVariable() const { return m_value; };
+
+private:
+  lldb::SBValue m_value;
+};
+
+struct VariableReferenceStorage {
   /// 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);
+  static bool IsPermanentVariableReference(var_ref_t var_ref);
 
   /// \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 masked_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);
+
+  static ReferenceKind GetReferenceKind(var_ref_t var_ref);
 
 private:
   /// Variable reference start index of temporary variables.
-  static constexpr int64_t TemporaryVariableStartIndex = 1;
+  static constexpr uint8_t k_temporary_kind_byte = 0b0000;
+  /// Permanent reference mask for permanent expandable variables.
+  static constexpr uint8_t k_permanent_kind_byte = 0b0001;
+  /// Scope reference mask for scope types.
+  static constexpr uint8_t k_scope_kind_byte = 0b0010;
+  static constexpr uint32_t max_reference_value =
+      std::numeric_limits<int32_t>::max();
+
+  /// The most significant byte is used for storing the reference kind.
+  static constexpr uint32_t k_reference_kind_bit_size =
+      std::numeric_limits<uint8_t>::digits;
+  /// The start bit offset in the variable reference used to store the 
reference
+  /// kind.
+  static constexpr uint32_t k_reference_kind_bit_offset =
+      std::numeric_limits<uint32_t>::digits - k_reference_kind_bit_size;
+  // we should be able to store at least 8 million variables for each store
+  // type at every stopped state.
+  static constexpr uint32_t k_min_number_of_variables = 8'000'000;
+  // Sanity check of the amount of variables we can store.
+  static_assert(((max_reference_value >> k_reference_kind_bit_size) >
+                 k_min_number_of_variables) &&
+                "Not enough space to store 8 million variables");
+  // Ensure reference kind bytes are unique.
+  static_assert(k_temporary_kind_byte != k_permanent_kind_byte,
+                "Temporary and permanent kind bytes must be different");
+  static_assert(k_temporary_kind_byte != k_scope_kind_byte,
+                "Temporary kind and scope bytes must be different");
+  static_assert(k_permanent_kind_byte != k_scope_kind_byte,
+                "Permanent kind and scope bytes must be different");
 
-  /// Variable reference start index of permanent expandable variable.
-  static constexpr int64_t PermanentVariableStartIndex = (1ll << 32);
+  /// 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 ReferenceKindByte
+  ///     The bitmask used to identify this pool's references
+  template <typename VariableStoreType, ReferenceKind Kind>
+  class ReferenceKindPool {
 
-  int64_t m_next_permanent_var_ref{PermanentVariableStartIndex};
-  int64_t m_next_temporary_var_ref{TemporaryVariableStartIndex};
+  public:
+    static constexpr uint8_t k_reference_kind_byte = []() {
+      switch (Kind) {
+      case eReferenceKindPermanent:
+        return k_permanent_kind_byte;
+      case eReferenceKindTemporary:
+        return k_temporary_kind_byte;
+      case eReferenceKindScope:
+        return k_scope_kind_byte;
+      }
+      llvm_unreachable("Unknown reference kind");
+    }();
 
-  // Variable Reference,                 dap_frame_id
-  std::map<int64_t, std::pair<ScopeKind, uint64_t>> m_scope_kinds;
+    static constexpr var_ref_t k_reference_mask =
+        k_reference_kind_byte << k_reference_kind_bit_offset;
+    static constexpr var_ref_t k_reference_max_size =
+        (1 << k_reference_kind_bit_offset) - 1;
+
+    static_assert(
+        ((k_reference_mask + k_min_number_of_variables) <
+         max_reference_value) &&
+        "Cannot store minimum number of variables without overflowing");
+
+    explicit ReferenceKindPool() = default;
+
+    /// Resets the count to zero and clears the pool.
+    template <ReferenceKind LHS = Kind,
+              ReferenceKind RHS = eReferenceKindPermanent>
+    std::enable_if_t<LHS != RHS, void> Clear() {
+      reference_count = 0;
+      m_pool.clear();
+    }
+
+    VariableStoreType *GetVariableStore(var_ref_t masked_var_ref) {
+      const var_ref_t var_ref = ClearMask(masked_var_ref);
+
+      if (var_ref != 0 && var_ref <= m_pool.size())
+        return &m_pool[var_ref - 1];
+      return nullptr;
+    }
+
+    var_ref_t ClearMask(var_ref_t masked_var_ref) {
+      return masked_var_ref & ~k_reference_mask;
+    }
+
+    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");
+
+      m_pool.emplace_back(std::forward<Args>(args)...);
+      const var_ref_t next_var_ref = NextReference();
+
+      assert(next_var_ref < k_reference_max_size &&
+             "Exceeds the maximum variablesReference");
+      return next_var_ref | k_reference_mask;
+    }
+
+    size_t Size() { return m_pool.size(); }
----------------
DrSergei wrote:

I guess some methods in this class should be marked as const (e.g. `Size`, 
`ClearMask`, `GetVariableStore`)

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

Reply via email to