1566bfbb7SDanil Stefaniuc //===-- GenericBitset.cpp //-----------------------------------------------===//
2566bfbb7SDanil Stefaniuc //
3566bfbb7SDanil Stefaniuc // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4566bfbb7SDanil Stefaniuc // See https://llvm.org/LICENSE.txt for license information.
5566bfbb7SDanil Stefaniuc // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6566bfbb7SDanil Stefaniuc //
7566bfbb7SDanil Stefaniuc //===----------------------------------------------------------------------===//
8566bfbb7SDanil Stefaniuc
9566bfbb7SDanil Stefaniuc #include "LibCxx.h"
10566bfbb7SDanil Stefaniuc #include "LibStdcpp.h"
11566bfbb7SDanil Stefaniuc #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
12566bfbb7SDanil Stefaniuc #include "lldb/DataFormatters/FormattersHelpers.h"
13566bfbb7SDanil Stefaniuc #include "lldb/Target/Target.h"
14566bfbb7SDanil Stefaniuc
15566bfbb7SDanil Stefaniuc using namespace lldb;
16566bfbb7SDanil Stefaniuc using namespace lldb_private;
17566bfbb7SDanil Stefaniuc
18566bfbb7SDanil Stefaniuc namespace {
19566bfbb7SDanil Stefaniuc
20566bfbb7SDanil Stefaniuc /// This class can be used for handling bitsets from both libcxx and libstdcpp.
21566bfbb7SDanil Stefaniuc class GenericBitsetFrontEnd : public SyntheticChildrenFrontEnd {
22566bfbb7SDanil Stefaniuc public:
23566bfbb7SDanil Stefaniuc enum class StdLib {
24566bfbb7SDanil Stefaniuc LibCxx,
25566bfbb7SDanil Stefaniuc LibStdcpp,
26566bfbb7SDanil Stefaniuc };
27566bfbb7SDanil Stefaniuc
28566bfbb7SDanil Stefaniuc GenericBitsetFrontEnd(ValueObject &valobj, StdLib stdlib);
29566bfbb7SDanil Stefaniuc
GetIndexOfChildWithName(ConstString name)30566bfbb7SDanil Stefaniuc size_t GetIndexOfChildWithName(ConstString name) override {
31566bfbb7SDanil Stefaniuc return formatters::ExtractIndexFromString(name.GetCString());
32566bfbb7SDanil Stefaniuc }
33566bfbb7SDanil Stefaniuc
MightHaveChildren()34566bfbb7SDanil Stefaniuc bool MightHaveChildren() override { return true; }
35566bfbb7SDanil Stefaniuc bool Update() override;
CalculateNumChildren()36566bfbb7SDanil Stefaniuc size_t CalculateNumChildren() override { return m_elements.size(); }
37566bfbb7SDanil Stefaniuc ValueObjectSP GetChildAtIndex(size_t idx) override;
38566bfbb7SDanil Stefaniuc
39566bfbb7SDanil Stefaniuc private:
40566bfbb7SDanil Stefaniuc ConstString GetDataContainerMemberName();
41566bfbb7SDanil Stefaniuc
42566bfbb7SDanil Stefaniuc // The lifetime of a ValueObject and all its derivative ValueObjects
43566bfbb7SDanil Stefaniuc // (children, clones, etc.) is managed by a ClusterManager. These
44566bfbb7SDanil Stefaniuc // objects are only destroyed when every shared pointer to any of them
45566bfbb7SDanil Stefaniuc // is destroyed, so we must not store a shared pointer to any ValueObject
46566bfbb7SDanil Stefaniuc // derived from our backend ValueObject (since we're in the same cluster).
47566bfbb7SDanil Stefaniuc // Value objects created from raw data (i.e. in a different cluster) must
48566bfbb7SDanil Stefaniuc // be referenced via shared pointer to keep them alive, however.
49566bfbb7SDanil Stefaniuc std::vector<ValueObjectSP> m_elements;
50566bfbb7SDanil Stefaniuc ValueObject *m_first = nullptr;
51566bfbb7SDanil Stefaniuc CompilerType m_bool_type;
52566bfbb7SDanil Stefaniuc ByteOrder m_byte_order = eByteOrderInvalid;
53566bfbb7SDanil Stefaniuc uint8_t m_byte_size = 0;
54566bfbb7SDanil Stefaniuc StdLib m_stdlib;
55566bfbb7SDanil Stefaniuc };
56566bfbb7SDanil Stefaniuc } // namespace
57566bfbb7SDanil Stefaniuc
GenericBitsetFrontEnd(ValueObject & valobj,StdLib stdlib)58566bfbb7SDanil Stefaniuc GenericBitsetFrontEnd::GenericBitsetFrontEnd(ValueObject &valobj, StdLib stdlib)
59566bfbb7SDanil Stefaniuc : SyntheticChildrenFrontEnd(valobj), m_stdlib(stdlib) {
60566bfbb7SDanil Stefaniuc m_bool_type = valobj.GetCompilerType().GetBasicTypeFromAST(eBasicTypeBool);
61566bfbb7SDanil Stefaniuc if (auto target_sp = m_backend.GetTargetSP()) {
62566bfbb7SDanil Stefaniuc m_byte_order = target_sp->GetArchitecture().GetByteOrder();
63566bfbb7SDanil Stefaniuc m_byte_size = target_sp->GetArchitecture().GetAddressByteSize();
64566bfbb7SDanil Stefaniuc Update();
65566bfbb7SDanil Stefaniuc }
66566bfbb7SDanil Stefaniuc }
67566bfbb7SDanil Stefaniuc
GetDataContainerMemberName()68566bfbb7SDanil Stefaniuc ConstString GenericBitsetFrontEnd::GetDataContainerMemberName() {
69566bfbb7SDanil Stefaniuc switch (m_stdlib) {
70566bfbb7SDanil Stefaniuc case StdLib::LibCxx:
71566bfbb7SDanil Stefaniuc return ConstString("__first_");
72566bfbb7SDanil Stefaniuc case StdLib::LibStdcpp:
73566bfbb7SDanil Stefaniuc return ConstString("_M_w");
74566bfbb7SDanil Stefaniuc }
75*49d38b1dSSimon Pilgrim llvm_unreachable("Unknown StdLib enum");
76566bfbb7SDanil Stefaniuc }
77566bfbb7SDanil Stefaniuc
Update()78566bfbb7SDanil Stefaniuc bool GenericBitsetFrontEnd::Update() {
79566bfbb7SDanil Stefaniuc m_elements.clear();
80566bfbb7SDanil Stefaniuc m_first = nullptr;
81566bfbb7SDanil Stefaniuc
82566bfbb7SDanil Stefaniuc TargetSP target_sp = m_backend.GetTargetSP();
83566bfbb7SDanil Stefaniuc if (!target_sp)
84566bfbb7SDanil Stefaniuc return false;
85566bfbb7SDanil Stefaniuc
86566bfbb7SDanil Stefaniuc size_t size = 0;
87566bfbb7SDanil Stefaniuc
88566bfbb7SDanil Stefaniuc if (auto arg = m_backend.GetCompilerType().GetIntegralTemplateArgument(0))
89193bf2e8SDanil Stefaniuc size = arg->value.getLimitedValue();
90566bfbb7SDanil Stefaniuc
91566bfbb7SDanil Stefaniuc m_elements.assign(size, ValueObjectSP());
92566bfbb7SDanil Stefaniuc m_first = m_backend.GetChildMemberWithName(GetDataContainerMemberName(), true)
93566bfbb7SDanil Stefaniuc .get();
94566bfbb7SDanil Stefaniuc return false;
95566bfbb7SDanil Stefaniuc }
96566bfbb7SDanil Stefaniuc
GetChildAtIndex(size_t idx)97566bfbb7SDanil Stefaniuc ValueObjectSP GenericBitsetFrontEnd::GetChildAtIndex(size_t idx) {
98566bfbb7SDanil Stefaniuc if (idx >= m_elements.size() || !m_first)
99566bfbb7SDanil Stefaniuc return ValueObjectSP();
100566bfbb7SDanil Stefaniuc
101566bfbb7SDanil Stefaniuc if (m_elements[idx])
102566bfbb7SDanil Stefaniuc return m_elements[idx];
103566bfbb7SDanil Stefaniuc
104566bfbb7SDanil Stefaniuc ExecutionContext ctx = m_backend.GetExecutionContextRef().Lock(false);
105566bfbb7SDanil Stefaniuc CompilerType type;
106566bfbb7SDanil Stefaniuc ValueObjectSP chunk;
107566bfbb7SDanil Stefaniuc // For small bitsets __first_ is not an array, but a plain size_t.
108566bfbb7SDanil Stefaniuc if (m_first->GetCompilerType().IsArrayType(&type)) {
109566bfbb7SDanil Stefaniuc llvm::Optional<uint64_t> bit_size =
110566bfbb7SDanil Stefaniuc type.GetBitSize(ctx.GetBestExecutionContextScope());
111566bfbb7SDanil Stefaniuc if (!bit_size || *bit_size == 0)
112566bfbb7SDanil Stefaniuc return {};
113566bfbb7SDanil Stefaniuc chunk = m_first->GetChildAtIndex(idx / *bit_size, true);
114566bfbb7SDanil Stefaniuc } else {
115566bfbb7SDanil Stefaniuc type = m_first->GetCompilerType();
116566bfbb7SDanil Stefaniuc chunk = m_first->GetSP();
117566bfbb7SDanil Stefaniuc }
118566bfbb7SDanil Stefaniuc if (!type || !chunk)
119566bfbb7SDanil Stefaniuc return {};
120566bfbb7SDanil Stefaniuc
121566bfbb7SDanil Stefaniuc llvm::Optional<uint64_t> bit_size =
122566bfbb7SDanil Stefaniuc type.GetBitSize(ctx.GetBestExecutionContextScope());
123566bfbb7SDanil Stefaniuc if (!bit_size || *bit_size == 0)
124566bfbb7SDanil Stefaniuc return {};
125566bfbb7SDanil Stefaniuc size_t chunk_idx = idx % *bit_size;
126566bfbb7SDanil Stefaniuc uint8_t value = !!(chunk->GetValueAsUnsigned(0) & (uint64_t(1) << chunk_idx));
127566bfbb7SDanil Stefaniuc DataExtractor data(&value, sizeof(value), m_byte_order, m_byte_size);
128566bfbb7SDanil Stefaniuc
129566bfbb7SDanil Stefaniuc m_elements[idx] = CreateValueObjectFromData(llvm::formatv("[{0}]", idx).str(),
130566bfbb7SDanil Stefaniuc data, ctx, m_bool_type);
131566bfbb7SDanil Stefaniuc
132566bfbb7SDanil Stefaniuc return m_elements[idx];
133566bfbb7SDanil Stefaniuc }
134566bfbb7SDanil Stefaniuc
LibStdcppBitsetSyntheticFrontEndCreator(CXXSyntheticChildren *,lldb::ValueObjectSP valobj_sp)135566bfbb7SDanil Stefaniuc SyntheticChildrenFrontEnd *formatters::LibStdcppBitsetSyntheticFrontEndCreator(
136566bfbb7SDanil Stefaniuc CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
137566bfbb7SDanil Stefaniuc if (valobj_sp)
138566bfbb7SDanil Stefaniuc return new GenericBitsetFrontEnd(*valobj_sp,
139566bfbb7SDanil Stefaniuc GenericBitsetFrontEnd::StdLib::LibStdcpp);
140566bfbb7SDanil Stefaniuc return nullptr;
141566bfbb7SDanil Stefaniuc }
142566bfbb7SDanil Stefaniuc
LibcxxBitsetSyntheticFrontEndCreator(CXXSyntheticChildren *,lldb::ValueObjectSP valobj_sp)143566bfbb7SDanil Stefaniuc SyntheticChildrenFrontEnd *formatters::LibcxxBitsetSyntheticFrontEndCreator(
144566bfbb7SDanil Stefaniuc CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
145566bfbb7SDanil Stefaniuc if (valobj_sp)
146566bfbb7SDanil Stefaniuc return new GenericBitsetFrontEnd(*valobj_sp,
147566bfbb7SDanil Stefaniuc GenericBitsetFrontEnd::StdLib::LibCxx);
148566bfbb7SDanil Stefaniuc return nullptr;
149566bfbb7SDanil Stefaniuc }
150