1 //===-- NSIndexPath.cpp -----------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
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/Symbol/ClangASTContext.h"
17 #include "lldb/Target/ObjCLanguageRuntime.h"
18 #include "lldb/Target/Process.h"
19 #include "lldb/Target/Target.h"
22 using namespace lldb_private;
23 using namespace lldb_private::formatters;
25 static constexpr size_t PACKED_INDEX_SHIFT_64(size_t i) {
26 return (60 - (13 * (4 - i)));
29 static constexpr size_t PACKED_INDEX_SHIFT_32(size_t i) {
30 return (32 - (13 * (2 - i)));
33 class NSIndexPathSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
35 NSIndexPathSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
36 : SyntheticChildrenFrontEnd(*valobj_sp.get()), m_descriptor_sp(nullptr),
37 m_impl(), m_ptr_size(0), m_uint_star_type() {
39 m_backend.GetTargetSP()->GetArchitecture().GetAddressByteSize();
42 ~NSIndexPathSyntheticFrontEnd() override = default;
44 size_t CalculateNumChildren() override { return m_impl.GetNumIndexes(); }
46 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override {
47 return m_impl.GetIndexAtIndex(idx, m_uint_star_type);
50 bool Update() override {
53 TypeSystem *type_system = m_backend.GetCompilerType().GetTypeSystem();
57 ClangASTContext *ast = m_backend.GetExecutionContextRef()
59 ->GetScratchClangASTContext();
63 m_uint_star_type = ast->GetPointerSizedIntType(false);
65 static ConstString g__indexes("_indexes");
66 static ConstString g__length("_length");
68 ProcessSP process_sp = m_backend.GetProcessSP();
72 ObjCLanguageRuntime *runtime =
73 (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
74 lldb::eLanguageTypeObjC);
79 ObjCLanguageRuntime::ClassDescriptorSP descriptor(
80 runtime->GetClassDescriptor(m_backend));
82 if (!descriptor.get() || !descriptor->IsValid())
85 uint64_t info_bits(0), value_bits(0), payload(0);
87 if (descriptor->GetTaggedPointerInfo(&info_bits, &value_bits, &payload)) {
88 m_impl.m_inlined.SetIndexes(payload, *process_sp);
89 m_impl.m_mode = Mode::Inlined;
91 ObjCLanguageRuntime::ClassDescriptor::iVarDescriptor _indexes_id;
92 ObjCLanguageRuntime::ClassDescriptor::iVarDescriptor _length_id;
94 bool has_indexes(false), has_length(false);
96 for (size_t x = 0; x < descriptor->GetNumIVars(); x++) {
97 const auto &ivar = descriptor->GetIVarAtIndex(x);
98 if (ivar.m_name == g__indexes) {
101 } else if (ivar.m_name == g__length) {
106 if (has_length && has_indexes)
110 if (has_length && has_indexes) {
111 m_impl.m_outsourced.m_indexes =
113 .GetSyntheticChildAtOffset(_indexes_id.m_offset,
114 m_uint_star_type.GetPointerType(),
117 ValueObjectSP length_sp(m_backend.GetSyntheticChildAtOffset(
118 _length_id.m_offset, m_uint_star_type, true));
120 m_impl.m_outsourced.m_count = length_sp->GetValueAsUnsigned(0);
121 if (m_impl.m_outsourced.m_indexes)
122 m_impl.m_mode = Mode::Outsourced;
129 bool MightHaveChildren() override { return m_impl.m_mode != Mode::Invalid; }
131 size_t GetIndexOfChildWithName(const ConstString &name) override {
132 const char *item_name = name.GetCString();
133 uint32_t idx = ExtractIndexFromString(item_name);
134 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
139 lldb::ValueObjectSP GetSyntheticValue() override { return nullptr; }
142 ObjCLanguageRuntime::ClassDescriptorSP m_descriptor_sp;
144 enum class Mode { Inlined, Outsourced, Invalid };
147 size_t GetNumIndexes() {
150 return m_inlined.GetNumIndexes();
151 case Mode::Outsourced:
152 return m_outsourced.m_count;
158 lldb::ValueObjectSP GetIndexAtIndex(size_t idx,
159 const CompilerType &desired_type) {
160 if (idx >= GetNumIndexes())
166 return m_inlined.GetIndexAtIndex(idx, desired_type);
167 case Mode::Outsourced:
168 return m_outsourced.GetIndexAtIndex(idx);
172 struct InlinedIndexes {
174 void SetIndexes(uint64_t value, Process &p) {
176 _lengthForInlinePayload(p.GetAddressByteSize());
180 size_t GetNumIndexes() { return m_count; }
182 lldb::ValueObjectSP GetIndexAtIndex(size_t idx,
183 const CompilerType &desired_type) {
187 std::pair<uint64_t, bool> value(_indexAtPositionForInlinePayload(idx));
192 if (m_ptr_size == 8) {
193 Scalar scalar((unsigned long long)value.first);
196 Scalar scalar((unsigned int)value.first);
200 v.SetCompilerType(desired_type);
202 StreamString idx_name;
203 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
205 return ValueObjectConstResult::Create(
206 m_process, v, ConstString(idx_name.GetString()));
217 : m_indexes(0), m_count(0), m_ptr_size(0), m_process(nullptr) {}
225 // cfr. Foundation for the details of this code
226 size_t _lengthForInlinePayload(uint32_t ptr_size) {
227 m_ptr_size = ptr_size;
229 m_count = ((m_indexes >> 3) & 0x7);
231 m_count = ((m_indexes >> 3) & 0x3);
235 std::pair<uint64_t, bool> _indexAtPositionForInlinePayload(size_t pos) {
236 static const uint64_t PACKED_INDEX_MASK = ((1 << 13) - 1);
237 if (m_ptr_size == 8) {
243 return {(m_indexes >> PACKED_INDEX_SHIFT_64(pos)) &
253 return {(m_indexes >> PACKED_INDEX_SHIFT_32(pos)) &
264 struct OutsourcedIndexes {
265 lldb::ValueObjectSP GetIndexAtIndex(size_t idx) {
267 ValueObjectSP index_sp(m_indexes->GetSyntheticArrayMember(idx, true));
278 OutsourcedIndexes() : m_indexes(nullptr), m_count(0) {}
280 ValueObject *m_indexes;
285 struct InlinedIndexes m_inlined;
286 struct OutsourcedIndexes m_outsourced;
290 m_mode = Mode::Invalid;
292 m_outsourced.Clear();
295 Impl() : m_mode(Mode::Invalid) {}
301 CompilerType m_uint_star_type;
304 namespace lldb_private {
305 namespace formatters {
307 SyntheticChildrenFrontEnd *
308 NSIndexPathSyntheticFrontEndCreator(CXXSyntheticChildren *,
309 lldb::ValueObjectSP valobj_sp) {
311 return new NSIndexPathSyntheticFrontEnd(valobj_sp);
315 } // namespace formatters
316 } // namespace lldb_private