This revision was automatically updated to reflect the committed changes.
Closed by commit rGa2154b195153: Cache the manual DWARF index out to the LLDB 
cache directory when the LLDB… (authored by clayborg).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D115951/new/

https://reviews.llvm.org/D115951

Files:
  lldb/include/lldb/Symbol/SymbolFile.h
  lldb/include/lldb/Symbol/Symtab.h
  lldb/include/lldb/Target/Statistics.h
  lldb/source/Plugins/SymbolFile/DWARF/DIERef.cpp
  lldb/source/Plugins/SymbolFile/DWARF/DIERef.h
  lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp
  lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h
  lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp
  lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.h
  lldb/source/Symbol/Symtab.cpp
  lldb/source/Target/Statistics.cpp
  lldb/test/API/commands/statistics/basic/TestStats.py
  lldb/test/API/functionalities/module_cache/debug_index/TestDebugIndexCache.py
  lldb/test/API/functionalities/module_cache/debug_index/exe.yaml
  lldb/test/API/functionalities/module_cache/simple_exe/TestModuleCacheSimple.py
  lldb/unittests/SymbolFile/DWARF/CMakeLists.txt
  lldb/unittests/SymbolFile/DWARF/DWARFIndexCachingTest.cpp

Index: lldb/unittests/SymbolFile/DWARF/DWARFIndexCachingTest.cpp
===================================================================
--- /dev/null
+++ lldb/unittests/SymbolFile/DWARF/DWARFIndexCachingTest.cpp
@@ -0,0 +1,198 @@
+//===-- DWARFIndexCachingTest.cpp -------------------------------------=---===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Plugins/SymbolFile/DWARF/DIERef.h"
+#include "Plugins/SymbolFile/DWARF/DWARFDIE.h"
+#include "Plugins/SymbolFile/DWARF/ManualDWARFIndex.h"
+#include "Plugins/SymbolFile/DWARF/NameToDIE.h"
+#include "TestingSupport/Symbol/YAMLModuleTester.h"
+#include "lldb/Core/DataFileCache.h"
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Utility/DataEncoder.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "llvm/ADT/STLExtras.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+static void EncodeDecode(const DIERef &object, ByteOrder byte_order) {
+  const uint8_t addr_size = 8;
+  DataEncoder encoder(byte_order, addr_size);
+  object.Encode(encoder);
+  llvm::ArrayRef<uint8_t> bytes = encoder.GetData();
+  DataExtractor data(bytes.data(), bytes.size(), byte_order, addr_size);
+  offset_t data_offset = 0;
+  EXPECT_EQ(object, DIERef::Decode(data, &data_offset));
+}
+
+static void EncodeDecode(const DIERef &object) {
+  EncodeDecode(object, eByteOrderLittle);
+  EncodeDecode(object, eByteOrderBig);
+}
+
+TEST(DWARFIndexCachingTest, DIERefEncodeDecode) {
+  // Tests DIERef::Encode(...) and DIERef::Decode(...)
+  EncodeDecode(DIERef(llvm::None, DIERef::Section::DebugInfo, 0x11223344));
+  EncodeDecode(DIERef(llvm::None, DIERef::Section::DebugTypes, 0x11223344));
+  EncodeDecode(DIERef(100, DIERef::Section::DebugInfo, 0x11223344));
+  EncodeDecode(DIERef(200, DIERef::Section::DebugTypes, 0x11223344));
+}
+
+static void EncodeDecode(const NameToDIE &object, ByteOrder byte_order) {
+  const uint8_t addr_size = 8;
+  DataEncoder encoder(byte_order, addr_size);
+  DataEncoder strtab_encoder(byte_order, addr_size);
+  ConstStringTable const_strtab;
+
+  object.Encode(encoder, const_strtab);
+
+  llvm::ArrayRef<uint8_t> bytes = encoder.GetData();
+  DataExtractor data(bytes.data(), bytes.size(), byte_order, addr_size);
+
+  const_strtab.Encode(strtab_encoder);
+  llvm::ArrayRef<uint8_t> strtab_bytes = strtab_encoder.GetData();
+  DataExtractor strtab_data(strtab_bytes.data(), strtab_bytes.size(),
+                            byte_order, addr_size);
+  StringTableReader strtab_reader;
+  offset_t strtab_data_offset = 0;
+  ASSERT_EQ(strtab_reader.Decode(strtab_data, &strtab_data_offset), true);
+
+  NameToDIE decoded_object;
+  offset_t data_offset = 0;
+  decoded_object.Decode(data, &data_offset, strtab_reader);
+  EXPECT_TRUE(object == decoded_object);
+}
+
+static void EncodeDecode(const NameToDIE &object) {
+  EncodeDecode(object, eByteOrderLittle);
+  EncodeDecode(object, eByteOrderBig);
+}
+
+TEST(DWARFIndexCachingTest, NameToDIEEncodeDecode) {
+  NameToDIE map;
+  // Make sure an empty NameToDIE map encodes and decodes correctly.
+  EncodeDecode(map);
+  map.Insert(ConstString("hello"),
+             DIERef(llvm::None, DIERef::Section::DebugInfo, 0x11223344));
+  map.Insert(ConstString("workd"),
+             DIERef(100, DIERef::Section::DebugInfo, 0x11223344));
+  // Make sure a valid NameToDIE map encodes and decodes correctly.
+  EncodeDecode(map);
+}
+
+static void EncodeDecode(const ManualDWARFIndex::IndexSet &object,
+                         ByteOrder byte_order) {
+  const uint8_t addr_size = 8;
+  DataEncoder encoder(byte_order, addr_size);
+  DataEncoder strtab_encoder(byte_order, addr_size);
+  object.Encode(encoder);
+  llvm::ArrayRef<uint8_t> bytes = encoder.GetData();
+  DataExtractor data(bytes.data(), bytes.size(), byte_order, addr_size);
+  ManualDWARFIndex::IndexSet decoded_object;
+  offset_t data_offset = 0;
+  decoded_object.Decode(data, &data_offset);
+  EXPECT_TRUE(object == decoded_object);
+}
+
+static void EncodeDecode(const ManualDWARFIndex::IndexSet &object) {
+  EncodeDecode(object, eByteOrderLittle);
+  EncodeDecode(object, eByteOrderBig);
+}
+
+TEST(DWARFIndexCachingTest, ManualDWARFIndexIndexSetEncodeDecode) {
+  ManualDWARFIndex::IndexSet set;
+  // Make sure empty IndexSet can be encoded and decoded correctly
+  EncodeDecode(set);
+
+  dw_offset_t die_offset = 0;
+  // Make sure an IndexSet with only items in IndexSet::function_basenames can
+  // be encoded and decoded correctly.
+  set.function_basenames.Insert(
+      ConstString("a"),
+      DIERef(llvm::None, DIERef::Section::DebugInfo, ++die_offset));
+  EncodeDecode(set);
+  set.function_basenames.Clear();
+  // Make sure an IndexSet with only items in IndexSet::function_fullnames can
+  // be encoded and decoded correctly.
+  set.function_fullnames.Insert(
+      ConstString("a"),
+      DIERef(llvm::None, DIERef::Section::DebugInfo, ++die_offset));
+  EncodeDecode(set);
+  set.function_fullnames.Clear();
+  // Make sure an IndexSet with only items in IndexSet::function_methods can
+  // be encoded and decoded correctly.
+  set.function_methods.Insert(
+      ConstString("a"),
+      DIERef(llvm::None, DIERef::Section::DebugInfo, ++die_offset));
+  EncodeDecode(set);
+  set.function_methods.Clear();
+  // Make sure an IndexSet with only items in IndexSet::function_selectors can
+  // be encoded and decoded correctly.
+  set.function_selectors.Insert(
+      ConstString("a"),
+      DIERef(llvm::None, DIERef::Section::DebugInfo, ++die_offset));
+  EncodeDecode(set);
+  set.function_selectors.Clear();
+  // Make sure an IndexSet with only items in IndexSet::objc_class_selectors can
+  // be encoded and decoded correctly.
+  set.objc_class_selectors.Insert(
+      ConstString("a"),
+      DIERef(llvm::None, DIERef::Section::DebugInfo, ++die_offset));
+  EncodeDecode(set);
+  set.objc_class_selectors.Clear();
+  // Make sure an IndexSet with only items in IndexSet::globals can
+  // be encoded and decoded correctly.
+  set.globals.Insert(
+      ConstString("a"),
+      DIERef(llvm::None, DIERef::Section::DebugInfo, ++die_offset));
+  EncodeDecode(set);
+  set.globals.Clear();
+  // Make sure an IndexSet with only items in IndexSet::types can
+  // be encoded and decoded correctly.
+  set.types.Insert(
+      ConstString("a"),
+      DIERef(llvm::None, DIERef::Section::DebugInfo, ++die_offset));
+  EncodeDecode(set);
+  set.types.Clear();
+  // Make sure an IndexSet with only items in IndexSet::namespaces can
+  // be encoded and decoded correctly.
+  set.namespaces.Insert(
+      ConstString("a"),
+      DIERef(llvm::None, DIERef::Section::DebugInfo, ++die_offset));
+  EncodeDecode(set);
+  set.namespaces.Clear();
+  // Make sure that an IndexSet with item in all NameToDIE maps can be
+  // be encoded and decoded correctly.
+  set.function_basenames.Insert(
+      ConstString("a"),
+      DIERef(llvm::None, DIERef::Section::DebugInfo, ++die_offset));
+  set.function_fullnames.Insert(
+      ConstString("b"),
+      DIERef(llvm::None, DIERef::Section::DebugInfo, ++die_offset));
+  set.function_methods.Insert(
+      ConstString("c"),
+      DIERef(llvm::None, DIERef::Section::DebugInfo, ++die_offset));
+  set.function_selectors.Insert(
+      ConstString("d"),
+      DIERef(llvm::None, DIERef::Section::DebugInfo, ++die_offset));
+  set.objc_class_selectors.Insert(
+      ConstString("e"),
+      DIERef(llvm::None, DIERef::Section::DebugInfo, ++die_offset));
+  set.globals.Insert(
+      ConstString("f"),
+      DIERef(llvm::None, DIERef::Section::DebugInfo, ++die_offset));
+  set.types.Insert(
+      ConstString("g"),
+      DIERef(llvm::None, DIERef::Section::DebugInfo, ++die_offset));
+  set.namespaces.Insert(
+      ConstString("h"),
+      DIERef(llvm::None, DIERef::Section::DebugInfo, ++die_offset));
+  EncodeDecode(set);
+}
Index: lldb/unittests/SymbolFile/DWARF/CMakeLists.txt
===================================================================
--- lldb/unittests/SymbolFile/DWARF/CMakeLists.txt
+++ lldb/unittests/SymbolFile/DWARF/CMakeLists.txt
@@ -1,6 +1,7 @@
 add_lldb_unittest(SymbolFileDWARFTests
   DWARFASTParserClangTests.cpp
   DWARFDIETest.cpp
+  DWARFIndexCachingTest.cpp
   DWARFUnitTest.cpp
   SymbolFileDWARFTests.cpp
   XcodeSDKModuleTests.cpp
Index: lldb/test/API/functionalities/module_cache/simple_exe/TestModuleCacheSimple.py
===================================================================
--- lldb/test/API/functionalities/module_cache/simple_exe/TestModuleCacheSimple.py
+++ lldb/test/API/functionalities/module_cache/simple_exe/TestModuleCacheSimple.py
@@ -31,7 +31,7 @@
 
     # Doesn't depend on any specific debug information.
     @no_debug_info_test
-    @skipIfWindows # Windows runs into trouble deleting the executable
+    @skipIfWindows
     def test(self):
         """
             Test module cache functionality for a simple object file.
Index: lldb/test/API/functionalities/module_cache/debug_index/exe.yaml
===================================================================
--- /dev/null
+++ lldb/test/API/functionalities/module_cache/debug_index/exe.yaml
@@ -0,0 +1,844 @@
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_EXEC
+  Machine: EM_386
+DWARF:
+  debug_str:
+    - 'Apple clang version 13.0.0 (clang-1300.0.29.3)'
+    - main.mm
+    - '/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk'
+    - MacOSX.sdk
+    - '/tmp/test'
+    - g_global
+    - int
+    - SimpleClass
+    - NSObject
+    - isa
+    - Class
+    - objc_class
+    - foo
+    - _Z3fooi
+    - '-[SimpleClass sayHello]'
+    - sayHello
+    - main
+    - baz
+    - Bar
+    - x
+    - _ZNK3baz3Bar3getEv
+    - get
+    - _ZN3baz3BarC1Ei
+    - _ZN3baz3BarC2Ei
+    - self
+    - _cmd
+    - SEL
+    - objc_selector
+    - argc
+    - argv
+    - char
+    - b
+    - this
+    - i
+  debug_abbrev:
+    - ID:              0
+      Table:
+        - Code:            0x1
+          Tag:             DW_TAG_compile_unit
+          Children:        DW_CHILDREN_yes
+          Attributes:
+            - Attribute:       DW_AT_producer
+              Form:            DW_FORM_strp
+            - Attribute:       DW_AT_language
+              Form:            DW_FORM_data2
+            - Attribute:       DW_AT_name
+              Form:            DW_FORM_strp
+            - Attribute:       DW_AT_LLVM_sysroot
+              Form:            DW_FORM_strp
+            - Attribute:       DW_AT_APPLE_sdk
+              Form:            DW_FORM_strp
+            - Attribute:       DW_AT_stmt_list
+              Form:            DW_FORM_sec_offset
+            - Attribute:       DW_AT_comp_dir
+              Form:            DW_FORM_strp
+            - Attribute:       DW_AT_APPLE_major_runtime_vers
+              Form:            DW_FORM_data1
+            - Attribute:       DW_AT_low_pc
+              Form:            DW_FORM_addr
+            - Attribute:       DW_AT_high_pc
+              Form:            DW_FORM_data4
+        - Code:            0x2
+          Tag:             DW_TAG_variable
+          Children:        DW_CHILDREN_no
+          Attributes:
+            - Attribute:       DW_AT_name
+              Form:            DW_FORM_strp
+            - Attribute:       DW_AT_type
+              Form:            DW_FORM_ref4
+            - Attribute:       DW_AT_external
+              Form:            DW_FORM_flag_present
+            - Attribute:       DW_AT_decl_file
+              Form:            DW_FORM_data1
+            - Attribute:       DW_AT_decl_line
+              Form:            DW_FORM_data1
+            - Attribute:       DW_AT_location
+              Form:            DW_FORM_exprloc
+        - Code:            0x3
+          Tag:             DW_TAG_base_type
+          Children:        DW_CHILDREN_no
+          Attributes:
+            - Attribute:       DW_AT_name
+              Form:            DW_FORM_strp
+            - Attribute:       DW_AT_encoding
+              Form:            DW_FORM_data1
+            - Attribute:       DW_AT_byte_size
+              Form:            DW_FORM_data1
+        - Code:            0x4
+          Tag:             DW_TAG_structure_type
+          Children:        DW_CHILDREN_yes
+          Attributes:
+            - Attribute:       DW_AT_APPLE_objc_complete_type
+              Form:            DW_FORM_flag_present
+            - Attribute:       DW_AT_name
+              Form:            DW_FORM_strp
+            - Attribute:       DW_AT_byte_size
+              Form:            DW_FORM_data1
+            - Attribute:       DW_AT_decl_file
+              Form:            DW_FORM_data1
+            - Attribute:       DW_AT_decl_line
+              Form:            DW_FORM_data1
+            - Attribute:       DW_AT_APPLE_runtime_class
+              Form:            DW_FORM_data1
+        - Code:            0x5
+          Tag:             DW_TAG_inheritance
+          Children:        DW_CHILDREN_no
+          Attributes:
+            - Attribute:       DW_AT_type
+              Form:            DW_FORM_ref4
+            - Attribute:       DW_AT_data_member_location
+              Form:            DW_FORM_data1
+        - Code:            0x6
+          Tag:             DW_TAG_structure_type
+          Children:        DW_CHILDREN_yes
+          Attributes:
+            - Attribute:       DW_AT_name
+              Form:            DW_FORM_strp
+            - Attribute:       DW_AT_byte_size
+              Form:            DW_FORM_data1
+            - Attribute:       DW_AT_decl_file
+              Form:            DW_FORM_data1
+            - Attribute:       DW_AT_decl_line
+              Form:            DW_FORM_data1
+            - Attribute:       DW_AT_APPLE_runtime_class
+              Form:            DW_FORM_data1
+        - Code:            0x7
+          Tag:             DW_TAG_member
+          Children:        DW_CHILDREN_no
+          Attributes:
+            - Attribute:       DW_AT_name
+              Form:            DW_FORM_strp
+            - Attribute:       DW_AT_type
+              Form:            DW_FORM_ref4
+            - Attribute:       DW_AT_decl_file
+              Form:            DW_FORM_data1
+            - Attribute:       DW_AT_decl_line
+              Form:            DW_FORM_data1
+            - Attribute:       DW_AT_data_member_location
+              Form:            DW_FORM_data1
+            - Attribute:       DW_AT_accessibility
+              Form:            DW_FORM_data1
+        - Code:            0x8
+          Tag:             DW_TAG_typedef
+          Children:        DW_CHILDREN_no
+          Attributes:
+            - Attribute:       DW_AT_type
+              Form:            DW_FORM_ref4
+            - Attribute:       DW_AT_name
+              Form:            DW_FORM_strp
+            - Attribute:       DW_AT_decl_file
+              Form:            DW_FORM_data1
+            - Attribute:       DW_AT_decl_line
+              Form:            DW_FORM_data1
+        - Code:            0x9
+          Tag:             DW_TAG_pointer_type
+          Children:        DW_CHILDREN_no
+          Attributes:
+            - Attribute:       DW_AT_type
+              Form:            DW_FORM_ref4
+        - Code:            0xA
+          Tag:             DW_TAG_structure_type
+          Children:        DW_CHILDREN_no
+          Attributes:
+            - Attribute:       DW_AT_name
+              Form:            DW_FORM_strp
+            - Attribute:       DW_AT_declaration
+              Form:            DW_FORM_flag_present
+        - Code:            0xB
+          Tag:             DW_TAG_subprogram
+          Children:        DW_CHILDREN_yes
+          Attributes:
+            - Attribute:       DW_AT_low_pc
+              Form:            DW_FORM_addr
+            - Attribute:       DW_AT_high_pc
+              Form:            DW_FORM_data4
+            - Attribute:       DW_AT_APPLE_omit_frame_ptr
+              Form:            DW_FORM_flag_present
+            - Attribute:       DW_AT_frame_base
+              Form:            DW_FORM_exprloc
+            - Attribute:       DW_AT_linkage_name
+              Form:            DW_FORM_strp
+            - Attribute:       DW_AT_name
+              Form:            DW_FORM_strp
+            - Attribute:       DW_AT_decl_file
+              Form:            DW_FORM_data1
+            - Attribute:       DW_AT_decl_line
+              Form:            DW_FORM_data1
+            - Attribute:       DW_AT_type
+              Form:            DW_FORM_ref4
+            - Attribute:       DW_AT_external
+              Form:            DW_FORM_flag_present
+        - Code:            0xC
+          Tag:             DW_TAG_formal_parameter
+          Children:        DW_CHILDREN_no
+          Attributes:
+            - Attribute:       DW_AT_location
+              Form:            DW_FORM_exprloc
+            - Attribute:       DW_AT_name
+              Form:            DW_FORM_strp
+            - Attribute:       DW_AT_decl_file
+              Form:            DW_FORM_data1
+            - Attribute:       DW_AT_decl_line
+              Form:            DW_FORM_data1
+            - Attribute:       DW_AT_type
+              Form:            DW_FORM_ref4
+        - Code:            0xD
+          Tag:             DW_TAG_subprogram
+          Children:        DW_CHILDREN_yes
+          Attributes:
+            - Attribute:       DW_AT_low_pc
+              Form:            DW_FORM_addr
+            - Attribute:       DW_AT_high_pc
+              Form:            DW_FORM_data4
+            - Attribute:       DW_AT_APPLE_omit_frame_ptr
+              Form:            DW_FORM_flag_present
+            - Attribute:       DW_AT_frame_base
+              Form:            DW_FORM_exprloc
+            - Attribute:       DW_AT_object_pointer
+              Form:            DW_FORM_ref4
+            - Attribute:       DW_AT_name
+              Form:            DW_FORM_strp
+            - Attribute:       DW_AT_decl_file
+              Form:            DW_FORM_data1
+            - Attribute:       DW_AT_decl_line
+              Form:            DW_FORM_data1
+        - Code:            0xE
+          Tag:             DW_TAG_formal_parameter
+          Children:        DW_CHILDREN_no
+          Attributes:
+            - Attribute:       DW_AT_location
+              Form:            DW_FORM_exprloc
+            - Attribute:       DW_AT_name
+              Form:            DW_FORM_strp
+            - Attribute:       DW_AT_type
+              Form:            DW_FORM_ref4
+            - Attribute:       DW_AT_artificial
+              Form:            DW_FORM_flag_present
+        - Code:            0xF
+          Tag:             DW_TAG_subprogram
+          Children:        DW_CHILDREN_yes
+          Attributes:
+            - Attribute:       DW_AT_low_pc
+              Form:            DW_FORM_addr
+            - Attribute:       DW_AT_high_pc
+              Form:            DW_FORM_data4
+            - Attribute:       DW_AT_frame_base
+              Form:            DW_FORM_exprloc
+            - Attribute:       DW_AT_name
+              Form:            DW_FORM_strp
+            - Attribute:       DW_AT_decl_file
+              Form:            DW_FORM_data1
+            - Attribute:       DW_AT_decl_line
+              Form:            DW_FORM_data1
+            - Attribute:       DW_AT_type
+              Form:            DW_FORM_ref4
+            - Attribute:       DW_AT_external
+              Form:            DW_FORM_flag_present
+        - Code:            0x10
+          Tag:             DW_TAG_variable
+          Children:        DW_CHILDREN_no
+          Attributes:
+            - Attribute:       DW_AT_location
+              Form:            DW_FORM_exprloc
+            - Attribute:       DW_AT_name
+              Form:            DW_FORM_strp
+            - Attribute:       DW_AT_decl_file
+              Form:            DW_FORM_data1
+            - Attribute:       DW_AT_decl_line
+              Form:            DW_FORM_data1
+            - Attribute:       DW_AT_type
+              Form:            DW_FORM_ref4
+        - Code:            0x11
+          Tag:             DW_TAG_namespace
+          Children:        DW_CHILDREN_yes
+          Attributes:
+            - Attribute:       DW_AT_name
+              Form:            DW_FORM_strp
+        - Code:            0x12
+          Tag:             DW_TAG_class_type
+          Children:        DW_CHILDREN_yes
+          Attributes:
+            - Attribute:       DW_AT_calling_convention
+              Form:            DW_FORM_data1
+            - Attribute:       DW_AT_name
+              Form:            DW_FORM_strp
+            - Attribute:       DW_AT_byte_size
+              Form:            DW_FORM_data1
+            - Attribute:       DW_AT_decl_file
+              Form:            DW_FORM_data1
+            - Attribute:       DW_AT_decl_line
+              Form:            DW_FORM_data1
+        - Code:            0x13
+          Tag:             DW_TAG_member
+          Children:        DW_CHILDREN_no
+          Attributes:
+            - Attribute:       DW_AT_name
+              Form:            DW_FORM_strp
+            - Attribute:       DW_AT_type
+              Form:            DW_FORM_ref4
+            - Attribute:       DW_AT_decl_file
+              Form:            DW_FORM_data1
+            - Attribute:       DW_AT_decl_line
+              Form:            DW_FORM_data1
+            - Attribute:       DW_AT_data_member_location
+              Form:            DW_FORM_data1
+        - Code:            0x14
+          Tag:             DW_TAG_subprogram
+          Children:        DW_CHILDREN_yes
+          Attributes:
+            - Attribute:       DW_AT_name
+              Form:            DW_FORM_strp
+            - Attribute:       DW_AT_decl_file
+              Form:            DW_FORM_data1
+            - Attribute:       DW_AT_decl_line
+              Form:            DW_FORM_data1
+            - Attribute:       DW_AT_declaration
+              Form:            DW_FORM_flag_present
+            - Attribute:       DW_AT_external
+              Form:            DW_FORM_flag_present
+            - Attribute:       DW_AT_accessibility
+              Form:            DW_FORM_data1
+        - Code:            0x15
+          Tag:             DW_TAG_formal_parameter
+          Children:        DW_CHILDREN_no
+          Attributes:
+            - Attribute:       DW_AT_type
+              Form:            DW_FORM_ref4
+            - Attribute:       DW_AT_artificial
+              Form:            DW_FORM_flag_present
+        - Code:            0x16
+          Tag:             DW_TAG_formal_parameter
+          Children:        DW_CHILDREN_no
+          Attributes:
+            - Attribute:       DW_AT_type
+              Form:            DW_FORM_ref4
+        - Code:            0x17
+          Tag:             DW_TAG_subprogram
+          Children:        DW_CHILDREN_yes
+          Attributes:
+            - Attribute:       DW_AT_linkage_name
+              Form:            DW_FORM_strp
+            - Attribute:       DW_AT_name
+              Form:            DW_FORM_strp
+            - Attribute:       DW_AT_decl_file
+              Form:            DW_FORM_data1
+            - Attribute:       DW_AT_decl_line
+              Form:            DW_FORM_data1
+            - Attribute:       DW_AT_type
+              Form:            DW_FORM_ref4
+            - Attribute:       DW_AT_declaration
+              Form:            DW_FORM_flag_present
+            - Attribute:       DW_AT_external
+              Form:            DW_FORM_flag_present
+            - Attribute:       DW_AT_accessibility
+              Form:            DW_FORM_data1
+        - Code:            0x18
+          Tag:             DW_TAG_const_type
+          Children:        DW_CHILDREN_no
+          Attributes:
+            - Attribute:       DW_AT_type
+              Form:            DW_FORM_ref4
+        - Code:            0x19
+          Tag:             DW_TAG_subprogram
+          Children:        DW_CHILDREN_yes
+          Attributes:
+            - Attribute:       DW_AT_low_pc
+              Form:            DW_FORM_addr
+            - Attribute:       DW_AT_high_pc
+              Form:            DW_FORM_data4
+            - Attribute:       DW_AT_frame_base
+              Form:            DW_FORM_exprloc
+            - Attribute:       DW_AT_object_pointer
+              Form:            DW_FORM_ref4
+            - Attribute:       DW_AT_linkage_name
+              Form:            DW_FORM_strp
+            - Attribute:       DW_AT_specification
+              Form:            DW_FORM_ref4
+        - Code:            0x1A
+          Tag:             DW_TAG_subprogram
+          Children:        DW_CHILDREN_yes
+          Attributes:
+            - Attribute:       DW_AT_low_pc
+              Form:            DW_FORM_addr
+            - Attribute:       DW_AT_high_pc
+              Form:            DW_FORM_data4
+            - Attribute:       DW_AT_APPLE_omit_frame_ptr
+              Form:            DW_FORM_flag_present
+            - Attribute:       DW_AT_frame_base
+              Form:            DW_FORM_exprloc
+            - Attribute:       DW_AT_object_pointer
+              Form:            DW_FORM_ref4
+            - Attribute:       DW_AT_linkage_name
+              Form:            DW_FORM_strp
+            - Attribute:       DW_AT_specification
+              Form:            DW_FORM_ref4
+  debug_info:
+    - Length:          0x21F
+      Version:         4
+      AbbrevTableID:   0
+      AbbrOffset:      0x0
+      AddrSize:        8
+      Entries:
+        - AbbrCode:        0x1
+          Values:
+            - Value:           0x0
+            - Value:           0x11
+            - Value:           0x2F
+            - Value:           0x37
+            - Value:           0x96
+            - Value:           0x0
+            - Value:           0xA1
+            - Value:           0x2
+            - Value:           0x0
+            - Value:           0xC4
+        - AbbrCode:        0x2
+          Values:
+            - Value:           0xAB
+            - Value:           0x48
+            - Value:           0x1
+            - Value:           0x1
+            - Value:           0x3
+            - Value:           0x9
+              BlockData:       [ 0x3, 0xC4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+                                 0x0 ]
+        - AbbrCode:        0x3
+          Values:
+            - Value:           0xB4
+            - Value:           0x5
+            - Value:           0x4
+        - AbbrCode:        0x4
+          Values:
+            - Value:           0x1
+            - Value:           0xB8
+            - Value:           0x8
+            - Value:           0x1
+            - Value:           0x13
+            - Value:           0x11
+        - AbbrCode:        0x5
+          Values:
+            - Value:           0x5F
+            - Value:           0x0
+        - AbbrCode:        0x0
+        - AbbrCode:        0x6
+          Values:
+            - Value:           0xC4
+            - Value:           0x8
+            - Value:           0x2
+            - Value:           0x35
+            - Value:           0x11
+        - AbbrCode:        0x7
+          Values:
+            - Value:           0xCD
+            - Value:           0x76
+            - Value:           0x2
+            - Value:           0x38
+            - Value:           0x0
+            - Value:           0x2
+        - AbbrCode:        0x0
+        - AbbrCode:        0x8
+          Values:
+            - Value:           0x81
+            - Value:           0xD1
+            - Value:           0x1
+            - Value:           0xD
+        - AbbrCode:        0x9
+          Values:
+            - Value:           0x86
+        - AbbrCode:        0xA
+          Values:
+            - Value:           0xD7
+            - Value:           0x1
+        - AbbrCode:        0xB
+          Values:
+            - Value:           0x0
+            - Value:           0x20
+            - Value:           0x1
+            - Value:           0x1
+              BlockData:       [ 0x6F ]
+            - Value:           0xE6
+            - Value:           0xE2
+            - Value:           0x1
+            - Value:           0x6
+            - Value:           0x48
+            - Value:           0x1
+        - AbbrCode:        0xC
+          Values:
+            - Value:           0x2
+              BlockData:       [ 0x91, 0xC ]
+            - Value:           0x11C
+            - Value:           0x1
+            - Value:           0x6
+            - Value:           0x48
+        - AbbrCode:        0x0
+        - AbbrCode:        0xD
+          Values:
+            - Value:           0x20
+            - Value:           0x14
+            - Value:           0x1
+            - Value:           0x1
+              BlockData:       [ 0x6F ]
+            - Value:           0xD0
+            - Value:           0xEE
+            - Value:           0x1
+            - Value:           0x18
+        - AbbrCode:        0xE
+          Values:
+            - Value:           0x2
+              BlockData:       [ 0x91, 0x8 ]
+            - Value:           0x155
+            - Value:           0x1ED
+            - Value:           0x1
+        - AbbrCode:        0xE
+          Values:
+            - Value:           0x2
+              BlockData:       [ 0x91, 0x0 ]
+            - Value:           0x15A
+            - Value:           0x1F2
+            - Value:           0x1
+        - AbbrCode:        0x0
+        - AbbrCode:        0xF
+          Values:
+            - Value:           0x34
+            - Value:           0x3C
+            - Value:           0x1
+              BlockData:       [ 0x6D ]
+            - Value:           0x10F
+            - Value:           0x1
+            - Value:           0x1B
+            - Value:           0x48
+            - Value:           0x1
+        - AbbrCode:        0xC
+          Values:
+            - Value:           0x2
+              BlockData:       [ 0x91, 0x78 ]
+            - Value:           0x171
+            - Value:           0x1
+            - Value:           0x1B
+            - Value:           0x48
+        - AbbrCode:        0xC
+          Values:
+            - Value:           0x2
+              BlockData:       [ 0x8F, 0x10 ]
+            - Value:           0x176
+            - Value:           0x1
+            - Value:           0x1B
+            - Value:           0x207
+        - AbbrCode:        0x10
+          Values:
+            - Value:           0x2
+              BlockData:       [ 0x8F, 0xC ]
+            - Value:           0x180
+            - Value:           0x1
+            - Value:           0x1C
+            - Value:           0x132
+        - AbbrCode:        0x0
+        - AbbrCode:        0x11
+          Values:
+            - Value:           0x114
+        - AbbrCode:        0x12
+          Values:
+            - Value:           0x5
+            - Value:           0x118
+            - Value:           0x4
+            - Value:           0x1
+            - Value:           0xA
+        - AbbrCode:        0x13
+          Values:
+            - Value:           0x11C
+            - Value:           0x48
+            - Value:           0x1
+            - Value:           0xB
+            - Value:           0x0
+        - AbbrCode:        0x14
+          Values:
+            - Value:           0x118
+            - Value:           0x1
+            - Value:           0xD
+            - Value:           0x1
+            - Value:           0x1
+            - Value:           0x1
+        - AbbrCode:        0x15
+          Values:
+            - Value:           0x172
+            - Value:           0x1
+        - AbbrCode:        0x16
+          Values:
+            - Value:           0x48
+        - AbbrCode:        0x0
+        - AbbrCode:        0x17
+          Values:
+            - Value:           0x11E
+            - Value:           0x131
+            - Value:           0x1
+            - Value:           0xF
+            - Value:           0x48
+            - Value:           0x1
+            - Value:           0x1
+            - Value:           0x1
+        - AbbrCode:        0x15
+          Values:
+            - Value:           0x177
+            - Value:           0x1
+        - AbbrCode:        0x0
+        - AbbrCode:        0x0
+        - AbbrCode:        0x0
+        - AbbrCode:        0x9
+          Values:
+            - Value:           0x132
+        - AbbrCode:        0x9
+          Values:
+            - Value:           0x17C
+        - AbbrCode:        0x18
+          Values:
+            - Value:           0x132
+        - AbbrCode:        0x19
+          Values:
+            - Value:           0x70
+            - Value:           0x34
+            - Value:           0x1
+              BlockData:       [ 0x6D ]
+            - Value:           0x19C
+            - Value:           0x135
+            - Value:           0x147
+        - AbbrCode:        0xE
+          Values:
+            - Value:           0x2
+              BlockData:       [ 0x91, 0x78 ]
+            - Value:           0x182
+            - Value:           0x21D
+            - Value:           0x1
+        - AbbrCode:        0xC
+          Values:
+            - Value:           0x2
+              BlockData:       [ 0x91, 0x74 ]
+            - Value:           0x187
+            - Value:           0x1
+            - Value:           0xD
+            - Value:           0x48
+        - AbbrCode:        0x0
+        - AbbrCode:        0x1A
+          Values:
+            - Value:           0xA4
+            - Value:           0x20
+            - Value:           0x1
+            - Value:           0x1
+              BlockData:       [ 0x6F ]
+            - Value:           0x1D2
+            - Value:           0x145
+            - Value:           0x147
+        - AbbrCode:        0xE
+          Values:
+            - Value:           0x2
+              BlockData:       [ 0x91, 0x8 ]
+            - Value:           0x182
+            - Value:           0x21D
+            - Value:           0x1
+        - AbbrCode:        0xC
+          Values:
+            - Value:           0x2
+              BlockData:       [ 0x91, 0x4 ]
+            - Value:           0x187
+            - Value:           0x1
+            - Value:           0xD
+            - Value:           0x48
+        - AbbrCode:        0x0
+        - AbbrCode:        0x9
+          Values:
+            - Value:           0x4F
+        - AbbrCode:        0x8
+          Values:
+            - Value:           0x1FD
+            - Value:           0x15F
+            - Value:           0x1
+            - Value:           0x8
+        - AbbrCode:        0x9
+          Values:
+            - Value:           0x202
+        - AbbrCode:        0xA
+          Values:
+            - Value:           0x163
+            - Value:           0x1
+        - AbbrCode:        0x9
+          Values:
+            - Value:           0x20C
+        - AbbrCode:        0x9
+          Values:
+            - Value:           0x211
+        - AbbrCode:        0x18
+          Values:
+            - Value:           0x216
+        - AbbrCode:        0x3
+          Values:
+            - Value:           0x17B
+            - Value:           0x6
+            - Value:           0x1
+        - AbbrCode:        0x9
+          Values:
+            - Value:           0x132
+        - AbbrCode:        0x0
+  debug_line:
+    - Length:          250
+      Version:         4
+      PrologueLength:  157
+      MinInstLength:   1
+      MaxOpsPerInst:   1
+      DefaultIsStmt:   1
+      LineBase:        251
+      LineRange:       14
+      OpcodeBase:      13
+      StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ]
+      IncludeDirs:
+        - '/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/objc'
+      Files:
+        - Name:            main.mm
+          DirIdx:          0
+          ModTime:         0
+          Length:          0
+        - Name:            NSObject.h
+          DirIdx:          1
+          ModTime:         0
+          Length:          0
+      Opcodes:
+        - Opcode:          DW_LNS_extended_op
+          ExtLen:          9
+          SubOpcode:       DW_LNE_set_address
+          Data:            0
+        - Opcode:          0x17
+          Data:            0
+        - Opcode:          DW_LNS_set_column
+          Data:            10
+        - Opcode:          DW_LNS_set_prologue_end
+          Data:            0
+        - Opcode:          0x83
+          Data:            0
+        - Opcode:          DW_LNS_set_column
+          Data:            0
+        - Opcode:          DW_LNS_negate_stmt
+          Data:            0
+        - Opcode:          DW_LNS_advance_line
+          SData:           -7
+          Data:            0
+        - Opcode:          0x4A
+          Data:            0
+        - Opcode:          DW_LNS_set_column
+          Data:            14
+        - Opcode:          0x51
+          Data:            0
+        - Opcode:          DW_LNS_set_column
+          Data:            12
+        - Opcode:          0x4A
+          Data:            0
+        - Opcode:          DW_LNS_set_column
+          Data:            3
+        - Opcode:          0x4A
+          Data:            0
+        - Opcode:          DW_LNS_set_column
+          Data:            0
+        - Opcode:          DW_LNS_negate_stmt
+          Data:            0
+        - Opcode:          DW_LNS_advance_line
+          SData:           17
+          Data:            0
+        - Opcode:          0x82
+          Data:            0
+        - Opcode:          DW_LNS_set_column
+          Data:            20
+        - Opcode:          DW_LNS_set_prologue_end
+          Data:            0
+        - Opcode:          0xBA
+          Data:            0
+        - Opcode:          DW_LNS_set_column
+          Data:            0
+        - Opcode:          0x85
+          Data:            0
+        - Opcode:          DW_LNS_set_column
+          Data:            12
+        - Opcode:          DW_LNS_set_prologue_end
+          Data:            0
+        - Opcode:          DW_LNS_advance_pc
+          Data:            40
+        - Opcode:          0x13
+          Data:            0
+        - Opcode:          DW_LNS_set_column
+          Data:            3
+        - Opcode:          0x83
+          Data:            0
+        - Opcode:          DW_LNS_set_column
+          Data:            0
+        - Opcode:          DW_LNS_advance_line
+          SData:           -16
+          Data:            0
+        - Opcode:          0xBA
+          Data:            0
+        - Opcode:          DW_LNS_set_column
+          Data:            21
+        - Opcode:          DW_LNS_set_prologue_end
+          Data:            0
+        - Opcode:          DW_LNS_const_add_pc
+          Data:            0
+        - Opcode:          0xAC
+          Data:            0
+        - Opcode:          DW_LNS_set_column
+          Data:            22
+        - Opcode:          DW_LNS_negate_stmt
+          Data:            0
+        - Opcode:          0xBA
+          Data:            0
+        - Opcode:          DW_LNS_set_column
+          Data:            0
+        - Opcode:          DW_LNS_negate_stmt
+          Data:            0
+        - Opcode:          0xBA
+          Data:            0
+        - Opcode:          DW_LNS_set_column
+          Data:            18
+        - Opcode:          DW_LNS_set_prologue_end
+          Data:            0
+        - Opcode:          0xF2
+          Data:            0
+        - Opcode:          DW_LNS_set_column
+          Data:            16
+        - Opcode:          DW_LNS_negate_stmt
+          Data:            0
+        - Opcode:          0x4A
+          Data:            0
+        - Opcode:          DW_LNS_set_column
+          Data:            22
+        - Opcode:          0x4A
+          Data:            0
+        - Opcode:          DW_LNS_advance_pc
+          Data:            8
+        - Opcode:          DW_LNS_extended_op
+          ExtLen:          1
+          SubOpcode:       DW_LNE_end_sequence
+          Data:            0
+...
Index: lldb/test/API/functionalities/module_cache/debug_index/TestDebugIndexCache.py
===================================================================
--- /dev/null
+++ lldb/test/API/functionalities/module_cache/debug_index/TestDebugIndexCache.py
@@ -0,0 +1,141 @@
+import glob
+import json
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+import os
+import time
+
+
+class DebugIndexCacheTestcase(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    def setUp(self):
+        # Call super's setUp().
+        TestBase.setUp(self)
+        # Set the lldb module cache directory to a directory inside the build
+        # artifacts directory so no other tests are interfered with.
+        self.cache_dir = os.path.join(self.getBuildDir(), 'lldb-module-cache')
+
+    def get_module_cache_files(self, basename):
+        module_cache_glob = os.path.join(self.cache_dir,
+                                         "llvmcache-*%s*dwarf-index*" % (basename))
+        return glob.glob(module_cache_glob)
+
+    def get_stats(self, log_path=None):
+        """
+            Get the output of the "statistics dump" and return the JSON as a
+            python dictionary.
+        """
+        # If log_path is set, open the path and emit the output of the command
+        # for debugging purposes.
+        if log_path is not None:
+            f = open(log_path, 'w')
+        else:
+            f = None
+        return_obj = lldb.SBCommandReturnObject()
+        command = "statistics dump "
+        if f:
+            f.write('(lldb) %s\n' % (command))
+        self.ci.HandleCommand(command, return_obj, False)
+        metrics_json = return_obj.GetOutput()
+        if f:
+            f.write(metrics_json)
+        return json.loads(metrics_json)
+
+    def enable_lldb_index_cache(self):
+        self.runCmd('settings set symbols.lldb-index-cache-path "%s"' % (self.cache_dir))
+        self.runCmd('settings set symbols.enable-lldb-index-cache true')
+
+    @no_debug_info_test
+    def test_with_caching_enabled(self):
+        """
+            Test module cache functionality for debug info index caching.
+
+            We test that a debug info index file is created for the debug
+            information when caching is enabled with a file that contains
+            at least one of each kind of DIE in ManualDWARFIndex::IndexSet.
+
+            The input file has DWARF that will fill in every member of the
+            ManualDWARFIndex::IndexSet class to ensure we can encode all of the
+            required information.
+
+            With caching enabled, we also verify that the appropriate statistics
+            specify that the cache file was saved to the cache.
+        """
+        self.enable_lldb_index_cache()
+        src_dir = self.getSourceDir()
+        yaml_path = os.path.join(src_dir, "exe.yaml")
+        yaml_base, ext = os.path.splitext(yaml_path)
+        obj_path = self.getBuildArtifact("main.o")
+        self.yaml2obj(yaml_path, obj_path)
+
+        # Create a target with the object file we just created from YAML
+        target = self.dbg.CreateTarget(obj_path)
+        self.assertTrue(target, VALID_TARGET)
+
+        debug_index_cache_files = self.get_module_cache_files('main.o')
+        self.assertEqual(len(debug_index_cache_files), 1,
+                "make sure there is one file in the module cache directory (%s) for main.o that is a debug info cache" % (self.cache_dir))
+
+        # Verify that the module statistics have the information that specifies
+        # if we loaded or saved the debug index and symtab to the cache
+        stats = self.get_stats()
+        module_stats = stats['modules'][0]
+        self.assertFalse(module_stats['debugInfoIndexLoadedFromCache'])
+        self.assertTrue(module_stats['debugInfoIndexSavedToCache'])
+        self.assertFalse(module_stats['symbolTableLoadedFromCache'])
+        self.assertTrue(module_stats['symbolTableSavedToCache'])
+        # Verify the top level stats track how many things were loaded or saved
+        # to the cache.
+        self.assertEqual(stats["totalDebugInfoIndexLoadedFromCache"], 0)
+        self.assertEqual(stats["totalDebugInfoIndexSavedToCache"], 1)
+        self.assertEqual(stats["totalSymbolTablesLoadedFromCache"], 0)
+        self.assertEqual(stats["totalSymbolTablesSavedToCache"], 1)
+
+    @no_debug_info_test
+    def test_with_caching_disabled(self):
+        """
+            Test module cache functionality for debug info index caching.
+
+            We test that a debug info index file is not created for the debug
+            information when caching is disabled with a file that contains
+            at least one of each kind of DIE in ManualDWARFIndex::IndexSet.
+
+            The input file has DWARF that will fill in every member of the
+            ManualDWARFIndex::IndexSet class to ensure we can encode all of the
+            required information.
+
+            With caching disabled, we also verify that the appropriate
+            statistics specify that the cache file was not saved to the cache.
+        """
+        src_dir = self.getSourceDir()
+        yaml_path = os.path.join(src_dir, "exe.yaml")
+        yaml_base, ext = os.path.splitext(yaml_path)
+        obj_path = self.getBuildArtifact("main.o")
+        self.yaml2obj(yaml_path, obj_path)
+
+        # Create a target with the object file we just created from YAML
+        target = self.dbg.CreateTarget(obj_path)
+        self.assertTrue(target, VALID_TARGET)
+
+        debug_index_cache_files = self.get_module_cache_files('main.o')
+        self.assertEqual(len(debug_index_cache_files), 0,
+                "make sure there is no file in the module cache directory (%s) for main.o that is a debug info cache" % (self.cache_dir))
+
+        # Verify that the module statistics have the information that specifies
+        # if we loaded or saved the debug index and symtab to the cache
+        stats = self.get_stats()
+        module_stats = stats['modules'][0]
+        self.assertFalse(module_stats['debugInfoIndexLoadedFromCache'])
+        self.assertFalse(module_stats['debugInfoIndexSavedToCache'])
+        self.assertFalse(module_stats['symbolTableLoadedFromCache'])
+        self.assertFalse(module_stats['symbolTableSavedToCache'])
+        # Verify the top level stats track how many things were loaded or saved
+        # to the cache.
+        self.assertEqual(stats["totalDebugInfoIndexLoadedFromCache"], 0)
+        self.assertEqual(stats["totalDebugInfoIndexSavedToCache"], 0)
+        self.assertEqual(stats["totalSymbolTablesLoadedFromCache"], 0)
+        self.assertEqual(stats["totalSymbolTablesSavedToCache"], 0)
Index: lldb/test/API/commands/statistics/basic/TestStats.py
===================================================================
--- lldb/test/API/commands/statistics/basic/TestStats.py
+++ lldb/test/API/commands/statistics/basic/TestStats.py
@@ -164,8 +164,12 @@
             'targets',
             'totalSymbolTableParseTime',
             'totalSymbolTableIndexTime',
+            'totalSymbolTablesLoadedFromCache',
+            'totalSymbolTablesSavedToCache',
             'totalDebugInfoByteSize',
             'totalDebugInfoIndexTime',
+            'totalDebugInfoIndexLoadedFromCache',
+            'totalDebugInfoIndexSavedToCache',
             'totalDebugInfoParseTime',
         ]
         self.verify_keys(debug_stats, '"debug_stats"', debug_stat_keys, None)
@@ -227,8 +231,12 @@
             'targets',
             'totalSymbolTableParseTime',
             'totalSymbolTableIndexTime',
+            'totalSymbolTablesLoadedFromCache',
+            'totalSymbolTablesSavedToCache',
             'totalDebugInfoByteSize',
             'totalDebugInfoIndexTime',
+            'totalDebugInfoIndexLoadedFromCache',
+            'totalDebugInfoIndexSavedToCache',
             'totalDebugInfoParseTime',
         ]
         self.verify_keys(debug_stats, '"debug_stats"', debug_stat_keys, None)
@@ -265,8 +273,12 @@
             'targets',
             'totalSymbolTableParseTime',
             'totalSymbolTableIndexTime',
+            'totalSymbolTablesLoadedFromCache',
+            'totalSymbolTablesSavedToCache',
             'totalDebugInfoParseTime',
             'totalDebugInfoIndexTime',
+            'totalDebugInfoIndexLoadedFromCache',
+            'totalDebugInfoIndexSavedToCache',
             'totalDebugInfoByteSize'
         ]
         self.verify_keys(debug_stats, '"debug_stats"', debug_stat_keys, None)
@@ -278,12 +290,16 @@
         exe_module = self.find_module_in_metrics(exe, debug_stats)
         module_keys = [
             'debugInfoByteSize',
+            'debugInfoIndexLoadedFromCache',
             'debugInfoIndexTime',
+            'debugInfoIndexSavedToCache',
             'debugInfoParseTime',
             'identifier',
             'path',
             'symbolTableIndexTime',
+            'symbolTableLoadedFromCache',
             'symbolTableParseTime',
+            'symbolTableSavedToCache',
             'triple',
             'uuid',
         ]
@@ -343,8 +359,12 @@
             'targets',
             'totalSymbolTableParseTime',
             'totalSymbolTableIndexTime',
+            'totalSymbolTablesLoadedFromCache',
+            'totalSymbolTablesSavedToCache',
             'totalDebugInfoParseTime',
             'totalDebugInfoIndexTime',
+            'totalDebugInfoIndexLoadedFromCache',
+            'totalDebugInfoIndexSavedToCache',
             'totalDebugInfoByteSize',
         ]
         self.verify_keys(debug_stats, '"debug_stats"', debug_stat_keys, None)
Index: lldb/source/Target/Statistics.cpp
===================================================================
--- lldb/source/Target/Statistics.cpp
+++ lldb/source/Target/Statistics.cpp
@@ -52,9 +52,15 @@
   module.try_emplace("identifier", identifier);
   module.try_emplace("symbolTableParseTime", symtab_parse_time);
   module.try_emplace("symbolTableIndexTime", symtab_index_time);
+  module.try_emplace("symbolTableLoadedFromCache", symtab_loaded_from_cache);
+  module.try_emplace("symbolTableSavedToCache", symtab_saved_to_cache);
   module.try_emplace("debugInfoParseTime", debug_parse_time);
   module.try_emplace("debugInfoIndexTime", debug_index_time);
   module.try_emplace("debugInfoByteSize", (int64_t)debug_info_size);
+  module.try_emplace("debugInfoIndexLoadedFromCache",
+                     debug_info_index_loaded_from_cache);
+  module.try_emplace("debugInfoIndexSavedToCache",
+                     debug_info_index_saved_to_cache);
   return module;
 }
 
@@ -144,6 +150,10 @@
   double symtab_index_time = 0.0;
   double debug_parse_time = 0.0;
   double debug_index_time = 0.0;
+  uint32_t symtabs_loaded = 0;
+  uint32_t symtabs_saved = 0;
+  uint32_t debug_index_loaded = 0;
+  uint32_t debug_index_saved = 0;
   uint64_t debug_info_size = 0;
   if (target) {
     json_targets.emplace_back(target->ReportStatistics());
@@ -169,11 +179,28 @@
     module_stat.triple = module->GetArchitecture().GetTriple().str();
     module_stat.symtab_parse_time = module->GetSymtabParseTime().count();
     module_stat.symtab_index_time = module->GetSymtabIndexTime().count();
+    Symtab *symtab = module->GetSymtab();
+    if (symtab) {
+      module_stat.symtab_loaded_from_cache = symtab->GetWasLoadedFromCache();
+      if (module_stat.symtab_loaded_from_cache)
+        ++symtabs_loaded;
+      module_stat.symtab_saved_to_cache = symtab->GetWasSavedToCache();
+      if (module_stat.symtab_saved_to_cache)
+        ++symtabs_saved;
+    }
     SymbolFile *sym_file = module->GetSymbolFile();
     if (sym_file) {
       module_stat.debug_index_time = sym_file->GetDebugInfoIndexTime().count();
       module_stat.debug_parse_time = sym_file->GetDebugInfoParseTime().count();
       module_stat.debug_info_size = sym_file->GetDebugInfoSize();
+      module_stat.debug_info_index_loaded_from_cache =
+          sym_file->GetDebugInfoIndexWasLoadedFromCache();
+      if (module_stat.debug_info_index_loaded_from_cache)
+        ++debug_index_loaded;
+      module_stat.debug_info_index_saved_to_cache =
+          sym_file->GetDebugInfoIndexWasSavedToCache();
+      if (module_stat.debug_info_index_saved_to_cache)
+        ++debug_index_saved;
     }
     symtab_parse_time += module_stat.symtab_parse_time;
     symtab_index_time += module_stat.symtab_index_time;
@@ -188,8 +215,12 @@
       {"modules", std::move(json_modules)},
       {"totalSymbolTableParseTime", symtab_parse_time},
       {"totalSymbolTableIndexTime", symtab_index_time},
+      {"totalSymbolTablesLoadedFromCache", symtabs_loaded},
+      {"totalSymbolTablesSavedToCache", symtabs_saved},
       {"totalDebugInfoParseTime", debug_parse_time},
       {"totalDebugInfoIndexTime", debug_index_time},
+      {"totalDebugInfoIndexLoadedFromCache", debug_index_loaded},
+      {"totalDebugInfoIndexSavedToCache", debug_index_saved},
       {"totalDebugInfoByteSize", debug_info_size},
   };
   return std::move(global_stats);
Index: lldb/source/Symbol/Symtab.cpp
===================================================================
--- lldb/source/Symbol/Symtab.cpp
+++ lldb/source/Symbol/Symtab.cpp
@@ -34,7 +34,8 @@
 Symtab::Symtab(ObjectFile *objfile)
     : m_objfile(objfile), m_symbols(), m_file_addr_to_index(*this),
       m_name_to_symbol_indices(), m_mutex(),
-      m_file_addr_to_index_computed(false), m_name_indexes_computed(false) {
+      m_file_addr_to_index_computed(false), m_name_indexes_computed(false),
+      m_loaded_from_cache(false), m_saved_to_cache(false) {
   m_name_to_symbol_indices.emplace(std::make_pair(
       lldb::eFunctionNameTypeNone, UniqueCStringMap<uint32_t>()));
   m_name_to_symbol_indices.emplace(std::make_pair(
@@ -1179,7 +1180,8 @@
   // Encode will return false if the symbol table's object file doesn't have
   // anything to make a signature from.
   if (Encode(file))
-    cache->SetCachedData(GetCacheKey(), file.GetData());
+    if (cache->SetCachedData(GetCacheKey(), file.GetData()))
+      SetWasSavedToCache();
 }
 
 constexpr llvm::StringLiteral kIdentifierCStrMap("CMAP");
@@ -1343,5 +1345,7 @@
   const bool result = Decode(data, &offset, signature_mismatch);
   if (signature_mismatch)
     cache->RemoveCacheFile(GetCacheKey());
+  if (result)
+    SetWasLoadedFromCache();
   return result;
 }
Index: lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.h
===================================================================
--- lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.h
+++ lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.h
@@ -48,6 +48,44 @@
                              const DIERef &die_ref)> const
               &callback) const;
 
+  /// Decode a serialized version of this object from data.
+  ///
+  /// \param data
+  ///   The decoder object that references the serialized data.
+  ///
+  /// \param offset_ptr
+  ///   A pointer that contains the offset from which the data will be decoded
+  ///   from that gets updated as data gets decoded.
+  ///
+  /// \param strtab
+  ///   All strings in cache files are put into string tables for efficiency
+  ///   and cache file size reduction. Strings are stored as uint32_t string
+  ///   table offsets in the cache data.
+  bool Decode(const lldb_private::DataExtractor &data,
+              lldb::offset_t *offset_ptr,
+              const lldb_private::StringTableReader &strtab);
+
+  /// Encode this object into a data encoder object.
+  ///
+  /// This allows this object to be serialized to disk.
+  ///
+  /// \param encoder
+  ///   A data encoder object that serialized bytes will be encoded into.
+  ///
+  /// \param strtab
+  ///   All strings in cache files are put into string tables for efficiency
+  ///   and cache file size reduction. Strings are stored as uint32_t string
+  ///   table offsets in the cache data.
+  void Encode(lldb_private::DataEncoder &encoder,
+              lldb_private::ConstStringTable &strtab) const;
+
+  /// Used for unit testing the encoding and decoding.
+  bool operator==(const NameToDIE &rhs) const;
+
+  bool IsEmpty() const { return m_map.IsEmpty(); }
+
+  void Clear() { m_map.Clear(); }
+
 protected:
   lldb_private::UniqueCStringMap<DIERef> m_map;
 };
Index: lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp
===================================================================
--- lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp
+++ lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp
@@ -8,8 +8,11 @@
 
 #include "NameToDIE.h"
 #include "DWARFUnit.h"
+#include "lldb/Core/DataFileCache.h"
 #include "lldb/Symbol/ObjectFile.h"
 #include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/DataEncoder.h"
+#include "lldb/Utility/DataExtractor.h"
 #include "lldb/Utility/RegularExpression.h"
 #include "lldb/Utility/Stream.h"
 #include "lldb/Utility/StreamString.h"
@@ -87,3 +90,50 @@
                  other.m_map.GetValueAtIndexUnchecked(i));
   }
 }
+
+constexpr llvm::StringLiteral kIdentifierNameToDIE("N2DI");
+
+bool NameToDIE::Decode(const DataExtractor &data, lldb::offset_t *offset_ptr,
+                       const StringTableReader &strtab) {
+  m_map.Clear();
+  llvm::StringRef identifier((const char *)data.GetData(offset_ptr, 4), 4);
+  if (identifier != kIdentifierNameToDIE)
+    return false;
+  const uint32_t count = data.GetU32(offset_ptr);
+  for (uint32_t i = 0; i < count; ++i) {
+    llvm::StringRef str(strtab.Get(data.GetU32(offset_ptr)));
+    // No empty strings allowed in the name to DIE maps.
+    if (str.empty())
+      return false;
+    if (llvm::Optional<DIERef> die_ref = DIERef::Decode(data, offset_ptr))
+      m_map.Append(ConstString(str), die_ref.getValue());
+    else
+      return false;
+  }
+  return true;
+}
+
+void NameToDIE::Encode(DataEncoder &encoder, ConstStringTable &strtab) const {
+  encoder.AppendData(kIdentifierNameToDIE);
+  encoder.AppendU32(m_map.GetSize());
+  for (const auto &entry : m_map) {
+    // Make sure there are no empty strings.
+    assert((bool)entry.cstring);
+    encoder.AppendU32(strtab.Add(entry.cstring));
+    entry.value.Encode(encoder);
+  }
+}
+
+bool NameToDIE::operator==(const NameToDIE &rhs) const {
+  const size_t size = m_map.GetSize();
+  if (size != rhs.m_map.GetSize())
+    return false;
+  for (size_t i = 0; i < size; ++i) {
+    if (m_map.GetCStringAtIndex(i) != rhs.m_map.GetCStringAtIndex(i))
+      return false;
+    if (m_map.GetValueRefAtIndexUnchecked(i) !=
+        rhs.m_map.GetValueRefAtIndexUnchecked(i))
+      return false;
+  }
+  return true;
+}
Index: lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h
===================================================================
--- lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h
+++ lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h
@@ -55,7 +55,7 @@
 
   void Dump(Stream &s) override;
 
-private:
+  // Make IndexSet public so we can unit test the encoding and decoding logic.
   struct IndexSet {
     NameToDIE function_basenames;
     NameToDIE function_fullnames;
@@ -65,21 +65,113 @@
     NameToDIE globals;
     NameToDIE types;
     NameToDIE namespaces;
+    bool Decode(const DataExtractor &data, lldb::offset_t *offset_ptr);
+    void Encode(DataEncoder &encoder) const;
+    bool operator==(const IndexSet &rhs) const {
+      return function_basenames == rhs.function_basenames &&
+             function_fullnames == rhs.function_fullnames &&
+             function_methods == rhs.function_methods &&
+             function_selectors == rhs.function_selectors &&
+             objc_class_selectors == rhs.objc_class_selectors &&
+             globals == rhs.globals && types == rhs.types &&
+             namespaces == rhs.namespaces;
+    }
   };
+
+private:
   void Index();
+
+  /// Decode a serialized version of this object from data.
+  ///
+  /// \param data
+  ///   The decoder object that references the serialized data.
+  ///
+  /// \param offset_ptr
+  ///   A pointer that contains the offset from which the data will be decoded
+  ///   from that gets updated as data gets decoded.
+  ///
+  /// \param strtab
+  ///   All strings in cache files are put into string tables for efficiency
+  ///   and cache file size reduction. Strings are stored as uint32_t string
+  ///   table offsets in the cache data.
+  bool Decode(const DataExtractor &data, lldb::offset_t *offset_ptr,
+              bool &signature_mismatch);
+
+  /// Encode this object into a data encoder object.
+  ///
+  /// This allows this object to be serialized to disk.
+  ///
+  /// \param encoder
+  ///   A data encoder object that serialized bytes will be encoded into.
+  ///
+  /// \param strtab
+  ///   All strings in cache files are put into string tables for efficiency
+  ///   and cache file size reduction. Strings are stored as uint32_t string
+  ///   table offsets in the cache data.
+  ///
+  /// \return
+  ///   True if the symbol table's object file can generate a valid signature
+  ///   and all data for the symbol table was encoded, false otherwise.
+  bool Encode(DataEncoder &encoder) const;
+
+  /// Get the cache key string for this symbol table.
+  ///
+  /// The cache key must start with the module's cache key and is followed
+  /// by information that indicates this key is for caching the symbol table
+  /// contents and should also include the has of the object file. A module can
+  /// be represented by an ObjectFile object for the main executable, but can
+  /// also have a symbol file that is from the same or a different object file.
+  /// This means we might have two symbol tables cached in the index cache, one
+  /// for the main executable and one for the symbol file.
+  ///
+  /// \return
+  ///   The unique cache key used to save and retrieve data from the index
+  ///   cache.
+  std::string GetCacheKey();
+
+  /// Save the symbol table data out into a cache.
+  ///
+  /// The symbol table will only be saved to a cache file if caching is enabled.
+  ///
+  /// We cache the contents of the symbol table since symbol tables in LLDB take
+  /// some time to initialize. This is due to the many sources for data that are
+  /// used to create a symbol table:
+  /// - standard symbol table
+  /// - dynamic symbol table (ELF)
+  /// - compressed debug info sections
+  /// - unwind information
+  /// - function pointers found in runtimes for global constructor/destructors
+  /// - other sources.
+  /// All of the above sources are combined and one symbol table results after
+  /// all sources have been considered.
+  void SaveToCache();
+
+  /// Load the symbol table from the index cache.
+  ///
+  /// Quickly load the finalized symbol table from the index cache. This saves
+  /// time when the debugger starts up. The index cache file for the symbol
+  /// table has the modification time set to the same time as the main module.
+  /// If the cache file exists and the modification times match, we will load
+  /// the symbol table from the serlized cache file.
+  ///
+  /// \return
+  ///   True if the symbol table was successfully loaded from the index cache,
+  ///   false if the symbol table wasn't cached or was out of date.
+  bool LoadFromCache();
+
   void IndexUnit(DWARFUnit &unit, SymbolFileDWARFDwo *dwp, IndexSet &set);
 
   static void IndexUnitImpl(DWARFUnit &unit,
                             const lldb::LanguageType cu_language,
                             IndexSet &set);
 
-  /// The DWARF file which we are indexing. Set to nullptr after the index is
-  /// built.
+  /// The DWARF file which we are indexing.
   SymbolFileDWARF *m_dwarf;
   /// Which dwarf units should we skip while building the index.
   llvm::DenseSet<dw_offset_t> m_units_to_avoid;
 
   IndexSet m_set;
+  bool m_indexed = false;
 };
 } // namespace lldb_private
 
Index: lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp
===================================================================
--- lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp
+++ lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp
@@ -12,9 +12,12 @@
 #include "Plugins/SymbolFile/DWARF/DWARFDeclContext.h"
 #include "Plugins/SymbolFile/DWARF/LogChannelDWARF.h"
 #include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h"
+#include "lldb/Core/DataFileCache.h"
 #include "lldb/Core/Module.h"
 #include "lldb/Core/Progress.h"
 #include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Utility/DataEncoder.h"
+#include "lldb/Utility/DataExtractor.h"
 #include "lldb/Utility/Stream.h"
 #include "lldb/Utility/Timer.h"
 #include "llvm/Support/FormatVariadic.h"
@@ -24,17 +27,19 @@
 using namespace lldb;
 
 void ManualDWARFIndex::Index() {
-  if (!m_dwarf)
+  if (m_indexed)
     return;
-
-  SymbolFileDWARF &main_dwarf = *m_dwarf;
-  m_dwarf = nullptr;
+  m_indexed = true;
 
   ElapsedTime elapsed(m_index_time);
-  LLDB_SCOPED_TIMERF("%p", static_cast<void *>(&main_dwarf));
+  LLDB_SCOPED_TIMERF("%p", static_cast<void *>(m_dwarf));
+  if (LoadFromCache()) {
+    m_dwarf->SetDebugInfoIndexWasLoadedFromCache();
+    return;
+  }
 
-  DWARFDebugInfo &main_info = main_dwarf.DebugInfo();
-  SymbolFileDWARFDwo *dwp_dwarf = main_dwarf.GetDwpSymbolFile().get();
+  DWARFDebugInfo &main_info = m_dwarf->DebugInfo();
+  SymbolFileDWARFDwo *dwp_dwarf = m_dwarf->GetDwpSymbolFile().get();
   DWARFDebugInfo *dwp_info = dwp_dwarf ? &dwp_dwarf->DebugInfo() : nullptr;
 
   std::vector<DWARFUnit *> units_to_index;
@@ -125,6 +130,8 @@
   pool.async(finalize_fn, &IndexSet::types);
   pool.async(finalize_fn, &IndexSet::namespaces);
   pool.wait();
+
+  SaveToCache();
 }
 
 void ManualDWARFIndex::IndexUnit(DWARFUnit &unit, SymbolFileDWARFDwo *dwp,
@@ -480,3 +487,214 @@
   s.Printf("\nNamespaces:\n");
   m_set.namespaces.Dump(&s);
 }
+
+constexpr llvm::StringLiteral kIdentifierManualDWARFIndex("DIDX");
+// Define IDs for the different tables when encoding and decoding the
+// ManualDWARFIndex NameToDIE objects so we can avoid saving any empty maps.
+enum DataID {
+  kDataIDFunctionBasenames = 1u,
+  kDataIDFunctionFullnames,
+  kDataIDFunctionMethods,
+  kDataIDFunctionSelectors,
+  kDataIDFunctionObjcClassSelectors,
+  kDataIDGlobals,
+  kDataIDTypes,
+  kDataIDNamespaces,
+  kDataIDEnd = 255u,
+
+};
+constexpr uint32_t CURRENT_CACHE_VERSION = 1;
+
+bool ManualDWARFIndex::IndexSet::Decode(const DataExtractor &data,
+                                        lldb::offset_t *offset_ptr) {
+  StringTableReader strtab;
+  // We now decode the string table for all strings in the data cache file.
+  if (!strtab.Decode(data, offset_ptr))
+    return false;
+
+  llvm::StringRef identifier((const char *)data.GetData(offset_ptr, 4), 4);
+  if (identifier != kIdentifierManualDWARFIndex)
+    return false;
+  const uint32_t version = data.GetU32(offset_ptr);
+  if (version != CURRENT_CACHE_VERSION)
+    return false;
+
+  bool done = false;
+  while (!done) {
+    switch (data.GetU8(offset_ptr)) {
+    default:
+      // If we got here, this is not expected, we expect the data IDs to match
+      // one of the values from the DataID enumeration.
+      return false;
+    case kDataIDFunctionBasenames:
+      if (!function_basenames.Decode(data, offset_ptr, strtab))
+        return false;
+      break;
+    case kDataIDFunctionFullnames:
+      if (!function_fullnames.Decode(data, offset_ptr, strtab))
+        return false;
+      break;
+    case kDataIDFunctionMethods:
+      if (!function_methods.Decode(data, offset_ptr, strtab))
+        return false;
+      break;
+    case kDataIDFunctionSelectors:
+      if (!function_selectors.Decode(data, offset_ptr, strtab))
+        return false;
+      break;
+    case kDataIDFunctionObjcClassSelectors:
+      if (!objc_class_selectors.Decode(data, offset_ptr, strtab))
+        return false;
+      break;
+    case kDataIDGlobals:
+      if (!globals.Decode(data, offset_ptr, strtab))
+        return false;
+      break;
+    case kDataIDTypes:
+      if (!types.Decode(data, offset_ptr, strtab))
+        return false;
+      break;
+    case kDataIDNamespaces:
+      if (!namespaces.Decode(data, offset_ptr, strtab))
+        return false;
+      break;
+    case kDataIDEnd:
+      // We got to the end of our NameToDIE encodings.
+      done = true;
+      break;
+    }
+  }
+  // Success!
+  return true;
+}
+
+void ManualDWARFIndex::IndexSet::Encode(DataEncoder &encoder) const {
+  ConstStringTable strtab;
+
+  // Encoder the DWARF index into a separate encoder first. This allows us
+  // gather all of the strings we willl need in "strtab" as we will need to
+  // write the string table out before the symbol table.
+  DataEncoder index_encoder(encoder.GetByteOrder(),
+                            encoder.GetAddressByteSize());
+
+  index_encoder.AppendData(kIdentifierManualDWARFIndex);
+  // Encode the data version.
+  index_encoder.AppendU32(CURRENT_CACHE_VERSION);
+
+  if (!function_basenames.IsEmpty()) {
+    index_encoder.AppendU8(kDataIDFunctionBasenames);
+    function_basenames.Encode(index_encoder, strtab);
+  }
+  if (!function_fullnames.IsEmpty()) {
+    index_encoder.AppendU8(kDataIDFunctionFullnames);
+    function_fullnames.Encode(index_encoder, strtab);
+  }
+  if (!function_methods.IsEmpty()) {
+    index_encoder.AppendU8(kDataIDFunctionMethods);
+    function_methods.Encode(index_encoder, strtab);
+  }
+  if (!function_selectors.IsEmpty()) {
+    index_encoder.AppendU8(kDataIDFunctionSelectors);
+    function_selectors.Encode(index_encoder, strtab);
+  }
+  if (!objc_class_selectors.IsEmpty()) {
+    index_encoder.AppendU8(kDataIDFunctionObjcClassSelectors);
+    objc_class_selectors.Encode(index_encoder, strtab);
+  }
+  if (!globals.IsEmpty()) {
+    index_encoder.AppendU8(kDataIDGlobals);
+    globals.Encode(index_encoder, strtab);
+  }
+  if (!types.IsEmpty()) {
+    index_encoder.AppendU8(kDataIDTypes);
+    types.Encode(index_encoder, strtab);
+  }
+  if (!namespaces.IsEmpty()) {
+    index_encoder.AppendU8(kDataIDNamespaces);
+    namespaces.Encode(index_encoder, strtab);
+  }
+  index_encoder.AppendU8(kDataIDEnd);
+
+  // Now that all strings have been gathered, we will emit the string table.
+  strtab.Encode(encoder);
+  // Followed the the symbol table data.
+  encoder.AppendData(index_encoder.GetData());
+}
+
+bool ManualDWARFIndex::Decode(const DataExtractor &data,
+                              lldb::offset_t *offset_ptr,
+                              bool &signature_mismatch) {
+  signature_mismatch = false;
+  CacheSignature signature;
+  if (!signature.Decode(data, offset_ptr))
+    return false;
+  if (CacheSignature(m_dwarf->GetObjectFile()) != signature) {
+    signature_mismatch = true;
+    return false;
+  }
+  IndexSet set;
+  if (!set.Decode(data, offset_ptr))
+    return false;
+  m_set = std::move(set);
+  return true;
+}
+
+bool ManualDWARFIndex::Encode(DataEncoder &encoder) const {
+  CacheSignature signature(m_dwarf->GetObjectFile());
+  if (!signature.Encode(encoder))
+    return false;
+  m_set.Encode(encoder);
+  return true;
+}
+
+std::string ManualDWARFIndex::GetCacheKey() {
+  std::string key;
+  llvm::raw_string_ostream strm(key);
+  // DWARF Index can come from different object files for the same module. A
+  // module can have one object file as the main executable and might have
+  // another object file in a separate symbol file, or we might have a .dwo file
+  // that claims its module is the main executable.
+  ObjectFile *objfile = m_dwarf->GetObjectFile();
+  strm << objfile->GetModule()->GetCacheKey() << "-dwarf-index-"
+      << llvm::format_hex(objfile->GetCacheHash(), 10);
+  return strm.str();
+}
+
+bool ManualDWARFIndex::LoadFromCache() {
+  DataFileCache *cache = Module::GetIndexCache();
+  if (!cache)
+    return false;
+  ObjectFile *objfile = m_dwarf->GetObjectFile();
+  if (!objfile)
+    return false;
+  std::unique_ptr<llvm::MemoryBuffer> mem_buffer_up =
+      cache->GetCachedData(GetCacheKey());
+  if (!mem_buffer_up)
+    return false;
+  DataExtractor data(mem_buffer_up->getBufferStart(),
+                     mem_buffer_up->getBufferSize(),
+                     endian::InlHostByteOrder(),
+                     objfile->GetAddressByteSize());
+  bool signature_mismatch = false;
+  lldb::offset_t offset = 0;
+  const bool result = Decode(data, &offset, signature_mismatch);
+  if (signature_mismatch)
+    cache->RemoveCacheFile(GetCacheKey());
+  return result;
+}
+
+void ManualDWARFIndex::SaveToCache() {
+  DataFileCache *cache = Module::GetIndexCache();
+  if (!cache)
+    return; // Caching is not enabled.
+  ObjectFile *objfile = m_dwarf->GetObjectFile();
+  if (!objfile)
+    return;
+  DataEncoder file(endian::InlHostByteOrder(), objfile->GetAddressByteSize());
+  // Encode will return false if the object file doesn't have anything to make
+  // a signature from.
+  if (Encode(file)) {
+    if (cache->SetCachedData(GetCacheKey(), file.GetData()))
+      m_dwarf->SetDebugInfoIndexWasSavedToCache();
+  }
+}
Index: lldb/source/Plugins/SymbolFile/DWARF/DIERef.h
===================================================================
--- lldb/source/Plugins/SymbolFile/DWARF/DIERef.h
+++ lldb/source/Plugins/SymbolFile/DWARF/DIERef.h
@@ -54,6 +54,37 @@
     return m_die_offset < other.m_die_offset;
   }
 
+  bool operator==(const DIERef &rhs) const {
+    return dwo_num() == rhs.dwo_num() && m_section == rhs.m_section &&
+           m_die_offset == rhs.m_die_offset;
+  }
+
+  bool operator!=(const DIERef &rhs) const { return !(*this == rhs); }
+
+  /// Decode a serialized version of this object from data.
+  ///
+  /// \param data
+  ///   The decoder object that references the serialized data.
+  ///
+  /// \param offset_ptr
+  ///   A pointer that contains the offset from which the data will be decoded
+  ///   from that gets updated as data gets decoded.
+  ///
+  /// \return
+  ///   Returns a valid DIERef if decoding succeeded, llvm::None if there was
+  ///   unsufficient or invalid values that were decoded.
+  static llvm::Optional<DIERef> Decode(const lldb_private::DataExtractor &data,
+                                       lldb::offset_t *offset_ptr);
+
+  /// Encode this object into a data encoder object.
+  ///
+  /// This allows this object to be serialized to disk.
+  ///
+  /// \param encoder
+  ///   A data encoder object that serialized bytes will be encoded into.
+  ///
+  void Encode(lldb_private::DataEncoder &encoder) const;
+
 private:
   uint32_t m_dwo_num : 30;
   uint32_t m_dwo_num_valid : 1;
Index: lldb/source/Plugins/SymbolFile/DWARF/DIERef.cpp
===================================================================
--- lldb/source/Plugins/SymbolFile/DWARF/DIERef.cpp
+++ lldb/source/Plugins/SymbolFile/DWARF/DIERef.cpp
@@ -7,8 +7,13 @@
 //===----------------------------------------------------------------------===//
 
 #include "DIERef.h"
+#include "lldb/Utility/DataEncoder.h"
+#include "lldb/Utility/DataExtractor.h"
 #include "llvm/Support/Format.h"
 
+using namespace lldb;
+using namespace lldb_private;
+
 void llvm::format_provider<DIERef>::format(const DIERef &ref, raw_ostream &OS,
                                            StringRef Style) {
   if (ref.dwo_num())
@@ -16,3 +21,35 @@
   OS << (ref.section() == DIERef::DebugInfo ? "INFO" : "TYPE");
   OS << "/" << format_hex_no_prefix(ref.die_offset(), 8);
 }
+
+constexpr uint32_t k_dwo_num_mask = 0x3FFFFFFF;
+constexpr uint32_t k_dwo_num_valid_bitmask = (1u << 30);
+constexpr uint32_t k_section_bitmask = (1u << 31);
+
+llvm::Optional<DIERef> DIERef::Decode(const DataExtractor &data,
+                                      lldb::offset_t *offset_ptr) {
+  const uint32_t bitfield_storage = data.GetU32(offset_ptr);
+  uint32_t dwo_num = bitfield_storage & k_dwo_num_mask;
+  bool dwo_num_valid = (bitfield_storage & (k_dwo_num_valid_bitmask)) != 0;
+  Section section = (Section)((bitfield_storage & (k_section_bitmask)) != 0);
+  // DIE offsets can't be zero and if we fail to decode something from data,
+  // it will return 0
+  dw_offset_t die_offset = data.GetU32(offset_ptr);
+  if (die_offset == 0)
+    return llvm::None;
+  if (dwo_num_valid)
+    return DIERef(dwo_num, section, die_offset);
+  else
+    return DIERef(llvm::None, section, die_offset);
+}
+
+void DIERef::Encode(DataEncoder &encoder) const {
+  uint32_t bitfield_storage = m_dwo_num;
+  if (m_dwo_num_valid)
+    bitfield_storage |= k_dwo_num_valid_bitmask;
+  if (m_section)
+    bitfield_storage |= k_section_bitmask;
+  encoder.AppendU32(bitfield_storage);
+  static_assert(sizeof(m_die_offset) == 4, "m_die_offset must be 4 bytes");
+  encoder.AppendU32(m_die_offset);
+}
Index: lldb/include/lldb/Target/Statistics.h
===================================================================
--- lldb/include/lldb/Target/Statistics.h
+++ lldb/include/lldb/Target/Statistics.h
@@ -84,6 +84,10 @@
   double debug_parse_time = 0.0;
   double debug_index_time = 0.0;
   uint64_t debug_info_size = 0;
+  bool symtab_loaded_from_cache = false;
+  bool symtab_saved_to_cache = false;
+  bool debug_info_index_loaded_from_cache = false;
+  bool debug_info_index_saved_to_cache = false;
 };
 
 /// A class that represents statistics for a since lldb_private::Target.
Index: lldb/include/lldb/Symbol/Symtab.h
===================================================================
--- lldb/include/lldb/Symbol/Symtab.h
+++ lldb/include/lldb/Symbol/Symtab.h
@@ -212,6 +212,30 @@
   ///   false if the symbol table wasn't cached or was out of date.
   bool LoadFromCache();
 
+
+  /// Accessors for the bool that indicates if the debug info index was loaded
+  /// from, or saved to the module index cache.
+  ///
+  /// In statistics it is handy to know if a module's debug info was loaded from
+  /// or saved to the cache. When the debug info index is loaded from the cache
+  /// startup times can be faster. When the cache is enabled and the debug info
+  /// index is saved to the cache, debug sessions can be slower. These accessors
+  /// can be accessed by the statistics and emitted to help track these costs.
+  /// \{
+  bool GetWasLoadedFromCache() const {
+    return m_loaded_from_cache;
+  }
+  void SetWasLoadedFromCache() {
+    m_loaded_from_cache = true;
+  }
+  bool GetWasSavedToCache() const {
+    return m_saved_to_cache;
+  }
+  void SetWasSavedToCache() {
+    m_saved_to_cache = true;
+  }
+  /// \}
+
 protected:
   typedef std::vector<Symbol> collection;
   typedef collection::iterator iterator;
@@ -252,7 +276,8 @@
       m_name_to_symbol_indices;
   mutable std::recursive_mutex
       m_mutex; // Provide thread safety for this symbol table
-  bool m_file_addr_to_index_computed : 1, m_name_indexes_computed : 1;
+  bool m_file_addr_to_index_computed : 1, m_name_indexes_computed : 1,
+    m_loaded_from_cache : 1, m_saved_to_cache : 1;
 
 private:
   UniqueCStringMap<uint32_t> &
Index: lldb/include/lldb/Symbol/SymbolFile.h
===================================================================
--- lldb/include/lldb/Symbol/SymbolFile.h
+++ lldb/include/lldb/Symbol/SymbolFile.h
@@ -67,8 +67,7 @@
 
   // Constructors and Destructors
   SymbolFile(lldb::ObjectFileSP objfile_sp)
-      : m_objfile_sp(std::move(objfile_sp)), m_abilities(0),
-        m_calculated_abilities(false) {}
+      : m_objfile_sp(std::move(objfile_sp)) {}
 
   ~SymbolFile() override = default;
 
@@ -326,6 +325,29 @@
   /// hasn't been indexed yet, or a valid duration if it has.
   virtual StatsDuration GetDebugInfoIndexTime() { return StatsDuration(0.0); }
 
+  /// Accessors for the bool that indicates if the debug info index was loaded
+  /// from, or saved to the module index cache.
+  ///
+  /// In statistics it is handy to know if a module's debug info was loaded from
+  /// or saved to the cache. When the debug info index is loaded from the cache
+  /// startup times can be faster. When the cache is enabled and the debug info
+  /// index is saved to the cache, debug sessions can be slower. These accessors
+  /// can be accessed by the statistics and emitted to help track these costs.
+  /// \{
+  bool GetDebugInfoIndexWasLoadedFromCache() const {
+    return m_index_was_loaded_from_cache;
+  }
+  void SetDebugInfoIndexWasLoadedFromCache() {
+    m_index_was_loaded_from_cache = true;
+  }
+  bool GetDebugInfoIndexWasSavedToCache() const {
+    return m_index_was_saved_to_cache;
+  }
+  void SetDebugInfoIndexWasSavedToCache() {
+    m_index_was_saved_to_cache = true;
+  }
+  /// \}
+
 protected:
   void AssertModuleLock();
   virtual uint32_t CalculateNumCompileUnits() = 0;
@@ -341,8 +363,10 @@
   llvm::Optional<std::vector<lldb::CompUnitSP>> m_compile_units;
   TypeList m_type_list;
   Symtab *m_symtab = nullptr;
-  uint32_t m_abilities;
-  bool m_calculated_abilities;
+  uint32_t m_abilities = 0;
+  bool m_calculated_abilities = false;
+  bool m_index_was_loaded_from_cache = false;
+  bool m_index_was_saved_to_cache = false;
 
 private:
   SymbolFile(const SymbolFile &) = delete;
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to