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/Core/ValueObject.h"
13 #include "lldb/Core/ValueObjectConstResult.h"
14 #include "lldb/DataFormatters/FormattersHelpers.h"
15 #include "lldb/DataFormatters/TypeSynthetic.h"
16 #include "lldb/Target/Process.h"
17 #include "lldb/Target/Target.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 size_t CalculateNumChildren() override
{ return m_impl
.GetNumIndexes(); }
45 lldb::ValueObjectSP
GetChildAtIndex(size_t idx
) override
{
46 return m_impl
.GetIndexAtIndex(idx
, m_uint_star_type
);
49 bool Update() override
{
52 auto type_system
= m_backend
.GetCompilerType().GetTypeSystem();
56 auto ast
= ScratchTypeSystemClang::GetForTarget(
57 *m_backend
.GetExecutionContextRef().GetTargetSP());
61 m_uint_star_type
= ast
->GetPointerSizedIntType(false);
63 static ConstString
g__indexes("_indexes");
64 static ConstString
g__length("_length");
66 ProcessSP process_sp
= m_backend
.GetProcessSP();
70 ObjCLanguageRuntime
*runtime
= ObjCLanguageRuntime::Get(*process_sp
);
75 ObjCLanguageRuntime::ClassDescriptorSP
descriptor(
76 runtime
->GetClassDescriptor(m_backend
));
78 if (!descriptor
.get() || !descriptor
->IsValid())
81 uint64_t info_bits(0), value_bits(0), payload(0);
83 if (descriptor
->GetTaggedPointerInfo(&info_bits
, &value_bits
, &payload
)) {
84 m_impl
.m_inlined
.SetIndexes(payload
, *process_sp
);
85 m_impl
.m_mode
= Mode::Inlined
;
87 ObjCLanguageRuntime::ClassDescriptor::iVarDescriptor _indexes_id
;
88 ObjCLanguageRuntime::ClassDescriptor::iVarDescriptor _length_id
;
90 bool has_indexes(false), has_length(false);
92 for (size_t x
= 0; x
< descriptor
->GetNumIVars(); x
++) {
93 const auto &ivar
= descriptor
->GetIVarAtIndex(x
);
94 if (ivar
.m_name
== g__indexes
) {
97 } else if (ivar
.m_name
== g__length
) {
102 if (has_length
&& has_indexes
)
106 if (has_length
&& has_indexes
) {
107 m_impl
.m_outsourced
.m_indexes
=
109 .GetSyntheticChildAtOffset(_indexes_id
.m_offset
,
110 m_uint_star_type
.GetPointerType(),
113 ValueObjectSP
length_sp(m_backend
.GetSyntheticChildAtOffset(
114 _length_id
.m_offset
, m_uint_star_type
, true));
116 m_impl
.m_outsourced
.m_count
= length_sp
->GetValueAsUnsigned(0);
117 if (m_impl
.m_outsourced
.m_indexes
)
118 m_impl
.m_mode
= Mode::Outsourced
;
125 bool MightHaveChildren() override
{ return m_impl
.m_mode
!= Mode::Invalid
; }
127 size_t GetIndexOfChildWithName(ConstString name
) override
{
128 const char *item_name
= name
.GetCString();
129 uint32_t idx
= ExtractIndexFromString(item_name
);
130 if (idx
< UINT32_MAX
&& idx
>= CalculateNumChildren())
135 lldb::ValueObjectSP
GetSyntheticValue() override
{ return nullptr; }
138 ObjCLanguageRuntime::ClassDescriptorSP m_descriptor_sp
;
140 enum class Mode
{ Inlined
, Outsourced
, Invalid
};
143 size_t GetNumIndexes() {
146 return m_inlined
.GetNumIndexes();
147 case Mode::Outsourced
:
148 return m_outsourced
.m_count
;
154 lldb::ValueObjectSP
GetIndexAtIndex(size_t idx
,
155 const CompilerType
&desired_type
) {
156 if (idx
>= GetNumIndexes())
162 return m_inlined
.GetIndexAtIndex(idx
, desired_type
);
163 case Mode::Outsourced
:
164 return m_outsourced
.GetIndexAtIndex(idx
);
168 struct InlinedIndexes
{
170 void SetIndexes(uint64_t value
, Process
&p
) {
172 _lengthForInlinePayload(p
.GetAddressByteSize());
176 size_t GetNumIndexes() { return m_count
; }
178 lldb::ValueObjectSP
GetIndexAtIndex(size_t idx
,
179 const CompilerType
&desired_type
) {
183 std::pair
<uint64_t, bool> value(_indexAtPositionForInlinePayload(idx
));
188 if (m_ptr_size
== 8) {
189 Scalar
scalar((unsigned long long)value
.first
);
192 Scalar
scalar((unsigned int)value
.first
);
196 v
.SetCompilerType(desired_type
);
198 StreamString idx_name
;
199 idx_name
.Printf("[%" PRIu64
"]", (uint64_t)idx
);
201 return ValueObjectConstResult::Create(
202 m_process
, v
, ConstString(idx_name
.GetString()));
215 uint64_t m_indexes
= 0;
217 uint32_t m_ptr_size
= 0;
218 Process
*m_process
= nullptr;
220 // cfr. Foundation for the details of this code
221 size_t _lengthForInlinePayload(uint32_t ptr_size
) {
222 m_ptr_size
= ptr_size
;
224 m_count
= ((m_indexes
>> 3) & 0x7);
226 m_count
= ((m_indexes
>> 3) & 0x3);
230 std::pair
<uint64_t, bool> _indexAtPositionForInlinePayload(size_t pos
) {
231 static const uint64_t PACKED_INDEX_MASK
= ((1 << 13) - 1);
232 if (m_ptr_size
== 8) {
238 return {(m_indexes
>> PACKED_INDEX_SHIFT_64(pos
)) &
248 return {(m_indexes
>> PACKED_INDEX_SHIFT_32(pos
)) &
259 struct OutsourcedIndexes
{
260 lldb::ValueObjectSP
GetIndexAtIndex(size_t idx
) {
262 ValueObjectSP
index_sp(m_indexes
->GetSyntheticArrayMember(idx
, true));
273 OutsourcedIndexes() {}
275 ValueObject
*m_indexes
= nullptr;
280 struct InlinedIndexes m_inlined
;
281 struct OutsourcedIndexes m_outsourced
;
289 case Mode::Outsourced
:
290 m_outsourced
.Clear();
295 m_mode
= Mode::Invalid
;
300 Mode m_mode
= Mode::Invalid
;
303 uint32_t m_ptr_size
= 0;
304 CompilerType m_uint_star_type
;
307 namespace lldb_private
{
308 namespace formatters
{
310 SyntheticChildrenFrontEnd
*
311 NSIndexPathSyntheticFrontEndCreator(CXXSyntheticChildren
*,
312 lldb::ValueObjectSP valobj_sp
) {
314 return new NSIndexPathSyntheticFrontEnd(valobj_sp
);
318 } // namespace formatters
319 } // namespace lldb_private