Updated AppleObjCV2Runtime to load the class
authorSean Callanan <scallanan@apple.com>
Wed, 19 Sep 2012 03:23:13 +0000 (03:23 +0000)
committerSean Callanan <scallanan@apple.com>
Wed, 19 Sep 2012 03:23:13 +0000 (03:23 +0000)
data structures more rapidly.  Also added fields
for the other data structures in a class.

I also fixed a problem where I accidentally used
hasExternalLexicalStorage() instead of
hasExternalVisibleStorage() to mark an
incomplete object.

llvm-svn: 164197

lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeVendor.cpp

index 326a34c..78ccc14 100644 (file)
@@ -991,6 +991,9 @@ public:
     virtual ConstString
     GetClassName ()
     {
+        if (!m_valid)
+            return ConstString();
+        
         return m_name;
     }
     
@@ -999,10 +1002,11 @@ public:
     {
         if (!m_valid)
             return ObjCLanguageRuntime::ClassDescriptorSP();
+        
         ProcessSP process_sp = m_process_wp.lock();
         if (!process_sp)
             return ObjCLanguageRuntime::ClassDescriptorSP();
-        return AppleObjCRuntime::ClassDescriptorSP(new ClassDescriptorV2(m_parent_isa,process_sp));
+        return AppleObjCRuntime::ClassDescriptorSP(new ClassDescriptorV2(m_objc_class.m_superclass,process_sp));
     }
     
     virtual bool
@@ -1020,30 +1024,43 @@ public:
     virtual uint64_t
     GetInstanceSize ()
     {
+        if (!m_valid)
+            return 0;
+        
         return m_instance_size;
     }
     
     virtual ObjCLanguageRuntime::ObjCISA
     GetISA ()
     {
-        return m_isa;
+        if (!m_valid)
+            return 0;
+        
+        return m_objc_class_la;
     }
     
     virtual bool
     CompleteInterface (clang::ObjCInterfaceDecl *interface_decl)
     {
+        if (!m_valid)
+            return false;
+        
         return false;
     }
     
     virtual bool
     IsRealized ()
     {
+        if (!m_valid)
+            return false;
+        
         return m_realized;
     }
     
     virtual
     ~ClassDescriptorV2 ()
-    {}
+    {
+    }
     
 protected:
     virtual bool
@@ -1056,107 +1073,136 @@ protected:
     }
     
     void
-    Initialize (ObjCLanguageRuntime::ObjCISA isa, lldb::ProcessSP process_sp)
+    Initialize (ObjCLanguageRuntime::ObjCISA pointer_to_isa, lldb::ProcessSP process_sp)
     {
-        if (!isa || !process_sp)
+        m_valid = true;
+
+        if (!pointer_to_isa || !process_sp)
         {
             m_valid = false;
             return;
         }
         
-        m_valid = true;
-        
+        size_t ptr_size = process_sp->GetAddressByteSize();
         Error error;
         
-        m_isa = process_sp->ReadPointerFromMemory(isa, error);
-        
+        m_objc_class_la = process_sp->ReadPointerFromMemory(pointer_to_isa, error);
+
         if (error.Fail())
         {
             m_valid = false;
             return;
         }
         
-        uint32_t ptr_size = process_sp->GetAddressByteSize();
-        
-        if (!IsPointerValid(m_isa,ptr_size,false,false,true))
-        {
-            m_valid = false;
-            return;
-        }
-        
-        lldb::addr_t data_ptr = process_sp->ReadPointerFromMemory(m_isa + 4 * ptr_size, error);
-        
-        if (error.Fail())
+        const bool allow_NULLs = false;
+        const bool allow_tagged = false;
+        const bool check_version_specific = true;
+
+        if (!IsPointerValid(m_objc_class_la, ptr_size, allow_NULLs, allow_tagged, check_version_specific))
         {
             m_valid = false;
             return;
         }
+                
+        size_t objc_class_size = ptr_size   // uintptr_t isa;
+                               + ptr_size   // Class superclass;
+                               + ptr_size   // void *cache;
+                               + ptr_size   // IMP *vtable;
+                               + ptr_size;  // uintptr_t data_NEVER_USE;
         
-        if (!IsPointerValid(data_ptr,ptr_size,false,false,true))
         {
-            m_valid = false;
-            return;
+            DataBufferHeap objc_class_buf (objc_class_size, '\0');
+            
+            process_sp->ReadMemory(m_objc_class_la, objc_class_buf.GetBytes(), objc_class_size, error);
+            if (error.Fail())
+            {
+                m_valid = false;
+                return;
+            }
+            
+            DataExtractor objc_class_extractor(objc_class_buf.GetBytes(), objc_class_size, process_sp->GetByteOrder(), process_sp->GetAddressByteSize());
+            
+            uint32_t cursor = 0;
+            
+            m_objc_class.m_isa          = objc_class_extractor.GetAddress_unchecked(&cursor);   // uintptr_t isa;
+            m_objc_class.m_superclass   = objc_class_extractor.GetAddress_unchecked(&cursor);   // Class superclass;
+            m_objc_class.m_cache_la     = objc_class_extractor.GetAddress_unchecked(&cursor);   // void *cache;
+            m_objc_class.m_vtable_la    = objc_class_extractor.GetAddress_unchecked(&cursor);   // IMP *vtable;
+            lldb::addr_t data_NEVER_USE = objc_class_extractor.GetAddress_unchecked(&cursor);   // uintptr_t data_NEVER_USE;
+            
+            m_objc_class.m_flags = (uint8_t)(data_NEVER_USE & (lldb::addr_t)3);
+            m_objc_class.m_data_la = data_NEVER_USE & ~(lldb::addr_t)3;
         }
-        
-        m_parent_isa = process_sp->ReadPointerFromMemory(isa + ptr_size,error);
-        
-        if (error.Fail())
+                    
+        // Now we just want to grab the instance size and the name.
+        // Since we find out whether the class is realized on the way, we'll remember that too.
+    
+        // The flags for class_r[ow]_t always are the first uint32_t.  So just read that.
+        if (!IsPointerValid(m_objc_class.m_data_la, ptr_size, allow_NULLs, allow_tagged, check_version_specific))
         {
             m_valid = false;
             return;
         }
         
-        // sanity checks
-        lldb::addr_t cache_ptr = process_sp->ReadPointerFromMemory(m_isa + 2*ptr_size, error);
+        uint32_t class_row_t_flags = process_sp->ReadUnsignedIntegerFromMemory(m_objc_class.m_data_la, sizeof(uint32_t), 0, error);
         if (error.Fail())
         {
             m_valid = false;
             return;
         }
-        if (!IsPointerValid(cache_ptr,ptr_size,true,false,true))
-        {
-            m_valid = false;
-            return;
-        }
         
-        lldb::addr_t rot_pointer;
+        m_realized = class_row_t_flags & RW_REALIZED;
         
-        // now construct the data object
+        lldb::addr_t class_ro_t_la = NULL;
         
-        uint32_t flags;
-        process_sp->ReadMemory(data_ptr, &flags, 4, error);
-        if (error.Fail())
+        if (m_realized)
         {
-            m_valid = false;
-            return;
-        }
-
-        if (flags & RW_REALIZED)
-        {
-            m_realized = true;
-            rot_pointer = process_sp->ReadPointerFromMemory(data_ptr + 8, error);
+            lldb::addr_t class_rw_t_la = m_objc_class.m_data_la;
+            
+            class_ro_t_la = process_sp->ReadPointerFromMemory(class_rw_t_la
+                                                              + sizeof(uint32_t)    // uint32_t flags
+                                                              + sizeof(uint32_t),   // uint32_t version
+                                                              error);
+            
+            if (error.Fail())
+            {
+                m_valid = false;
+                return;
+            }
         }
         else
         {
-            m_realized = false;
-            rot_pointer = data_ptr;
+            class_ro_t_la = m_objc_class.m_data_la;
         }
         
-        if (error.Fail())
+        if (!IsPointerValid(class_ro_t_la, ptr_size))
         {
             m_valid = false;
             return;
         }
         
-        if (!IsPointerValid(rot_pointer,ptr_size))
+        // Now that we have a handle on class_ro_t_la, read the desired data out
+        
+        m_instance_size = process_sp->ReadUnsignedIntegerFromMemory(class_ro_t_la
+                                                                    + sizeof(uint32_t)                        // uint32_t flags
+                                                                    + sizeof(uint32_t),                       // uint32_t instanceStart
+                                                                    sizeof(uint32_t),
+                                                                    0,
+                                                                    error);
+        
+        if (error.Fail())
         {
             m_valid = false;
             return;
         }
         
-        // now read from the rot
-        
-        lldb::addr_t name_ptr = process_sp->ReadPointerFromMemory(rot_pointer + (ptr_size == 8 ? 24 : 16) ,error);
+        lldb::addr_t name_ptr = process_sp->ReadPointerFromMemory(class_ro_t_la
+                                                                  + sizeof(uint32_t)                        // uint32_t flags
+                                                                  + sizeof(uint32_t)                        // uint32_t instanceStart
+                                                                  + sizeof(uint32_t)                        // uint32_t instanceSize
+                                                                  + (ptr_size == 8 ? sizeof(uint32_t) : 0)  // uint32_t reserved (__LP64__ only)
+                                                                  + ptr_size,                               // const uint8_t *ivarLayout
+                                                                  error);
         
         if (error.Fail())
         {
@@ -1164,9 +1210,10 @@ protected:
             return;
         }
         
-        lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024, 0));
+        const size_t buffer_size = 1024;
         
-        size_t count = process_sp->ReadCStringFromMemory(name_ptr, (char*)buffer_sp->GetBytes(), 1024, error);
+        DataBufferHeap buffer(buffer_size, 0);
+        size_t count = process_sp->ReadCStringFromMemory(name_ptr, (char*)buffer.GetBytes(), buffer_size, error);
         
         if (error.Fail())
         {
@@ -1175,24 +1222,72 @@ protected:
         }
         
         if (count)
-            m_name = ConstString((char*)buffer_sp->GetBytes());
+            m_name = ConstString((char*)buffer.GetBytes());
         else
             m_name = ConstString();
-        
-        m_instance_size = process_sp->ReadUnsignedIntegerFromMemory(rot_pointer + 8, ptr_size, 0, error);
-        
+                
         m_process_wp = lldb::ProcessWP(process_sp);
     }
     
 private:
     static const uint32_t RW_REALIZED = (1 << 31);
-    ConstString m_name;
-    ObjCLanguageRuntime::ObjCISA m_isa;
-    ObjCLanguageRuntime::ObjCISA m_parent_isa;
-    bool m_valid;
+    
+    bool                                m_valid;            // Gates whether we trust anything here at all.
+    lldb::addr_t                        m_objc_class_la;    // The address of the objc_class_t.
+    
+    struct objc_class_t {
+        ObjCLanguageRuntime::ObjCISA    m_isa;              // The class's metaclass.
+        ObjCLanguageRuntime::ObjCISA    m_superclass;
+        lldb::addr_t                    m_cache_la;
+        lldb::addr_t                    m_vtable_la;
+        lldb::addr_t                    m_data_la;
+        uint8_t                         m_flags;
+    };
+    
+    objc_class_t                        m_objc_class;
+    
+    // cached information from the class_r[ow]_t
+    ConstString                         m_name;
+    uint32_t                            m_instance_size;
+    bool                                m_realized;
+    
+    struct class_ro_t {
+        uint32_t                        m_flags;
+        uint32_t                        m_instanceStart;
+        uint32_t                        m_instanceSize;
+        uint32_t                        m_reserved;
+        
+        lldb::addr_t                    m_ivarLayout_la;
+        lldb::addr_t                    m_name_la;
+        lldb::addr_t                    m_baseMethods_la;
+        lldb::addr_t                    m_baseProtocols_la;
+        lldb::addr_t                    m_ivars_la;
+        
+        lldb::addr_t                    m_weakIvarLayout_la;
+        lldb::addr_t                    m_baseProperties_la;
+    };
+    
+    std::auto_ptr<class_ro_t>           m_class_ro;
+    
+    struct class_rw_t {
+        uint32_t                        m_flags;
+        uint32_t                        m_version;
+        
+        lldb::addr_t                    m_ro_la;
+        union {
+            lldb::addr_t                m_method_list_la;
+            lldb::addr_t                m_method_lists_la;
+        };
+        lldb::addr_t                    m_properties_la;
+        lldb::addr_t                    m_protocols_la;
+        
+        ObjCLanguageRuntime::ObjCISA    m_firstSubclass;
+        ObjCLanguageRuntime::ObjCISA    m_nextSiblingClass;
+    };
+    
+    std::auto_ptr<class_rw_t>           m_class_rw;
+    
     lldb::ProcessWP m_process_wp;
-    uint64_t m_instance_size;
-    bool m_realized;
 };
 
 class ClassDescriptorV2Tagged : public ObjCLanguageRuntime::ClassDescriptor
index ced2026..ac29394 100644 (file)
@@ -71,10 +71,10 @@ public:
                     break;
                 
                 if (descriptor->CompleteInterface(non_const_interface_decl))
-                    non_const_interface_decl->setHasExternalLexicalStorage(false);
+                    non_const_interface_decl->setHasExternalVisibleStorage(false);
             }
 
-            if (non_const_interface_decl->hasExternalLexicalStorage()) // hasExternalLexicalStorage() is cleared during completion
+            if (non_const_interface_decl->hasExternalVisibleStorage())
                 break;
             
             return non_const_interface_decl->lookup(name);
@@ -253,7 +253,7 @@ AppleObjCTypeVendor::FindTypes (const ConstString &name,
         
         // It's not.  If it exists, we have to put it into our ASTContext.
         
-        // TODO Actually do this.  But we have to search the class list first.  Until then we'll just give up.
+        // TODO Remove this break once testing is complete.
         break;
         
         ObjCLanguageRuntime::ObjCISA isa = m_runtime.GetISA(name);