xref: /freebsd-src/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
15ffd83dbSDimitry Andric //===-- NSDictionary.cpp --------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include <mutex>
100b57cec5SDimitry Andric 
110b57cec5SDimitry Andric #include "clang/AST/DeclCXX.h"
120b57cec5SDimitry Andric 
135ffd83dbSDimitry Andric #include "CFBasicHash.h"
140b57cec5SDimitry Andric #include "NSDictionary.h"
150b57cec5SDimitry Andric 
160b57cec5SDimitry Andric #include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h"
175ffd83dbSDimitry Andric #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
180b57cec5SDimitry Andric 
190b57cec5SDimitry Andric #include "lldb/Core/ValueObject.h"
200b57cec5SDimitry Andric #include "lldb/Core/ValueObjectConstResult.h"
210b57cec5SDimitry Andric #include "lldb/DataFormatters/FormattersHelpers.h"
220b57cec5SDimitry Andric #include "lldb/Target/Language.h"
230b57cec5SDimitry Andric #include "lldb/Target/StackFrame.h"
240b57cec5SDimitry Andric #include "lldb/Target/Target.h"
250b57cec5SDimitry Andric #include "lldb/Utility/DataBufferHeap.h"
260b57cec5SDimitry Andric #include "lldb/Utility/Endian.h"
270b57cec5SDimitry Andric #include "lldb/Utility/Status.h"
280b57cec5SDimitry Andric #include "lldb/Utility/Stream.h"
290b57cec5SDimitry Andric 
300b57cec5SDimitry Andric using namespace lldb;
310b57cec5SDimitry Andric using namespace lldb_private;
320b57cec5SDimitry Andric using namespace lldb_private::formatters;
330b57cec5SDimitry Andric 
340b57cec5SDimitry Andric NSDictionary_Additionals::AdditionalFormatterMatching::Prefix::Prefix(
350b57cec5SDimitry Andric     ConstString p)
360b57cec5SDimitry Andric     : m_prefix(p) {}
370b57cec5SDimitry Andric 
380b57cec5SDimitry Andric bool NSDictionary_Additionals::AdditionalFormatterMatching::Prefix::Match(
390b57cec5SDimitry Andric     ConstString class_name) {
405f757f3fSDimitry Andric   return class_name.GetStringRef().starts_with(m_prefix.GetStringRef());
410b57cec5SDimitry Andric }
420b57cec5SDimitry Andric 
430b57cec5SDimitry Andric NSDictionary_Additionals::AdditionalFormatterMatching::Full::Full(ConstString n)
440b57cec5SDimitry Andric     : m_name(n) {}
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric bool NSDictionary_Additionals::AdditionalFormatterMatching::Full::Match(
470b57cec5SDimitry Andric     ConstString class_name) {
480b57cec5SDimitry Andric   return (class_name == m_name);
490b57cec5SDimitry Andric }
500b57cec5SDimitry Andric 
510b57cec5SDimitry Andric NSDictionary_Additionals::AdditionalFormatters<
520b57cec5SDimitry Andric     CXXFunctionSummaryFormat::Callback> &
530b57cec5SDimitry Andric NSDictionary_Additionals::GetAdditionalSummaries() {
540b57cec5SDimitry Andric   static AdditionalFormatters<CXXFunctionSummaryFormat::Callback> g_map;
550b57cec5SDimitry Andric   return g_map;
560b57cec5SDimitry Andric }
570b57cec5SDimitry Andric 
580b57cec5SDimitry Andric NSDictionary_Additionals::AdditionalFormatters<
590b57cec5SDimitry Andric     CXXSyntheticChildren::CreateFrontEndCallback> &
600b57cec5SDimitry Andric NSDictionary_Additionals::GetAdditionalSynthetics() {
610b57cec5SDimitry Andric   static AdditionalFormatters<CXXSyntheticChildren::CreateFrontEndCallback>
620b57cec5SDimitry Andric       g_map;
630b57cec5SDimitry Andric   return g_map;
640b57cec5SDimitry Andric }
650b57cec5SDimitry Andric 
660b57cec5SDimitry Andric static CompilerType GetLLDBNSPairType(TargetSP target_sp) {
670b57cec5SDimitry Andric   CompilerType compiler_type;
68bdd1243dSDimitry Andric   TypeSystemClangSP scratch_ts_sp =
69e8d8bef9SDimitry Andric       ScratchTypeSystemClang::GetForTarget(*target_sp);
700b57cec5SDimitry Andric 
7106c3fb27SDimitry Andric   if (!scratch_ts_sp)
7206c3fb27SDimitry Andric     return compiler_type;
730b57cec5SDimitry Andric 
7406c3fb27SDimitry Andric   static constexpr llvm::StringLiteral g_lldb_autogen_nspair("__lldb_autogen_nspair");
7506c3fb27SDimitry Andric 
7606c3fb27SDimitry Andric   compiler_type = scratch_ts_sp->GetTypeForIdentifier<clang::CXXRecordDecl>(g_lldb_autogen_nspair);
770b57cec5SDimitry Andric 
780b57cec5SDimitry Andric   if (!compiler_type) {
79bdd1243dSDimitry Andric     compiler_type = scratch_ts_sp->CreateRecordType(
805ffd83dbSDimitry Andric         nullptr, OptionalClangModuleID(), lldb::eAccessPublic,
815f757f3fSDimitry Andric         g_lldb_autogen_nspair, llvm::to_underlying(clang::TagTypeKind::Struct),
825f757f3fSDimitry Andric         lldb::eLanguageTypeC);
830b57cec5SDimitry Andric 
840b57cec5SDimitry Andric     if (compiler_type) {
855ffd83dbSDimitry Andric       TypeSystemClang::StartTagDeclarationDefinition(compiler_type);
860b57cec5SDimitry Andric       CompilerType id_compiler_type =
87bdd1243dSDimitry Andric           scratch_ts_sp->GetBasicType(eBasicTypeObjCID);
885ffd83dbSDimitry Andric       TypeSystemClang::AddFieldToRecordType(
890b57cec5SDimitry Andric           compiler_type, "key", id_compiler_type, lldb::eAccessPublic, 0);
905ffd83dbSDimitry Andric       TypeSystemClang::AddFieldToRecordType(
910b57cec5SDimitry Andric           compiler_type, "value", id_compiler_type, lldb::eAccessPublic, 0);
925ffd83dbSDimitry Andric       TypeSystemClang::CompleteTagDeclarationDefinition(compiler_type);
930b57cec5SDimitry Andric     }
940b57cec5SDimitry Andric   }
950b57cec5SDimitry Andric   return compiler_type;
960b57cec5SDimitry Andric }
970b57cec5SDimitry Andric 
980b57cec5SDimitry Andric namespace lldb_private {
990b57cec5SDimitry Andric namespace formatters {
1000b57cec5SDimitry Andric class NSDictionaryISyntheticFrontEnd : public SyntheticChildrenFrontEnd {
1010b57cec5SDimitry Andric public:
1020b57cec5SDimitry Andric   NSDictionaryISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
1030b57cec5SDimitry Andric 
1040b57cec5SDimitry Andric   ~NSDictionaryISyntheticFrontEnd() override;
1050b57cec5SDimitry Andric 
106*0fca6ea1SDimitry Andric   llvm::Expected<uint32_t> CalculateNumChildren() override;
1070b57cec5SDimitry Andric 
108*0fca6ea1SDimitry Andric   lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
1090b57cec5SDimitry Andric 
110*0fca6ea1SDimitry Andric   lldb::ChildCacheState Update() override;
1110b57cec5SDimitry Andric 
1120b57cec5SDimitry Andric   bool MightHaveChildren() override;
1130b57cec5SDimitry Andric 
1140b57cec5SDimitry Andric   size_t GetIndexOfChildWithName(ConstString name) override;
1150b57cec5SDimitry Andric 
1160b57cec5SDimitry Andric private:
1170b57cec5SDimitry Andric   struct DataDescriptor_32 {
1180b57cec5SDimitry Andric     uint32_t _used : 26;
1190b57cec5SDimitry Andric     uint32_t _szidx : 6;
1200b57cec5SDimitry Andric   };
1210b57cec5SDimitry Andric 
1220b57cec5SDimitry Andric   struct DataDescriptor_64 {
1230b57cec5SDimitry Andric     uint64_t _used : 58;
1240b57cec5SDimitry Andric     uint32_t _szidx : 6;
1250b57cec5SDimitry Andric   };
1260b57cec5SDimitry Andric 
1270b57cec5SDimitry Andric   struct DictionaryItemDescriptor {
1280b57cec5SDimitry Andric     lldb::addr_t key_ptr;
1290b57cec5SDimitry Andric     lldb::addr_t val_ptr;
1300b57cec5SDimitry Andric     lldb::ValueObjectSP valobj_sp;
1310b57cec5SDimitry Andric   };
1320b57cec5SDimitry Andric 
1330b57cec5SDimitry Andric   ExecutionContextRef m_exe_ctx_ref;
13481ad6265SDimitry Andric   uint8_t m_ptr_size = 8;
13581ad6265SDimitry Andric   lldb::ByteOrder m_order = lldb::eByteOrderInvalid;
13681ad6265SDimitry Andric   DataDescriptor_32 *m_data_32 = nullptr;
13781ad6265SDimitry Andric   DataDescriptor_64 *m_data_64 = nullptr;
138fcaf7f86SDimitry Andric   lldb::addr_t m_data_ptr = LLDB_INVALID_ADDRESS;
1390b57cec5SDimitry Andric   CompilerType m_pair_type;
1400b57cec5SDimitry Andric   std::vector<DictionaryItemDescriptor> m_children;
1410b57cec5SDimitry Andric };
1420b57cec5SDimitry Andric 
143349cc55cSDimitry Andric class NSConstantDictionarySyntheticFrontEnd : public SyntheticChildrenFrontEnd {
144349cc55cSDimitry Andric public:
145349cc55cSDimitry Andric   NSConstantDictionarySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
146349cc55cSDimitry Andric 
147*0fca6ea1SDimitry Andric   llvm::Expected<uint32_t> CalculateNumChildren() override;
148349cc55cSDimitry Andric 
149*0fca6ea1SDimitry Andric   lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
150349cc55cSDimitry Andric 
151*0fca6ea1SDimitry Andric   lldb::ChildCacheState Update() override;
152349cc55cSDimitry Andric 
153349cc55cSDimitry Andric   bool MightHaveChildren() override;
154349cc55cSDimitry Andric 
155349cc55cSDimitry Andric   size_t GetIndexOfChildWithName(ConstString name) override;
156349cc55cSDimitry Andric 
157349cc55cSDimitry Andric private:
158349cc55cSDimitry Andric   ExecutionContextRef m_exe_ctx_ref;
159349cc55cSDimitry Andric   CompilerType m_pair_type;
160349cc55cSDimitry Andric   uint8_t m_ptr_size = 8;
161349cc55cSDimitry Andric   lldb::ByteOrder m_order = lldb::eByteOrderInvalid;
162349cc55cSDimitry Andric   unsigned int m_size = 0;
163349cc55cSDimitry Andric   lldb::addr_t m_keys_ptr = LLDB_INVALID_ADDRESS;
164349cc55cSDimitry Andric   lldb::addr_t m_objects_ptr = LLDB_INVALID_ADDRESS;
165349cc55cSDimitry Andric 
166349cc55cSDimitry Andric   struct DictionaryItemDescriptor {
167349cc55cSDimitry Andric     lldb::addr_t key_ptr;
168349cc55cSDimitry Andric     lldb::addr_t val_ptr;
169349cc55cSDimitry Andric     lldb::ValueObjectSP valobj_sp;
170349cc55cSDimitry Andric   };
171349cc55cSDimitry Andric 
172349cc55cSDimitry Andric   std::vector<DictionaryItemDescriptor> m_children;
173349cc55cSDimitry Andric };
174349cc55cSDimitry Andric 
1755ffd83dbSDimitry Andric class NSCFDictionarySyntheticFrontEnd : public SyntheticChildrenFrontEnd {
1765ffd83dbSDimitry Andric public:
1775ffd83dbSDimitry Andric   NSCFDictionarySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
1785ffd83dbSDimitry Andric 
179*0fca6ea1SDimitry Andric   llvm::Expected<uint32_t> CalculateNumChildren() override;
1805ffd83dbSDimitry Andric 
181*0fca6ea1SDimitry Andric   lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
1825ffd83dbSDimitry Andric 
183*0fca6ea1SDimitry Andric   lldb::ChildCacheState Update() override;
1845ffd83dbSDimitry Andric 
1855ffd83dbSDimitry Andric   bool MightHaveChildren() override;
1865ffd83dbSDimitry Andric 
1875ffd83dbSDimitry Andric   size_t GetIndexOfChildWithName(ConstString name) override;
1885ffd83dbSDimitry Andric 
1895ffd83dbSDimitry Andric private:
1905ffd83dbSDimitry Andric   struct DictionaryItemDescriptor {
1915ffd83dbSDimitry Andric     lldb::addr_t key_ptr;
1925ffd83dbSDimitry Andric     lldb::addr_t val_ptr;
1935ffd83dbSDimitry Andric     lldb::ValueObjectSP valobj_sp;
1945ffd83dbSDimitry Andric   };
1955ffd83dbSDimitry Andric 
1965ffd83dbSDimitry Andric   ExecutionContextRef m_exe_ctx_ref;
19781ad6265SDimitry Andric   uint8_t m_ptr_size = 8;
19881ad6265SDimitry Andric   lldb::ByteOrder m_order = lldb::eByteOrderInvalid;
1995ffd83dbSDimitry Andric 
2005ffd83dbSDimitry Andric   CFBasicHash m_hashtable;
2015ffd83dbSDimitry Andric 
2025ffd83dbSDimitry Andric   CompilerType m_pair_type;
2035ffd83dbSDimitry Andric   std::vector<DictionaryItemDescriptor> m_children;
2045ffd83dbSDimitry Andric };
2055ffd83dbSDimitry Andric 
2060b57cec5SDimitry Andric class NSDictionary1SyntheticFrontEnd : public SyntheticChildrenFrontEnd {
2070b57cec5SDimitry Andric public:
2080b57cec5SDimitry Andric   NSDictionary1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
2090b57cec5SDimitry Andric 
2100b57cec5SDimitry Andric   ~NSDictionary1SyntheticFrontEnd() override = default;
2110b57cec5SDimitry Andric 
212*0fca6ea1SDimitry Andric   llvm::Expected<uint32_t> CalculateNumChildren() override;
2130b57cec5SDimitry Andric 
214*0fca6ea1SDimitry Andric   lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
2150b57cec5SDimitry Andric 
216*0fca6ea1SDimitry Andric   lldb::ChildCacheState Update() override;
2170b57cec5SDimitry Andric 
2180b57cec5SDimitry Andric   bool MightHaveChildren() override;
2190b57cec5SDimitry Andric 
2200b57cec5SDimitry Andric   size_t GetIndexOfChildWithName(ConstString name) override;
2210b57cec5SDimitry Andric 
2220b57cec5SDimitry Andric private:
2230b57cec5SDimitry Andric   ValueObjectSP m_pair;
2240b57cec5SDimitry Andric };
2250b57cec5SDimitry Andric 
2260b57cec5SDimitry Andric template <typename D32, typename D64>
2270b57cec5SDimitry Andric class GenericNSDictionaryMSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
2280b57cec5SDimitry Andric public:
2290b57cec5SDimitry Andric   GenericNSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
2300b57cec5SDimitry Andric 
2310b57cec5SDimitry Andric   ~GenericNSDictionaryMSyntheticFrontEnd() override;
2320b57cec5SDimitry Andric 
233*0fca6ea1SDimitry Andric   llvm::Expected<uint32_t> CalculateNumChildren() override;
2340b57cec5SDimitry Andric 
235*0fca6ea1SDimitry Andric   lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
2360b57cec5SDimitry Andric 
237*0fca6ea1SDimitry Andric   lldb::ChildCacheState Update() override;
2380b57cec5SDimitry Andric 
2390b57cec5SDimitry Andric   bool MightHaveChildren() override;
2400b57cec5SDimitry Andric 
2410b57cec5SDimitry Andric   size_t GetIndexOfChildWithName(ConstString name) override;
2420b57cec5SDimitry Andric 
2430b57cec5SDimitry Andric private:
2440b57cec5SDimitry Andric   struct DictionaryItemDescriptor {
2450b57cec5SDimitry Andric     lldb::addr_t key_ptr;
2460b57cec5SDimitry Andric     lldb::addr_t val_ptr;
2470b57cec5SDimitry Andric     lldb::ValueObjectSP valobj_sp;
2480b57cec5SDimitry Andric   };
2490b57cec5SDimitry Andric 
2500b57cec5SDimitry Andric   ExecutionContextRef m_exe_ctx_ref;
25181ad6265SDimitry Andric   uint8_t m_ptr_size = 8;
25281ad6265SDimitry Andric   lldb::ByteOrder m_order = lldb::eByteOrderInvalid;
2530b57cec5SDimitry Andric   D32 *m_data_32;
2540b57cec5SDimitry Andric   D64 *m_data_64;
2550b57cec5SDimitry Andric   CompilerType m_pair_type;
2560b57cec5SDimitry Andric   std::vector<DictionaryItemDescriptor> m_children;
2570b57cec5SDimitry Andric };
2580b57cec5SDimitry Andric 
2590b57cec5SDimitry Andric namespace Foundation1100 {
2600b57cec5SDimitry Andric   class NSDictionaryMSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
2610b57cec5SDimitry Andric   public:
2620b57cec5SDimitry Andric     NSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
2630b57cec5SDimitry Andric 
2640b57cec5SDimitry Andric     ~NSDictionaryMSyntheticFrontEnd() override;
2650b57cec5SDimitry Andric 
266*0fca6ea1SDimitry Andric     llvm::Expected<uint32_t> CalculateNumChildren() override;
2670b57cec5SDimitry Andric 
268*0fca6ea1SDimitry Andric     lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
2690b57cec5SDimitry Andric 
270*0fca6ea1SDimitry Andric     lldb::ChildCacheState Update() override;
2710b57cec5SDimitry Andric 
2720b57cec5SDimitry Andric     bool MightHaveChildren() override;
2730b57cec5SDimitry Andric 
2740b57cec5SDimitry Andric     size_t GetIndexOfChildWithName(ConstString name) override;
2750b57cec5SDimitry Andric 
2760b57cec5SDimitry Andric   private:
2770b57cec5SDimitry Andric     struct DataDescriptor_32 {
2780b57cec5SDimitry Andric       uint32_t _used : 26;
2790b57cec5SDimitry Andric       uint32_t _kvo : 1;
2800b57cec5SDimitry Andric       uint32_t _size;
2810b57cec5SDimitry Andric       uint32_t _mutations;
2820b57cec5SDimitry Andric       uint32_t _objs_addr;
2830b57cec5SDimitry Andric       uint32_t _keys_addr;
2840b57cec5SDimitry Andric     };
2850b57cec5SDimitry Andric 
2860b57cec5SDimitry Andric     struct DataDescriptor_64 {
2870b57cec5SDimitry Andric       uint64_t _used : 58;
2880b57cec5SDimitry Andric       uint32_t _kvo : 1;
2890b57cec5SDimitry Andric       uint64_t _size;
2900b57cec5SDimitry Andric       uint64_t _mutations;
2910b57cec5SDimitry Andric       uint64_t _objs_addr;
2920b57cec5SDimitry Andric       uint64_t _keys_addr;
2930b57cec5SDimitry Andric     };
2940b57cec5SDimitry Andric 
2950b57cec5SDimitry Andric     struct DictionaryItemDescriptor {
2960b57cec5SDimitry Andric       lldb::addr_t key_ptr;
2970b57cec5SDimitry Andric       lldb::addr_t val_ptr;
2980b57cec5SDimitry Andric       lldb::ValueObjectSP valobj_sp;
2990b57cec5SDimitry Andric     };
3000b57cec5SDimitry Andric 
3010b57cec5SDimitry Andric     ExecutionContextRef m_exe_ctx_ref;
30281ad6265SDimitry Andric     uint8_t m_ptr_size = 8;
30381ad6265SDimitry Andric     lldb::ByteOrder m_order = lldb::eByteOrderInvalid;
30481ad6265SDimitry Andric     DataDescriptor_32 *m_data_32 = nullptr;
30581ad6265SDimitry Andric     DataDescriptor_64 *m_data_64 = nullptr;
3060b57cec5SDimitry Andric     CompilerType m_pair_type;
3070b57cec5SDimitry Andric     std::vector<DictionaryItemDescriptor> m_children;
3080b57cec5SDimitry Andric   };
3090b57cec5SDimitry Andric }
3100b57cec5SDimitry Andric 
3110b57cec5SDimitry Andric namespace Foundation1428 {
3125ffd83dbSDimitry Andric   namespace {
3130b57cec5SDimitry Andric     struct DataDescriptor_32 {
3140b57cec5SDimitry Andric       uint32_t _used : 26;
3150b57cec5SDimitry Andric       uint32_t _kvo : 1;
3160b57cec5SDimitry Andric       uint32_t _size;
3170b57cec5SDimitry Andric       uint32_t _buffer;
3180b57cec5SDimitry Andric       uint64_t GetSize() { return _size; }
3190b57cec5SDimitry Andric     };
3200b57cec5SDimitry Andric 
3210b57cec5SDimitry Andric     struct DataDescriptor_64 {
3220b57cec5SDimitry Andric       uint64_t _used : 58;
3230b57cec5SDimitry Andric       uint32_t _kvo : 1;
3240b57cec5SDimitry Andric       uint64_t _size;
3250b57cec5SDimitry Andric       uint64_t _buffer;
3260b57cec5SDimitry Andric       uint64_t GetSize() { return _size; }
3270b57cec5SDimitry Andric     };
3285ffd83dbSDimitry Andric   }
3290b57cec5SDimitry Andric 
3300b57cec5SDimitry Andric   using NSDictionaryMSyntheticFrontEnd =
3310b57cec5SDimitry Andric     GenericNSDictionaryMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
3320b57cec5SDimitry Andric }
3330b57cec5SDimitry Andric 
3340b57cec5SDimitry Andric namespace Foundation1437 {
3350b57cec5SDimitry Andric     static const uint64_t NSDictionaryCapacities[] = {
3360b57cec5SDimitry Andric         0, 3, 7, 13, 23, 41, 71, 127, 191, 251, 383, 631, 1087, 1723,
3370b57cec5SDimitry Andric         2803, 4523, 7351, 11959, 19447, 31231, 50683, 81919, 132607,
3380b57cec5SDimitry Andric         214519, 346607, 561109, 907759, 1468927, 2376191, 3845119,
3390b57cec5SDimitry Andric         6221311, 10066421, 16287743, 26354171, 42641881, 68996069,
3400b57cec5SDimitry Andric         111638519, 180634607, 292272623, 472907251
3410b57cec5SDimitry Andric     };
3420b57cec5SDimitry Andric 
3435ffd83dbSDimitry Andric     static const size_t NSDictionaryNumSizeBuckets =
3445ffd83dbSDimitry Andric         sizeof(NSDictionaryCapacities) / sizeof(uint64_t);
3450b57cec5SDimitry Andric 
346349cc55cSDimitry Andric     namespace {
3470b57cec5SDimitry Andric     struct DataDescriptor_32 {
3480b57cec5SDimitry Andric       uint32_t _buffer;
3490b57cec5SDimitry Andric       uint32_t _muts;
3500b57cec5SDimitry Andric       uint32_t _used : 25;
3510b57cec5SDimitry Andric       uint32_t _kvo : 1;
3520b57cec5SDimitry Andric       uint32_t _szidx : 6;
3530b57cec5SDimitry Andric 
3540b57cec5SDimitry Andric       uint64_t GetSize() {
3550b57cec5SDimitry Andric         return (_szidx) >= NSDictionaryNumSizeBuckets ?
3560b57cec5SDimitry Andric             0 : NSDictionaryCapacities[_szidx];
3570b57cec5SDimitry Andric       }
3580b57cec5SDimitry Andric     };
3590b57cec5SDimitry Andric 
3600b57cec5SDimitry Andric     struct DataDescriptor_64 {
3610b57cec5SDimitry Andric       uint64_t _buffer;
3620b57cec5SDimitry Andric       uint32_t _muts;
3630b57cec5SDimitry Andric       uint32_t _used : 25;
3640b57cec5SDimitry Andric       uint32_t _kvo : 1;
3650b57cec5SDimitry Andric       uint32_t _szidx : 6;
3660b57cec5SDimitry Andric 
3670b57cec5SDimitry Andric       uint64_t GetSize() {
3680b57cec5SDimitry Andric         return (_szidx) >= NSDictionaryNumSizeBuckets ?
3690b57cec5SDimitry Andric             0 : NSDictionaryCapacities[_szidx];
3700b57cec5SDimitry Andric       }
3710b57cec5SDimitry Andric     };
372349cc55cSDimitry Andric     } // namespace
3730b57cec5SDimitry Andric 
3740b57cec5SDimitry Andric   using NSDictionaryMSyntheticFrontEnd =
3750b57cec5SDimitry Andric     GenericNSDictionaryMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
3760b57cec5SDimitry Andric 
3770b57cec5SDimitry Andric   template <typename DD>
3780b57cec5SDimitry Andric   uint64_t
3790b57cec5SDimitry Andric   __NSDictionaryMSize_Impl(lldb_private::Process &process,
3800b57cec5SDimitry Andric                            lldb::addr_t valobj_addr, Status &error) {
3810b57cec5SDimitry Andric     const lldb::addr_t start_of_descriptor =
3820b57cec5SDimitry Andric         valobj_addr + process.GetAddressByteSize();
3830b57cec5SDimitry Andric     DD descriptor = DD();
3840b57cec5SDimitry Andric     process.ReadMemory(start_of_descriptor, &descriptor, sizeof(descriptor),
3850b57cec5SDimitry Andric                        error);
3860b57cec5SDimitry Andric     if (error.Fail()) {
3870b57cec5SDimitry Andric       return 0;
3880b57cec5SDimitry Andric     }
3890b57cec5SDimitry Andric     return descriptor._used;
3900b57cec5SDimitry Andric   }
3910b57cec5SDimitry Andric 
3920b57cec5SDimitry Andric   uint64_t
3930b57cec5SDimitry Andric   __NSDictionaryMSize(lldb_private::Process &process, lldb::addr_t valobj_addr,
3940b57cec5SDimitry Andric                Status &error) {
3950b57cec5SDimitry Andric     if (process.GetAddressByteSize() == 4) {
3960b57cec5SDimitry Andric       return __NSDictionaryMSize_Impl<DataDescriptor_32>(process, valobj_addr,
3970b57cec5SDimitry Andric                                                          error);
3980b57cec5SDimitry Andric     } else {
3990b57cec5SDimitry Andric       return __NSDictionaryMSize_Impl<DataDescriptor_64>(process, valobj_addr,
4000b57cec5SDimitry Andric                                                          error);
4010b57cec5SDimitry Andric     }
4020b57cec5SDimitry Andric   }
4030b57cec5SDimitry Andric 
4040b57cec5SDimitry Andric }
4050b57cec5SDimitry Andric } // namespace formatters
4060b57cec5SDimitry Andric } // namespace lldb_private
4070b57cec5SDimitry Andric 
4080b57cec5SDimitry Andric template <bool name_entries>
4090b57cec5SDimitry Andric bool lldb_private::formatters::NSDictionarySummaryProvider(
4100b57cec5SDimitry Andric     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
41106c3fb27SDimitry Andric   static constexpr llvm::StringLiteral g_TypeHint("NSDictionary");
4120b57cec5SDimitry Andric   ProcessSP process_sp = valobj.GetProcessSP();
4130b57cec5SDimitry Andric   if (!process_sp)
4140b57cec5SDimitry Andric     return false;
4150b57cec5SDimitry Andric 
4160b57cec5SDimitry Andric   ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
4170b57cec5SDimitry Andric 
4180b57cec5SDimitry Andric   if (!runtime)
4190b57cec5SDimitry Andric     return false;
4200b57cec5SDimitry Andric 
4210b57cec5SDimitry Andric   ObjCLanguageRuntime::ClassDescriptorSP descriptor(
422e8d8bef9SDimitry Andric       runtime->GetNonKVOClassDescriptor(valobj));
4230b57cec5SDimitry Andric 
4240b57cec5SDimitry Andric   if (!descriptor || !descriptor->IsValid())
4250b57cec5SDimitry Andric     return false;
4260b57cec5SDimitry Andric 
4270b57cec5SDimitry Andric   uint32_t ptr_size = process_sp->GetAddressByteSize();
4280b57cec5SDimitry Andric   bool is_64bit = (ptr_size == 8);
4290b57cec5SDimitry Andric 
4300b57cec5SDimitry Andric   lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
4310b57cec5SDimitry Andric 
4320b57cec5SDimitry Andric   if (!valobj_addr)
4330b57cec5SDimitry Andric     return false;
4340b57cec5SDimitry Andric 
4350b57cec5SDimitry Andric   uint64_t value = 0;
4360b57cec5SDimitry Andric 
4370b57cec5SDimitry Andric   ConstString class_name(descriptor->GetClassName());
4380b57cec5SDimitry Andric 
4390b57cec5SDimitry Andric   static const ConstString g_DictionaryI("__NSDictionaryI");
4400b57cec5SDimitry Andric   static const ConstString g_DictionaryM("__NSDictionaryM");
4410b57cec5SDimitry Andric   static const ConstString g_DictionaryMLegacy("__NSDictionaryM_Legacy");
4420b57cec5SDimitry Andric   static const ConstString g_DictionaryMImmutable("__NSDictionaryM_Immutable");
443fe6060f1SDimitry Andric   static const ConstString g_DictionaryMFrozen("__NSFrozenDictionaryM");
4440b57cec5SDimitry Andric   static const ConstString g_Dictionary1("__NSSingleEntryDictionaryI");
4450b57cec5SDimitry Andric   static const ConstString g_Dictionary0("__NSDictionary0");
4465ffd83dbSDimitry Andric   static const ConstString g_DictionaryCF("__CFDictionary");
4475ffd83dbSDimitry Andric   static const ConstString g_DictionaryNSCF("__NSCFDictionary");
4485ffd83dbSDimitry Andric   static const ConstString g_DictionaryCFRef("CFDictionaryRef");
449349cc55cSDimitry Andric   static const ConstString g_ConstantDictionary("NSConstantDictionary");
4500b57cec5SDimitry Andric 
4510b57cec5SDimitry Andric   if (class_name.IsEmpty())
4520b57cec5SDimitry Andric     return false;
4530b57cec5SDimitry Andric 
4540b57cec5SDimitry Andric   if (class_name == g_DictionaryI || class_name == g_DictionaryMImmutable) {
4550b57cec5SDimitry Andric     Status error;
4560b57cec5SDimitry Andric     value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
4570b57cec5SDimitry Andric                                                       ptr_size, 0, error);
4580b57cec5SDimitry Andric     if (error.Fail())
4590b57cec5SDimitry Andric       return false;
4605ffd83dbSDimitry Andric 
4610b57cec5SDimitry Andric     value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
462349cc55cSDimitry Andric   } else if (class_name == g_ConstantDictionary) {
463349cc55cSDimitry Andric     Status error;
464349cc55cSDimitry Andric     value = process_sp->ReadUnsignedIntegerFromMemory(
465349cc55cSDimitry Andric         valobj_addr + 2 * ptr_size, ptr_size, 0, error);
466349cc55cSDimitry Andric     if (error.Fail())
467349cc55cSDimitry Andric       return false;
468349cc55cSDimitry Andric   } else if (class_name == g_DictionaryM || class_name == g_DictionaryMLegacy ||
469349cc55cSDimitry Andric              class_name == g_DictionaryMFrozen) {
4700b57cec5SDimitry Andric     AppleObjCRuntime *apple_runtime =
4710b57cec5SDimitry Andric     llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime);
4720b57cec5SDimitry Andric     Status error;
4730b57cec5SDimitry Andric     if (apple_runtime && apple_runtime->GetFoundationVersion() >= 1437) {
4740b57cec5SDimitry Andric       value = Foundation1437::__NSDictionaryMSize(*process_sp, valobj_addr,
4750b57cec5SDimitry Andric                                                   error);
4760b57cec5SDimitry Andric     } else {
4770b57cec5SDimitry Andric       value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
4780b57cec5SDimitry Andric                                                         ptr_size, 0, error);
4790b57cec5SDimitry Andric       value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
4800b57cec5SDimitry Andric     }
4810b57cec5SDimitry Andric     if (error.Fail())
4820b57cec5SDimitry Andric       return false;
4830b57cec5SDimitry Andric   } else if (class_name == g_Dictionary1) {
4840b57cec5SDimitry Andric     value = 1;
4850b57cec5SDimitry Andric   } else if (class_name == g_Dictionary0) {
4860b57cec5SDimitry Andric     value = 0;
487349cc55cSDimitry Andric   } else if (class_name == g_DictionaryCF || class_name == g_DictionaryNSCF ||
4885ffd83dbSDimitry Andric              class_name == g_DictionaryCFRef) {
4895ffd83dbSDimitry Andric     ExecutionContext exe_ctx(process_sp);
4905ffd83dbSDimitry Andric     CFBasicHash cfbh;
4915ffd83dbSDimitry Andric     if (!cfbh.Update(valobj_addr, exe_ctx))
4925ffd83dbSDimitry Andric       return false;
4935ffd83dbSDimitry Andric     value = cfbh.GetCount();
4945ffd83dbSDimitry Andric   } else {
4950b57cec5SDimitry Andric     auto &map(NSDictionary_Additionals::GetAdditionalSummaries());
4960b57cec5SDimitry Andric     for (auto &candidate : map) {
4970b57cec5SDimitry Andric       if (candidate.first && candidate.first->Match(class_name))
4980b57cec5SDimitry Andric         return candidate.second(valobj, stream, options);
4990b57cec5SDimitry Andric     }
5000b57cec5SDimitry Andric     return false;
5010b57cec5SDimitry Andric   }
5020b57cec5SDimitry Andric 
50306c3fb27SDimitry Andric   llvm::StringRef prefix, suffix;
50406c3fb27SDimitry Andric   if (Language *language = Language::FindPlugin(options.GetLanguage()))
50506c3fb27SDimitry Andric     std::tie(prefix, suffix) = language->GetFormatterPrefixSuffix(g_TypeHint);
5060b57cec5SDimitry Andric 
50706c3fb27SDimitry Andric   stream << prefix;
50806c3fb27SDimitry Andric   stream.Printf("%" PRIu64 " %s%s", value, "key/value pair",
50906c3fb27SDimitry Andric                 value == 1 ? "" : "s");
51006c3fb27SDimitry Andric   stream << suffix;
5110b57cec5SDimitry Andric   return true;
5120b57cec5SDimitry Andric }
5130b57cec5SDimitry Andric 
5140b57cec5SDimitry Andric SyntheticChildrenFrontEnd *
5150b57cec5SDimitry Andric lldb_private::formatters::NSDictionarySyntheticFrontEndCreator(
5160b57cec5SDimitry Andric     CXXSyntheticChildren *synth, lldb::ValueObjectSP valobj_sp) {
5170b57cec5SDimitry Andric   lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
5180b57cec5SDimitry Andric   if (!process_sp)
5190b57cec5SDimitry Andric     return nullptr;
5200b57cec5SDimitry Andric   AppleObjCRuntime *runtime = llvm::dyn_cast_or_null<AppleObjCRuntime>(
5210b57cec5SDimitry Andric       ObjCLanguageRuntime::Get(*process_sp));
5220b57cec5SDimitry Andric   if (!runtime)
5230b57cec5SDimitry Andric     return nullptr;
5240b57cec5SDimitry Andric 
5250b57cec5SDimitry Andric   CompilerType valobj_type(valobj_sp->GetCompilerType());
5260b57cec5SDimitry Andric   Flags flags(valobj_type.GetTypeInfo());
5270b57cec5SDimitry Andric 
5280b57cec5SDimitry Andric   if (flags.IsClear(eTypeIsPointer)) {
5290b57cec5SDimitry Andric     Status error;
5300b57cec5SDimitry Andric     valobj_sp = valobj_sp->AddressOf(error);
5310b57cec5SDimitry Andric     if (error.Fail() || !valobj_sp)
5320b57cec5SDimitry Andric       return nullptr;
5330b57cec5SDimitry Andric   }
5340b57cec5SDimitry Andric 
5350b57cec5SDimitry Andric   ObjCLanguageRuntime::ClassDescriptorSP descriptor(
5360b57cec5SDimitry Andric       runtime->GetClassDescriptor(*valobj_sp));
5370b57cec5SDimitry Andric 
5380b57cec5SDimitry Andric   if (!descriptor || !descriptor->IsValid())
5390b57cec5SDimitry Andric     return nullptr;
5400b57cec5SDimitry Andric 
5410b57cec5SDimitry Andric   ConstString class_name(descriptor->GetClassName());
5420b57cec5SDimitry Andric 
5430b57cec5SDimitry Andric   static const ConstString g_DictionaryI("__NSDictionaryI");
5440b57cec5SDimitry Andric   static const ConstString g_DictionaryM("__NSDictionaryM");
5450b57cec5SDimitry Andric   static const ConstString g_Dictionary1("__NSSingleEntryDictionaryI");
5460b57cec5SDimitry Andric   static const ConstString g_DictionaryImmutable("__NSDictionaryM_Immutable");
547fe6060f1SDimitry Andric   static const ConstString g_DictionaryMFrozen("__NSFrozenDictionaryM");
5480b57cec5SDimitry Andric   static const ConstString g_DictionaryMLegacy("__NSDictionaryM_Legacy");
5490b57cec5SDimitry Andric   static const ConstString g_Dictionary0("__NSDictionary0");
5505ffd83dbSDimitry Andric   static const ConstString g_DictionaryCF("__CFDictionary");
5515ffd83dbSDimitry Andric   static const ConstString g_DictionaryNSCF("__NSCFDictionary");
5525ffd83dbSDimitry Andric   static const ConstString g_DictionaryCFRef("CFDictionaryRef");
553349cc55cSDimitry Andric   static const ConstString g_ConstantDictionary("NSConstantDictionary");
5540b57cec5SDimitry Andric 
5550b57cec5SDimitry Andric   if (class_name.IsEmpty())
5560b57cec5SDimitry Andric     return nullptr;
5570b57cec5SDimitry Andric 
5580b57cec5SDimitry Andric   if (class_name == g_DictionaryI) {
5590b57cec5SDimitry Andric     return (new NSDictionaryISyntheticFrontEnd(valobj_sp));
560349cc55cSDimitry Andric   } else if (class_name == g_ConstantDictionary) {
561349cc55cSDimitry Andric     return (new NSConstantDictionarySyntheticFrontEnd(valobj_sp));
562fe6060f1SDimitry Andric   } else if (class_name == g_DictionaryM || class_name == g_DictionaryMFrozen) {
5630b57cec5SDimitry Andric     if (runtime->GetFoundationVersion() >= 1437) {
5640b57cec5SDimitry Andric       return (new Foundation1437::NSDictionaryMSyntheticFrontEnd(valobj_sp));
5650b57cec5SDimitry Andric     } else if (runtime->GetFoundationVersion() >= 1428) {
5660b57cec5SDimitry Andric       return (new Foundation1428::NSDictionaryMSyntheticFrontEnd(valobj_sp));
5670b57cec5SDimitry Andric     } else {
5680b57cec5SDimitry Andric       return (new Foundation1100::NSDictionaryMSyntheticFrontEnd(valobj_sp));
5690b57cec5SDimitry Andric     }
5700b57cec5SDimitry Andric   } else if (class_name == g_DictionaryMLegacy) {
5710b57cec5SDimitry Andric     return (new Foundation1100::NSDictionaryMSyntheticFrontEnd(valobj_sp));
5720b57cec5SDimitry Andric   } else if (class_name == g_Dictionary1) {
5730b57cec5SDimitry Andric     return (new NSDictionary1SyntheticFrontEnd(valobj_sp));
574349cc55cSDimitry Andric   } else if (class_name == g_DictionaryCF || class_name == g_DictionaryNSCF ||
5755ffd83dbSDimitry Andric              class_name == g_DictionaryCFRef) {
5765ffd83dbSDimitry Andric     return (new NSCFDictionarySyntheticFrontEnd(valobj_sp));
5770b57cec5SDimitry Andric   } else {
5780b57cec5SDimitry Andric     auto &map(NSDictionary_Additionals::GetAdditionalSynthetics());
5790b57cec5SDimitry Andric     for (auto &candidate : map) {
5800b57cec5SDimitry Andric       if (candidate.first && candidate.first->Match((class_name)))
5810b57cec5SDimitry Andric         return candidate.second(synth, valobj_sp);
5820b57cec5SDimitry Andric     }
5830b57cec5SDimitry Andric   }
5840b57cec5SDimitry Andric 
5850b57cec5SDimitry Andric   return nullptr;
5860b57cec5SDimitry Andric }
5870b57cec5SDimitry Andric 
5880b57cec5SDimitry Andric lldb_private::formatters::NSDictionaryISyntheticFrontEnd::
5890b57cec5SDimitry Andric     NSDictionaryISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
59081ad6265SDimitry Andric     : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_pair_type() {}
5910b57cec5SDimitry Andric 
5920b57cec5SDimitry Andric lldb_private::formatters::NSDictionaryISyntheticFrontEnd::
5930b57cec5SDimitry Andric     ~NSDictionaryISyntheticFrontEnd() {
5940b57cec5SDimitry Andric   delete m_data_32;
5950b57cec5SDimitry Andric   m_data_32 = nullptr;
5960b57cec5SDimitry Andric   delete m_data_64;
5970b57cec5SDimitry Andric   m_data_64 = nullptr;
5980b57cec5SDimitry Andric }
5990b57cec5SDimitry Andric 
6000b57cec5SDimitry Andric size_t lldb_private::formatters::NSDictionaryISyntheticFrontEnd::
6010b57cec5SDimitry Andric     GetIndexOfChildWithName(ConstString name) {
6020b57cec5SDimitry Andric   const char *item_name = name.GetCString();
6030b57cec5SDimitry Andric   uint32_t idx = ExtractIndexFromString(item_name);
604*0fca6ea1SDimitry Andric   if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors())
6050b57cec5SDimitry Andric     return UINT32_MAX;
6060b57cec5SDimitry Andric   return idx;
6070b57cec5SDimitry Andric }
6080b57cec5SDimitry Andric 
609*0fca6ea1SDimitry Andric llvm::Expected<uint32_t> lldb_private::formatters::
610*0fca6ea1SDimitry Andric     NSDictionaryISyntheticFrontEnd::CalculateNumChildren() {
6110b57cec5SDimitry Andric   if (!m_data_32 && !m_data_64)
6120b57cec5SDimitry Andric     return 0;
6130b57cec5SDimitry Andric   return (m_data_32 ? m_data_32->_used : m_data_64->_used);
6140b57cec5SDimitry Andric }
6150b57cec5SDimitry Andric 
616*0fca6ea1SDimitry Andric lldb::ChildCacheState
617*0fca6ea1SDimitry Andric lldb_private::formatters::NSDictionaryISyntheticFrontEnd::Update() {
6180b57cec5SDimitry Andric   m_children.clear();
6190b57cec5SDimitry Andric   delete m_data_32;
6200b57cec5SDimitry Andric   m_data_32 = nullptr;
6210b57cec5SDimitry Andric   delete m_data_64;
6220b57cec5SDimitry Andric   m_data_64 = nullptr;
6230b57cec5SDimitry Andric   m_ptr_size = 0;
6240b57cec5SDimitry Andric   ValueObjectSP valobj_sp = m_backend.GetSP();
6250b57cec5SDimitry Andric   if (!valobj_sp)
626*0fca6ea1SDimitry Andric     return lldb::ChildCacheState::eRefetch;
6270b57cec5SDimitry Andric   m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
6280b57cec5SDimitry Andric   Status error;
6290b57cec5SDimitry Andric   error.Clear();
6300b57cec5SDimitry Andric   lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
6310b57cec5SDimitry Andric   if (!process_sp)
632*0fca6ea1SDimitry Andric     return lldb::ChildCacheState::eRefetch;
6330b57cec5SDimitry Andric   m_ptr_size = process_sp->GetAddressByteSize();
6340b57cec5SDimitry Andric   m_order = process_sp->GetByteOrder();
6350b57cec5SDimitry Andric   uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
6360b57cec5SDimitry Andric   if (m_ptr_size == 4) {
6370b57cec5SDimitry Andric     m_data_32 = new DataDescriptor_32();
6380b57cec5SDimitry Andric     process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),
6390b57cec5SDimitry Andric                            error);
6400b57cec5SDimitry Andric   } else {
6410b57cec5SDimitry Andric     m_data_64 = new DataDescriptor_64();
6420b57cec5SDimitry Andric     process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),
6430b57cec5SDimitry Andric                            error);
6440b57cec5SDimitry Andric   }
6450b57cec5SDimitry Andric   if (error.Fail())
646*0fca6ea1SDimitry Andric     return lldb::ChildCacheState::eRefetch;
6470b57cec5SDimitry Andric   m_data_ptr = data_location + m_ptr_size;
648*0fca6ea1SDimitry Andric   return lldb::ChildCacheState::eRefetch;
6490b57cec5SDimitry Andric }
6500b57cec5SDimitry Andric 
6510b57cec5SDimitry Andric bool lldb_private::formatters::NSDictionaryISyntheticFrontEnd::
6520b57cec5SDimitry Andric     MightHaveChildren() {
6530b57cec5SDimitry Andric   return true;
6540b57cec5SDimitry Andric }
6550b57cec5SDimitry Andric 
6560b57cec5SDimitry Andric lldb::ValueObjectSP
6570b57cec5SDimitry Andric lldb_private::formatters::NSDictionaryISyntheticFrontEnd::GetChildAtIndex(
658*0fca6ea1SDimitry Andric     uint32_t idx) {
659*0fca6ea1SDimitry Andric   uint32_t num_children = CalculateNumChildrenIgnoringErrors();
6600b57cec5SDimitry Andric 
6610b57cec5SDimitry Andric   if (idx >= num_children)
6620b57cec5SDimitry Andric     return lldb::ValueObjectSP();
6630b57cec5SDimitry Andric 
6640b57cec5SDimitry Andric   if (m_children.empty()) {
6650b57cec5SDimitry Andric     // do the scan phase
6660b57cec5SDimitry Andric     lldb::addr_t key_at_idx = 0, val_at_idx = 0;
6670b57cec5SDimitry Andric 
6680b57cec5SDimitry Andric     uint32_t tries = 0;
6690b57cec5SDimitry Andric     uint32_t test_idx = 0;
6700b57cec5SDimitry Andric 
6710b57cec5SDimitry Andric     while (tries < num_children) {
6720b57cec5SDimitry Andric       key_at_idx = m_data_ptr + (2 * test_idx * m_ptr_size);
6730b57cec5SDimitry Andric       val_at_idx = key_at_idx + m_ptr_size;
6740b57cec5SDimitry Andric       ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
6750b57cec5SDimitry Andric       if (!process_sp)
6760b57cec5SDimitry Andric         return lldb::ValueObjectSP();
6770b57cec5SDimitry Andric       Status error;
6780b57cec5SDimitry Andric       key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
6790b57cec5SDimitry Andric       if (error.Fail())
6800b57cec5SDimitry Andric         return lldb::ValueObjectSP();
6810b57cec5SDimitry Andric       val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
6820b57cec5SDimitry Andric       if (error.Fail())
6830b57cec5SDimitry Andric         return lldb::ValueObjectSP();
6840b57cec5SDimitry Andric 
6850b57cec5SDimitry Andric       test_idx++;
6860b57cec5SDimitry Andric 
6870b57cec5SDimitry Andric       if (!key_at_idx || !val_at_idx)
6880b57cec5SDimitry Andric         continue;
6890b57cec5SDimitry Andric       tries++;
6900b57cec5SDimitry Andric 
6910b57cec5SDimitry Andric       DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,
6920b57cec5SDimitry Andric                                              lldb::ValueObjectSP()};
6930b57cec5SDimitry Andric 
6940b57cec5SDimitry Andric       m_children.push_back(descriptor);
6950b57cec5SDimitry Andric     }
6960b57cec5SDimitry Andric   }
6970b57cec5SDimitry Andric 
6980b57cec5SDimitry Andric   if (idx >= m_children.size()) // should never happen
6990b57cec5SDimitry Andric     return lldb::ValueObjectSP();
7000b57cec5SDimitry Andric 
7010b57cec5SDimitry Andric   DictionaryItemDescriptor &dict_item = m_children[idx];
7020b57cec5SDimitry Andric   if (!dict_item.valobj_sp) {
7030b57cec5SDimitry Andric     if (!m_pair_type.IsValid()) {
7040b57cec5SDimitry Andric       TargetSP target_sp(m_backend.GetTargetSP());
7050b57cec5SDimitry Andric       if (!target_sp)
7060b57cec5SDimitry Andric         return ValueObjectSP();
7070b57cec5SDimitry Andric       m_pair_type = GetLLDBNSPairType(target_sp);
7080b57cec5SDimitry Andric     }
7090b57cec5SDimitry Andric     if (!m_pair_type.IsValid())
7100b57cec5SDimitry Andric       return ValueObjectSP();
7110b57cec5SDimitry Andric 
71281ad6265SDimitry Andric     WritableDataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
7130b57cec5SDimitry Andric 
7140b57cec5SDimitry Andric     if (m_ptr_size == 8) {
7150b57cec5SDimitry Andric       uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
7160b57cec5SDimitry Andric       *data_ptr = dict_item.key_ptr;
7170b57cec5SDimitry Andric       *(data_ptr + 1) = dict_item.val_ptr;
7180b57cec5SDimitry Andric     } else {
7190b57cec5SDimitry Andric       uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
7200b57cec5SDimitry Andric       *data_ptr = dict_item.key_ptr;
7210b57cec5SDimitry Andric       *(data_ptr + 1) = dict_item.val_ptr;
7220b57cec5SDimitry Andric     }
7230b57cec5SDimitry Andric 
7240b57cec5SDimitry Andric     StreamString idx_name;
7250b57cec5SDimitry Andric     idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
7260b57cec5SDimitry Andric     DataExtractor data(buffer_sp, m_order, m_ptr_size);
7270b57cec5SDimitry Andric     dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
7280b57cec5SDimitry Andric                                                     m_exe_ctx_ref, m_pair_type);
7290b57cec5SDimitry Andric   }
7300b57cec5SDimitry Andric   return dict_item.valobj_sp;
7310b57cec5SDimitry Andric }
7320b57cec5SDimitry Andric 
7335ffd83dbSDimitry Andric lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::
7345ffd83dbSDimitry Andric     NSCFDictionarySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
73581ad6265SDimitry Andric     : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_hashtable(),
73681ad6265SDimitry Andric       m_pair_type() {}
7375ffd83dbSDimitry Andric 
7385ffd83dbSDimitry Andric size_t lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::
7395ffd83dbSDimitry Andric     GetIndexOfChildWithName(ConstString name) {
7405ffd83dbSDimitry Andric   const char *item_name = name.GetCString();
7415ffd83dbSDimitry Andric   const uint32_t idx = ExtractIndexFromString(item_name);
742*0fca6ea1SDimitry Andric   if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors())
7435ffd83dbSDimitry Andric     return UINT32_MAX;
7445ffd83dbSDimitry Andric   return idx;
7455ffd83dbSDimitry Andric }
7465ffd83dbSDimitry Andric 
747*0fca6ea1SDimitry Andric llvm::Expected<uint32_t> lldb_private::formatters::
748*0fca6ea1SDimitry Andric     NSCFDictionarySyntheticFrontEnd::CalculateNumChildren() {
7495ffd83dbSDimitry Andric   if (!m_hashtable.IsValid())
7505ffd83dbSDimitry Andric     return 0;
7515ffd83dbSDimitry Andric   return m_hashtable.GetCount();
7525ffd83dbSDimitry Andric }
7535ffd83dbSDimitry Andric 
754*0fca6ea1SDimitry Andric lldb::ChildCacheState
755*0fca6ea1SDimitry Andric lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::Update() {
7565ffd83dbSDimitry Andric   m_children.clear();
7575ffd83dbSDimitry Andric   ValueObjectSP valobj_sp = m_backend.GetSP();
7585ffd83dbSDimitry Andric   m_ptr_size = 0;
7595ffd83dbSDimitry Andric   if (!valobj_sp)
760*0fca6ea1SDimitry Andric     return lldb::ChildCacheState::eRefetch;
7615ffd83dbSDimitry Andric   m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
7625ffd83dbSDimitry Andric 
7635ffd83dbSDimitry Andric   lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
7645ffd83dbSDimitry Andric   if (!process_sp)
765*0fca6ea1SDimitry Andric     return lldb::ChildCacheState::eRefetch;
7665ffd83dbSDimitry Andric   m_ptr_size = process_sp->GetAddressByteSize();
7675ffd83dbSDimitry Andric   m_order = process_sp->GetByteOrder();
768*0fca6ea1SDimitry Andric   return m_hashtable.Update(valobj_sp->GetValueAsUnsigned(0), m_exe_ctx_ref)
769*0fca6ea1SDimitry Andric              ? lldb::ChildCacheState::eReuse
770*0fca6ea1SDimitry Andric              : lldb::ChildCacheState::eRefetch;
7715ffd83dbSDimitry Andric }
7725ffd83dbSDimitry Andric 
7735ffd83dbSDimitry Andric bool lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::
7745ffd83dbSDimitry Andric     MightHaveChildren() {
7755ffd83dbSDimitry Andric   return true;
7765ffd83dbSDimitry Andric }
7775ffd83dbSDimitry Andric 
7785ffd83dbSDimitry Andric lldb::ValueObjectSP
7795ffd83dbSDimitry Andric lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::GetChildAtIndex(
780*0fca6ea1SDimitry Andric     uint32_t idx) {
7815ffd83dbSDimitry Andric   lldb::addr_t m_keys_ptr = m_hashtable.GetKeyPointer();
7825ffd83dbSDimitry Andric   lldb::addr_t m_values_ptr = m_hashtable.GetValuePointer();
7835ffd83dbSDimitry Andric 
784*0fca6ea1SDimitry Andric   const uint32_t num_children = CalculateNumChildrenIgnoringErrors();
7855ffd83dbSDimitry Andric 
7865ffd83dbSDimitry Andric   if (idx >= num_children)
7875ffd83dbSDimitry Andric     return lldb::ValueObjectSP();
7885ffd83dbSDimitry Andric 
7895ffd83dbSDimitry Andric   if (m_children.empty()) {
7905ffd83dbSDimitry Andric     ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
7915ffd83dbSDimitry Andric     if (!process_sp)
7925ffd83dbSDimitry Andric       return lldb::ValueObjectSP();
7935ffd83dbSDimitry Andric 
7945ffd83dbSDimitry Andric     Status error;
7955ffd83dbSDimitry Andric     lldb::addr_t key_at_idx = 0, val_at_idx = 0;
7965ffd83dbSDimitry Andric 
7975ffd83dbSDimitry Andric     uint32_t tries = 0;
7985ffd83dbSDimitry Andric     uint32_t test_idx = 0;
7995ffd83dbSDimitry Andric 
8005ffd83dbSDimitry Andric     // Iterate over inferior memory, reading key/value pointers by shifting each
8015ffd83dbSDimitry Andric     // cursor by test_index * m_ptr_size. Returns an empty ValueObject if a read
8025ffd83dbSDimitry Andric     // fails, otherwise, continue until the number of tries matches the number
8035ffd83dbSDimitry Andric     // of childen.
8045ffd83dbSDimitry Andric     while (tries < num_children) {
8055ffd83dbSDimitry Andric       key_at_idx = m_keys_ptr + (test_idx * m_ptr_size);
8065ffd83dbSDimitry Andric       val_at_idx = m_values_ptr + (test_idx * m_ptr_size);
8075ffd83dbSDimitry Andric 
8085ffd83dbSDimitry Andric       key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
8095ffd83dbSDimitry Andric       if (error.Fail())
8105ffd83dbSDimitry Andric         return lldb::ValueObjectSP();
8115ffd83dbSDimitry Andric       val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
8125ffd83dbSDimitry Andric       if (error.Fail())
8135ffd83dbSDimitry Andric         return lldb::ValueObjectSP();
8145ffd83dbSDimitry Andric 
8155ffd83dbSDimitry Andric       test_idx++;
8165ffd83dbSDimitry Andric 
8175ffd83dbSDimitry Andric       if (!key_at_idx || !val_at_idx)
8185ffd83dbSDimitry Andric         continue;
8195ffd83dbSDimitry Andric       tries++;
8205ffd83dbSDimitry Andric 
8215ffd83dbSDimitry Andric       DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,
8225ffd83dbSDimitry Andric                                              lldb::ValueObjectSP()};
8235ffd83dbSDimitry Andric 
8245ffd83dbSDimitry Andric       m_children.push_back(descriptor);
8255ffd83dbSDimitry Andric     }
8265ffd83dbSDimitry Andric   }
8275ffd83dbSDimitry Andric 
8285ffd83dbSDimitry Andric   if (idx >= m_children.size()) // should never happen
8295ffd83dbSDimitry Andric     return lldb::ValueObjectSP();
8305ffd83dbSDimitry Andric 
8315ffd83dbSDimitry Andric   DictionaryItemDescriptor &dict_item = m_children[idx];
8325ffd83dbSDimitry Andric   if (!dict_item.valobj_sp) {
8335ffd83dbSDimitry Andric     if (!m_pair_type.IsValid()) {
8345ffd83dbSDimitry Andric       TargetSP target_sp(m_backend.GetTargetSP());
8355ffd83dbSDimitry Andric       if (!target_sp)
8365ffd83dbSDimitry Andric         return ValueObjectSP();
8375ffd83dbSDimitry Andric       m_pair_type = GetLLDBNSPairType(target_sp);
8385ffd83dbSDimitry Andric     }
8395ffd83dbSDimitry Andric     if (!m_pair_type.IsValid())
8405ffd83dbSDimitry Andric       return ValueObjectSP();
8415ffd83dbSDimitry Andric 
84281ad6265SDimitry Andric     WritableDataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
8435ffd83dbSDimitry Andric 
8445ffd83dbSDimitry Andric     switch (m_ptr_size) {
8455ffd83dbSDimitry Andric     case 0: // architecture has no clue - fail
8465ffd83dbSDimitry Andric       return lldb::ValueObjectSP();
8475ffd83dbSDimitry Andric     case 4: {
8485ffd83dbSDimitry Andric       uint32_t *data_ptr = reinterpret_cast<uint32_t *>(buffer_sp->GetBytes());
8495ffd83dbSDimitry Andric       *data_ptr = dict_item.key_ptr;
8505ffd83dbSDimitry Andric       *(data_ptr + 1) = dict_item.val_ptr;
8515ffd83dbSDimitry Andric     } break;
8525ffd83dbSDimitry Andric     case 8: {
8535ffd83dbSDimitry Andric       uint64_t *data_ptr = reinterpret_cast<uint64_t *>(buffer_sp->GetBytes());
8545ffd83dbSDimitry Andric       *data_ptr = dict_item.key_ptr;
8555ffd83dbSDimitry Andric       *(data_ptr + 1) = dict_item.val_ptr;
8565ffd83dbSDimitry Andric     } break;
8575ffd83dbSDimitry Andric     default:
8585ffd83dbSDimitry Andric       lldbassert(false && "pointer size is not 4 nor 8");
8595ffd83dbSDimitry Andric     }
8605ffd83dbSDimitry Andric 
8615ffd83dbSDimitry Andric     StreamString idx_name;
8625ffd83dbSDimitry Andric     idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
8635ffd83dbSDimitry Andric     DataExtractor data(buffer_sp, m_order, m_ptr_size);
8645ffd83dbSDimitry Andric     dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
8655ffd83dbSDimitry Andric                                                     m_exe_ctx_ref, m_pair_type);
8665ffd83dbSDimitry Andric   }
8675ffd83dbSDimitry Andric   return dict_item.valobj_sp;
8685ffd83dbSDimitry Andric }
8695ffd83dbSDimitry Andric 
870349cc55cSDimitry Andric lldb_private::formatters::NSConstantDictionarySyntheticFrontEnd::
871349cc55cSDimitry Andric     NSConstantDictionarySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
872349cc55cSDimitry Andric     : SyntheticChildrenFrontEnd(*valobj_sp) {}
873349cc55cSDimitry Andric 
874349cc55cSDimitry Andric size_t lldb_private::formatters::NSConstantDictionarySyntheticFrontEnd::
875349cc55cSDimitry Andric     GetIndexOfChildWithName(ConstString name) {
876349cc55cSDimitry Andric   const char *item_name = name.GetCString();
877349cc55cSDimitry Andric   uint32_t idx = ExtractIndexFromString(item_name);
878*0fca6ea1SDimitry Andric   if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors())
879349cc55cSDimitry Andric     return UINT32_MAX;
880349cc55cSDimitry Andric   return idx;
881349cc55cSDimitry Andric }
882349cc55cSDimitry Andric 
883*0fca6ea1SDimitry Andric llvm::Expected<uint32_t> lldb_private::formatters::
884*0fca6ea1SDimitry Andric     NSConstantDictionarySyntheticFrontEnd::CalculateNumChildren() {
885349cc55cSDimitry Andric   return m_size;
886349cc55cSDimitry Andric }
887349cc55cSDimitry Andric 
888*0fca6ea1SDimitry Andric lldb::ChildCacheState
889*0fca6ea1SDimitry Andric lldb_private::formatters::NSConstantDictionarySyntheticFrontEnd::Update() {
890349cc55cSDimitry Andric   ValueObjectSP valobj_sp = m_backend.GetSP();
891349cc55cSDimitry Andric   if (!valobj_sp)
892*0fca6ea1SDimitry Andric     return lldb::ChildCacheState::eRefetch;
893349cc55cSDimitry Andric   m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
894349cc55cSDimitry Andric   Status error;
895349cc55cSDimitry Andric   error.Clear();
896349cc55cSDimitry Andric   lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
897349cc55cSDimitry Andric   if (!process_sp)
898*0fca6ea1SDimitry Andric     return lldb::ChildCacheState::eRefetch;
899349cc55cSDimitry Andric   m_ptr_size = process_sp->GetAddressByteSize();
900349cc55cSDimitry Andric   m_order = process_sp->GetByteOrder();
901349cc55cSDimitry Andric   uint64_t valobj_addr = valobj_sp->GetValueAsUnsigned(0);
902349cc55cSDimitry Andric   m_size = process_sp->ReadUnsignedIntegerFromMemory(
903349cc55cSDimitry Andric       valobj_addr + 2 * m_ptr_size, m_ptr_size, 0, error);
904349cc55cSDimitry Andric   if (error.Fail())
905*0fca6ea1SDimitry Andric     return lldb::ChildCacheState::eRefetch;
906349cc55cSDimitry Andric   m_keys_ptr =
907349cc55cSDimitry Andric       process_sp->ReadPointerFromMemory(valobj_addr + 3 * m_ptr_size, error);
908349cc55cSDimitry Andric   if (error.Fail())
909*0fca6ea1SDimitry Andric     return lldb::ChildCacheState::eRefetch;
910349cc55cSDimitry Andric   m_objects_ptr =
911349cc55cSDimitry Andric       process_sp->ReadPointerFromMemory(valobj_addr + 4 * m_ptr_size, error);
912*0fca6ea1SDimitry Andric 
913*0fca6ea1SDimitry Andric   return error.Success() ? lldb::ChildCacheState::eReuse
914*0fca6ea1SDimitry Andric                          : lldb::ChildCacheState::eRefetch;
915349cc55cSDimitry Andric }
916349cc55cSDimitry Andric 
917349cc55cSDimitry Andric bool lldb_private::formatters::NSConstantDictionarySyntheticFrontEnd::
918349cc55cSDimitry Andric     MightHaveChildren() {
919349cc55cSDimitry Andric   return true;
920349cc55cSDimitry Andric }
921349cc55cSDimitry Andric 
922349cc55cSDimitry Andric lldb::ValueObjectSP lldb_private::formatters::
923*0fca6ea1SDimitry Andric     NSConstantDictionarySyntheticFrontEnd::GetChildAtIndex(uint32_t idx) {
924*0fca6ea1SDimitry Andric   uint32_t num_children = CalculateNumChildrenIgnoringErrors();
925349cc55cSDimitry Andric 
926349cc55cSDimitry Andric   if (idx >= num_children)
927349cc55cSDimitry Andric     return lldb::ValueObjectSP();
928349cc55cSDimitry Andric 
929349cc55cSDimitry Andric   if (m_children.empty()) {
930349cc55cSDimitry Andric     // do the scan phase
931349cc55cSDimitry Andric     lldb::addr_t key_at_idx = 0, val_at_idx = 0;
932349cc55cSDimitry Andric     ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
933349cc55cSDimitry Andric     if (!process_sp)
934349cc55cSDimitry Andric       return lldb::ValueObjectSP();
935349cc55cSDimitry Andric 
936349cc55cSDimitry Andric     for (unsigned int child = 0; child < num_children; ++child) {
937349cc55cSDimitry Andric       Status error;
938349cc55cSDimitry Andric       key_at_idx = process_sp->ReadPointerFromMemory(
939349cc55cSDimitry Andric           m_keys_ptr + child * m_ptr_size, error);
940349cc55cSDimitry Andric       if (error.Fail())
941349cc55cSDimitry Andric         return lldb::ValueObjectSP();
942349cc55cSDimitry Andric       val_at_idx = process_sp->ReadPointerFromMemory(
943349cc55cSDimitry Andric           m_objects_ptr + child * m_ptr_size, error);
944349cc55cSDimitry Andric       if (error.Fail())
945349cc55cSDimitry Andric         return lldb::ValueObjectSP();
946349cc55cSDimitry Andric       DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,
947349cc55cSDimitry Andric                                              lldb::ValueObjectSP()};
948349cc55cSDimitry Andric       m_children.push_back(descriptor);
949349cc55cSDimitry Andric     }
950349cc55cSDimitry Andric   }
951349cc55cSDimitry Andric 
952349cc55cSDimitry Andric   if (idx >= m_children.size()) // should never happen
953349cc55cSDimitry Andric     return lldb::ValueObjectSP();
954349cc55cSDimitry Andric 
955349cc55cSDimitry Andric   DictionaryItemDescriptor &dict_item = m_children[idx];
956349cc55cSDimitry Andric   if (!dict_item.valobj_sp) {
957349cc55cSDimitry Andric     if (!m_pair_type.IsValid()) {
958349cc55cSDimitry Andric       TargetSP target_sp(m_backend.GetTargetSP());
959349cc55cSDimitry Andric       if (!target_sp)
960349cc55cSDimitry Andric         return ValueObjectSP();
961349cc55cSDimitry Andric       m_pair_type = GetLLDBNSPairType(target_sp);
962349cc55cSDimitry Andric     }
963349cc55cSDimitry Andric     if (!m_pair_type.IsValid())
964349cc55cSDimitry Andric       return ValueObjectSP();
965349cc55cSDimitry Andric 
96681ad6265SDimitry Andric     WritableDataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
967349cc55cSDimitry Andric 
968349cc55cSDimitry Andric     if (m_ptr_size == 8) {
969349cc55cSDimitry Andric       uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
970349cc55cSDimitry Andric       *data_ptr = dict_item.key_ptr;
971349cc55cSDimitry Andric       *(data_ptr + 1) = dict_item.val_ptr;
972349cc55cSDimitry Andric     } else {
973349cc55cSDimitry Andric       uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
974349cc55cSDimitry Andric       *data_ptr = dict_item.key_ptr;
975349cc55cSDimitry Andric       *(data_ptr + 1) = dict_item.val_ptr;
976349cc55cSDimitry Andric     }
977349cc55cSDimitry Andric 
978349cc55cSDimitry Andric     StreamString idx_name;
979349cc55cSDimitry Andric     idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
980349cc55cSDimitry Andric     DataExtractor data(buffer_sp, m_order, m_ptr_size);
981349cc55cSDimitry Andric     dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
982349cc55cSDimitry Andric                                                     m_exe_ctx_ref, m_pair_type);
983349cc55cSDimitry Andric   }
984349cc55cSDimitry Andric   return dict_item.valobj_sp;
985349cc55cSDimitry Andric }
986349cc55cSDimitry Andric 
9870b57cec5SDimitry Andric lldb_private::formatters::NSDictionary1SyntheticFrontEnd::
9880b57cec5SDimitry Andric     NSDictionary1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
9890b57cec5SDimitry Andric     : SyntheticChildrenFrontEnd(*valobj_sp.get()), m_pair(nullptr) {}
9900b57cec5SDimitry Andric 
9910b57cec5SDimitry Andric size_t lldb_private::formatters::NSDictionary1SyntheticFrontEnd::
9920b57cec5SDimitry Andric     GetIndexOfChildWithName(ConstString name) {
9930b57cec5SDimitry Andric   static const ConstString g_zero("[0]");
9940b57cec5SDimitry Andric   return name == g_zero ? 0 : UINT32_MAX;
9950b57cec5SDimitry Andric }
9960b57cec5SDimitry Andric 
997*0fca6ea1SDimitry Andric llvm::Expected<uint32_t> lldb_private::formatters::
998*0fca6ea1SDimitry Andric     NSDictionary1SyntheticFrontEnd::CalculateNumChildren() {
9990b57cec5SDimitry Andric   return 1;
10000b57cec5SDimitry Andric }
10010b57cec5SDimitry Andric 
1002*0fca6ea1SDimitry Andric lldb::ChildCacheState
1003*0fca6ea1SDimitry Andric lldb_private::formatters::NSDictionary1SyntheticFrontEnd::Update() {
10040b57cec5SDimitry Andric   m_pair.reset();
1005*0fca6ea1SDimitry Andric   return lldb::ChildCacheState::eRefetch;
10060b57cec5SDimitry Andric }
10070b57cec5SDimitry Andric 
10080b57cec5SDimitry Andric bool lldb_private::formatters::NSDictionary1SyntheticFrontEnd::
10090b57cec5SDimitry Andric     MightHaveChildren() {
10100b57cec5SDimitry Andric   return true;
10110b57cec5SDimitry Andric }
10120b57cec5SDimitry Andric 
10130b57cec5SDimitry Andric lldb::ValueObjectSP
10140b57cec5SDimitry Andric lldb_private::formatters::NSDictionary1SyntheticFrontEnd::GetChildAtIndex(
1015*0fca6ea1SDimitry Andric     uint32_t idx) {
10160b57cec5SDimitry Andric   if (idx != 0)
10170b57cec5SDimitry Andric     return lldb::ValueObjectSP();
10180b57cec5SDimitry Andric 
10190b57cec5SDimitry Andric   if (m_pair.get())
10200b57cec5SDimitry Andric     return m_pair;
10210b57cec5SDimitry Andric 
10220b57cec5SDimitry Andric   auto process_sp(m_backend.GetProcessSP());
10230b57cec5SDimitry Andric   if (!process_sp)
10240b57cec5SDimitry Andric     return nullptr;
10250b57cec5SDimitry Andric 
10260b57cec5SDimitry Andric   auto ptr_size = process_sp->GetAddressByteSize();
10270b57cec5SDimitry Andric 
10280b57cec5SDimitry Andric   lldb::addr_t key_ptr =
10290b57cec5SDimitry Andric       m_backend.GetValueAsUnsigned(LLDB_INVALID_ADDRESS) + ptr_size;
10300b57cec5SDimitry Andric   lldb::addr_t value_ptr = key_ptr + ptr_size;
10310b57cec5SDimitry Andric 
10320b57cec5SDimitry Andric   Status error;
10330b57cec5SDimitry Andric 
10340b57cec5SDimitry Andric   lldb::addr_t value_at_idx = process_sp->ReadPointerFromMemory(key_ptr, error);
10350b57cec5SDimitry Andric   if (error.Fail())
10360b57cec5SDimitry Andric     return nullptr;
10370b57cec5SDimitry Andric   lldb::addr_t key_at_idx = process_sp->ReadPointerFromMemory(value_ptr, error);
10380b57cec5SDimitry Andric   if (error.Fail())
10390b57cec5SDimitry Andric     return nullptr;
10400b57cec5SDimitry Andric 
10410b57cec5SDimitry Andric   auto pair_type =
10420b57cec5SDimitry Andric       GetLLDBNSPairType(process_sp->GetTarget().shared_from_this());
10430b57cec5SDimitry Andric 
104481ad6265SDimitry Andric   WritableDataBufferSP buffer_sp(new DataBufferHeap(2 * ptr_size, 0));
10450b57cec5SDimitry Andric 
10460b57cec5SDimitry Andric   if (ptr_size == 8) {
10470b57cec5SDimitry Andric     uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
10480b57cec5SDimitry Andric     *data_ptr = key_at_idx;
10490b57cec5SDimitry Andric     *(data_ptr + 1) = value_at_idx;
10500b57cec5SDimitry Andric   } else {
10510b57cec5SDimitry Andric     uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
10520b57cec5SDimitry Andric     *data_ptr = key_at_idx;
10530b57cec5SDimitry Andric     *(data_ptr + 1) = value_at_idx;
10540b57cec5SDimitry Andric   }
10550b57cec5SDimitry Andric 
10560b57cec5SDimitry Andric   DataExtractor data(buffer_sp, process_sp->GetByteOrder(), ptr_size);
10570b57cec5SDimitry Andric   m_pair = CreateValueObjectFromData(
10580b57cec5SDimitry Andric       "[0]", data, m_backend.GetExecutionContextRef(), pair_type);
10590b57cec5SDimitry Andric 
10600b57cec5SDimitry Andric   return m_pair;
10610b57cec5SDimitry Andric }
10620b57cec5SDimitry Andric 
10630b57cec5SDimitry Andric template <typename D32, typename D64>
10640b57cec5SDimitry Andric lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32, D64>::
10650b57cec5SDimitry Andric     GenericNSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
106681ad6265SDimitry Andric     : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(),
106781ad6265SDimitry Andric       m_data_32(nullptr), m_data_64(nullptr), m_pair_type() {}
10680b57cec5SDimitry Andric 
10690b57cec5SDimitry Andric template <typename D32, typename D64>
1070*0fca6ea1SDimitry Andric lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<
1071*0fca6ea1SDimitry Andric     D32, D64>::GenericNSDictionaryMSyntheticFrontEnd::
1072*0fca6ea1SDimitry Andric     ~GenericNSDictionaryMSyntheticFrontEnd() {
10730b57cec5SDimitry Andric   delete m_data_32;
10740b57cec5SDimitry Andric   m_data_32 = nullptr;
10750b57cec5SDimitry Andric   delete m_data_64;
10760b57cec5SDimitry Andric   m_data_64 = nullptr;
10770b57cec5SDimitry Andric }
10780b57cec5SDimitry Andric 
10790b57cec5SDimitry Andric template <typename D32, typename D64>
10805ffd83dbSDimitry Andric size_t lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<
10815ffd83dbSDimitry Andric     D32, D64>::GetIndexOfChildWithName(ConstString name) {
10820b57cec5SDimitry Andric   const char *item_name = name.GetCString();
10830b57cec5SDimitry Andric   uint32_t idx = ExtractIndexFromString(item_name);
1084*0fca6ea1SDimitry Andric   if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors())
10850b57cec5SDimitry Andric     return UINT32_MAX;
10860b57cec5SDimitry Andric   return idx;
10870b57cec5SDimitry Andric }
10880b57cec5SDimitry Andric 
10890b57cec5SDimitry Andric template <typename D32, typename D64>
1090*0fca6ea1SDimitry Andric llvm::Expected<uint32_t>
1091*0fca6ea1SDimitry Andric lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<
1092*0fca6ea1SDimitry Andric     D32, D64>::CalculateNumChildren() {
10930b57cec5SDimitry Andric   if (!m_data_32 && !m_data_64)
10940b57cec5SDimitry Andric     return 0;
1095*0fca6ea1SDimitry Andric   return (m_data_32 ? (uint32_t)m_data_32->_used : (uint32_t)m_data_64->_used);
10960b57cec5SDimitry Andric }
10970b57cec5SDimitry Andric 
10980b57cec5SDimitry Andric template <typename D32, typename D64>
1099*0fca6ea1SDimitry Andric lldb::ChildCacheState
1100*0fca6ea1SDimitry Andric lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,
1101*0fca6ea1SDimitry Andric                                                                 D64>::Update() {
11020b57cec5SDimitry Andric   m_children.clear();
11030b57cec5SDimitry Andric   ValueObjectSP valobj_sp = m_backend.GetSP();
11040b57cec5SDimitry Andric   m_ptr_size = 0;
11050b57cec5SDimitry Andric   delete m_data_32;
11060b57cec5SDimitry Andric   m_data_32 = nullptr;
11070b57cec5SDimitry Andric   delete m_data_64;
11080b57cec5SDimitry Andric   m_data_64 = nullptr;
11090b57cec5SDimitry Andric   if (!valobj_sp)
1110*0fca6ea1SDimitry Andric     return lldb::ChildCacheState::eRefetch;
11110b57cec5SDimitry Andric   m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
11120b57cec5SDimitry Andric   Status error;
11130b57cec5SDimitry Andric   error.Clear();
11140b57cec5SDimitry Andric   lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
11150b57cec5SDimitry Andric   if (!process_sp)
1116*0fca6ea1SDimitry Andric     return lldb::ChildCacheState::eRefetch;
11170b57cec5SDimitry Andric   m_ptr_size = process_sp->GetAddressByteSize();
11180b57cec5SDimitry Andric   m_order = process_sp->GetByteOrder();
11190b57cec5SDimitry Andric   uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
11200b57cec5SDimitry Andric   if (m_ptr_size == 4) {
11210b57cec5SDimitry Andric     m_data_32 = new D32();
11220b57cec5SDimitry Andric     process_sp->ReadMemory(data_location, m_data_32, sizeof(D32),
11230b57cec5SDimitry Andric                            error);
11240b57cec5SDimitry Andric   } else {
11250b57cec5SDimitry Andric     m_data_64 = new D64();
11260b57cec5SDimitry Andric     process_sp->ReadMemory(data_location, m_data_64, sizeof(D64),
11270b57cec5SDimitry Andric                            error);
11280b57cec5SDimitry Andric   }
1129bdd1243dSDimitry Andric 
1130*0fca6ea1SDimitry Andric   return error.Success() ? lldb::ChildCacheState::eReuse
1131*0fca6ea1SDimitry Andric                          : lldb::ChildCacheState::eRefetch;
11320b57cec5SDimitry Andric }
11330b57cec5SDimitry Andric 
11340b57cec5SDimitry Andric template <typename D32, typename D64>
11350b57cec5SDimitry Andric bool
11360b57cec5SDimitry Andric lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::
11370b57cec5SDimitry Andric     MightHaveChildren() {
11380b57cec5SDimitry Andric   return true;
11390b57cec5SDimitry Andric }
11400b57cec5SDimitry Andric 
11410b57cec5SDimitry Andric template <typename D32, typename D64>
11420b57cec5SDimitry Andric lldb::ValueObjectSP
11435ffd83dbSDimitry Andric lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<
1144*0fca6ea1SDimitry Andric     D32, D64>::GetChildAtIndex(uint32_t idx) {
11450b57cec5SDimitry Andric   lldb::addr_t m_keys_ptr;
11460b57cec5SDimitry Andric   lldb::addr_t m_values_ptr;
11470b57cec5SDimitry Andric   if (m_data_32) {
11480b57cec5SDimitry Andric     uint32_t size = m_data_32->GetSize();
11490b57cec5SDimitry Andric     m_keys_ptr = m_data_32->_buffer;
11500b57cec5SDimitry Andric     m_values_ptr = m_data_32->_buffer + (m_ptr_size * size);
11510b57cec5SDimitry Andric   } else {
11520b57cec5SDimitry Andric     uint32_t size = m_data_64->GetSize();
11530b57cec5SDimitry Andric     m_keys_ptr = m_data_64->_buffer;
11540b57cec5SDimitry Andric     m_values_ptr = m_data_64->_buffer + (m_ptr_size * size);
11550b57cec5SDimitry Andric   }
11560b57cec5SDimitry Andric 
1157*0fca6ea1SDimitry Andric   uint32_t num_children = CalculateNumChildrenIgnoringErrors();
11580b57cec5SDimitry Andric 
11590b57cec5SDimitry Andric   if (idx >= num_children)
11600b57cec5SDimitry Andric     return lldb::ValueObjectSP();
11610b57cec5SDimitry Andric 
11620b57cec5SDimitry Andric   if (m_children.empty()) {
11630b57cec5SDimitry Andric     // do the scan phase
11640b57cec5SDimitry Andric     lldb::addr_t key_at_idx = 0, val_at_idx = 0;
11650b57cec5SDimitry Andric 
11660b57cec5SDimitry Andric     uint32_t tries = 0;
11670b57cec5SDimitry Andric     uint32_t test_idx = 0;
11680b57cec5SDimitry Andric 
11690b57cec5SDimitry Andric     while (tries < num_children) {
11700b57cec5SDimitry Andric       key_at_idx = m_keys_ptr + (test_idx * m_ptr_size);
11710b57cec5SDimitry Andric       val_at_idx = m_values_ptr + (test_idx * m_ptr_size);
11720b57cec5SDimitry Andric       ;
11730b57cec5SDimitry Andric       ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
11740b57cec5SDimitry Andric       if (!process_sp)
11750b57cec5SDimitry Andric         return lldb::ValueObjectSP();
11760b57cec5SDimitry Andric       Status error;
11770b57cec5SDimitry Andric       key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
11780b57cec5SDimitry Andric       if (error.Fail())
11790b57cec5SDimitry Andric         return lldb::ValueObjectSP();
11800b57cec5SDimitry Andric       val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
11810b57cec5SDimitry Andric       if (error.Fail())
11820b57cec5SDimitry Andric         return lldb::ValueObjectSP();
11830b57cec5SDimitry Andric 
11840b57cec5SDimitry Andric       test_idx++;
11850b57cec5SDimitry Andric 
11860b57cec5SDimitry Andric       if (!key_at_idx || !val_at_idx)
11870b57cec5SDimitry Andric         continue;
11880b57cec5SDimitry Andric       tries++;
11890b57cec5SDimitry Andric 
11900b57cec5SDimitry Andric       DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,
11910b57cec5SDimitry Andric                                              lldb::ValueObjectSP()};
11920b57cec5SDimitry Andric 
11930b57cec5SDimitry Andric       m_children.push_back(descriptor);
11940b57cec5SDimitry Andric     }
11950b57cec5SDimitry Andric   }
11960b57cec5SDimitry Andric 
11970b57cec5SDimitry Andric   if (idx >= m_children.size()) // should never happen
11980b57cec5SDimitry Andric     return lldb::ValueObjectSP();
11990b57cec5SDimitry Andric 
12000b57cec5SDimitry Andric   DictionaryItemDescriptor &dict_item = m_children[idx];
12010b57cec5SDimitry Andric   if (!dict_item.valobj_sp) {
12020b57cec5SDimitry Andric     if (!m_pair_type.IsValid()) {
12030b57cec5SDimitry Andric       TargetSP target_sp(m_backend.GetTargetSP());
12040b57cec5SDimitry Andric       if (!target_sp)
12050b57cec5SDimitry Andric         return ValueObjectSP();
12060b57cec5SDimitry Andric       m_pair_type = GetLLDBNSPairType(target_sp);
12070b57cec5SDimitry Andric     }
12080b57cec5SDimitry Andric     if (!m_pair_type.IsValid())
12090b57cec5SDimitry Andric       return ValueObjectSP();
12100b57cec5SDimitry Andric 
121181ad6265SDimitry Andric     WritableDataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
12120b57cec5SDimitry Andric 
12130b57cec5SDimitry Andric     if (m_ptr_size == 8) {
12140b57cec5SDimitry Andric       uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
12150b57cec5SDimitry Andric       *data_ptr = dict_item.key_ptr;
12160b57cec5SDimitry Andric       *(data_ptr + 1) = dict_item.val_ptr;
12170b57cec5SDimitry Andric     } else {
12180b57cec5SDimitry Andric       uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
12190b57cec5SDimitry Andric       *data_ptr = dict_item.key_ptr;
12200b57cec5SDimitry Andric       *(data_ptr + 1) = dict_item.val_ptr;
12210b57cec5SDimitry Andric     }
12220b57cec5SDimitry Andric 
12230b57cec5SDimitry Andric     StreamString idx_name;
12240b57cec5SDimitry Andric     idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
12250b57cec5SDimitry Andric     DataExtractor data(buffer_sp, m_order, m_ptr_size);
12260b57cec5SDimitry Andric     dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
12270b57cec5SDimitry Andric                                                     m_exe_ctx_ref, m_pair_type);
12280b57cec5SDimitry Andric   }
12290b57cec5SDimitry Andric   return dict_item.valobj_sp;
12300b57cec5SDimitry Andric }
12310b57cec5SDimitry Andric 
123281ad6265SDimitry Andric lldb_private::formatters::Foundation1100::NSDictionaryMSyntheticFrontEnd::
12330b57cec5SDimitry Andric     NSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
123481ad6265SDimitry Andric     : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_pair_type() {}
12350b57cec5SDimitry Andric 
12360b57cec5SDimitry Andric lldb_private::formatters::Foundation1100::
12370b57cec5SDimitry Andric   NSDictionaryMSyntheticFrontEnd::~NSDictionaryMSyntheticFrontEnd() {
12380b57cec5SDimitry Andric   delete m_data_32;
12390b57cec5SDimitry Andric   m_data_32 = nullptr;
12400b57cec5SDimitry Andric   delete m_data_64;
12410b57cec5SDimitry Andric   m_data_64 = nullptr;
12420b57cec5SDimitry Andric }
12430b57cec5SDimitry Andric 
12440b57cec5SDimitry Andric size_t
12450b57cec5SDimitry Andric lldb_private::formatters::Foundation1100::
12460b57cec5SDimitry Andric   NSDictionaryMSyntheticFrontEnd::GetIndexOfChildWithName(ConstString name) {
12470b57cec5SDimitry Andric   const char *item_name = name.GetCString();
12480b57cec5SDimitry Andric   uint32_t idx = ExtractIndexFromString(item_name);
1249*0fca6ea1SDimitry Andric   if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors())
12500b57cec5SDimitry Andric     return UINT32_MAX;
12510b57cec5SDimitry Andric   return idx;
12520b57cec5SDimitry Andric }
12530b57cec5SDimitry Andric 
1254*0fca6ea1SDimitry Andric llvm::Expected<uint32_t> lldb_private::formatters::Foundation1100::
12550b57cec5SDimitry Andric     NSDictionaryMSyntheticFrontEnd::CalculateNumChildren() {
12560b57cec5SDimitry Andric   if (!m_data_32 && !m_data_64)
12570b57cec5SDimitry Andric     return 0;
12580b57cec5SDimitry Andric   return (m_data_32 ? m_data_32->_used : m_data_64->_used);
12590b57cec5SDimitry Andric }
12600b57cec5SDimitry Andric 
1261*0fca6ea1SDimitry Andric lldb::ChildCacheState lldb_private::formatters::Foundation1100::
12620b57cec5SDimitry Andric     NSDictionaryMSyntheticFrontEnd::Update() {
12630b57cec5SDimitry Andric   m_children.clear();
12640b57cec5SDimitry Andric   ValueObjectSP valobj_sp = m_backend.GetSP();
12650b57cec5SDimitry Andric   m_ptr_size = 0;
12660b57cec5SDimitry Andric   delete m_data_32;
12670b57cec5SDimitry Andric   m_data_32 = nullptr;
12680b57cec5SDimitry Andric   delete m_data_64;
12690b57cec5SDimitry Andric   m_data_64 = nullptr;
12700b57cec5SDimitry Andric   if (!valobj_sp)
1271*0fca6ea1SDimitry Andric     return lldb::ChildCacheState::eRefetch;
12720b57cec5SDimitry Andric   m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
12730b57cec5SDimitry Andric   Status error;
12740b57cec5SDimitry Andric   error.Clear();
12750b57cec5SDimitry Andric   lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
12760b57cec5SDimitry Andric   if (!process_sp)
1277*0fca6ea1SDimitry Andric     return lldb::ChildCacheState::eRefetch;
12780b57cec5SDimitry Andric   m_ptr_size = process_sp->GetAddressByteSize();
12790b57cec5SDimitry Andric   m_order = process_sp->GetByteOrder();
12800b57cec5SDimitry Andric   uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
12810b57cec5SDimitry Andric   if (m_ptr_size == 4) {
12820b57cec5SDimitry Andric     m_data_32 = new DataDescriptor_32();
12830b57cec5SDimitry Andric     process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),
12840b57cec5SDimitry Andric                            error);
12850b57cec5SDimitry Andric   } else {
12860b57cec5SDimitry Andric     m_data_64 = new DataDescriptor_64();
12870b57cec5SDimitry Andric     process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),
12880b57cec5SDimitry Andric                            error);
12890b57cec5SDimitry Andric   }
1290bdd1243dSDimitry Andric 
1291*0fca6ea1SDimitry Andric   return error.Success() ? lldb::ChildCacheState::eReuse
1292*0fca6ea1SDimitry Andric                          : lldb::ChildCacheState::eRefetch;
12930b57cec5SDimitry Andric }
12940b57cec5SDimitry Andric 
12950b57cec5SDimitry Andric bool
12960b57cec5SDimitry Andric lldb_private::formatters::Foundation1100::
12970b57cec5SDimitry Andric   NSDictionaryMSyntheticFrontEnd::MightHaveChildren() {
12980b57cec5SDimitry Andric   return true;
12990b57cec5SDimitry Andric }
13000b57cec5SDimitry Andric 
13010b57cec5SDimitry Andric lldb::ValueObjectSP
13020b57cec5SDimitry Andric lldb_private::formatters::Foundation1100::
1303*0fca6ea1SDimitry Andric   NSDictionaryMSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) {
13040b57cec5SDimitry Andric   lldb::addr_t m_keys_ptr =
13050b57cec5SDimitry Andric       (m_data_32 ? m_data_32->_keys_addr : m_data_64->_keys_addr);
13060b57cec5SDimitry Andric   lldb::addr_t m_values_ptr =
13070b57cec5SDimitry Andric       (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr);
13080b57cec5SDimitry Andric 
1309*0fca6ea1SDimitry Andric   uint32_t num_children = CalculateNumChildrenIgnoringErrors();
13100b57cec5SDimitry Andric 
13110b57cec5SDimitry Andric   if (idx >= num_children)
13120b57cec5SDimitry Andric     return lldb::ValueObjectSP();
13130b57cec5SDimitry Andric 
13140b57cec5SDimitry Andric   if (m_children.empty()) {
13150b57cec5SDimitry Andric     // do the scan phase
13160b57cec5SDimitry Andric     lldb::addr_t key_at_idx = 0, val_at_idx = 0;
13170b57cec5SDimitry Andric 
13180b57cec5SDimitry Andric     uint32_t tries = 0;
13190b57cec5SDimitry Andric     uint32_t test_idx = 0;
13200b57cec5SDimitry Andric 
13210b57cec5SDimitry Andric     while (tries < num_children) {
13220b57cec5SDimitry Andric       key_at_idx = m_keys_ptr + (test_idx * m_ptr_size);
13230b57cec5SDimitry Andric       val_at_idx = m_values_ptr + (test_idx * m_ptr_size);
13240b57cec5SDimitry Andric       ;
13250b57cec5SDimitry Andric       ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
13260b57cec5SDimitry Andric       if (!process_sp)
13270b57cec5SDimitry Andric         return lldb::ValueObjectSP();
13280b57cec5SDimitry Andric       Status error;
13290b57cec5SDimitry Andric       key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
13300b57cec5SDimitry Andric       if (error.Fail())
13310b57cec5SDimitry Andric         return lldb::ValueObjectSP();
13320b57cec5SDimitry Andric       val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
13330b57cec5SDimitry Andric       if (error.Fail())
13340b57cec5SDimitry Andric         return lldb::ValueObjectSP();
13350b57cec5SDimitry Andric 
13360b57cec5SDimitry Andric       test_idx++;
13370b57cec5SDimitry Andric 
13380b57cec5SDimitry Andric       if (!key_at_idx || !val_at_idx)
13390b57cec5SDimitry Andric         continue;
13400b57cec5SDimitry Andric       tries++;
13410b57cec5SDimitry Andric 
13420b57cec5SDimitry Andric       DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,
13430b57cec5SDimitry Andric                                              lldb::ValueObjectSP()};
13440b57cec5SDimitry Andric 
13450b57cec5SDimitry Andric       m_children.push_back(descriptor);
13460b57cec5SDimitry Andric     }
13470b57cec5SDimitry Andric   }
13480b57cec5SDimitry Andric 
13490b57cec5SDimitry Andric   if (idx >= m_children.size()) // should never happen
13500b57cec5SDimitry Andric     return lldb::ValueObjectSP();
13510b57cec5SDimitry Andric 
13520b57cec5SDimitry Andric   DictionaryItemDescriptor &dict_item = m_children[idx];
13530b57cec5SDimitry Andric   if (!dict_item.valobj_sp) {
13540b57cec5SDimitry Andric     if (!m_pair_type.IsValid()) {
13550b57cec5SDimitry Andric       TargetSP target_sp(m_backend.GetTargetSP());
13560b57cec5SDimitry Andric       if (!target_sp)
13570b57cec5SDimitry Andric         return ValueObjectSP();
13580b57cec5SDimitry Andric       m_pair_type = GetLLDBNSPairType(target_sp);
13590b57cec5SDimitry Andric     }
13600b57cec5SDimitry Andric     if (!m_pair_type.IsValid())
13610b57cec5SDimitry Andric       return ValueObjectSP();
13620b57cec5SDimitry Andric 
136381ad6265SDimitry Andric     WritableDataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
13640b57cec5SDimitry Andric 
13650b57cec5SDimitry Andric     if (m_ptr_size == 8) {
13660b57cec5SDimitry Andric       uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
13670b57cec5SDimitry Andric       *data_ptr = dict_item.key_ptr;
13680b57cec5SDimitry Andric       *(data_ptr + 1) = dict_item.val_ptr;
13690b57cec5SDimitry Andric     } else {
13700b57cec5SDimitry Andric       uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
13710b57cec5SDimitry Andric       *data_ptr = dict_item.key_ptr;
13720b57cec5SDimitry Andric       *(data_ptr + 1) = dict_item.val_ptr;
13730b57cec5SDimitry Andric     }
13740b57cec5SDimitry Andric 
13750b57cec5SDimitry Andric     StreamString idx_name;
13760b57cec5SDimitry Andric     idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
13770b57cec5SDimitry Andric     DataExtractor data(buffer_sp, m_order, m_ptr_size);
13780b57cec5SDimitry Andric     dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
13790b57cec5SDimitry Andric                                                     m_exe_ctx_ref, m_pair_type);
13800b57cec5SDimitry Andric   }
13810b57cec5SDimitry Andric   return dict_item.valobj_sp;
13820b57cec5SDimitry Andric }
13830b57cec5SDimitry Andric 
13840b57cec5SDimitry Andric template bool lldb_private::formatters::NSDictionarySummaryProvider<true>(
13850b57cec5SDimitry Andric     ValueObject &, Stream &, const TypeSummaryOptions &);
13860b57cec5SDimitry Andric 
13870b57cec5SDimitry Andric template bool lldb_private::formatters::NSDictionarySummaryProvider<false>(
13880b57cec5SDimitry Andric     ValueObject &, Stream &, const TypeSummaryOptions &);
1389