Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / lldb / source / Plugins / Language / ObjC / NSIndexPath.cpp
blob2a4ce80224e9e92ae743fc1129e75eb917eda4da
1 //===-- NSIndexPath.cpp ---------------------------------------------------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
9 #include "Cocoa.h"
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"
20 using namespace lldb;
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 {
33 public:
34 NSIndexPathSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
35 : SyntheticChildrenFrontEnd(*valobj_sp.get()), m_descriptor_sp(nullptr),
36 m_impl(), m_uint_star_type() {
37 m_ptr_size =
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 {
50 m_impl.Clear();
52 auto type_system = m_backend.GetCompilerType().GetTypeSystem();
53 if (!type_system)
54 return false;
56 auto ast = ScratchTypeSystemClang::GetForTarget(
57 *m_backend.GetExecutionContextRef().GetTargetSP());
58 if (!ast)
59 return false;
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();
67 if (!process_sp)
68 return false;
70 ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
72 if (!runtime)
73 return false;
75 ObjCLanguageRuntime::ClassDescriptorSP descriptor(
76 runtime->GetClassDescriptor(m_backend));
78 if (!descriptor.get() || !descriptor->IsValid())
79 return false;
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;
86 } else {
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) {
95 _indexes_id = ivar;
96 has_indexes = true;
97 } else if (ivar.m_name == g__length) {
98 _length_id = ivar;
99 has_length = true;
102 if (has_length && has_indexes)
103 break;
106 if (has_length && has_indexes) {
107 m_impl.m_outsourced.m_indexes =
108 m_backend
109 .GetSyntheticChildAtOffset(_indexes_id.m_offset,
110 m_uint_star_type.GetPointerType(),
111 true)
112 .get();
113 ValueObjectSP length_sp(m_backend.GetSyntheticChildAtOffset(
114 _length_id.m_offset, m_uint_star_type, true));
115 if (length_sp) {
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;
122 return false;
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())
131 return UINT32_MAX;
132 return idx;
135 lldb::ValueObjectSP GetSyntheticValue() override { return nullptr; }
137 protected:
138 ObjCLanguageRuntime::ClassDescriptorSP m_descriptor_sp;
140 enum class Mode { Inlined, Outsourced, Invalid };
142 struct Impl {
143 size_t GetNumIndexes() {
144 switch (m_mode) {
145 case Mode::Inlined:
146 return m_inlined.GetNumIndexes();
147 case Mode::Outsourced:
148 return m_outsourced.m_count;
149 default:
150 return 0;
154 lldb::ValueObjectSP GetIndexAtIndex(size_t idx,
155 const CompilerType &desired_type) {
156 if (idx >= GetNumIndexes())
157 return nullptr;
158 switch (m_mode) {
159 default:
160 return nullptr;
161 case Mode::Inlined:
162 return m_inlined.GetIndexAtIndex(idx, desired_type);
163 case Mode::Outsourced:
164 return m_outsourced.GetIndexAtIndex(idx);
168 struct InlinedIndexes {
169 public:
170 void SetIndexes(uint64_t value, Process &p) {
171 m_indexes = value;
172 _lengthForInlinePayload(p.GetAddressByteSize());
173 m_process = &p;
176 size_t GetNumIndexes() { return m_count; }
178 lldb::ValueObjectSP GetIndexAtIndex(size_t idx,
179 const CompilerType &desired_type) {
180 if (!m_process)
181 return nullptr;
183 std::pair<uint64_t, bool> value(_indexAtPositionForInlinePayload(idx));
184 if (!value.second)
185 return nullptr;
187 Value v;
188 if (m_ptr_size == 8) {
189 Scalar scalar((unsigned long long)value.first);
190 v = Value(scalar);
191 } else {
192 Scalar scalar((unsigned int)value.first);
193 v = Value(scalar);
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()));
205 void Clear() {
206 m_indexes = 0;
207 m_count = 0;
208 m_ptr_size = 0;
209 m_process = nullptr;
212 InlinedIndexes() {}
214 private:
215 uint64_t m_indexes = 0;
216 size_t m_count = 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;
223 if (m_ptr_size == 8)
224 m_count = ((m_indexes >> 3) & 0x7);
225 else
226 m_count = ((m_indexes >> 3) & 0x3);
227 return m_count;
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) {
233 switch (pos) {
234 case 3:
235 case 2:
236 case 1:
237 case 0:
238 return {(m_indexes >> PACKED_INDEX_SHIFT_64(pos)) &
239 PACKED_INDEX_MASK,
240 true};
241 default:
242 return {0, false};
244 } else {
245 switch (pos) {
246 case 0:
247 case 1:
248 return {(m_indexes >> PACKED_INDEX_SHIFT_32(pos)) &
249 PACKED_INDEX_MASK,
250 true};
251 default:
252 return {0, false};
255 return {0, false};
259 struct OutsourcedIndexes {
260 lldb::ValueObjectSP GetIndexAtIndex(size_t idx) {
261 if (m_indexes) {
262 ValueObjectSP index_sp(m_indexes->GetSyntheticArrayMember(idx, true));
263 return index_sp;
265 return nullptr;
268 void Clear() {
269 m_indexes = nullptr;
270 m_count = 0;
273 OutsourcedIndexes() {}
275 ValueObject *m_indexes = nullptr;
276 size_t m_count = 0;
279 union {
280 struct InlinedIndexes m_inlined;
281 struct OutsourcedIndexes m_outsourced;
284 void Clear() {
285 switch (m_mode) {
286 case Mode::Inlined:
287 m_inlined.Clear();
288 break;
289 case Mode::Outsourced:
290 m_outsourced.Clear();
291 break;
292 case Mode::Invalid:
293 break;
295 m_mode = Mode::Invalid;
298 Impl() {}
300 Mode m_mode = Mode::Invalid;
301 } m_impl;
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) {
313 if (valobj_sp)
314 return new NSIndexPathSyntheticFrontEnd(valobj_sp);
315 return nullptr;
318 } // namespace formatters
319 } // namespace lldb_private