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