[Lldb-commits] [lldb] r270488 - We have many radars showing that stepping through C++ code can result in slow steps.

Greg Clayton via lldb-commits lldb-commits at lists.llvm.org
Mon May 23 13:37:24 PDT 2016


Author: gclayton
Date: Mon May 23 15:37:24 2016
New Revision: 270488

URL: http://llvm.org/viewvc/llvm-project?rev=270488&view=rev
Log:
We have many radars showing that stepping through C++ code can result in slow steps.

One of the things slowing us down is that ItaniumABILanguageRuntime class doesn't cache vtable to types in a map. This causes us, on every step, for every variable, to read the first pointer in a C++ type that could be dynamic and lookup the symbol, possibly in every symbol file (some symbols files on Darwin can end up having thousands of .o files when using DWARF in .o files, so thousands of .o files are searched each time). 

This fix caches lldb_private::Address (the resolved vtable symbol address in section + offset format) to TypeAndOrName instances inside the one ItaniumABILanguageRuntime in a process. This allows caching of dynamic types and stops us from always doing deep searches in each file.

<rdar://problem/18890778>


Modified:
    lldb/trunk/include/lldb/Target/Process.h
    lldb/trunk/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp
    lldb/trunk/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h
    lldb/trunk/source/Target/Process.cpp

Modified: lldb/trunk/include/lldb/Target/Process.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/Process.h?rev=270488&r1=270487&r2=270488&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/Process.h (original)
+++ lldb/trunk/include/lldb/Target/Process.h Mon May 23 15:37:24 2016
@@ -2232,11 +2232,11 @@ public:
     ///     order.
     //------------------------------------------------------------------
     uint64_t
-    ReadUnsignedIntegerFromMemory (lldb::addr_t load_addr, 
-                                   size_t byte_size,
-                                   uint64_t fail_value, 
-                                   Error &error);
-    
+    ReadUnsignedIntegerFromMemory(lldb::addr_t load_addr, size_t byte_size, uint64_t fail_value, Error &error);
+
+    int64_t
+    ReadSignedIntegerFromMemory(lldb::addr_t load_addr, size_t byte_size, int64_t fail_value, Error &error);
+
     lldb::addr_t
     ReadPointerFromMemory (lldb::addr_t vm_addr, 
                            Error &error);

Modified: lldb/trunk/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp?rev=270488&r1=270487&r2=270488&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp (original)
+++ lldb/trunk/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp Mon May 23 15:37:24 2016
@@ -48,68 +48,26 @@ ItaniumABILanguageRuntime::CouldHaveDyna
     return in_value.GetCompilerType().IsPossibleDynamicType (NULL, check_cxx, check_objc);
 }
 
-bool
-ItaniumABILanguageRuntime::GetDynamicTypeAndAddress (ValueObject &in_value, 
-                                                     lldb::DynamicValueType use_dynamic, 
-                                                     TypeAndOrName &class_type_or_name, 
-                                                     Address &dynamic_address,
-                                                     Value::ValueType &value_type)
+TypeAndOrName
+ItaniumABILanguageRuntime::GetTypeInfoFromVTableAddress(ValueObject &in_value, lldb::addr_t original_ptr,
+                                                        lldb::addr_t vtable_load_addr)
 {
-    // For Itanium, if the type has a vtable pointer in the object, it will be at offset 0
-    // in the object.  That will point to the "address point" within the vtable (not the beginning of the
-    // vtable.)  We can then look up the symbol containing this "address point" and that symbol's name 
-    // demangled will contain the full class name.
-    // The second pointer above the "address point" is the "offset_to_top".  We'll use that to get the
-    // start of the value object which holds the dynamic type.
-    //
-    
-    class_type_or_name.Clear();
-    value_type = Value::ValueType::eValueTypeScalar;
-    
-    // Only a pointer or reference type can have a different dynamic and static type:
-    if (CouldHaveDynamicValue (in_value))
+    if (m_process && vtable_load_addr != LLDB_INVALID_ADDRESS)
     {
-        // First job, pull out the address at 0 offset from the object.
-        AddressType address_type;
-        lldb::addr_t original_ptr = in_value.GetPointerValue(&address_type);
-        if (original_ptr == LLDB_INVALID_ADDRESS)
-            return false;
-        
-        ExecutionContext exe_ctx (in_value.GetExecutionContextRef());
-
-        Target *target = exe_ctx.GetTargetPtr();
-        Process *process = exe_ctx.GetProcessPtr();
-
-        char memory_buffer[16];
-        DataExtractor data(memory_buffer, sizeof(memory_buffer), 
-                           process->GetByteOrder(), 
-                           process->GetAddressByteSize());
-        size_t address_byte_size = process->GetAddressByteSize();
-        Error error;
-        size_t bytes_read = process->ReadMemory (original_ptr, 
-                                                 memory_buffer, 
-                                                 address_byte_size, 
-                                                 error);
-        if (!error.Success() || (bytes_read != address_byte_size))
-        {
-            return false;
-        }
-        
-        lldb::offset_t offset = 0;
-        lldb::addr_t vtable_address_point = data.GetAddress (&offset);
-            
-        if (offset == 0)
-            return false;
-        
-        // Now find the symbol that contains this address:
-        
-        SymbolContext sc;
-        Address address_point_address;
-        if (target && !target->GetSectionLoadList().IsEmpty())
+        // Find the symbol that contains the "vtable_load_addr" address
+        Address vtable_addr;
+        Target &target = m_process->GetTarget();
+        if (!target.GetSectionLoadList().IsEmpty())
         {
-            if (target->GetSectionLoadList().ResolveLoadAddress (vtable_address_point, address_point_address))
+            if (target.GetSectionLoadList().ResolveLoadAddress(vtable_load_addr, vtable_addr))
             {
-                target->GetImages().ResolveSymbolContextForAddress (address_point_address, eSymbolContextSymbol, sc);
+                // See if we have cached info for this type already
+                TypeAndOrName type_info = GetDynamicTypeInfo(vtable_addr);
+                if (type_info)
+                    return type_info;
+
+                SymbolContext sc;
+                target.GetImages().ResolveSymbolContextForAddress(vtable_addr, eSymbolContextSymbol, sc);
                 Symbol *symbol = sc.symbol;
                 if (symbol != NULL)
                 {
@@ -124,10 +82,10 @@ ItaniumABILanguageRuntime::GetDynamicTyp
                                          name);
                         // We are a C++ class, that's good.  Get the class name and look it up:
                         const char *class_name = name + strlen(vtable_demangled_prefix);
-                        class_type_or_name.SetName (class_name);
+                        type_info.SetName(class_name);
                         const bool exact_match = true;
                         TypeList class_types;
-                        
+
                         uint32_t num_matches = 0;
                         // First look in the module that the vtable symbol came from
                         // and look for a single exact match.
@@ -141,38 +99,39 @@ ItaniumABILanguageRuntime::GetDynamicTyp
                                                                    searched_symbol_files,
                                                                    class_types);
                         }
-                        
+
                         // If we didn't find a symbol, then move on to the entire
                         // module list in the target and get as many unique matches
                         // as possible
                         if (num_matches == 0)
                         {
-                            num_matches = target->GetImages().FindTypes (sc,
-                                                                         ConstString(class_name),
-                                                                         exact_match,
-                                                                         UINT32_MAX,
-                                                                         searched_symbol_files,
-                                                                         class_types);
+                            num_matches = target.GetImages().FindTypes(sc, ConstString(class_name), exact_match,
+                                                                       UINT32_MAX, searched_symbol_files, class_types);
                         }
-                        
+
                         lldb::TypeSP type_sp;
                         if (num_matches == 0)
                         {
                             if (log)
                                 log->Printf("0x%16.16" PRIx64 ": is not dynamic\n", original_ptr);
-                            return false;
+                            return TypeAndOrName();
                         }
                         if (num_matches == 1)
                         {
                             type_sp = class_types.GetTypeAtIndex(0);
-                            if (log)
-                                log->Printf ("0x%16.16" PRIx64 ": static-type = '%s' has dynamic type: uid={0x%" PRIx64 "}, type-name='%s'\n",
-                                             original_ptr,
-                                             in_value.GetTypeName().AsCString(),
-                                             type_sp->GetID(),
-                                             type_sp->GetName().GetCString());
-
-                            class_type_or_name.SetTypeSP(class_types.GetTypeAtIndex(0));
+                            if (type_sp)
+                            {
+                                if (ClangASTContext::IsCXXClassType(type_sp->GetForwardCompilerType()))
+                                {
+                                    if (log)
+                                        log->Printf("0x%16.16" PRIx64
+                                                    ": static-type = '%s' has dynamic type: uid={0x%" PRIx64
+                                                    "}, type-name='%s'\n",
+                                                    original_ptr, in_value.GetTypeName().AsCString(), type_sp->GetID(),
+                                                    type_sp->GetName().GetCString());
+                                    type_info.SetTypeSP(type_sp);
+                                }
+                            }
                         }
                         else if (num_matches > 1)
                         {
@@ -207,74 +166,112 @@ ItaniumABILanguageRuntime::GetDynamicTyp
                                                          in_value.GetTypeName().AsCString(),
                                                          type_sp->GetID(),
                                                          type_sp->GetName().GetCString());
-                                        class_type_or_name.SetTypeSP(type_sp);
-                                        break;
+                                        type_info.SetTypeSP(type_sp);
                                     }
                                 }
                             }
-                            
-                            if (i == num_matches)
-                            {
-                                if (log)
-                                    log->Printf ("0x%16.16" PRIx64 ": static-type = '%s' has multiple matching dynamic types, didn't find a C++ match\n",
-                                                 original_ptr,
-                                                 in_value.GetTypeName().AsCString());
-                                return false;
-                            }
-                        }
 
-                        // There can only be one type with a given name,
-                        // so we've just found duplicate definitions, and this
-                        // one will do as well as any other.
-                        // We don't consider something to have a dynamic type if
-                        // it is the same as the static type.  So compare against
-                        // the value we were handed.
-                        if (type_sp)
-                        {
-                            if (ClangASTContext::AreTypesSame (in_value.GetCompilerType(),
-                                                               type_sp->GetForwardCompilerType ()))
+                            if (log && i == num_matches)
                             {
-                                // The dynamic type we found was the same type,
-                                // so we don't have a dynamic type here...
-                                return false;
+                                log->Printf("0x%16.16" PRIx64 ": static-type = '%s' has multiple matching dynamic "
+                                                              "types, didn't find a C++ match\n",
+                                            original_ptr, in_value.GetTypeName().AsCString());
                             }
-
-                            // The offset_to_top is two pointers above the address.
-                            Address offset_to_top_address = address_point_address;
-                            int64_t slide = -2 * ((int64_t) target->GetArchitecture().GetAddressByteSize());
-                            offset_to_top_address.Slide (slide);
-                            
-                            Error error;
-                            lldb::addr_t offset_to_top_location = offset_to_top_address.GetLoadAddress(target);
-                            
-                            size_t bytes_read = process->ReadMemory (offset_to_top_location, 
-                                                                     memory_buffer, 
-                                                                     address_byte_size, 
-                                                                     error);
-                                                                     
-                            if (!error.Success() || (bytes_read != address_byte_size))
-                            {
-                                return false;
-                            }
-                            
-                            offset = 0;
-                            int64_t offset_to_top = data.GetMaxS64(&offset, process->GetAddressByteSize());
-                            
-                            // So the dynamic type is a value that starts at offset_to_top
-                            // above the original address.
-                            lldb::addr_t dynamic_addr = original_ptr + offset_to_top;
-                            if (!target->GetSectionLoadList().ResolveLoadAddress (dynamic_addr, dynamic_address))
-                            {
-                                dynamic_address.SetRawAddress(dynamic_addr);
-                            }
-                            return true;
                         }
+                        if (type_info)
+                            SetDynamicTypeInfo(vtable_addr, type_info);
+                        return type_info;
                     }
                 }
             }
         }
     }
-    
+    return TypeAndOrName();
+}
+
+bool
+ItaniumABILanguageRuntime::GetDynamicTypeAndAddress(ValueObject &in_value, lldb::DynamicValueType use_dynamic,
+                                                    TypeAndOrName &class_type_or_name, Address &dynamic_address,
+                                                    Value::ValueType &value_type)
+{
+    // For Itanium, if the type has a vtable pointer in the object, it will be at offset 0
+    // in the object.  That will point to the "address point" within the vtable (not the beginning of the
+    // vtable.)  We can then look up the symbol containing this "address point" and that symbol's name
+    // demangled will contain the full class name.
+    // The second pointer above the "address point" is the "offset_to_top".  We'll use that to get the
+    // start of the value object which holds the dynamic type.
+    //
+
+    class_type_or_name.Clear();
+    value_type = Value::ValueType::eValueTypeScalar;
+
+    // Only a pointer or reference type can have a different dynamic and static type:
+    if (CouldHaveDynamicValue(in_value))
+    {
+        // First job, pull out the address at 0 offset from the object.
+        AddressType address_type;
+        lldb::addr_t original_ptr = in_value.GetPointerValue(&address_type);
+        if (original_ptr == LLDB_INVALID_ADDRESS)
+            return false;
+
+        ExecutionContext exe_ctx(in_value.GetExecutionContextRef());
+
+        Process *process = exe_ctx.GetProcessPtr();
+
+        if (process == nullptr)
+            return false;
+
+        Error error;
+        const lldb::addr_t vtable_address_point = process->ReadPointerFromMemory(original_ptr, error);
+
+        if (!error.Success() || vtable_address_point == LLDB_INVALID_ADDRESS)
+        {
+            return false;
+        }
+
+        class_type_or_name = GetTypeInfoFromVTableAddress(in_value, original_ptr, vtable_address_point);
+
+        if (class_type_or_name)
+        {
+            TypeSP type_sp = class_type_or_name.GetTypeSP();
+            // There can only be one type with a given name,
+            // so we've just found duplicate definitions, and this
+            // one will do as well as any other.
+            // We don't consider something to have a dynamic type if
+            // it is the same as the static type.  So compare against
+            // the value we were handed.
+            if (type_sp)
+            {
+                if (ClangASTContext::AreTypesSame(in_value.GetCompilerType(), type_sp->GetForwardCompilerType()))
+                {
+                    // The dynamic type we found was the same type,
+                    // so we don't have a dynamic type here...
+                    return false;
+                }
+
+                // The offset_to_top is two pointers above the vtable pointer.
+                const uint32_t addr_byte_size = process->GetAddressByteSize();
+                const lldb::addr_t offset_to_top_location = vtable_address_point - 2 * addr_byte_size;
+                // Watch for underflow, offset_to_top_location should be less than vtable_address_point
+                if (offset_to_top_location >= vtable_address_point)
+                    return false;
+                const int64_t offset_to_top =
+                    process->ReadSignedIntegerFromMemory(offset_to_top_location, addr_byte_size, INT64_MIN, error);
+
+                if (offset_to_top == INT64_MIN)
+                    return false;
+                // So the dynamic type is a value that starts at offset_to_top
+                // above the original address.
+                lldb::addr_t dynamic_addr = original_ptr + offset_to_top;
+                if (!process->GetTarget().GetSectionLoadList().ResolveLoadAddress(dynamic_addr, dynamic_address))
+                {
+                    dynamic_address.SetRawAddress(dynamic_addr);
+                }
+                return true;
+            }
+        }
+    }
+
     return class_type_or_name.IsEmpty() == false;
 }
 
@@ -603,3 +600,21 @@ ItaniumABILanguageRuntime::ExceptionBrea
                                                                                m_cxx_exception_bp_sp->GetID());
     
 }
+
+TypeAndOrName
+ItaniumABILanguageRuntime::GetDynamicTypeInfo(const lldb_private::Address &vtable_addr)
+{
+    std::lock_guard<std::mutex> locker(m_dynamic_type_map_mutex);
+    DynamicTypeCache::const_iterator pos = m_dynamic_type_map.find(vtable_addr);
+    if (pos == m_dynamic_type_map.end())
+        return TypeAndOrName();
+    else
+        return pos->second;
+}
+
+void
+ItaniumABILanguageRuntime::SetDynamicTypeInfo(const lldb_private::Address &vtable_addr, const TypeAndOrName &type_info)
+{
+    std::lock_guard<std::mutex> locker(m_dynamic_type_map_mutex);
+    m_dynamic_type_map[vtable_addr] = type_info;
+}

Modified: lldb/trunk/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h?rev=270488&r1=270487&r2=270488&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h (original)
+++ lldb/trunk/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h Mon May 23 15:37:24 2016
@@ -12,6 +12,8 @@
 
 // C Includes
 // C++ Includes
+#include <map>
+#include <mutex>
 #include <vector>
 
 // Other libraries and framework includes
@@ -100,9 +102,29 @@ namespace lldb_private {
                                   bool is_internal);
         
     private:
-        ItaniumABILanguageRuntime(Process *process) : lldb_private::CPPLanguageRuntime(process) { } // Call CreateInstance instead.
-        
-        lldb::BreakpointSP                              m_cxx_exception_bp_sp;
+        typedef std::map<lldb_private::Address, TypeAndOrName> DynamicTypeCache;
+
+        ItaniumABILanguageRuntime(Process *process)
+            : // Call CreateInstance instead.
+              lldb_private::CPPLanguageRuntime(process),
+              m_cxx_exception_bp_sp(),
+              m_dynamic_type_map(),
+              m_dynamic_type_map_mutex()
+        {
+        }
+
+        lldb::BreakpointSP m_cxx_exception_bp_sp;
+        DynamicTypeCache m_dynamic_type_map;
+        std::mutex m_dynamic_type_map_mutex;
+
+        TypeAndOrName
+        GetTypeInfoFromVTableAddress(ValueObject &in_value, lldb::addr_t original_ptr, lldb::addr_t vtable_addr);
+
+        TypeAndOrName
+        GetDynamicTypeInfo(const lldb_private::Address &vtable_addr);
+
+        void
+        SetDynamicTypeInfo(const lldb_private::Address &vtable_addr, const TypeAndOrName &type_info);
     };
     
 } // namespace lldb_private

Modified: lldb/trunk/source/Target/Process.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Process.cpp?rev=270488&r1=270487&r2=270488&view=diff
==============================================================================
--- lldb/trunk/source/Target/Process.cpp (original)
+++ lldb/trunk/source/Target/Process.cpp Mon May 23 15:37:24 2016
@@ -2524,7 +2524,8 @@ Process::ReadMemoryFromInferior (addr_t
 }
 
 uint64_t
-Process::ReadUnsignedIntegerFromMemory (lldb::addr_t vm_addr, size_t integer_byte_size, uint64_t fail_value, Error &error)
+Process::ReadUnsignedIntegerFromMemory(lldb::addr_t vm_addr, size_t integer_byte_size, uint64_t fail_value,
+                                       Error &error)
 {
     Scalar scalar;
     if (ReadScalarIntegerFromMemory(vm_addr, integer_byte_size, false, scalar, error))
@@ -2532,6 +2533,15 @@ Process::ReadUnsignedIntegerFromMemory (
     return fail_value;
 }
 
+int64_t
+Process::ReadSignedIntegerFromMemory(lldb::addr_t vm_addr, size_t integer_byte_size, int64_t fail_value, Error &error)
+{
+    Scalar scalar;
+    if (ReadScalarIntegerFromMemory(vm_addr, integer_byte_size, true, scalar, error))
+        return scalar.SLongLong(fail_value);
+    return fail_value;
+}
+
 addr_t
 Process::ReadPointerFromMemory (lldb::addr_t vm_addr, Error &error)
 {




More information about the lldb-commits mailing list