[cfe-commits] [libcxxabi] r147981 - in /libcxxabi/trunk/src: private_typeinfo.cpp private_typeinfo.h

Howard Hinnant hhinnant at apple.com
Wed Jan 11 15:49:18 PST 2012


Author: hhinnant
Date: Wed Jan 11 17:49:18 2012
New Revision: 147981

URL: http://llvm.org/viewvc/llvm-project?rev=147981&view=rev
Log:
Initial implementaiton of __dynamic_cast.  There is still lots of debugging code in here that needs to be stripped out.  And many, many unit tests need to be written.  And comments and probably code cleanliness needs to be improved.  But I *think* the basic algorithm is sound.  There also may still be some oportunities for algorithm optimization, I'm not positive.

Modified:
    libcxxabi/trunk/src/private_typeinfo.cpp
    libcxxabi/trunk/src/private_typeinfo.h

Modified: libcxxabi/trunk/src/private_typeinfo.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/private_typeinfo.cpp?rev=147981&r1=147980&r2=147981&view=diff
==============================================================================
--- libcxxabi/trunk/src/private_typeinfo.cpp (original)
+++ libcxxabi/trunk/src/private_typeinfo.cpp Wed Jan 11 17:49:18 2012
@@ -9,7 +9,9 @@
 
 #include "private_typeinfo.h"
 
+// temporary headers
 #include <iostream>
+#include <cassert>
 
 namespace std
 {
@@ -57,6 +59,95 @@
 {
 }
 
+// __dynamic_cast notes:
+// Up or above refers to base classes and base objects.
+// Down or below refers to derived classes/objects.
+
+// search1 is a search algorithm used by __dynamic_cast.
+// If a static_type is found
+//     If dynamic_ptr == static_ptr
+//         Record the path to get here.
+//         if the path to get here is public
+//             stop search
+//     Otherwise continue search only below this node
+// Else
+//     Continue search above and below this node.
+
+// __class_type_info::search1
+// There are no nodes to search above this node
+// Returns:  1 if search should be continued, otherwise 0
+int
+__class_type_info::search1(__dynamic_cast_info* info, const void* dynamic_ptr,
+                           int path_below) const
+{
+    if (this == info->static_type)
+    {
+        if (dynamic_ptr == info->static_ptr)
+        {
+            if (path_below == public_path)
+            {
+                info->path_dynamic_ptr_to_static_ptr = public_path;
+                return 0;
+            }
+            info->path_dynamic_ptr_to_static_ptr = not_public_path;
+        }
+    }
+    return 1;
+}
+
+// search2 is a search algorithm used by __dynamic_cast.
+// if this is a dst_type
+//     if this has already been classified then
+//        If the path to get here is public, overwrite existing path_dynamic_ptr_to_dst_ptr.
+//     else we haven't been to this dst_type before.
+//        Record the path to get here in path_dynamic_ptr_to_dst_ptr.
+//        Is (static_ptr, static_type) above this dst_type?
+//           Yes:
+//             Record it as dst_ptr_leading_to_static_ptr and increment the
+//                number of such recordings.
+//             If this is not the first of such recordings, then stop searching.
+//             Otherwise continue searching both above and below this node.
+//           No:
+//             record it as dst_ptr_not_leading_to_static_ptr and increment
+//                 the number of such recordings.
+// else if this is a static_type
+//     if this is *our* static_type
+//        if we found it above a dst_type, record the path from the dst_type
+//        else record the path from the dynamic_type being careful not to overwrite a
+//           previous public path in this latter case.
+//        Record that we found our static_type.
+//     Continue searching only below this node
+// else 
+//     Continue searching above and below this node.
+int
+__class_type_info::search2(__dynamic_cast_info* info, const void* dynamic_ptr,
+                           int path_below) const
+{
+    if (this == info->dst_type)
+    {
+        if (dynamic_ptr == info->dst_ptr_not_leading_to_static_ptr)
+        {
+            if (path_below == public_path)
+                info->path_dynamic_ptr_to_dst_ptr = public_path;
+        }
+        else
+        {
+            info->path_dynamic_ptr_to_dst_ptr = path_below;
+            info->dst_ptr_not_leading_to_static_ptr = dynamic_ptr;
+            info->number_to_dst_ptr += 1;
+        }
+    }
+    else if (this == info->static_type && dynamic_ptr == info->static_ptr)
+    {
+        if (info->above_dst_ptr)
+            info->path_dst_ptr_to_static_ptr = path_below;
+        else if (info->path_dynamic_ptr_to_static_ptr != public_path)
+            info->path_dynamic_ptr_to_static_ptr = path_below;
+        info->found_static_ptr = true;
+    }
+    return 1;
+}
+
 void
 __class_type_info::display(const void* obj) const
 {
@@ -69,6 +160,70 @@
 {
 }
 
+int
+__si_class_type_info::search1(__dynamic_cast_info* info, const void* dynamic_ptr,
+                              int path_below) const
+{
+    if (this == info->static_type)
+    {
+        if (dynamic_ptr == info->static_ptr)
+        {
+            if (path_below == public_path)
+            {
+                info->path_dynamic_ptr_to_static_ptr = public_path;
+                return 0;
+            }
+        }
+        return 1;
+    }
+    return __base_type->search1(info, dynamic_ptr, path_below);
+}
+
+int
+__si_class_type_info::search2(__dynamic_cast_info* info, const void* dynamic_ptr,
+                              int path_below) const
+{
+    if (this == info->dst_type)
+    {
+        if (dynamic_ptr == info->dst_ptr_leading_to_static_ptr ||
+            dynamic_ptr == info->dst_ptr_not_leading_to_static_ptr)
+        {
+            if (path_below == public_path)
+                info->path_dynamic_ptr_to_dst_ptr = public_path;
+        }
+        else
+        {
+            info->path_dynamic_ptr_to_dst_ptr = path_below;
+            info->above_dst_ptr = true;
+            (void)__base_type->search2(info, dynamic_ptr, public_path);
+            info->above_dst_ptr = false;
+            if (info->found_static_ptr)
+            {
+                info->found_static_ptr = false;
+                info->dst_ptr_leading_to_static_ptr = dynamic_ptr;
+                info->number_to_static_ptr += 1;
+                return info->number_to_static_ptr == 1;
+            }
+            info->dst_ptr_not_leading_to_static_ptr = dynamic_ptr;
+            info->number_to_dst_ptr += 1;
+        }
+        return 1;
+    }
+    else if (this == info->static_type)
+    {
+        if (dynamic_ptr == info->static_ptr)
+        {
+            if (info->above_dst_ptr)
+                info->path_dst_ptr_to_static_ptr = path_below;
+            else if (info->path_dynamic_ptr_to_static_ptr != public_path)
+                info->path_dynamic_ptr_to_static_ptr = path_below;
+            info->found_static_ptr = true;
+        }
+        return 1;
+    }
+    return __base_type->search2(info, dynamic_ptr, path_below);
+}
+
 void
 __si_class_type_info::display(const void* obj) const
 {
@@ -82,6 +237,123 @@
 {
 }
 
+int
+__vmi_class_type_info::search1(__dynamic_cast_info* info, const void* dynamic_ptr,
+                               int path_below) const
+{
+    typedef const __base_class_type_info* Iter;
+    if (this == info->static_type)
+    {
+        if (dynamic_ptr == info->static_ptr)
+        {
+            if (path_below == public_path)
+            {
+                info->path_dynamic_ptr_to_static_ptr = public_path;
+                return 0;
+            }
+        }
+        return 1;
+    }
+    for (Iter p = __base_info, e = __base_info + __base_count; p < e; ++p)
+    {
+        int r = p->search1(info, dynamic_ptr, path_below);
+        if (r == 0)
+            return 0;
+    }
+    return 1;
+}
+
+int
+__base_class_type_info::search1(__dynamic_cast_info* info, const void* dynamic_ptr,
+                                int path_below) const
+{
+    ptrdiff_t offset_to_base = __offset_flags >> __offset_shift;
+    if (__offset_flags & __virtual_mask)
+    {
+        char* vtable = *(char**)dynamic_ptr;
+        offset_to_base = (ptrdiff_t)vtable[offset_to_base];
+    }
+    return __base_type->search1(info, (char*)dynamic_ptr + offset_to_base,
+                                (__offset_flags & __public_mask) ? path_below :
+                                                                   not_public_path);
+}
+
+int
+__vmi_class_type_info::search2(__dynamic_cast_info* info, const void* dynamic_ptr,
+                               int path_below) const
+{
+    typedef const __base_class_type_info* Iter;
+    if (this == info->dst_type)
+    {
+        if (dynamic_ptr == info->dst_ptr_leading_to_static_ptr ||
+            dynamic_ptr == info->dst_ptr_not_leading_to_static_ptr)
+        {
+            if (path_below == public_path)
+                info->path_dynamic_ptr_to_dst_ptr = public_path;
+        }
+        else
+        {
+            info->path_dynamic_ptr_to_dst_ptr = path_below;
+            for (Iter p = __base_info, e = __base_info + __base_count; p < e; ++p)
+            {
+                info->above_dst_ptr = true;
+                int r = p->search2(info, dynamic_ptr, public_path);
+                info->above_dst_ptr = false;
+                if (r == 0)
+                    return 0;
+                if (info->found_static_ptr)
+                {
+                    info->found_static_ptr = false;
+                    info->dst_ptr_leading_to_static_ptr = dynamic_ptr;
+                    info->number_to_static_ptr += 1;
+                    if (info->number_to_static_ptr != 1)
+                        return 0;
+                }
+                else
+                {
+                    info->dst_ptr_not_leading_to_static_ptr = dynamic_ptr;
+                    info->number_to_dst_ptr += 1;
+                }
+            }
+        }
+        return 1;
+    }
+    else if (this == info->static_type)
+    {
+        if (dynamic_ptr == info->static_ptr)
+        {
+            if (info->above_dst_ptr)
+                info->path_dst_ptr_to_static_ptr = path_below;
+            else if (info->path_dynamic_ptr_to_static_ptr != public_path)
+                info->path_dynamic_ptr_to_static_ptr = path_below;
+            info->found_static_ptr = true;
+        }
+        return 1;
+    }
+    for (Iter p = __base_info, e = __base_info + __base_count; p < e; ++p)
+    {
+        int r = p->search2(info, dynamic_ptr, path_below);
+        if (r == 0)
+            return 0;
+    }
+    return 1;
+}
+
+int
+__base_class_type_info::search2(__dynamic_cast_info* info, const void* dynamic_ptr,
+                                int path_below) const
+{
+    ptrdiff_t offset_to_base = __offset_flags >> __offset_shift;
+    if (__offset_flags & __virtual_mask)
+    {
+        char* vtable = *(char**)dynamic_ptr;
+        offset_to_base = (ptrdiff_t)vtable[offset_to_base];
+    }
+    return __base_type->search2(info, (char*)dynamic_ptr + offset_to_base,
+                                (__offset_flags & __public_mask) ? path_below :
+                                                                   not_public_path);
+}
+
 void
 __vmi_class_type_info::display(const void* obj) const
 {
@@ -151,12 +423,31 @@
 //    2.  dynamic_ptr adjusted from static_ptr given a public path from
 //        (static_ptr, static_type) to (dynamic_ptr, dynamic_type) and also
 //        a public path from (dynamic_ptr, dynamic_type) to dst_type without
-//        ambiguity.
-// Things I think I know:
-//     This is a DAG rooted at dynamic_type and going up.
-//     Don't care about anything above static_type.
-//     There can be only one dynamic_type and it is at the root.
-//     A dst_type can never appear above another dst_type.
+//        ambiguity, or
+//    3.  nullptr
+// Knowns:
+//     (dynamic_ptr, dynamic_type) can be derived from static_ptr.
+//     dynamic_ptr is a pointer to the complete run time object.
+//     dynamic_type is the type of the complete run time object.
+//     The type hierarchy is a DAG rooted at (dynamic_ptr, dynamic_type) and
+//     traveling up.  Each node represents a distinct sub-object and is
+//     uniquely identified by a (const void*, const __class_type_info*) pair.
+//     __dynamic_cast is not called if dst_type == static_type, or if dst_type
+//     appears as a node above (static_ptr, static_type), or if static_ptr is
+//     nullptr.  In these cases the compiler already knows the answer.
+//     So if dst_type appears in the DAG, it appears at the root
+//     (dst_type == dynamic_type) or between the root and any static_types.
+//     No type can appear above a node of the same type in the DAG.  Thus
+//     there is only one node with type dynamic_type.
+//     A node can appear above more than one node, as well as below more than
+//     one node.
+//     If dst_type == dynamic_type then there is only one dst_type in the
+//        DAG and cases 1 and 2 collapse to the same degenerate case.  And
+//        this degenerate case is easier/faster to search:
+//        Returns dynamic_ptr if there exists a public path from
+//           (dynamic_ptr, dynamic_type) to (static_ptr, static_type),
+//           else returns nullptr.
+//        This check is purely an optimization and does not impact correctness.
 extern "C"
 void*
 __dynamic_cast(const void* static_ptr,
@@ -175,7 +466,33 @@
 std::cout << "dynamic_ptr = " << dynamic_ptr << '\n';
 std::cout << "dynamic_type = " << dynamic_type << '\n';
 dynamic_type->display(dynamic_ptr);
-    return 0;
+
+    const void* dst_ptr = 0;
+    __dynamic_cast_info info = {dst_type, static_ptr, static_type, src2dst_offset, 0};
+    if (dynamic_type == dst_type)
+    {
+        (void)dynamic_type->search1(&info, dynamic_ptr, public_path);
+        if (info.path_dynamic_ptr_to_static_ptr == public_path)
+            dst_ptr = dynamic_ptr;
+    }
+    else
+    {
+        (void)dynamic_type->search2(&info, dynamic_ptr, public_path);
+        switch (info.number_to_static_ptr)
+        {
+        case 0:
+            if (info.number_to_dst_ptr == 1 &&
+                    info.path_dynamic_ptr_to_static_ptr == public_path &&
+                    info.path_dynamic_ptr_to_dst_ptr == public_path)
+                dst_ptr = info.dst_ptr_not_leading_to_static_ptr;
+            break;
+        case 1:
+            if (info.path_dst_ptr_to_static_ptr == public_path)
+                dst_ptr = info.dst_ptr_leading_to_static_ptr;
+            break;
+        }
+    }
+    return const_cast<void*>(dst_ptr);
 }
 
 }  // __cxxabiv1

Modified: libcxxabi/trunk/src/private_typeinfo.h
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/private_typeinfo.h?rev=147981&r1=147980&r2=147981&view=diff
==============================================================================
--- libcxxabi/trunk/src/private_typeinfo.h (original)
+++ libcxxabi/trunk/src/private_typeinfo.h Wed Jan 11 17:49:18 2012
@@ -11,6 +11,7 @@
 #define __PRIVATE_TYPEINFO_H_
 
 #include <typeinfo>
+#include <cstddef>
 
 namespace __cxxabiv1
 {
@@ -43,6 +44,49 @@
     virtual ~__enum_type_info();
 };
 
+enum
+{
+    unknown = 0,
+    public_path,
+    not_public_path
+};
+
+class __class_type_info;
+
+struct __dynamic_cast_info
+{
+    // const data supplied to the search
+
+    const __class_type_info* const dst_type;
+    const void* const static_ptr;
+    const __class_type_info* const static_type;
+    const std::ptrdiff_t src2dst_offset;
+
+    // non-const data learned during the search
+
+    // pointer to a dst_type which has (static_ptr, static_type) above it
+    const void* dst_ptr_leading_to_static_ptr;
+    // pointer to a dst_type which does not have (static_ptr, static_type) above it
+    const void* dst_ptr_not_leading_to_static_ptr;
+    // access of path from dst_ptr_leading_to_static_ptr to (static_ptr, static_type)
+    int path_dst_ptr_to_static_ptr;
+    // access of path from (dynamic_ptr, dynamic_type) to (static_ptr, static_type)
+    //    when there is no dst_type along the path
+    int path_dynamic_ptr_to_static_ptr;
+    // access of path from (dynamic_ptr, dynamic_type) to dst_type
+    //    (not used if there is a (static_ptr, static_type) above a dst_type).
+    int path_dynamic_ptr_to_dst_ptr;
+    // Number of dst_types below (static_ptr, static_type)
+    int number_to_static_ptr;
+    // Number of dst_types not below (static_ptr, static_type)
+    int number_to_dst_ptr;
+    // true when the search is above a dst_type, else false
+    bool above_dst_ptr;
+    // communicates to a dst_type node that (static_ptr, static_type) was found
+    //    above it.
+    bool found_static_ptr;
+};
+
 // Has no base class
 class __class_type_info
     : public std::type_info
@@ -50,6 +94,8 @@
 public:
     virtual ~__class_type_info();
 
+    virtual int search1(__dynamic_cast_info*, const void*, int) const;
+    virtual int search2(__dynamic_cast_info*, const void*, int) const;
     virtual void display(const void* obj) const;
 };
 
@@ -62,6 +108,8 @@
 
     virtual ~__si_class_type_info();
 
+    virtual int search1(__dynamic_cast_info*, const void*, int) const;
+    virtual int search2(__dynamic_cast_info*, const void*, int) const;
     virtual void display(const void* obj) const;
 };
 
@@ -78,6 +126,8 @@
         __offset_shift = 8
     };
 
+    int search1(__dynamic_cast_info*, const void*, int) const;
+    int search2(__dynamic_cast_info*, const void*, int) const;
     void display(const void* obj) const;
 };
 
@@ -100,6 +150,8 @@
 
     virtual ~__vmi_class_type_info();
 
+    virtual int search1(__dynamic_cast_info*, const void*, int) const;
+    virtual int search2(__dynamic_cast_info*, const void*, int) const;
     virtual void display(const void* obj) const;
 };
 





More information about the cfe-commits mailing list