<rdar://problem/11485744> Implement important data formatters in C++. Have the Objective-C language runtime plugin expose class descriptors objects akin to the objc_runtime.py Pythonic implementation. Rewrite the data formatters for some core Cocoa classes in C++ instead of Python.

git-svn-id: https://llvm.org/svn/llvm-project/lldb/trunk@163155 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/source/API/SBModule.cpp b/source/API/SBModule.cpp
index 44ac2d3..446a693 100644
--- a/source/API/SBModule.cpp
+++ b/source/API/SBModule.cpp
@@ -542,17 +542,15 @@
 {
     ModuleSP module_sp (GetSP ());
     if (module_sp)
+        return module_sp->GetVersion(versions, num_versions);
+    else
     {
-        ObjectFile *obj_file = module_sp->GetObjectFile();
-        if (obj_file)
-            return obj_file->GetVersion (versions, num_versions);
+        if (versions && num_versions)
+        {
+            for (uint32_t i=0; i<num_versions; ++i)
+                versions[i] = UINT32_MAX;
+        }
+        return 0;
     }
-    
-    if (versions && num_versions)
-    {
-        for (uint32_t i=0; i<num_versions; ++i)
-            versions[i] = UINT32_MAX;
-    }
-    return 0;
 }
 
diff --git a/source/API/SBTypeSummary.cpp b/source/API/SBTypeSummary.cpp
index 86cb89b..4108da0 100644
--- a/source/API/SBTypeSummary.cpp
+++ b/source/API/SBTypeSummary.cpp
@@ -99,6 +99,9 @@
     if (!IsValid())
         return false;
     
+    if (m_opaque_sp->GetType() == lldb_private::TypeSummaryImpl::eTypeCallback)
+        return false;
+    
     return !m_opaque_sp->IsScripted();
 }
 
@@ -107,6 +110,8 @@
 {
     if (!IsValid())
         return NULL;
+    if (m_opaque_sp->GetType() == lldb_private::TypeSummaryImpl::eTypeCallback)
+        return NULL;
     if (m_opaque_sp->IsScripted())
     {
         ScriptSummaryFormat* script_summary_ptr = (ScriptSummaryFormat*)m_opaque_sp.get();
@@ -144,7 +149,7 @@
 {
     if (!IsValid())
         return;
-    if (m_opaque_sp->IsScripted())
+    if (m_opaque_sp->IsScripted() || (m_opaque_sp->GetType() == lldb_private::TypeSummaryImpl::eTypeCallback))
         ChangeSummaryType(false);
     ((StringSummaryFormat*)m_opaque_sp.get())->SetSummaryString(data);
 }
@@ -205,6 +210,16 @@
 {
     if (IsValid() == false)
         return !rhs.IsValid();
+
+    if (m_opaque_sp->GetType() != rhs.m_opaque_sp->GetType())
+        return false;
+    
+    if (m_opaque_sp->GetType() == lldb_private::TypeSummaryImpl::eTypeCallback)
+    {
+        lldb_private::CXXFunctionSummaryFormat *self_cxx = (lldb_private::CXXFunctionSummaryFormat*)m_opaque_sp.get();
+        lldb_private::CXXFunctionSummaryFormat *other_cxx = (lldb_private::CXXFunctionSummaryFormat*)rhs.m_opaque_sp.get();
+        return (self_cxx->m_impl == other_cxx->m_impl);
+    }
     
     if (m_opaque_sp->IsScripted() != rhs.m_opaque_sp->IsScripted())
         return false;
@@ -255,12 +270,20 @@
 {
     if (!IsValid())
         return false;
+    
     if (m_opaque_sp.unique())
         return true;
     
     TypeSummaryImplSP new_sp;
     
-    if (m_opaque_sp->IsScripted())
+    if (m_opaque_sp->GetType() == lldb_private::TypeSummaryImpl::eTypeCallback)
+    {
+        CXXFunctionSummaryFormat* current_summary_ptr = (CXXFunctionSummaryFormat*)m_opaque_sp.get();
+        new_sp = TypeSummaryImplSP(new CXXFunctionSummaryFormat(GetOptions(),
+                                                                current_summary_ptr->m_impl,
+                                                                current_summary_ptr->m_description.c_str()));
+    }
+    else if (m_opaque_sp->IsScripted())
     {
         ScriptSummaryFormat* current_summary_ptr = (ScriptSummaryFormat*)m_opaque_sp.get();
         new_sp = TypeSummaryImplSP(new ScriptSummaryFormat(GetOptions(),
@@ -284,15 +307,23 @@
     if (!IsValid())
         return false;
     
-    if (want_script == m_opaque_sp->IsScripted())
-        return CopyOnWrite_Impl();
-    
     TypeSummaryImplSP new_sp;
     
-    if (want_script)
-        new_sp = TypeSummaryImplSP(new ScriptSummaryFormat(GetOptions(), "", ""));
-    else
-        new_sp = TypeSummaryImplSP(new StringSummaryFormat(GetOptions(), ""));
+    if (want_script == m_opaque_sp->IsScripted())
+    {
+        if (m_opaque_sp->GetType() == lldb_private::TypeSummaryImpl::eTypeCallback && !want_script)
+            new_sp = TypeSummaryImplSP(new StringSummaryFormat(GetOptions(), ""));
+        else
+            return CopyOnWrite_Impl();
+    }
+    
+    if (!new_sp)
+    {
+        if (want_script)
+            new_sp = TypeSummaryImplSP(new ScriptSummaryFormat(GetOptions(), "", ""));
+        else
+            new_sp = TypeSummaryImplSP(new StringSummaryFormat(GetOptions(), ""));
+    }
     
     SetSP(new_sp);
     
diff --git a/source/Core/FormatClasses.cpp b/source/Core/FormatClasses.cpp
index 706a7a7..c76a0e5 100644
--- a/source/Core/FormatClasses.cpp
+++ b/source/Core/FormatClasses.cpp
@@ -157,6 +157,42 @@
     return sstr.GetString();
 }
 
+CXXFunctionSummaryFormat::CXXFunctionSummaryFormat (const TypeSummaryImpl::Flags& flags,
+                                                    Callback impl,
+                                                    const char* description) :
+                                                    TypeSummaryImpl(flags),
+                                                    m_impl(impl),
+                                                    m_description(description ? description : "")
+{
+}
+    
+bool
+CXXFunctionSummaryFormat::FormatObject(ValueObject *valobj,
+                                       std::string& dest)
+{
+    dest.clear();
+    StreamString stream;
+    if (!m_impl || m_impl(*valobj,stream) == false)
+        return false;
+    dest.assign(stream.GetData());
+    return true;
+}
+
+std::string
+CXXFunctionSummaryFormat::GetDescription()
+{
+    StreamString sstr;
+    sstr.Printf ("`%s (%p) `%s%s%s%s%s%s%s",      m_description.c_str(),m_impl,
+                 Cascades() ? "" : " (not cascading)",
+                 !DoesPrintChildren() ? "" : " (show children)",
+                 !DoesPrintValue() ? " (hide value)" : "",
+                 IsOneliner() ? " (one-line printout)" : "",
+                 SkipsPointers() ? " (skip pointers)" : "",
+                 SkipsReferences() ? " (skip references)" : "",
+                 HideNames() ? " (hide member names)" : "");
+    return sstr.GetString();
+}
+
 #ifndef LLDB_DISABLE_PYTHON
 
 
diff --git a/source/Core/FormatManager.cpp b/source/Core/FormatManager.cpp
index fb2441d..2222783 100644
--- a/source/Core/FormatManager.cpp
+++ b/source/Core/FormatManager.cpp
@@ -14,6 +14,7 @@
 // Other libraries and framework includes
 // Project includes
 
+#include "lldb/Core/CXXFormatterFunctions.h"
 #include "lldb/Core/Debugger.h"
 
 using namespace lldb;
@@ -896,6 +897,18 @@
 }
 #endif
 
+static void
+AddCXXSummary (TypeCategoryImpl::SharedPointer category_sp,
+               CXXFunctionSummaryFormat::Callback funct,
+               const char* description,
+               ConstString type_name,
+               TypeSummaryImpl::Flags flags)
+{
+    lldb::TypeSummaryImplSP summary_sp(new CXXFunctionSummaryFormat(flags,funct,description));
+    category_sp->GetSummaryNavigator()->Add(type_name,
+                                            summary_sp);
+}
+
 #ifndef LLDB_DISABLE_PYTHON
 void
 FormatManager::LoadObjCFormatters()
@@ -1025,12 +1038,13 @@
     .SetShowMembersOneLiner(false)
     .SetHideItemNames(false);
 
-    AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFArray.CFArray_SummaryProvider", ConstString("NSArray"), appkit_flags);
-    AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFArray.CFArray_SummaryProvider", ConstString("__NSArrayI"), appkit_flags);
-    AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFArray.CFArray_SummaryProvider", ConstString("__NSArrayM"), appkit_flags);
-    AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFArray.CFArray_SummaryProvider", ConstString("__NSCFArray"), appkit_flags);
-    AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFArray.CFArray_SummaryProvider", ConstString("CFArrayRef"), appkit_flags);
-    AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFArray.CFArray_SummaryProvider", ConstString("CFMutableArrayRef"), appkit_flags);
+    AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSArray_SummaryProvider, "NSArray summary provider", ConstString("NSArray"), appkit_flags);
+    AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSArray_SummaryProvider, "NSArray summary provider", ConstString("NSMutableArray"), appkit_flags);
+    AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSArray_SummaryProvider, "NSArray summary provider", ConstString("__NSArrayI"), appkit_flags);
+    AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSArray_SummaryProvider, "NSArray summary provider", ConstString("__NSArrayM"), appkit_flags);
+    AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSArray_SummaryProvider, "NSArray summary provider", ConstString("__NSCFArray"), appkit_flags);
+    AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSArray_SummaryProvider, "NSArray summary provider", ConstString("CFArrayRef"), appkit_flags);
+    AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSArray_SummaryProvider, "NSArray summary provider", ConstString("CFMutableArrayRef"), appkit_flags);
 
     AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFBag.CFBag_SummaryProvider", ConstString("CFBagRef"), appkit_flags);
     AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFBag.CFBag_SummaryProvider", ConstString("__CFBag"), appkit_flags);
@@ -1040,31 +1054,32 @@
     AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFBinaryHeap.CFBinaryHeap_SummaryProvider", ConstString("CFBinaryHeapRef"), appkit_flags);
     AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFBinaryHeap.CFBinaryHeap_SummaryProvider", ConstString("__CFBinaryHeap"), appkit_flags);
 
-    AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFDictionary.CFDictionary_SummaryProvider", ConstString("NSDictionary"), appkit_flags);
-    AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFDictionary.CFDictionary_SummaryProvider2", ConstString("CFDictionaryRef"), appkit_flags);
-    AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFDictionary.CFDictionary_SummaryProvider2", ConstString("CFMutableDictionaryRef"), appkit_flags);
-    AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFDictionary.CFDictionary_SummaryProvider", ConstString("__NSCFDictionary"), appkit_flags);
-    AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFDictionary.CFDictionary_SummaryProvider", ConstString("__NSDictionaryI"), appkit_flags);
-    AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFDictionary.CFDictionary_SummaryProvider", ConstString("__NSDictionaryM"), appkit_flags);
+    AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSDictionary_SummaryProvider<false>, "NSDictionary summary provider", ConstString("NSDictionary"), appkit_flags);
+    AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSDictionary_SummaryProvider<false>, "NSDictionary summary provider", ConstString("__NSCFDictionary"), appkit_flags);
+    AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSDictionary_SummaryProvider<false>, "NSDictionary summary provider", ConstString("__NSDictionaryI"), appkit_flags);
+    AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSDictionary_SummaryProvider<false>, "NSDictionary summary provider", ConstString("__NSDictionaryM"), appkit_flags);
+    AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSDictionary_SummaryProvider<true>, "NSDictionary summary provider", ConstString("CFDictionaryRef"), appkit_flags);
+    AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSDictionary_SummaryProvider<true>, "NSDictionary summary provider", ConstString("CFMutableDictionaryRef"), appkit_flags);
 
-    AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFString.CFString_SummaryProvider", ConstString("NSString"), appkit_flags);
-    AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFString.CFString_SummaryProvider", ConstString("CFStringRef"), appkit_flags);
-    AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFString.CFString_SummaryProvider", ConstString("CFMutableStringRef"), appkit_flags);
+    AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSString_SummaryProvider, "NSString summary provider", ConstString("NSString"), appkit_flags);
+    AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSString_SummaryProvider, "NSString summary provider", ConstString("CFStringRef"), appkit_flags);
+    AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSString_SummaryProvider, "NSString summary provider", ConstString("CFMutableStringRef"), appkit_flags);
+    AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSString_SummaryProvider, "NSString summary provider", ConstString("__NSCFConstantString"), appkit_flags);
+    AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSString_SummaryProvider, "NSString summary provider", ConstString("__NSCFString"), appkit_flags);
+    AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSString_SummaryProvider, "NSString summary provider", ConstString("NSCFConstantString"), appkit_flags);
+    AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSString_SummaryProvider, "NSString summary provider", ConstString("NSCFString"), appkit_flags);
+    AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSString_SummaryProvider, "NSString summary provider", ConstString("NSPathStore2"), appkit_flags);
+    
     AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFString.CFAttributedString_SummaryProvider", ConstString("NSAttributedString"), appkit_flags);
-    AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFString.CFString_SummaryProvider", ConstString("__NSCFConstantString"), appkit_flags);
-    AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFString.CFString_SummaryProvider", ConstString("__NSCFString"), appkit_flags);
-    AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFString.CFString_SummaryProvider", ConstString("NSCFConstantString"), appkit_flags);
-    AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFString.CFString_SummaryProvider", ConstString("NSCFString"), appkit_flags);
-    AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFString.CFString_SummaryProvider", ConstString("NSPathStore2"), appkit_flags);
     
     AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.NSBundle.NSBundle_SummaryProvider", ConstString("NSBundle"), appkit_flags);
     
-    AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.NSData.NSData_SummaryProvider", ConstString("NSData"), appkit_flags);
-    AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.NSData.NSData_SummaryProvider2", ConstString("CFDataRef"), appkit_flags);
-    AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.NSData.NSData_SummaryProvider2", ConstString("CFMutableDataRef"), appkit_flags);
-    AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.NSData.NSData_SummaryProvider", ConstString("NSConcreteData"), appkit_flags);
-    AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.NSData.NSData_SummaryProvider", ConstString("NSConcreteMutableData"), appkit_flags);
-    AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.NSData.NSData_SummaryProvider", ConstString("__NSCFData"), appkit_flags);
+    AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSData_SummaryProvider<false>, "NSData summary provider", ConstString("NSData"), appkit_flags);
+    AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSData_SummaryProvider<false>, "NSData summary provider", ConstString("NSConcreteData"), appkit_flags);
+    AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSData_SummaryProvider<false>, "NSData summary provider", ConstString("NSConcreteMutableData"), appkit_flags);
+    AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSData_SummaryProvider<false>, "NSData summary provider", ConstString("__NSCFData"), appkit_flags);
+    AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSData_SummaryProvider<true>, "NSData summary provider", ConstString("CFDataRef"), appkit_flags);
+    AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSData_SummaryProvider<true>, "NSData summary provider", ConstString("CFMutableDataRef"), appkit_flags);
 
     AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.NSException.NSException_SummaryProvider", ConstString("NSException"), appkit_flags);
 
@@ -1073,11 +1088,11 @@
     AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.NSNotification.NSNotification_SummaryProvider", ConstString("NSNotification"), appkit_flags);
     AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.NSNotification.NSNotification_SummaryProvider", ConstString("NSConcreteNotification"), appkit_flags);
 
-    AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.NSNumber.NSNumber_SummaryProvider", ConstString("NSNumber"), appkit_flags);
-    AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.NSNumber.NSNumber_SummaryProvider", ConstString("__NSCFBoolean"), appkit_flags);
-    AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.NSNumber.NSNumber_SummaryProvider", ConstString("__NSCFNumber"), appkit_flags);
-    AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.NSNumber.NSNumber_SummaryProvider", ConstString("NSCFBoolean"), appkit_flags);
-    AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.NSNumber.NSNumber_SummaryProvider", ConstString("NSCFNumber"), appkit_flags);
+    AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSNumber_SummaryProvider, "NSNumber summary provider", ConstString("NSNumber"), appkit_flags);
+    AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSNumber_SummaryProvider, "NSNumber summary provider", ConstString("__NSCFBoolean"), appkit_flags);
+    AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSNumber_SummaryProvider, "NSNumber summary provider", ConstString("__NSCFNumber"), appkit_flags);
+    AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSNumber_SummaryProvider, "NSNumber summary provider", ConstString("NSCFBoolean"), appkit_flags);
+    AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSNumber_SummaryProvider, "NSNumber summary provider", ConstString("NSCFNumber"), appkit_flags);
 
     AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.NSSet.NSSet_SummaryProvider", ConstString("NSSet"), appkit_flags);
     AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.NSSet.NSSet_SummaryProvider2", ConstString("CFSetRef"), appkit_flags);
diff --git a/source/Core/Module.cpp b/source/Core/Module.cpp
index 7818530..15ad72c 100644
--- a/source/Core/Module.cpp
+++ b/source/Core/Module.cpp
@@ -1205,3 +1205,17 @@
     return m_source_mappings.RemapPath(path, new_path);
 }
 
+uint32_t
+Module::GetVersion (uint32_t *versions, uint32_t num_versions)
+{
+    ObjectFile *obj_file = GetObjectFile();
+    if (obj_file)
+        return obj_file->GetVersion (versions, num_versions);
+        
+    if (versions && num_versions)
+    {
+        for (uint32_t i=0; i<num_versions; ++i)
+            versions[i] = UINT32_MAX;
+    }
+    return 0;
+}
diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h
index 3db7477..e835a0c 100644
--- a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h
+++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h
@@ -75,18 +75,6 @@
         return 0;
     }
     
-    virtual ConstString
-    GetActualTypeName(ObjCISA isa)
-    {
-        return ConstString(NULL);
-    }
-    
-    virtual ObjCISA
-    GetParentClass(ObjCISA isa)
-    {
-        return 0;
-    }
-    
     //------------------------------------------------------------------
     // Static Functions
     //------------------------------------------------------------------
diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp
index a811710..cab4e9d 100644
--- a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp
+++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp
@@ -152,3 +152,169 @@
 
     return new ClangUtilityFunction(buf->contents, name);
 }
+
+// this code relies on the assumption that an Objective-C object always starts
+// with an ISA at offset 0.
+ObjCLanguageRuntime::ObjCISA
+AppleObjCRuntimeV1::GetISA(ValueObject& valobj)
+{
+    if (ClangASTType::GetMinimumLanguage(valobj.GetClangAST(),valobj.GetClangType()) != eLanguageTypeObjC)
+        return 0;
+    
+    // if we get an invalid VO (which might still happen when playing around
+    // with pointers returned by the expression parser, don't consider this
+    // a valid ObjC object)
+    if (valobj.GetValue().GetContextType() == Value::eContextTypeInvalid)
+        return 0;
+    
+    addr_t isa_pointer = valobj.GetPointerValue();
+    
+    ExecutionContext exe_ctx (valobj.GetExecutionContextRef());
+    
+    Process *process = exe_ctx.GetProcessPtr();
+    if (process)
+    {
+        uint8_t pointer_size = process->GetAddressByteSize();
+        
+        Error error;
+        return process->ReadUnsignedIntegerFromMemory (isa_pointer,
+                                                       pointer_size,
+                                                       0,
+                                                       error);
+    }
+    return 0;
+}
+
+AppleObjCRuntimeV1::ClassDescriptorV1::ClassDescriptorV1 (ValueObject &isa_pointer)
+{
+    ObjCISA ptr_value = isa_pointer.GetValueAsUnsigned(0);
+
+    lldb::ProcessSP process_sp = isa_pointer.GetProcessSP();
+
+    Initialize (ptr_value,process_sp);
+}
+
+AppleObjCRuntimeV1::ClassDescriptorV1::ClassDescriptorV1 (ObjCISA isa, lldb::ProcessSP process_sp)
+{
+    Initialize (isa, process_sp);
+}
+
+void
+AppleObjCRuntimeV1::ClassDescriptorV1::Initialize (ObjCISA isa, lldb::ProcessSP process_sp)
+{
+    if (!isa || !process_sp)
+    {
+        m_valid = false;
+        return;
+    }
+    
+    m_valid = true;
+    
+    Error error;
+    
+    m_isa = process_sp->ReadPointerFromMemory(isa, error);
+    
+    if (error.Fail())
+    {
+        m_valid = false;
+        return;
+    }
+    
+    uint32_t ptr_size = process_sp->GetAddressByteSize();
+    
+    if (!IsPointerValid(m_isa,ptr_size))
+    {
+        m_valid = false;
+        return;
+    }
+
+    m_parent_isa = process_sp->ReadPointerFromMemory(m_isa + ptr_size,error);
+    
+    if (error.Fail())
+    {
+        m_valid = false;
+        return;
+    }
+    
+    if (!IsPointerValid(m_parent_isa,ptr_size,true))
+    {
+        m_valid = false;
+        return;
+    }
+    
+    lldb::addr_t name_ptr = process_sp->ReadPointerFromMemory(m_isa + 2 * ptr_size,error);
+    
+    if (error.Fail())
+    {
+        m_valid = false;
+        return;
+    }
+    
+    lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024, 0));
+    
+    size_t count = process_sp->ReadCStringFromMemory(name_ptr, (char*)buffer_sp->GetBytes(), 1024, error);
+    
+    if (error.Fail())
+    {
+        m_valid = false;
+        return;
+    }
+    
+    if (count)
+        m_name = ConstString((char*)buffer_sp->GetBytes());
+    else
+        m_name = ConstString();
+    
+    m_instance_size = process_sp->ReadUnsignedIntegerFromMemory(m_isa + 5 * ptr_size, ptr_size, 0, error);
+    
+    if (error.Fail())
+    {
+        m_valid = false;
+        return;
+    }
+    
+    m_process_wp = lldb::ProcessWP(process_sp);
+}
+
+AppleObjCRuntime::ClassDescriptorSP
+AppleObjCRuntimeV1::ClassDescriptorV1::GetSuperclass ()
+{
+    if (!m_valid)
+        return NULL;
+    ProcessSP process_sp = m_process_wp.lock();
+    if (!process_sp)
+        return NULL;
+    return ObjCLanguageRuntime::ClassDescriptorSP(new AppleObjCRuntimeV1::ClassDescriptorV1(m_parent_isa,process_sp));
+}
+
+ObjCLanguageRuntime::ClassDescriptorSP
+AppleObjCRuntimeV1::GetClassDescriptor (ValueObject& in_value)
+{
+    ObjCISA isa = GetISA(in_value);
+    
+    ObjCLanguageRuntime::ISAToDescriptorIterator found = m_isa_to_descriptor_cache.find(isa);
+    ObjCLanguageRuntime::ISAToDescriptorIterator end = m_isa_to_descriptor_cache.end();
+    
+    if (found != end && found->second)
+        return found->second;
+    
+    ClassDescriptorSP descriptor = ClassDescriptorSP(new ClassDescriptorV1(in_value));
+    if (descriptor && descriptor->IsValid())
+        m_isa_to_descriptor_cache[descriptor->GetISA()] = descriptor;
+    return descriptor;
+}
+
+ObjCLanguageRuntime::ClassDescriptorSP
+AppleObjCRuntimeV1::GetClassDescriptor (ObjCISA isa)
+{
+    ObjCLanguageRuntime::ISAToDescriptorIterator found = m_isa_to_descriptor_cache.find(isa);
+    ObjCLanguageRuntime::ISAToDescriptorIterator end = m_isa_to_descriptor_cache.end();
+    
+    if (found != end && found->second)
+        return found->second;
+    
+    ClassDescriptorSP descriptor = ClassDescriptorSP(new ClassDescriptorV1(isa,m_process->CalculateProcess()));
+    if (descriptor && descriptor->IsValid())
+        m_isa_to_descriptor_cache[descriptor->GetISA()] = descriptor;
+    return descriptor;
+}
diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h
index df8b6b4..2a0dbad 100644
--- a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h
+++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h
@@ -24,6 +24,63 @@
         public AppleObjCRuntime
 {
 public:
+    
+    class ClassDescriptorV1 : public ObjCLanguageRuntime::ClassDescriptor
+    {
+    public:
+        ClassDescriptorV1 (ValueObject &isa_pointer);
+        ClassDescriptorV1 (ObjCISA isa, lldb::ProcessSP process_sp);
+        
+        virtual ConstString
+        GetClassName ()
+        {
+            return m_name;
+        }
+        
+        virtual ClassDescriptorSP
+        GetSuperclass ();
+        
+        virtual bool
+        IsValid ()
+        {
+            return m_valid;
+        }
+        
+        virtual bool
+        IsTagged ()
+        {
+            return false;   // v1 runtime does not support tagged pointers
+        }
+        
+        virtual uint64_t
+        GetInstanceSize ()
+        {
+            return m_instance_size;
+        }
+        
+        virtual ObjCISA
+        GetISA ()
+        {
+            return m_isa;
+        }
+        
+        virtual
+        ~ClassDescriptorV1 ()
+        {}
+        
+    protected:
+        void
+        Initialize (ObjCISA isa, lldb::ProcessSP process_sp);
+        
+    private:
+        ConstString m_name;
+        ObjCISA m_isa;
+        ObjCISA m_parent_isa;
+        bool m_valid;
+        lldb::ProcessWP m_process_wp;
+        uint64_t m_instance_size;
+    };
+    
     virtual ~AppleObjCRuntimeV1() { }
     
     // These are generic runtime functions:
@@ -69,26 +126,17 @@
     virtual bool
     IsValidISA(ObjCISA isa)
     {
-        return false;
+        return (isa != 0) && ( (isa % 2) == 0);
     }
     
     virtual ObjCISA
-    GetISA(ValueObject& valobj)
-    {
-        return 0;
-    }
+    GetISA(ValueObject& valobj);
     
-    virtual ConstString
-    GetActualTypeName(ObjCISA isa)
-    {
-        return ConstString(NULL);
-    }
+    virtual ClassDescriptorSP
+    GetClassDescriptor (ValueObject& in_value);
     
-    virtual ObjCISA
-    GetParentClass(ObjCISA isa)
-    {
-        return 0;
-    }
+    virtual ClassDescriptorSP
+    GetClassDescriptor (ObjCISA isa);
 
 protected:
     virtual lldb::BreakpointResolverSP
diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
index 1e0bf4d..6b146d9 100644
--- a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
+++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
@@ -104,9 +104,7 @@
                                         const ModuleSP &objc_module_sp) : 
     AppleObjCRuntime (process),
     m_get_class_name_args(LLDB_INVALID_ADDRESS),
-    m_get_class_name_args_mutex(Mutex::eMutexTypeNormal),
-    m_isa_to_name_cache(),
-    m_isa_to_parent_cache()
+    m_get_class_name_args_mutex(Mutex::eMutexTypeNormal)
 {
     static const ConstString g_gdb_object_getClass("gdb_object_getClass");
     m_has_object_getClass = (objc_module_sp->FindFirstSymbolWithNameAndType(g_gdb_object_getClass, eSymbolTypeCode) != NULL);
@@ -587,6 +585,46 @@
     return (ptr & 0x01);
 }
 
+ObjCLanguageRuntime::ClassDescriptorSP
+AppleObjCRuntimeV2::GetClassDescriptor (ObjCISA isa)
+{
+    ObjCLanguageRuntime::ISAToDescriptorIterator found = m_isa_to_descriptor_cache.find(isa);
+    ObjCLanguageRuntime::ISAToDescriptorIterator end = m_isa_to_descriptor_cache.end();
+    
+    if (found != end && found->second)
+        return found->second;
+    
+    ClassDescriptorSP descriptor = ClassDescriptorSP(new ClassDescriptorV2(isa,m_process->CalculateProcess()));
+    if (descriptor && descriptor->IsValid())
+        m_isa_to_descriptor_cache[descriptor->GetISA()] = descriptor;
+    return descriptor;
+}
+
+ObjCLanguageRuntime::ClassDescriptorSP
+AppleObjCRuntimeV2::GetClassDescriptor (ValueObject& in_value)
+{
+    uint64_t ptr_value = in_value.GetValueAsUnsigned(0);
+    if (ptr_value == 0)
+        return NULL;
+    
+    ObjCISA isa = GetISA(in_value);
+    
+    ObjCLanguageRuntime::ISAToDescriptorIterator found = m_isa_to_descriptor_cache.find(isa);
+    ObjCLanguageRuntime::ISAToDescriptorIterator end = m_isa_to_descriptor_cache.end();
+    
+    if (found != end && found->second)
+        return found->second;
+    
+    ClassDescriptorSP descriptor;
+    
+    if (ptr_value & 1)
+        return ClassDescriptorSP(new ClassDescriptorV2Tagged(in_value)); // do not save tagged pointers
+    descriptor = ClassDescriptorSP(new ClassDescriptorV2(in_value));
+    
+    if (descriptor && descriptor->IsValid())
+        m_isa_to_descriptor_cache[descriptor->GetISA()] = descriptor;
+    return descriptor;
+}
 
 // this code relies on the assumption that an Objective-C object always starts
 // with an ISA at offset 0. an ISA is effectively a pointer to an instance of
@@ -641,135 +679,25 @@
         return g_objc_tagged_isa_name;
     }
     
-    ISAToNameIterator found = m_isa_to_name_cache.find(isa);
-    ISAToNameIterator end = m_isa_to_name_cache.end();
+    ISAToDescriptorIterator found = m_isa_to_descriptor_cache.find(isa);
+    ISAToDescriptorIterator end = m_isa_to_descriptor_cache.end();
     
-    if (found != end)
-        return found->second;
+    if (found != end && found->second)
+        return found->second->GetClassName();
     
-    uint8_t pointer_size = m_process->GetAddressByteSize();
-    Error error;
-    
-    /*
-     struct class_t *isa;
-     struct class_t *superclass;
-     Cache cache;
-     IMP *vtable;
--->     class_rw_t data;
-     */
-    
-    addr_t rw_pointer = isa + (4 * pointer_size);
-    //printf("rw_pointer: %llx\n", rw_pointer);
-    uint64_t data_pointer =  m_process->ReadUnsignedIntegerFromMemory(rw_pointer,
-                                                                      pointer_size,
-                                                                      0,
-                                                                      error);
-    if (error.Fail())
+    ClassDescriptorSP descriptor(GetClassDescriptor(isa));
+    if (!descriptor.get() || !descriptor->IsValid())
+        return ConstString();
+    ConstString class_name = descriptor->GetClassName();
+    if (descriptor->IsKVO())
     {
-        return g_unknown;
-
+        ClassDescriptorSP superclass(descriptor->GetSuperclass());
+        if (!superclass.get() || !superclass->IsValid())
+            return ConstString();
+        descriptor = superclass;
     }
-    
-    /*
-     uint32_t flags;
-     uint32_t version;
-     
--->     const class_ro_t *ro;
-     */
-    data_pointer += 8;
-    //printf("data_pointer: %llx\n", data_pointer);
-    uint64_t ro_pointer = m_process->ReadUnsignedIntegerFromMemory(data_pointer,
-                                                                   pointer_size,
-                                                                   0,
-                                                                   error);
-    if (error.Fail())
-        return g_unknown;
-    
-    /*
-     uint32_t flags;
-     uint32_t instanceStart;
-     uint32_t instanceSize;
-     #ifdef __LP64__
-     uint32_t reserved;
-     #endif
-     
-     const uint8_t * ivarLayout;
-     
--->     const char * name;
-     */
-    ro_pointer += 12;
-    if (pointer_size == 8)
-        ro_pointer += 4;
-    ro_pointer += pointer_size;
-    //printf("ro_pointer: %llx\n", ro_pointer);
-    uint64_t name_pointer = m_process->ReadUnsignedIntegerFromMemory(ro_pointer,
-                                                                     pointer_size,
-                                                                     0,
-                                                                     error);
-    if (error.Fail())
-        return g_unknown;
-    
-    //printf("name_pointer: %llx\n", name_pointer);
-    char cstr[512];
-    if (m_process->ReadCStringFromMemory(name_pointer, cstr, sizeof(cstr), error) > 0)
-    {
-        if (::strstr(cstr, "NSKVONotify") == cstr)
-        {
-            // the ObjC runtime implements KVO by replacing the isa with a special
-            // NSKVONotifying_className that overrides the relevant methods
-            // the side effect on us is that getting the typename for a KVO-ed object
-            // will return the swizzled class instead of the actual one
-            // this swizzled class is a descendant of the real class, so just
-            // return the parent type and all should be fine
-            ConstString class_name = GetActualTypeName(GetParentClass(isa));
-            m_isa_to_name_cache[isa] = class_name;
-            return class_name;
-        }
-        else
-        {
-            ConstString class_name = ConstString(cstr);
-            m_isa_to_name_cache[isa] = class_name;
-            return class_name;
-        }
-    }
-    else
-        return g_unknown;
-}
-
-ObjCLanguageRuntime::ObjCISA
-AppleObjCRuntimeV2::GetParentClass(ObjCLanguageRuntime::ObjCISA isa)
-{
-    if (!IsValidISA(isa))
-        return 0;
-    
-    if (isa == g_objc_Tagged_ISA)
-        return 0;
-    
-    ISAToParentIterator found = m_isa_to_parent_cache.find(isa);
-    ISAToParentIterator end = m_isa_to_parent_cache.end();
-    
-    if (found != end)
-        return found->second;
-    
-    uint8_t pointer_size = m_process->GetAddressByteSize();
-    Error error;
-    /*
-     struct class_t *isa;
--->     struct class_t *superclass;
-     */
-    addr_t parent_pointer = isa + pointer_size;
-    //printf("rw_pointer: %llx\n", rw_pointer);
-    
-    uint64_t parent_isa =  m_process->ReadUnsignedIntegerFromMemory(parent_pointer,
-                                                                    pointer_size,
-                                                                    0,
-                                                                    error);
-    if (error.Fail())
-        return 0;
-    
-    m_isa_to_parent_cache[isa] = parent_isa;
-    
-    return parent_isa;
+    m_isa_to_descriptor_cache[isa] = descriptor;
+    return descriptor->GetClassName();
 }
 
 SymbolVendor *
@@ -780,3 +708,254 @@
     
     return m_symbol_vendor_ap.get();
 }
+
+AppleObjCRuntimeV2::ClassDescriptorV2::ClassDescriptorV2 (ValueObject &isa_pointer)
+{
+    ObjCISA ptr_value = isa_pointer.GetValueAsUnsigned(0);
+    
+    lldb::ProcessSP process_sp = isa_pointer.GetProcessSP();
+    
+    Initialize (ptr_value,process_sp);
+}
+
+AppleObjCRuntimeV2::ClassDescriptorV2::ClassDescriptorV2 (ObjCISA isa, lldb::ProcessSP process_sp)
+{
+    Initialize (isa, process_sp);
+}
+
+void
+AppleObjCRuntimeV2::ClassDescriptorV2::Initialize (ObjCISA isa, lldb::ProcessSP process_sp)
+{
+    if (!isa || !process_sp)
+    {
+        m_valid = false;
+        return;
+    }
+    
+    m_valid = true;
+    
+    Error error;
+    
+    m_isa = process_sp->ReadPointerFromMemory(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())
+    {
+        m_valid = false;
+        return;
+    }
+    
+    if (!IsPointerValid(data_ptr,ptr_size,false,false,true))
+    {
+        m_valid = false;
+        return;
+    }
+    
+    m_parent_isa = process_sp->ReadPointerFromMemory(isa + ptr_size,error);
+    
+    if (error.Fail())
+    {
+        m_valid = false;
+        return;
+    }
+    
+    // sanity checks
+    lldb::addr_t cache_ptr = process_sp->ReadPointerFromMemory(m_isa + 2*ptr_size, error);
+    if (error.Fail())
+    {
+        m_valid = false;
+        return;
+    }
+    if (!IsPointerValid(cache_ptr,ptr_size,true,false,true))
+    {
+        m_valid = false;
+        return;
+    }
+    lldb::addr_t vtable_ptr = process_sp->ReadPointerFromMemory(m_isa + 3*ptr_size, error);
+    if (error.Fail())
+    {
+        m_valid = false;
+        return;
+    }
+    if (!IsPointerValid(vtable_ptr,ptr_size,true,false,true))
+    {
+        m_valid = false;
+        return;
+    }
+
+    // now construct the data object
+    
+    lldb::addr_t rot_pointer = process_sp->ReadPointerFromMemory(data_ptr + 8, error);
+    
+    if (error.Fail())
+    {
+        m_valid = false;
+        return;
+    }
+    
+    if (!IsPointerValid(rot_pointer,ptr_size))
+    {
+        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);
+    
+    if (error.Fail())
+    {
+        m_valid = false;
+        return;
+    }
+    
+    lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024, 0));
+    
+    size_t count = process_sp->ReadCStringFromMemory(name_ptr, (char*)buffer_sp->GetBytes(), 1024, error);
+    
+    if (error.Fail())
+    {
+        m_valid = false;
+        return;
+    }
+    
+    if (count)
+        m_name = ConstString((char*)buffer_sp->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);
+}
+
+AppleObjCRuntime::ClassDescriptorSP
+AppleObjCRuntimeV2::ClassDescriptorV2::GetSuperclass ()
+{
+    if (!m_valid)
+        return NULL;
+    ProcessSP process_sp = m_process_wp.lock();
+    if (!process_sp)
+        return NULL;
+    return AppleObjCRuntime::ClassDescriptorSP(new AppleObjCRuntimeV2::ClassDescriptorV2(m_parent_isa,process_sp));
+}
+
+AppleObjCRuntimeV2::ClassDescriptorV2Tagged::ClassDescriptorV2Tagged (ValueObject &isa_pointer)
+{
+    m_valid = false;
+    uint64_t value = isa_pointer.GetValueAsUnsigned(0);
+    lldb::ProcessSP process_sp = isa_pointer.GetProcessSP();
+    if (process_sp)
+        m_pointer_size = process_sp->GetAddressByteSize();
+    else
+    {
+        m_name = ConstString("");
+        m_pointer_size = 0;
+        return;
+    }
+    
+    m_valid = true;
+    m_class_bits = (value & 0xE) >> 1;
+    lldb::TargetSP target_sp = isa_pointer.GetTargetSP();
+    
+    LazyBool is_lion = IsLion(target_sp);
+    
+    // TODO: check for OSX version - for now assume Mtn Lion
+    if (is_lion == eLazyBoolCalculate)
+    {
+        // if we can't determine the matching table (e.g. we have no Foundation),
+        // assume this is not a valid tagged pointer
+        m_valid = false;
+    }
+    else if (is_lion == eLazyBoolNo)
+    {
+        switch (m_class_bits)
+        {
+            case 0:
+                m_name = ConstString("NSAtom");
+                break;
+            case 3:
+                m_name = ConstString("NSNumber");
+                break;
+            case 4:
+                m_name = ConstString("NSDateTS");
+                break;
+            case 5:
+                m_name = ConstString("NSManagedObject");
+                break;
+            case 6:
+                m_name = ConstString("NSDate");
+                break;
+            default:
+                m_valid = false;
+                break;
+        }
+    }
+    else
+    {
+        switch (m_class_bits)
+        {
+            case 1:
+                m_name = ConstString("NSNumber");
+                break;
+            case 5:
+                m_name = ConstString("NSManagedObject");
+                break;
+            case 6:
+                m_name = ConstString("NSDate");
+                break;
+            case 7:
+                m_name = ConstString("NSDateTS");
+                break;
+            default:
+                m_valid = false;
+                break;
+        }
+    }
+    if (!m_valid)
+        m_name = ConstString("");
+    else
+    {
+        m_info_bits = (value & 0xF0ULL) >> 4;
+        m_value_bits = (value & ~0x0000000000000000FFULL) >> 8;
+    }
+}
+
+LazyBool
+AppleObjCRuntimeV2::ClassDescriptorV2Tagged::IsLion (lldb::TargetSP &target_sp)
+{
+    if (!target_sp)
+        return eLazyBoolCalculate;
+    ModuleList& modules = target_sp->GetImages();
+    for (uint32_t idx = 0; idx < modules.GetSize(); idx++)
+    {
+        lldb::ModuleSP module_sp = modules.GetModuleAtIndex(idx);
+        if (!module_sp)
+            continue;
+        if (strcmp(module_sp->GetFileSpec().GetFilename().AsCString(""),"Foundation") == 0)
+        {
+            uint32_t major = UINT32_MAX;
+            module_sp->GetVersion(&major,1);
+            if (major == UINT32_MAX)
+                return eLazyBoolCalculate;
+            
+            return (major > 900 ? eLazyBoolNo : eLazyBoolYes);
+        }
+    }
+    return eLazyBoolCalculate;
+}
diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h
index 057fa62..ff94b81 100644
--- a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h
+++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h
@@ -27,6 +27,165 @@
         public AppleObjCRuntime
 {
 public:
+    
+    class ClassDescriptorV2 : public ObjCLanguageRuntime::ClassDescriptor
+    {
+    public:
+        ClassDescriptorV2 (ValueObject &isa_pointer);
+        ClassDescriptorV2 (ObjCISA isa, lldb::ProcessSP process);
+        
+        virtual ConstString
+        GetClassName ()
+        {
+            return m_name;
+        }
+        
+        virtual ClassDescriptorSP
+        GetSuperclass ();
+        
+        virtual bool
+        IsValid ()
+        {
+            return m_valid;
+        }
+        
+        virtual bool
+        IsTagged ()
+        {
+            return false;   // we use a special class for tagged descriptors
+        }
+        
+        virtual uint64_t
+        GetInstanceSize ()
+        {
+            return m_instance_size;
+        }
+        
+        virtual ObjCISA
+        GetISA ()
+        {
+            return m_isa;
+        }
+        
+        virtual
+        ~ClassDescriptorV2 ()
+        {}
+        
+    protected:
+        virtual bool
+        CheckPointer (lldb::addr_t value,
+                      uint32_t ptr_size)
+        {
+            if (ptr_size != 8)
+                return true;
+            return ((value & 0xFFFF800000000000) == 0);
+        }
+        
+        void
+        Initialize (ObjCISA isa, lldb::ProcessSP process_sp);
+        
+    private:
+        ConstString m_name;
+        ObjCISA m_isa;
+        ObjCISA m_parent_isa;
+        bool m_valid;
+        lldb::ProcessWP m_process_wp;
+        uint64_t m_instance_size;
+    };
+    
+    class ClassDescriptorV2Tagged : public ObjCLanguageRuntime::ClassDescriptor
+    {
+    public:
+        ClassDescriptorV2Tagged (ValueObject &isa_pointer);
+        
+        virtual ConstString
+        GetClassName ()
+        {
+            return m_name;
+        }
+        
+        virtual ClassDescriptorSP
+        GetSuperclass ()
+        {
+            // tagged pointers can represent a class that has a superclass, but since that information is not
+            // stored in the object itself, we would have to query the runtime to discover the hierarchy
+            // for the time being, we skip this step in the interest of static discovery
+            return ClassDescriptorSP(new ObjCLanguageRuntime::ClassDescriptor_Invalid());
+        }
+        
+        virtual bool
+        IsValid ()
+        {
+            return m_valid;
+        }
+        
+        virtual bool
+        IsKVO ()
+        {
+            return false; // tagged pointers are not KVO'ed
+        }
+        
+        virtual bool
+        IsCFType ()
+        {
+            return false; // tagged pointers are not CF objects
+        }
+        
+        virtual bool
+        IsTagged ()
+        {
+            return true;   // we use this class to describe tagged pointers
+        }
+        
+        virtual uint64_t
+        GetInstanceSize ()
+        {
+            return (IsValid() ? m_pointer_size : 0);
+        }
+        
+        virtual ObjCISA
+        GetISA ()
+        {
+            return 0; // tagged pointers have no ISA
+        }
+
+        virtual uint64_t
+        GetClassBits ()
+        {
+            return (IsValid() ? m_class_bits : 0);
+        }
+        
+        // these calls are not part of any formal tagged pointers specification
+        virtual uint64_t
+        GetValueBits ()
+        {
+            return (IsValid() ? m_value_bits : 0);
+        }
+        
+        virtual uint64_t
+        GetInfoBits ()
+        {
+            return (IsValid() ? m_info_bits : 0);
+        }
+        
+        virtual
+        ~ClassDescriptorV2Tagged ()
+        {}
+        
+    protected:
+        // TODO make this into a smarter OS version detector
+        LazyBool
+        IsLion (lldb::TargetSP &target_sp);
+        
+    private:
+        ConstString m_name;
+        uint8_t m_pointer_size;
+        bool m_valid;
+        uint64_t m_class_bits;
+        uint64_t m_info_bits;
+        uint64_t m_value_bits;
+    };
+    
     virtual ~AppleObjCRuntimeV2() { }
     
     // These are generic runtime functions:
@@ -90,8 +249,11 @@
     virtual ConstString
     GetActualTypeName(ObjCLanguageRuntime::ObjCISA isa);
     
-    virtual ObjCLanguageRuntime::ObjCISA
-    GetParentClass(ObjCLanguageRuntime::ObjCISA isa);
+    virtual ClassDescriptorSP
+    GetClassDescriptor (ValueObject& in_value);
+    
+    virtual ClassDescriptorSP
+    GetClassDescriptor (ObjCISA isa);
     
     virtual SymbolVendor *
     GetSymbolVendor();
@@ -102,13 +264,7 @@
 
 private:
     
-    typedef std::map<ObjCLanguageRuntime::ObjCISA, ConstString> ISAToNameCache;
-    typedef std::map<ObjCLanguageRuntime::ObjCISA, ObjCLanguageRuntime::ObjCISA> ISAToParentCache;
-    
-    typedef ISAToNameCache::iterator ISAToNameIterator;
-    typedef ISAToParentCache::iterator ISAToParentIterator;
-    
-    AppleObjCRuntimeV2 (Process *process, 
+    AppleObjCRuntimeV2 (Process *process,
                         const lldb::ModuleSP &objc_module_sp);
     
     bool
@@ -122,9 +278,6 @@
     lldb::addr_t                        m_get_class_name_args;
     Mutex                               m_get_class_name_args_mutex;
     
-    ISAToNameCache                      m_isa_to_name_cache;
-    ISAToParentCache                    m_isa_to_parent_cache;
-    
     std::auto_ptr<SymbolVendor>         m_symbol_vendor_ap;
     
     static const char *g_find_class_name_function_name;
diff --git a/source/Target/ObjCLanguageRuntime.cpp b/source/Target/ObjCLanguageRuntime.cpp
index c41db3c..a404ce4 100644
--- a/source/Target/ObjCLanguageRuntime.cpp
+++ b/source/Target/ObjCLanguageRuntime.cpp
@@ -262,3 +262,85 @@
     }
     return result;
 }
+
+bool
+ObjCLanguageRuntime::ClassDescriptor::IsPointerValid (lldb::addr_t value,
+                                                      uint32_t ptr_size,
+                                                      bool allow_NULLs,
+                                                      bool allow_tagged,
+                                                      bool check_version_specific)
+{
+    if (!value)
+        return allow_NULLs;
+    if ( (value % 2) == 1  && allow_tagged)
+        return true;
+    if ((value % ptr_size) == 0)
+        return (check_version_specific ? CheckPointer(value,ptr_size) : true);
+    else
+        return false;
+}
+
+ObjCLanguageRuntime::ObjCISA
+ObjCLanguageRuntime::GetParentClass(ObjCLanguageRuntime::ObjCISA isa)
+{
+    if (!IsValidISA(isa))
+        return 0;
+    
+    ISAToDescriptorIterator found = m_isa_to_descriptor_cache.find(isa);
+    ISAToDescriptorIterator end = m_isa_to_descriptor_cache.end();
+    
+    if (found != end && found->second)
+    {
+        ClassDescriptorSP superclass = found->second->GetSuperclass();
+        if (!superclass || !superclass->IsValid())
+            return 0;
+        else
+        {
+            ObjCISA parent_isa = superclass->GetISA();
+            m_isa_to_descriptor_cache[parent_isa] = superclass;
+            return parent_isa;
+        }
+    }
+    
+    ClassDescriptorSP descriptor(GetClassDescriptor(isa));
+    if (!descriptor.get() || !descriptor->IsValid())
+        return 0;
+    m_isa_to_descriptor_cache[isa] = descriptor;
+    ClassDescriptorSP superclass(descriptor->GetSuperclass());
+    if (!superclass.get() || !superclass->IsValid())
+        return 0;
+    ObjCISA parent_isa = superclass->GetISA();
+    m_isa_to_descriptor_cache[parent_isa] = superclass;
+    return parent_isa;
+}
+
+// TODO: should we have a transparent_kvo parameter here to say if we
+// want to replace the KVO swizzled class with the actual user-level type?
+ConstString
+ObjCLanguageRuntime::GetActualTypeName(ObjCLanguageRuntime::ObjCISA isa)
+{
+    static const ConstString g_unknown ("unknown");
+    
+    if (!IsValidISA(isa))
+        return ConstString();
+    
+    ISAToDescriptorIterator found = m_isa_to_descriptor_cache.find(isa);
+    ISAToDescriptorIterator end = m_isa_to_descriptor_cache.end();
+    
+    if (found != end && found->second)
+        return found->second->GetClassName();
+    
+    ClassDescriptorSP descriptor(GetClassDescriptor(isa));
+    if (!descriptor.get() || !descriptor->IsValid())
+        return ConstString();
+    ConstString class_name = descriptor->GetClassName();
+    if (descriptor->IsKVO())
+    {
+        ClassDescriptorSP superclass(descriptor->GetSuperclass());
+        if (!superclass.get() || !superclass->IsValid())
+            return ConstString();
+        descriptor = superclass;
+    }
+    m_isa_to_descriptor_cache[isa] = descriptor;
+    return descriptor->GetClassName();
+}