1 //===-- NSIndexPath.cpp ---------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
11 #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
12 #include "lldb/DataFormatters/FormattersHelpers.h"
13 #include "lldb/DataFormatters/TypeSynthetic.h"
14 #include "lldb/Target/Process.h"
15 #include "lldb/Target/Target.h"
16 #include "lldb/ValueObject/ValueObject.h"
17 #include "lldb/ValueObject/ValueObjectConstResult.h"
19 #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
21 using namespace lldb_private
;
22 using namespace lldb_private::formatters
;
24 static constexpr size_t PACKED_INDEX_SHIFT_64(size_t i
) {
25 return (60 - (13 * (4 - i
)));
28 static constexpr size_t PACKED_INDEX_SHIFT_32(size_t i
) {
29 return (32 - (13 * (2 - i
)));
32 class NSIndexPathSyntheticFrontEnd
: public SyntheticChildrenFrontEnd
{
34 NSIndexPathSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp
)
35 : SyntheticChildrenFrontEnd(*valobj_sp
.get()), m_descriptor_sp(nullptr),
36 m_impl(), m_uint_star_type() {
38 m_backend
.GetTargetSP()->GetArchitecture().GetAddressByteSize();
41 ~NSIndexPathSyntheticFrontEnd() override
= default;
43 llvm::Expected
<uint32_t> CalculateNumChildren() override
{
44 return m_impl
.GetNumIndexes();
47 lldb::ValueObjectSP
GetChildAtIndex(uint32_t idx
) override
{
48 return m_impl
.GetIndexAtIndex(idx
, m_uint_star_type
);
51 lldb::ChildCacheState
Update() override
{
54 auto type_system
= m_backend
.GetCompilerType().GetTypeSystem();
56 return lldb::ChildCacheState::eRefetch
;
58 auto ast
= ScratchTypeSystemClang::GetForTarget(
59 *m_backend
.GetExecutionContextRef().GetTargetSP());
61 return lldb::ChildCacheState::eRefetch
;
63 m_uint_star_type
= ast
->GetPointerSizedIntType(false);
65 static ConstString
g__indexes("_indexes");
66 static ConstString
g__length("_length");
68 ProcessSP process_sp
= m_backend
.GetProcessSP();
70 return lldb::ChildCacheState::eRefetch
;
72 ObjCLanguageRuntime
*runtime
= ObjCLanguageRuntime::Get(*process_sp
);
75 return lldb::ChildCacheState::eRefetch
;
77 ObjCLanguageRuntime::ClassDescriptorSP
descriptor(
78 runtime
->GetClassDescriptor(m_backend
));
80 if (!descriptor
.get() || !descriptor
->IsValid())
81 return lldb::ChildCacheState::eRefetch
;
83 uint64_t info_bits(0), value_bits(0), payload(0);
85 if (descriptor
->GetTaggedPointerInfo(&info_bits
, &value_bits
, &payload
)) {
86 m_impl
.m_inlined
.SetIndexes(payload
, *process_sp
);
87 m_impl
.m_mode
= Mode::Inlined
;
89 ObjCLanguageRuntime::ClassDescriptor::iVarDescriptor _indexes_id
;
90 ObjCLanguageRuntime::ClassDescriptor::iVarDescriptor _length_id
;
92 bool has_indexes(false), has_length(false);
94 for (size_t x
= 0; x
< descriptor
->GetNumIVars(); x
++) {
95 const auto &ivar
= descriptor
->GetIVarAtIndex(x
);
96 if (ivar
.m_name
== g__indexes
) {
99 } else if (ivar
.m_name
== g__length
) {
104 if (has_length
&& has_indexes
)
108 if (has_length
&& has_indexes
) {
109 m_impl
.m_outsourced
.m_indexes
=
111 .GetSyntheticChildAtOffset(_indexes_id
.m_offset
,
112 m_uint_star_type
.GetPointerType(),
115 ValueObjectSP
length_sp(m_backend
.GetSyntheticChildAtOffset(
116 _length_id
.m_offset
, m_uint_star_type
, true));
118 m_impl
.m_outsourced
.m_count
= length_sp
->GetValueAsUnsigned(0);
119 if (m_impl
.m_outsourced
.m_indexes
)
120 m_impl
.m_mode
= Mode::Outsourced
;
124 return lldb::ChildCacheState::eRefetch
;
127 bool MightHaveChildren() override
{ return m_impl
.m_mode
!= Mode::Invalid
; }
129 size_t GetIndexOfChildWithName(ConstString name
) override
{
130 const char *item_name
= name
.GetCString();
131 uint32_t idx
= ExtractIndexFromString(item_name
);
132 if (idx
< UINT32_MAX
&& idx
>= CalculateNumChildrenIgnoringErrors())
137 lldb::ValueObjectSP
GetSyntheticValue() override
{ return nullptr; }
140 ObjCLanguageRuntime::ClassDescriptorSP m_descriptor_sp
;
142 enum class Mode
{ Inlined
, Outsourced
, Invalid
};
145 size_t GetNumIndexes() {
148 return m_inlined
.GetNumIndexes();
149 case Mode::Outsourced
:
150 return m_outsourced
.m_count
;
156 lldb::ValueObjectSP
GetIndexAtIndex(size_t idx
,
157 const CompilerType
&desired_type
) {
158 if (idx
>= GetNumIndexes())
164 return m_inlined
.GetIndexAtIndex(idx
, desired_type
);
165 case Mode::Outsourced
:
166 return m_outsourced
.GetIndexAtIndex(idx
);
170 struct InlinedIndexes
{
172 void SetIndexes(uint64_t value
, Process
&p
) {
174 _lengthForInlinePayload(p
.GetAddressByteSize());
178 size_t GetNumIndexes() { return m_count
; }
180 lldb::ValueObjectSP
GetIndexAtIndex(size_t idx
,
181 const CompilerType
&desired_type
) {
185 std::pair
<uint64_t, bool> value(_indexAtPositionForInlinePayload(idx
));
190 if (m_ptr_size
== 8) {
191 Scalar
scalar((unsigned long long)value
.first
);
194 Scalar
scalar((unsigned int)value
.first
);
198 v
.SetCompilerType(desired_type
);
200 StreamString idx_name
;
201 idx_name
.Printf("[%" PRIu64
"]", (uint64_t)idx
);
203 return ValueObjectConstResult::Create(
204 m_process
, v
, ConstString(idx_name
.GetString()));
217 uint64_t m_indexes
= 0;
219 uint32_t m_ptr_size
= 0;
220 Process
*m_process
= nullptr;
222 // cfr. Foundation for the details of this code
223 size_t _lengthForInlinePayload(uint32_t ptr_size
) {
224 m_ptr_size
= ptr_size
;
226 m_count
= ((m_indexes
>> 3) & 0x7);
228 m_count
= ((m_indexes
>> 3) & 0x3);
232 std::pair
<uint64_t, bool> _indexAtPositionForInlinePayload(size_t pos
) {
233 static const uint64_t PACKED_INDEX_MASK
= ((1 << 13) - 1);
234 if (m_ptr_size
== 8) {
240 return {(m_indexes
>> PACKED_INDEX_SHIFT_64(pos
)) &
250 return {(m_indexes
>> PACKED_INDEX_SHIFT_32(pos
)) &
261 struct OutsourcedIndexes
{
262 lldb::ValueObjectSP
GetIndexAtIndex(size_t idx
) {
264 ValueObjectSP
index_sp(m_indexes
->GetSyntheticArrayMember(idx
, true));
275 OutsourcedIndexes() {}
277 ValueObject
*m_indexes
= nullptr;
282 struct InlinedIndexes m_inlined
;
283 struct OutsourcedIndexes m_outsourced
;
291 case Mode::Outsourced
:
292 m_outsourced
.Clear();
297 m_mode
= Mode::Invalid
;
302 Mode m_mode
= Mode::Invalid
;
305 uint32_t m_ptr_size
= 0;
306 CompilerType m_uint_star_type
;
309 namespace lldb_private
{
310 namespace formatters
{
312 SyntheticChildrenFrontEnd
*
313 NSIndexPathSyntheticFrontEndCreator(CXXSyntheticChildren
*,
314 lldb::ValueObjectSP valobj_sp
) {
316 return new NSIndexPathSyntheticFrontEnd(valobj_sp
);
320 } // namespace formatters
321 } // namespace lldb_private