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