================
@@ -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 ®isters;
- }
+/// 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