================
@@ -40,92 +48,225 @@ enum ScopeKind : unsigned {
///
/// \return
/// A `protocol::Scope`
-protocol::Scope CreateScope(const ScopeKind kind, int64_t variablesReference,
- int64_t namedVariables, bool expensive);
+protocol::Scope CreateScope(ScopeKind kind, uint32_t variablesReference,
+ uint32_t namedVariables, 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(uint32_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);
+ uint32_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(uint32_t var_ref);
/// Insert a new \p variable.
/// \return variableReference assigned to this expandable variable.
- int64_t InsertVariable(lldb::SBValue variable, bool is_permanent);
+ uint32_t InsertVariable(const lldb::SBValue &variable, bool is_permanent);
- std::optional<ScopeData> GetTopLevelScope(int64_t variablesReference);
+ lldb::SBValue FindVariable(uint32_t variablesReference, llvm::StringRef
name);
- lldb::SBValue FindVariable(uint64_t variablesReference, llvm::StringRef
name);
+ std::vector<protocol::Scope> CreateScopes(lldb::SBFrame &frame);
+
+ void Clear() {
+ m_temporary_kind_pool.Clear();
+ m_scope_kind_pool.Clear();
+ }
- /// 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);
+ VariableStore *GetVariableStore(uint32_t var_ref);
- /// Clear all scope variables and non-permanent expandable variables.
- void Clear();
+ static ReferenceKind GetReferenceKind(uint32_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();
- /// Variable reference start index of permanent expandable variable.
- static constexpr int64_t PermanentVariableStartIndex = (1ll << 32);
+ /// 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");
- int64_t m_next_permanent_var_ref{PermanentVariableStartIndex};
- int64_t m_next_temporary_var_ref{TemporaryVariableStartIndex};
+ /// 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 {
----------------
da-viper wrote:
I used the template because I can disable the `Clear` function for permanent
types and I don't need to store the ReferenceKind's mask created
https://github.com/llvm/llvm-project/pull/179262
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits