[Lldb-commits] [lldb] r152371 - in /lldb/trunk: examples/synthetic/gnu_libstdcpp.py include/lldb/Core/ValueObject.h source/Core/ValueObject.cpp source/Core/ValueObjectRegister.cpp

Enrico Granata egranata at apple.com
Thu Mar 8 19:09:58 PST 2012


Author: enrico
Date: Thu Mar  8 21:09:58 2012
New Revision: 152371

URL: http://llvm.org/viewvc/llvm-project?rev=152371&view=rev
Log:
Changed ValueObject to use a dedicated ChildrenManager class to store its children, instead of an std::vector
This solves an issue where a ValueObject was getting a wrong children count (usually, a huge value) and trying to resize the vector of children to fit that many ValueObject*

Added a loop detection algorithm to the synthetic children provider for std::list

Added a few more checks to the synthetic children provider for std::vector

Both std::list and std::vector's synthetic children providers now cache the count of children instead of recomputing it every time
std::map has a field that stores the count, so there is little need to cache it on our side

Modified:
    lldb/trunk/examples/synthetic/gnu_libstdcpp.py
    lldb/trunk/include/lldb/Core/ValueObject.h
    lldb/trunk/source/Core/ValueObject.cpp
    lldb/trunk/source/Core/ValueObjectRegister.cpp

Modified: lldb/trunk/examples/synthetic/gnu_libstdcpp.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/examples/synthetic/gnu_libstdcpp.py?rev=152371&r1=152370&r2=152371&view=diff
==============================================================================
--- lldb/trunk/examples/synthetic/gnu_libstdcpp.py (original)
+++ lldb/trunk/examples/synthetic/gnu_libstdcpp.py Thu Mar  8 21:09:58 2012
@@ -12,7 +12,36 @@
 		self.valobj = valobj
 		self.update()
 
+	def next_node(self,node):
+		return node.GetChildMemberWithName('_M_next')
+
+	def is_valid(self,node):
+		return self.value(self.next_node(node)) != self.node_address
+
+	def value(self,node):
+		return node.GetValueAsUnsigned()
+
+	# Floyd's cyle-finding algorithm
+	# try to detect if this list has a loop
+	def has_loop(self):
+		slow = self.next
+		fast1 = self.next
+		fast2 = self.next
+		while self.is_valid(slow):
+			slow_value = self.value(slow)
+			fast1 = self.next_node(fast2)
+			fast2 = self.next_node(fast1)
+			if self.value(fast1) == slow_value or self.value(fast2) == slow_value:
+				return True
+			slow = self.next_node(slow)
+		return False
+
 	def num_children(self):
+		if self.count == None:
+			self.count = self.num_children_impl()
+		return self.count
+
+	def num_children_impl(self):
 		try:
 			next_val = self.next.GetValueAsUnsigned(0)
 			prev_val = self.prev.GetValueAsUnsigned(0)
@@ -23,6 +52,8 @@
 				return 0
 			if next_val == prev_val:
 				return 1
+			if self.has_loop():
+				return 0
 			size = 2
 			current = self.next
 			while current.GetChildMemberWithName('_M_next').GetValueAsUnsigned(0) != self.node_address:
@@ -70,6 +101,7 @@
 			self.prev = node.GetChildMemberWithName('_M_prev')
 			self.data_type = self.extract_type()
 			self.data_size = self.data_type.GetByteSize()
+			self.count = None
 		except:
 			pass
 
@@ -80,6 +112,16 @@
 		self.update()
 
 	def num_children(self):
+		if self.count == None:
+			self.count = self.num_children_impl()
+		return self.count
+
+	def is_valid_pointer(ptr,process):
+		error = lldb.SBError()
+		process.ReadMemory(ptr,1,error)
+		return False if error.Fail() else True
+
+	def num_children_impl(self):
 		try:
 			start_val = self.start.GetValueAsUnsigned(0)
 			finish_val = self.finish.GetValueAsUnsigned(0)
@@ -101,7 +143,14 @@
 			if finish_val > end_val:
 				return 0
 
-			num_children = (finish_val-start_val)/self.data_size
+			# if we have a struct (or other data type that the compiler pads to native word size)
+			# this check might fail, unless the sizeof() we get is itself incremented to take the
+			# padding bytes into account - on current clang it looks like this is the case
+			num_children = (finish_val-start_val)
+			if (num_children % self.data_size) != 0:
+				return 0
+			else:
+				num_children = num_children/self.data_size
 			return num_children
 		except:
 			return 0;
@@ -131,6 +180,11 @@
 			self.end = impl.GetChildMemberWithName('_M_end_of_storage')
 			self.data_type = self.start.GetType().GetPointeeType()
 			self.data_size = self.data_type.GetByteSize()
+			# if any of these objects is invalid, it means there is no point in trying to fetch anything
+			if self.start.IsValid() and self.finish.IsValid() and self.end.IsValid() and self.data_type.IsValid():
+				self.count = None
+			else:
+				self.count = 0
 		except:
 			pass
 

Modified: lldb/trunk/include/lldb/Core/ValueObject.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/ValueObject.h?rev=152371&r1=152370&r2=152371&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Core/ValueObject.h (original)
+++ lldb/trunk/include/lldb/Core/ValueObject.h Thu Mar  8 21:09:58 2012
@@ -993,6 +993,73 @@
     
 protected:
     typedef ClusterManager<ValueObject> ValueObjectManager;
+    
+    class ChildrenManager
+    {
+    public:
+        ChildrenManager() :
+        m_mutex(Mutex::eMutexTypeRecursive),
+        m_children(),
+        m_children_count(0)
+        {}
+        
+        bool
+        HasChildAtIndex (uint32_t idx)
+        {
+            Mutex::Locker(m_mutex);
+            ChildrenIterator iter = m_children.find(idx);
+            ChildrenIterator end = m_children.end();
+            return (iter != end);
+        }
+        
+        ValueObject*
+        GetChildAtIndex (uint32_t idx)
+        {
+            Mutex::Locker(m_mutex);
+            ChildrenIterator iter = m_children.find(idx);
+            ChildrenIterator end = m_children.end();
+            if (iter == end)
+                return NULL;
+            else
+                return iter->second;
+        }
+        
+        void
+        SetChildAtIndex (uint32_t idx, ValueObject* valobj)
+        {
+            ChildrenPair pair(idx,valobj); // we do not need to be mutex-protected to make a pair
+            Mutex::Locker(m_mutex);
+            m_children.insert(pair);
+        }
+        
+        void
+        SetChildrenCount (uint32_t count)
+        {
+            m_children_count = count;
+        }
+        
+        uint32_t
+        GetChildrenCount ()
+        {
+            return m_children_count;
+        }
+        
+        void
+        Clear()
+        {
+            m_children_count = 0;
+            Mutex::Locker(m_mutex);
+            m_children.clear();
+        }
+        
+    private:
+        typedef std::map<uint32_t, ValueObject*> ChildrenMap;
+        typedef ChildrenMap::iterator ChildrenIterator;
+        typedef ChildrenMap::value_type ChildrenPair;
+        Mutex m_mutex;
+        ChildrenMap m_children;
+        uint32_t m_children_count;
+    };
 
     //------------------------------------------------------------------
     // Classes that inherit from ValueObject can see and modify these
@@ -1020,7 +1087,7 @@
                                         // as a shared pointer to any of them has been handed out.  Shared pointers to
                                         // value objects must always be made with the GetSP method.
 
-    std::vector<ValueObject *>           m_children;
+    ChildrenManager                      m_children;
     std::map<ConstString, ValueObject *> m_synthetic_children;
     
     ValueObject*                         m_dynamic_value;

Modified: lldb/trunk/source/Core/ValueObject.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/ValueObject.cpp?rev=152371&r1=152370&r2=152371&view=diff
==============================================================================
--- lldb/trunk/source/Core/ValueObject.cpp (original)
+++ lldb/trunk/source/Core/ValueObject.cpp Thu Mar  8 21:09:58 2012
@@ -493,15 +493,16 @@
     if (idx < GetNumChildren())
     {
         // Check if we have already made the child value object?
-        if (can_create && m_children[idx] == NULL)
+        if (can_create && !m_children.HasChildAtIndex(idx))
         {
             // No we haven't created the child at this index, so lets have our
             // subclass do it and cache the result for quick future access.
-            m_children[idx] = CreateChildAtIndex (idx, false, 0);
+            m_children.SetChildAtIndex(idx,CreateChildAtIndex (idx, false, 0));
         }
         
-        if (m_children[idx] != NULL)
-            return m_children[idx]->GetSP();
+        ValueObject* child = m_children.GetChildAtIndex(idx);
+        if (child != NULL)
+            return child->GetSP();
     }
     return child_sp;
 }
@@ -568,13 +569,13 @@
     {
         SetNumChildren (CalculateNumChildren());
     }
-    return m_children.size();
+    return m_children.GetChildrenCount();
 }
 void
 ValueObject::SetNumChildren (uint32_t num_children)
 {
     m_children_count_valid = true;
-    m_children.resize(num_children);
+    m_children.SetChildrenCount(num_children);
 }
 
 void

Modified: lldb/trunk/source/Core/ValueObjectRegister.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/ValueObjectRegister.cpp?rev=152371&r1=152370&r2=152371&view=diff
==============================================================================
--- lldb/trunk/source/Core/ValueObjectRegister.cpp (original)
+++ lldb/trunk/source/Core/ValueObjectRegister.cpp Thu Mar  8 21:09:58 2012
@@ -204,7 +204,7 @@
     {
         SetValueIsValid (false);
         m_error.SetErrorToGenericError ();
-        m_children.clear();
+        m_children.Clear();
     }
     return m_error.Success();
 }





More information about the lldb-commits mailing list