]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - source/Plugins/Language/ObjC/NSIndexPath.cpp
Vendor import of lldb trunk r290819:
[FreeBSD/FreeBSD.git] / source / Plugins / Language / ObjC / NSIndexPath.cpp
1 //===-- NSIndexPath.cpp -----------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 // C Includes
11 // C++ Includes
12 // Other libraries and framework includes
13 // Project includes
14 #include "Cocoa.h"
15
16 #include "lldb/Core/ValueObject.h"
17 #include "lldb/Core/ValueObjectConstResult.h"
18 #include "lldb/DataFormatters/FormattersHelpers.h"
19 #include "lldb/DataFormatters/TypeSynthetic.h"
20 #include "lldb/Symbol/ClangASTContext.h"
21 #include "lldb/Target/ObjCLanguageRuntime.h"
22 #include "lldb/Target/Process.h"
23 #include "lldb/Target/Target.h"
24
25 using namespace lldb;
26 using namespace lldb_private;
27 using namespace lldb_private::formatters;
28
29 static constexpr size_t PACKED_INDEX_SHIFT_64(size_t i) {
30   return (60 - (13 * (4 - i)));
31 }
32
33 static constexpr size_t PACKED_INDEX_SHIFT_32(size_t i) {
34   return (32 - (13 * (2 - i)));
35 }
36
37 class NSIndexPathSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
38 public:
39   NSIndexPathSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
40       : SyntheticChildrenFrontEnd(*valobj_sp.get()), m_descriptor_sp(nullptr),
41         m_impl(), m_ptr_size(0), m_uint_star_type() {
42     m_ptr_size =
43         m_backend.GetTargetSP()->GetArchitecture().GetAddressByteSize();
44   }
45
46   ~NSIndexPathSyntheticFrontEnd() override = default;
47
48   size_t CalculateNumChildren() override { return m_impl.GetNumIndexes(); }
49
50   lldb::ValueObjectSP GetChildAtIndex(size_t idx) override {
51     return m_impl.GetIndexAtIndex(idx, m_uint_star_type);
52   }
53
54   bool Update() override {
55     m_impl.Clear();
56
57     TypeSystem *type_system = m_backend.GetCompilerType().GetTypeSystem();
58     if (!type_system)
59       return false;
60
61     ClangASTContext *ast = m_backend.GetExecutionContextRef()
62                                .GetTargetSP()
63                                ->GetScratchClangASTContext();
64     if (!ast)
65       return false;
66
67     m_uint_star_type = ast->GetPointerSizedIntType(false);
68
69     static ConstString g__indexes("_indexes");
70     static ConstString g__length("_length");
71
72     ProcessSP process_sp = m_backend.GetProcessSP();
73     if (!process_sp)
74       return false;
75
76     ObjCLanguageRuntime *runtime =
77         (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
78             lldb::eLanguageTypeObjC);
79
80     if (!runtime)
81       return false;
82
83     ObjCLanguageRuntime::ClassDescriptorSP descriptor(
84         runtime->GetClassDescriptor(m_backend));
85
86     if (!descriptor.get() || !descriptor->IsValid())
87       return false;
88
89     uint64_t info_bits(0), value_bits(0), payload(0);
90
91     if (descriptor->GetTaggedPointerInfo(&info_bits, &value_bits, &payload)) {
92       m_impl.m_inlined.SetIndexes(payload, *process_sp);
93       m_impl.m_mode = Mode::Inlined;
94     } else {
95       ObjCLanguageRuntime::ClassDescriptor::iVarDescriptor _indexes_id;
96       ObjCLanguageRuntime::ClassDescriptor::iVarDescriptor _length_id;
97
98       bool has_indexes(false), has_length(false);
99
100       for (size_t x = 0; x < descriptor->GetNumIVars(); x++) {
101         const auto &ivar = descriptor->GetIVarAtIndex(x);
102         if (ivar.m_name == g__indexes) {
103           _indexes_id = ivar;
104           has_indexes = true;
105         } else if (ivar.m_name == g__length) {
106           _length_id = ivar;
107           has_length = true;
108         }
109
110         if (has_length && has_indexes)
111           break;
112       }
113
114       if (has_length && has_indexes) {
115         m_impl.m_outsourced.m_indexes =
116             m_backend
117                 .GetSyntheticChildAtOffset(_indexes_id.m_offset,
118                                            m_uint_star_type.GetPointerType(),
119                                            true)
120                 .get();
121         ValueObjectSP length_sp(m_backend.GetSyntheticChildAtOffset(
122             _length_id.m_offset, m_uint_star_type, true));
123         if (length_sp) {
124           m_impl.m_outsourced.m_count = length_sp->GetValueAsUnsigned(0);
125           if (m_impl.m_outsourced.m_indexes)
126             m_impl.m_mode = Mode::Outsourced;
127         }
128       }
129     }
130     return false;
131   }
132
133   bool MightHaveChildren() override {
134     if (m_impl.m_mode == Mode::Invalid)
135       return false;
136     return true;
137   }
138
139   size_t GetIndexOfChildWithName(const ConstString &name) override {
140     const char *item_name = name.GetCString();
141     uint32_t idx = ExtractIndexFromString(item_name);
142     if (idx < UINT32_MAX && idx >= CalculateNumChildren())
143       return UINT32_MAX;
144     return idx;
145   }
146
147   lldb::ValueObjectSP GetSyntheticValue() override { return nullptr; }
148
149 protected:
150   ObjCLanguageRuntime::ClassDescriptorSP m_descriptor_sp;
151
152   enum class Mode { Inlined, Outsourced, Invalid };
153
154   struct Impl {
155     size_t GetNumIndexes() {
156       switch (m_mode) {
157       case Mode::Inlined:
158         return m_inlined.GetNumIndexes();
159       case Mode::Outsourced:
160         return m_outsourced.m_count;
161       default:
162         return 0;
163       }
164     }
165
166     lldb::ValueObjectSP GetIndexAtIndex(size_t idx,
167                                         const CompilerType &desired_type) {
168       if (idx >= GetNumIndexes())
169         return nullptr;
170       switch (m_mode) {
171       default:
172         return nullptr;
173       case Mode::Inlined:
174         return m_inlined.GetIndexAtIndex(idx, desired_type);
175       case Mode::Outsourced:
176         return m_outsourced.GetIndexAtIndex(idx);
177       }
178     }
179
180     struct InlinedIndexes {
181     public:
182       void SetIndexes(uint64_t value, Process &p) {
183         m_indexes = value;
184         _lengthForInlinePayload(p.GetAddressByteSize());
185         m_process = &p;
186       }
187
188       size_t GetNumIndexes() { return m_count; }
189
190       lldb::ValueObjectSP GetIndexAtIndex(size_t idx,
191                                           const CompilerType &desired_type) {
192         if (!m_process)
193           return nullptr;
194
195         std::pair<uint64_t, bool> value(_indexAtPositionForInlinePayload(idx));
196         if (!value.second)
197           return nullptr;
198
199         Value v;
200         if (m_ptr_size == 8) {
201           Scalar scalar((unsigned long long)value.first);
202           v = Value(scalar);
203         } else {
204           Scalar scalar((unsigned int)value.first);
205           v = Value(scalar);
206         }
207
208         v.SetCompilerType(desired_type);
209
210         StreamString idx_name;
211         idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
212
213         return ValueObjectConstResult::Create(
214             m_process, v, ConstString(idx_name.GetString()));
215       }
216
217       void Clear() {
218         m_indexes = 0;
219         m_count = 0;
220         m_ptr_size = 0;
221         m_process = nullptr;
222       }
223
224       InlinedIndexes()
225           : m_indexes(0), m_count(0), m_ptr_size(0), m_process(nullptr) {}
226
227     private:
228       uint64_t m_indexes;
229       size_t m_count;
230       uint32_t m_ptr_size;
231       Process *m_process;
232
233       // cfr. Foundation for the details of this code
234       size_t _lengthForInlinePayload(uint32_t ptr_size) {
235         m_ptr_size = ptr_size;
236         if (m_ptr_size == 8)
237           m_count = ((m_indexes >> 3) & 0x7);
238         else
239           m_count = ((m_indexes >> 3) & 0x3);
240         return m_count;
241       }
242
243       std::pair<uint64_t, bool> _indexAtPositionForInlinePayload(size_t pos) {
244         static const uint64_t PACKED_INDEX_MASK = ((1 << 13) - 1);
245         if (m_ptr_size == 8) {
246           switch (pos) {
247           case 3:
248           case 2:
249           case 1:
250           case 0:
251             return {(m_indexes >> PACKED_INDEX_SHIFT_64(pos)) &
252                         PACKED_INDEX_MASK,
253                     true};
254           default:
255             return {0, false};
256           }
257         } else {
258           switch (pos) {
259           case 0:
260           case 1:
261             return {(m_indexes >> PACKED_INDEX_SHIFT_32(pos)) &
262                         PACKED_INDEX_MASK,
263                     true};
264           default:
265             return {0, false};
266           }
267         }
268         return {0, false};
269       }
270     };
271
272     struct OutsourcedIndexes {
273       lldb::ValueObjectSP GetIndexAtIndex(size_t idx) {
274         if (m_indexes) {
275           ValueObjectSP index_sp(m_indexes->GetSyntheticArrayMember(idx, true));
276           return index_sp;
277         }
278         return nullptr;
279       }
280
281       void Clear() {
282         m_indexes = nullptr;
283         m_count = 0;
284       }
285
286       OutsourcedIndexes() : m_indexes(nullptr), m_count(0) {}
287
288       ValueObject *m_indexes;
289       size_t m_count;
290     };
291
292     union {
293       struct InlinedIndexes m_inlined;
294       struct OutsourcedIndexes m_outsourced;
295     };
296
297     void Clear() {
298       m_mode = Mode::Invalid;
299       m_inlined.Clear();
300       m_outsourced.Clear();
301     }
302
303     Impl() : m_mode(Mode::Invalid) {}
304
305     Mode m_mode;
306   } m_impl;
307
308   uint32_t m_ptr_size;
309   CompilerType m_uint_star_type;
310 };
311
312 namespace lldb_private {
313 namespace formatters {
314
315 SyntheticChildrenFrontEnd *
316 NSIndexPathSyntheticFrontEndCreator(CXXSyntheticChildren *,
317                                     lldb::ValueObjectSP valobj_sp) {
318   if (valobj_sp)
319     return new NSIndexPathSyntheticFrontEnd(valobj_sp);
320   return nullptr;
321 }
322
323 } // namespace formatters
324 } // namespace lldb_private