180814287SRaphael Isemann //===-- NSIndexPath.cpp ---------------------------------------------------===//
2170c395eSEnrico Granata //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6170c395eSEnrico Granata //
7170c395eSEnrico Granata //===----------------------------------------------------------------------===//
8170c395eSEnrico Granata
9170c395eSEnrico Granata #include "Cocoa.h"
10170c395eSEnrico Granata
118be30215SAlex Langford #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
12170c395eSEnrico Granata #include "lldb/Core/ValueObject.h"
13170c395eSEnrico Granata #include "lldb/Core/ValueObjectConstResult.h"
14170c395eSEnrico Granata #include "lldb/DataFormatters/FormattersHelpers.h"
15170c395eSEnrico Granata #include "lldb/DataFormatters/TypeSynthetic.h"
16170c395eSEnrico Granata #include "lldb/Target/Process.h"
17d717cc9fSEnrico Granata #include "lldb/Target/Target.h"
18170c395eSEnrico Granata
19b5701710SAlex Langford #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
20170c395eSEnrico Granata using namespace lldb;
21170c395eSEnrico Granata using namespace lldb_private;
22170c395eSEnrico Granata using namespace lldb_private::formatters;
23170c395eSEnrico Granata
PACKED_INDEX_SHIFT_64(size_t i)24b9c1b51eSKate Stone static constexpr size_t PACKED_INDEX_SHIFT_64(size_t i) {
25df43d25fSEnrico Granata return (60 - (13 * (4 - i)));
26df43d25fSEnrico Granata }
27df43d25fSEnrico Granata
PACKED_INDEX_SHIFT_32(size_t i)28b9c1b51eSKate Stone static constexpr size_t PACKED_INDEX_SHIFT_32(size_t i) {
29df43d25fSEnrico Granata return (32 - (13 * (2 - i)));
30df43d25fSEnrico Granata }
31df43d25fSEnrico Granata
32b9c1b51eSKate Stone class NSIndexPathSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
33170c395eSEnrico Granata public:
NSIndexPathSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)34b9c1b51eSKate Stone NSIndexPathSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
35b9c1b51eSKate Stone : SyntheticChildrenFrontEnd(*valobj_sp.get()), m_descriptor_sp(nullptr),
3628c878aeSShafik Yaghmour m_impl(), m_uint_star_type() {
37b9c1b51eSKate Stone m_ptr_size =
38b9c1b51eSKate Stone m_backend.GetTargetSP()->GetArchitecture().GetAddressByteSize();
39170c395eSEnrico Granata }
40170c395eSEnrico Granata
418d15f33bSEugene Zelenko ~NSIndexPathSyntheticFrontEnd() override = default;
428d15f33bSEugene Zelenko
CalculateNumChildren()43b9c1b51eSKate Stone size_t CalculateNumChildren() override { return m_impl.GetNumIndexes(); }
44170c395eSEnrico Granata
GetChildAtIndex(size_t idx)45b9c1b51eSKate Stone lldb::ValueObjectSP GetChildAtIndex(size_t idx) override {
46170c395eSEnrico Granata return m_impl.GetIndexAtIndex(idx, m_uint_star_type);
47170c395eSEnrico Granata }
48170c395eSEnrico Granata
Update()49b9c1b51eSKate Stone bool Update() override {
50170c395eSEnrico Granata m_impl.Clear();
51170c395eSEnrico Granata
52170c395eSEnrico Granata TypeSystem *type_system = m_backend.GetCompilerType().GetTypeSystem();
53170c395eSEnrico Granata if (!type_system)
54170c395eSEnrico Granata return false;
55170c395eSEnrico Granata
56594308c7SRaphael Isemann TypeSystemClang *ast = ScratchTypeSystemClang::GetForTarget(
573031818aSAlex Langford *m_backend.GetExecutionContextRef().GetTargetSP());
58170c395eSEnrico Granata if (!ast)
59170c395eSEnrico Granata return false;
60170c395eSEnrico Granata
61170c395eSEnrico Granata m_uint_star_type = ast->GetPointerSizedIntType(false);
62170c395eSEnrico Granata
63170c395eSEnrico Granata static ConstString g__indexes("_indexes");
64170c395eSEnrico Granata static ConstString g__length("_length");
65170c395eSEnrico Granata
66170c395eSEnrico Granata ProcessSP process_sp = m_backend.GetProcessSP();
67170c395eSEnrico Granata if (!process_sp)
68170c395eSEnrico Granata return false;
69170c395eSEnrico Granata
70e823bbe8SAlex Langford ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
71170c395eSEnrico Granata
72170c395eSEnrico Granata if (!runtime)
73170c395eSEnrico Granata return false;
74170c395eSEnrico Granata
75b9c1b51eSKate Stone ObjCLanguageRuntime::ClassDescriptorSP descriptor(
76b9c1b51eSKate Stone runtime->GetClassDescriptor(m_backend));
77170c395eSEnrico Granata
78170c395eSEnrico Granata if (!descriptor.get() || !descriptor->IsValid())
79170c395eSEnrico Granata return false;
80170c395eSEnrico Granata
81170c395eSEnrico Granata uint64_t info_bits(0), value_bits(0), payload(0);
82170c395eSEnrico Granata
83b9c1b51eSKate Stone if (descriptor->GetTaggedPointerInfo(&info_bits, &value_bits, &payload)) {
84170c395eSEnrico Granata m_impl.m_inlined.SetIndexes(payload, *process_sp);
85170c395eSEnrico Granata m_impl.m_mode = Mode::Inlined;
86b9c1b51eSKate Stone } else {
87170c395eSEnrico Granata ObjCLanguageRuntime::ClassDescriptor::iVarDescriptor _indexes_id;
88170c395eSEnrico Granata ObjCLanguageRuntime::ClassDescriptor::iVarDescriptor _length_id;
89170c395eSEnrico Granata
90170c395eSEnrico Granata bool has_indexes(false), has_length(false);
91170c395eSEnrico Granata
92b9c1b51eSKate Stone for (size_t x = 0; x < descriptor->GetNumIVars(); x++) {
93170c395eSEnrico Granata const auto &ivar = descriptor->GetIVarAtIndex(x);
94b9c1b51eSKate Stone if (ivar.m_name == g__indexes) {
95170c395eSEnrico Granata _indexes_id = ivar;
96170c395eSEnrico Granata has_indexes = true;
97b9c1b51eSKate Stone } else if (ivar.m_name == g__length) {
98170c395eSEnrico Granata _length_id = ivar;
99170c395eSEnrico Granata has_length = true;
100170c395eSEnrico Granata }
101170c395eSEnrico Granata
102170c395eSEnrico Granata if (has_length && has_indexes)
103170c395eSEnrico Granata break;
104170c395eSEnrico Granata }
105170c395eSEnrico Granata
106b9c1b51eSKate Stone if (has_length && has_indexes) {
107b9c1b51eSKate Stone m_impl.m_outsourced.m_indexes =
108b9c1b51eSKate Stone m_backend
109b9c1b51eSKate Stone .GetSyntheticChildAtOffset(_indexes_id.m_offset,
110170c395eSEnrico Granata m_uint_star_type.GetPointerType(),
111b9c1b51eSKate Stone true)
112b9c1b51eSKate Stone .get();
113b9c1b51eSKate Stone ValueObjectSP length_sp(m_backend.GetSyntheticChildAtOffset(
114b9c1b51eSKate Stone _length_id.m_offset, m_uint_star_type, true));
115b9c1b51eSKate Stone if (length_sp) {
116170c395eSEnrico Granata m_impl.m_outsourced.m_count = length_sp->GetValueAsUnsigned(0);
117170c395eSEnrico Granata if (m_impl.m_outsourced.m_indexes)
118170c395eSEnrico Granata m_impl.m_mode = Mode::Outsourced;
119170c395eSEnrico Granata }
120170c395eSEnrico Granata }
121170c395eSEnrico Granata }
122170c395eSEnrico Granata return false;
123170c395eSEnrico Granata }
124170c395eSEnrico Granata
MightHaveChildren()125a6682a41SJonas Devlieghere bool MightHaveChildren() override { return m_impl.m_mode != Mode::Invalid; }
126170c395eSEnrico Granata
GetIndexOfChildWithName(ConstString name)1270e4c4821SAdrian Prantl size_t GetIndexOfChildWithName(ConstString name) override {
128170c395eSEnrico Granata const char *item_name = name.GetCString();
129170c395eSEnrico Granata uint32_t idx = ExtractIndexFromString(item_name);
130170c395eSEnrico Granata if (idx < UINT32_MAX && idx >= CalculateNumChildren())
131170c395eSEnrico Granata return UINT32_MAX;
132170c395eSEnrico Granata return idx;
133170c395eSEnrico Granata }
134170c395eSEnrico Granata
GetSyntheticValue()135b9c1b51eSKate Stone lldb::ValueObjectSP GetSyntheticValue() override { return nullptr; }
136170c395eSEnrico Granata
137170c395eSEnrico Granata protected:
138170c395eSEnrico Granata ObjCLanguageRuntime::ClassDescriptorSP m_descriptor_sp;
139170c395eSEnrico Granata
140b9c1b51eSKate Stone enum class Mode { Inlined, Outsourced, Invalid };
141170c395eSEnrico Granata
142b9c1b51eSKate Stone struct Impl {
GetNumIndexesNSIndexPathSyntheticFrontEnd::Impl143b9c1b51eSKate Stone size_t GetNumIndexes() {
144b9c1b51eSKate Stone switch (m_mode) {
145170c395eSEnrico Granata case Mode::Inlined:
146170c395eSEnrico Granata return m_inlined.GetNumIndexes();
147170c395eSEnrico Granata case Mode::Outsourced:
148170c395eSEnrico Granata return m_outsourced.m_count;
149170c395eSEnrico Granata default:
150170c395eSEnrico Granata return 0;
151170c395eSEnrico Granata }
152170c395eSEnrico Granata }
153170c395eSEnrico Granata
GetIndexAtIndexNSIndexPathSyntheticFrontEnd::Impl154b9c1b51eSKate Stone lldb::ValueObjectSP GetIndexAtIndex(size_t idx,
155b9c1b51eSKate Stone const CompilerType &desired_type) {
156170c395eSEnrico Granata if (idx >= GetNumIndexes())
157170c395eSEnrico Granata return nullptr;
158b9c1b51eSKate Stone switch (m_mode) {
159b9c1b51eSKate Stone default:
160b9c1b51eSKate Stone return nullptr;
161170c395eSEnrico Granata case Mode::Inlined:
162170c395eSEnrico Granata return m_inlined.GetIndexAtIndex(idx, desired_type);
163170c395eSEnrico Granata case Mode::Outsourced:
164170c395eSEnrico Granata return m_outsourced.GetIndexAtIndex(idx);
165170c395eSEnrico Granata }
166170c395eSEnrico Granata }
167170c395eSEnrico Granata
168b9c1b51eSKate Stone struct InlinedIndexes {
169170c395eSEnrico Granata public:
SetIndexesNSIndexPathSyntheticFrontEnd::Impl::InlinedIndexes170b9c1b51eSKate Stone void SetIndexes(uint64_t value, Process &p) {
171170c395eSEnrico Granata m_indexes = value;
172170c395eSEnrico Granata _lengthForInlinePayload(p.GetAddressByteSize());
173170c395eSEnrico Granata m_process = &p;
174170c395eSEnrico Granata }
175170c395eSEnrico Granata
GetNumIndexesNSIndexPathSyntheticFrontEnd::Impl::InlinedIndexes176b9c1b51eSKate Stone size_t GetNumIndexes() { return m_count; }
177170c395eSEnrico Granata
GetIndexAtIndexNSIndexPathSyntheticFrontEnd::Impl::InlinedIndexes178b9c1b51eSKate Stone lldb::ValueObjectSP GetIndexAtIndex(size_t idx,
179b9c1b51eSKate Stone const CompilerType &desired_type) {
1807031867bSEnrico Granata if (!m_process)
1817031867bSEnrico Granata return nullptr;
1827031867bSEnrico Granata
183170c395eSEnrico Granata std::pair<uint64_t, bool> value(_indexAtPositionForInlinePayload(idx));
184170c395eSEnrico Granata if (!value.second)
185170c395eSEnrico Granata return nullptr;
186170c395eSEnrico Granata
187170c395eSEnrico Granata Value v;
188b9c1b51eSKate Stone if (m_ptr_size == 8) {
189170c395eSEnrico Granata Scalar scalar((unsigned long long)value.first);
190170c395eSEnrico Granata v = Value(scalar);
191b9c1b51eSKate Stone } else {
192170c395eSEnrico Granata Scalar scalar((unsigned int)value.first);
193170c395eSEnrico Granata v = Value(scalar);
194170c395eSEnrico Granata }
195170c395eSEnrico Granata
196170c395eSEnrico Granata v.SetCompilerType(desired_type);
197170c395eSEnrico Granata
198170c395eSEnrico Granata StreamString idx_name;
199170c395eSEnrico Granata idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
200170c395eSEnrico Granata
201c156427dSZachary Turner return ValueObjectConstResult::Create(
202c156427dSZachary Turner m_process, v, ConstString(idx_name.GetString()));
203170c395eSEnrico Granata }
204170c395eSEnrico Granata
ClearNSIndexPathSyntheticFrontEnd::Impl::InlinedIndexes205b9c1b51eSKate Stone void Clear() {
206170c395eSEnrico Granata m_indexes = 0;
207170c395eSEnrico Granata m_count = 0;
208170c395eSEnrico Granata m_ptr_size = 0;
209170c395eSEnrico Granata m_process = nullptr;
210170c395eSEnrico Granata }
211170c395eSEnrico Granata
InlinedIndexesNSIndexPathSyntheticFrontEnd::Impl::InlinedIndexes2129494c510SJonas Devlieghere InlinedIndexes() {}
2137031867bSEnrico Granata
214170c395eSEnrico Granata private:
2159494c510SJonas Devlieghere uint64_t m_indexes = 0;
2169494c510SJonas Devlieghere size_t m_count = 0;
2179494c510SJonas Devlieghere uint32_t m_ptr_size = 0;
2189494c510SJonas Devlieghere Process *m_process = nullptr;
219170c395eSEnrico Granata
220170c395eSEnrico Granata // cfr. Foundation for the details of this code
_lengthForInlinePayloadNSIndexPathSyntheticFrontEnd::Impl::InlinedIndexes221170c395eSEnrico Granata size_t _lengthForInlinePayload(uint32_t ptr_size) {
222170c395eSEnrico Granata m_ptr_size = ptr_size;
223170c395eSEnrico Granata if (m_ptr_size == 8)
224170c395eSEnrico Granata m_count = ((m_indexes >> 3) & 0x7);
225170c395eSEnrico Granata else
226170c395eSEnrico Granata m_count = ((m_indexes >> 3) & 0x3);
227170c395eSEnrico Granata return m_count;
228170c395eSEnrico Granata }
229170c395eSEnrico Granata
_indexAtPositionForInlinePayloadNSIndexPathSyntheticFrontEnd::Impl::InlinedIndexes230b9c1b51eSKate Stone std::pair<uint64_t, bool> _indexAtPositionForInlinePayload(size_t pos) {
231df43d25fSEnrico Granata static const uint64_t PACKED_INDEX_MASK = ((1 << 13) - 1);
232b9c1b51eSKate Stone if (m_ptr_size == 8) {
233b9c1b51eSKate Stone switch (pos) {
234df43d25fSEnrico Granata case 3:
235df43d25fSEnrico Granata case 2:
236df43d25fSEnrico Granata case 1:
237df43d25fSEnrico Granata case 0:
238b9c1b51eSKate Stone return {(m_indexes >> PACKED_INDEX_SHIFT_64(pos)) &
239b9c1b51eSKate Stone PACKED_INDEX_MASK,
240b9c1b51eSKate Stone true};
241df43d25fSEnrico Granata default:
242df43d25fSEnrico Granata return {0, false};
243170c395eSEnrico Granata }
244b9c1b51eSKate Stone } else {
245b9c1b51eSKate Stone switch (pos) {
246df43d25fSEnrico Granata case 0:
247df43d25fSEnrico Granata case 1:
248b9c1b51eSKate Stone return {(m_indexes >> PACKED_INDEX_SHIFT_32(pos)) &
249b9c1b51eSKate Stone PACKED_INDEX_MASK,
250b9c1b51eSKate Stone true};
251df43d25fSEnrico Granata default:
252df43d25fSEnrico Granata return {0, false};
253170c395eSEnrico Granata }
254170c395eSEnrico Granata }
255170c395eSEnrico Granata return {0, false};
256170c395eSEnrico Granata }
257170c395eSEnrico Granata };
258170c395eSEnrico Granata
259b9c1b51eSKate Stone struct OutsourcedIndexes {
GetIndexAtIndexNSIndexPathSyntheticFrontEnd::Impl::OutsourcedIndexes260b9c1b51eSKate Stone lldb::ValueObjectSP GetIndexAtIndex(size_t idx) {
261b9c1b51eSKate Stone if (m_indexes) {
262170c395eSEnrico Granata ValueObjectSP index_sp(m_indexes->GetSyntheticArrayMember(idx, true));
263170c395eSEnrico Granata return index_sp;
264170c395eSEnrico Granata }
265170c395eSEnrico Granata return nullptr;
266170c395eSEnrico Granata }
267170c395eSEnrico Granata
ClearNSIndexPathSyntheticFrontEnd::Impl::OutsourcedIndexes268b9c1b51eSKate Stone void Clear() {
269170c395eSEnrico Granata m_indexes = nullptr;
270170c395eSEnrico Granata m_count = 0;
271170c395eSEnrico Granata }
2727031867bSEnrico Granata
OutsourcedIndexesNSIndexPathSyntheticFrontEnd::Impl::OutsourcedIndexes2739494c510SJonas Devlieghere OutsourcedIndexes() {}
2747031867bSEnrico Granata
2759494c510SJonas Devlieghere ValueObject *m_indexes = nullptr;
2769494c510SJonas Devlieghere size_t m_count = 0;
277170c395eSEnrico Granata };
278170c395eSEnrico Granata
279b9c1b51eSKate Stone union {
280170c395eSEnrico Granata struct InlinedIndexes m_inlined;
281170c395eSEnrico Granata struct OutsourcedIndexes m_outsourced;
282170c395eSEnrico Granata };
283170c395eSEnrico Granata
ClearNSIndexPathSyntheticFrontEnd::Impl284b9c1b51eSKate Stone void Clear() {
285*14cad95dSShafik Yaghmour switch (m_mode) {
286*14cad95dSShafik Yaghmour case Mode::Inlined:
287170c395eSEnrico Granata m_inlined.Clear();
288*14cad95dSShafik Yaghmour break;
289*14cad95dSShafik Yaghmour case Mode::Outsourced:
290170c395eSEnrico Granata m_outsourced.Clear();
291*14cad95dSShafik Yaghmour break;
292*14cad95dSShafik Yaghmour case Mode::Invalid:
293*14cad95dSShafik Yaghmour break;
294*14cad95dSShafik Yaghmour }
295*14cad95dSShafik Yaghmour m_mode = Mode::Invalid;
296170c395eSEnrico Granata }
2977031867bSEnrico Granata
ImplNSIndexPathSyntheticFrontEnd::Impl2989494c510SJonas Devlieghere Impl() {}
2997031867bSEnrico Granata
3009494c510SJonas Devlieghere Mode m_mode = Mode::Invalid;
301170c395eSEnrico Granata } m_impl;
302170c395eSEnrico Granata
30328c878aeSShafik Yaghmour uint32_t m_ptr_size = 0;
304170c395eSEnrico Granata CompilerType m_uint_star_type;
305170c395eSEnrico Granata };
306170c395eSEnrico Granata
307170c395eSEnrico Granata namespace lldb_private {
308170c395eSEnrico Granata namespace formatters {
309170c395eSEnrico Granata
310b9c1b51eSKate Stone SyntheticChildrenFrontEnd *
NSIndexPathSyntheticFrontEndCreator(CXXSyntheticChildren *,lldb::ValueObjectSP valobj_sp)311b9c1b51eSKate Stone NSIndexPathSyntheticFrontEndCreator(CXXSyntheticChildren *,
312b9c1b51eSKate Stone lldb::ValueObjectSP valobj_sp) {
313170c395eSEnrico Granata if (valobj_sp)
314170c395eSEnrico Granata return new NSIndexPathSyntheticFrontEnd(valobj_sp);
315170c395eSEnrico Granata return nullptr;
316170c395eSEnrico Granata }
3178d15f33bSEugene Zelenko
3188d15f33bSEugene Zelenko } // namespace formatters
3198d15f33bSEugene Zelenko } // namespace lldb_private
320