mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-29 01:26:07 +00:00
Fixed a couple of bugs, updated many comments, and am including a comprehensive test for when there are only 3 types in place. I need to do something similar for 4 and maybe more types, but I'm not sure how comprehensive I can make the test at 4 and above types.
llvm-svn: 148038
This commit is contained in:
parent
b02c5e9356
commit
af07bfdb67
@ -62,6 +62,11 @@ __class_type_info::~__class_type_info()
|
|||||||
// __dynamic_cast notes:
|
// __dynamic_cast notes:
|
||||||
// Up or above refers to base classes and base objects.
|
// Up or above refers to base classes and base objects.
|
||||||
// Down or below refers to derived classes/objects.
|
// Down or below refers to derived classes/objects.
|
||||||
|
// There are two search algorithms, search1 and search2.
|
||||||
|
// search1 is nothing but an optimization of search2 for a special case.
|
||||||
|
// Take it away and things should still work correctly.
|
||||||
|
// Both algorithms return 1 if the search should continue below the current node
|
||||||
|
// and 0 if the search should be aborted (because the answer is now known).
|
||||||
|
|
||||||
// search1 is a search algorithm used by __dynamic_cast.
|
// search1 is a search algorithm used by __dynamic_cast.
|
||||||
// If a static_type is found
|
// If a static_type is found
|
||||||
@ -73,9 +78,34 @@ __class_type_info::~__class_type_info()
|
|||||||
// Else
|
// Else
|
||||||
// Continue search above and below this node.
|
// Continue search above and below this node.
|
||||||
|
|
||||||
|
// search2 is a search algorithm used by __dynamic_cast.
|
||||||
|
// if this is a dst_type
|
||||||
|
// if this node 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 (ptr, dst_type) before.
|
||||||
|
// Record the path to get here in path_dynamic_ptr_to_dst_ptr.
|
||||||
|
// For each base 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.
|
||||||
|
// Continue searching both above and below this node.
|
||||||
|
// 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.
|
||||||
|
|
||||||
// __class_type_info::search1
|
// __class_type_info::search1
|
||||||
// There are no nodes to search above this node
|
// There are no nodes to search above this node
|
||||||
// Returns: 1 if search should be continued, otherwise 0
|
|
||||||
int
|
int
|
||||||
__class_type_info::search1(__dynamic_cast_info* info, const void* dynamic_ptr,
|
__class_type_info::search1(__dynamic_cast_info* info, const void* dynamic_ptr,
|
||||||
int path_below) const
|
int path_below) const
|
||||||
@ -95,30 +125,8 @@ __class_type_info::search1(__dynamic_cast_info* info, const void* dynamic_ptr,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// search2 is a search algorithm used by __dynamic_cast.
|
// __class_type_info::search2
|
||||||
// if this is a dst_type
|
// There are no nodes to search above this node
|
||||||
// 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
|
int
|
||||||
__class_type_info::search2(__dynamic_cast_info* info, const void* dynamic_ptr,
|
__class_type_info::search2(__dynamic_cast_info* info, const void* dynamic_ptr,
|
||||||
int path_below) const
|
int path_below) const
|
||||||
@ -160,6 +168,9 @@ __si_class_type_info::~__si_class_type_info()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// __si_class_type_info::search1
|
||||||
|
// There is one node to search above this node. The path to it is public
|
||||||
|
// and dynamic_ptr needs no adjustment in moving to that node.
|
||||||
int
|
int
|
||||||
__si_class_type_info::search1(__dynamic_cast_info* info, const void* dynamic_ptr,
|
__si_class_type_info::search1(__dynamic_cast_info* info, const void* dynamic_ptr,
|
||||||
int path_below) const
|
int path_below) const
|
||||||
@ -179,6 +190,9 @@ __si_class_type_info::search1(__dynamic_cast_info* info, const void* dynamic_ptr
|
|||||||
return __base_type->search1(info, dynamic_ptr, path_below);
|
return __base_type->search1(info, dynamic_ptr, path_below);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// __si_class_type_info::search2
|
||||||
|
// There is one node to search above this node. The path to it is public
|
||||||
|
// and dynamic_ptr needs no adjustment in moving to that node.
|
||||||
int
|
int
|
||||||
__si_class_type_info::search2(__dynamic_cast_info* info, const void* dynamic_ptr,
|
__si_class_type_info::search2(__dynamic_cast_info* info, const void* dynamic_ptr,
|
||||||
int path_below) const
|
int path_below) const
|
||||||
@ -237,6 +251,11 @@ __vmi_class_type_info::~__vmi_class_type_info()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// __vmi_class_type_info::search1
|
||||||
|
// There are one or more nodes to search above this node. The path to it
|
||||||
|
// may be public or not and the dynamic_ptr may need to be adjusted. Both
|
||||||
|
// of these details are handled by a pseudo-node in __base_class_type_info
|
||||||
|
// which has no type associated with it.
|
||||||
int
|
int
|
||||||
__vmi_class_type_info::search1(__dynamic_cast_info* info, const void* dynamic_ptr,
|
__vmi_class_type_info::search1(__dynamic_cast_info* info, const void* dynamic_ptr,
|
||||||
int path_below) const
|
int path_below) const
|
||||||
@ -263,21 +282,11 @@ __vmi_class_type_info::search1(__dynamic_cast_info* info, const void* dynamic_pt
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
// __vmi_class_type_info::search2
|
||||||
__base_class_type_info::search1(__dynamic_cast_info* info, const void* dynamic_ptr,
|
// There are one or more nodes to search above this node. The path to it
|
||||||
int path_below) const
|
// may be public or not and the dynamic_ptr may need to be adjusted. Both
|
||||||
{
|
// of these details are handled by a pseudo-node in __base_class_type_info
|
||||||
ptrdiff_t offset_to_base = __offset_flags >> __offset_shift;
|
// which has no type associated with it.
|
||||||
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
|
int
|
||||||
__vmi_class_type_info::search2(__dynamic_cast_info* info, const void* dynamic_ptr,
|
__vmi_class_type_info::search2(__dynamic_cast_info* info, const void* dynamic_ptr,
|
||||||
int path_below) const
|
int path_below) const
|
||||||
@ -297,10 +306,10 @@ __vmi_class_type_info::search2(__dynamic_cast_info* info, const void* dynamic_pt
|
|||||||
for (Iter p = __base_info, e = __base_info + __base_count; p < e; ++p)
|
for (Iter p = __base_info, e = __base_info + __base_count; p < e; ++p)
|
||||||
{
|
{
|
||||||
info->above_dst_ptr = true;
|
info->above_dst_ptr = true;
|
||||||
int r = p->search2(info, dynamic_ptr, public_path);
|
// Only a dst_type can abort the search, and one can't be
|
||||||
|
// above here. So it is safe to ignore return.
|
||||||
|
(void)p->search2(info, dynamic_ptr, public_path);
|
||||||
info->above_dst_ptr = false;
|
info->above_dst_ptr = false;
|
||||||
if (r == 0)
|
|
||||||
return 0;
|
|
||||||
if (info->found_static_ptr)
|
if (info->found_static_ptr)
|
||||||
{
|
{
|
||||||
info->found_static_ptr = false;
|
info->found_static_ptr = false;
|
||||||
@ -339,6 +348,35 @@ __vmi_class_type_info::search2(__dynamic_cast_info* info, const void* dynamic_pt
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// __base_class_type_info::search1
|
||||||
|
// This is a psuedo-node which does nothing but adjust the path access and
|
||||||
|
// dynamic_ptr prior to calling the base node above.
|
||||||
|
// The dynamic_ptr adjustment depends upon whether or not this node is marked
|
||||||
|
// virtual.
|
||||||
|
// If the path up is public, no change is made to the path (it may already be
|
||||||
|
// marked private from below). If the path up is private, it is forced so.
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// __base_class_type_info::search2
|
||||||
|
// This is a psuedo-node which does nothing but adjust the path access and
|
||||||
|
// dynamic_ptr prior to calling the base node above.
|
||||||
|
// The dynamic_ptr adjustment depends upon whether or not this node is marked
|
||||||
|
// virtual.
|
||||||
|
// If the path up is public, no change is made to the path (it may already be
|
||||||
|
// marked private from below). If the path up is private, it is forced so.
|
||||||
int
|
int
|
||||||
__base_class_type_info::search2(__dynamic_cast_info* info, const void* dynamic_ptr,
|
__base_class_type_info::search2(__dynamic_cast_info* info, const void* dynamic_ptr,
|
||||||
int path_below) const
|
int path_below) const
|
||||||
@ -347,7 +385,7 @@ __base_class_type_info::search2(__dynamic_cast_info* info, const void* dynamic_p
|
|||||||
if (__offset_flags & __virtual_mask)
|
if (__offset_flags & __virtual_mask)
|
||||||
{
|
{
|
||||||
char* vtable = *(char**)dynamic_ptr;
|
char* vtable = *(char**)dynamic_ptr;
|
||||||
offset_to_base = (ptrdiff_t)vtable[offset_to_base];
|
offset_to_base = *(ptrdiff_t*)(vtable + offset_to_base);
|
||||||
}
|
}
|
||||||
return __base_type->search2(info, (char*)dynamic_ptr + offset_to_base,
|
return __base_type->search2(info, (char*)dynamic_ptr + offset_to_base,
|
||||||
(__offset_flags & __public_mask) ? path_below :
|
(__offset_flags & __public_mask) ? path_below :
|
||||||
@ -378,7 +416,7 @@ __base_class_type_info::display(const void* obj) const
|
|||||||
if (__offset_flags & __virtual_mask)
|
if (__offset_flags & __virtual_mask)
|
||||||
{
|
{
|
||||||
char* vtable = *(char**)obj;
|
char* vtable = *(char**)obj;
|
||||||
offset_to_base = (ptrdiff_t)vtable[offset_to_base];
|
offset_to_base = *(ptrdiff_t*)(vtable + offset_to_base);
|
||||||
}
|
}
|
||||||
__base_type->display((char*)obj + offset_to_base);
|
__base_type->display((char*)obj + offset_to_base);
|
||||||
}
|
}
|
||||||
@ -426,7 +464,7 @@ __pointer_to_member_type_info::~__pointer_to_member_type_info()
|
|||||||
// ambiguity, or
|
// ambiguity, or
|
||||||
// 3. nullptr
|
// 3. nullptr
|
||||||
// Knowns:
|
// Knowns:
|
||||||
// (dynamic_ptr, dynamic_type) can be derived from static_ptr.
|
// (dynamic_ptr, dynamic_type) can be extracted from static_ptr.
|
||||||
// dynamic_ptr is a pointer to the complete run time object.
|
// dynamic_ptr is a pointer to the complete run time object.
|
||||||
// dynamic_type is the type of 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
|
// The type hierarchy is a DAG rooted at (dynamic_ptr, dynamic_type) and
|
||||||
@ -448,6 +486,27 @@ __pointer_to_member_type_info::~__pointer_to_member_type_info()
|
|||||||
// (dynamic_ptr, dynamic_type) to (static_ptr, static_type),
|
// (dynamic_ptr, dynamic_type) to (static_ptr, static_type),
|
||||||
// else returns nullptr.
|
// else returns nullptr.
|
||||||
// This check is purely an optimization and does not impact correctness.
|
// This check is purely an optimization and does not impact correctness.
|
||||||
|
// Algorithm:
|
||||||
|
// Extract (dynamic_ptr, dynamic_type) from static_ptr.
|
||||||
|
// If dynamic_type == dst_type
|
||||||
|
// If there is a public path from (dynamic_ptr, dynamic_type) to
|
||||||
|
// (static_ptr, static_type), return dynamic_ptr else return nullptr.
|
||||||
|
// Else dynamic_type != dst_type
|
||||||
|
// If there is a single dst_type derived (below) (static_ptr, static_type)
|
||||||
|
// If the path from that unique dst_type to (static_ptr, static_type)
|
||||||
|
// is public, return a pointer to that dst_type else return nullptr.
|
||||||
|
// Else if there are no dst_type's which don't point to (static_ptr, static_type)
|
||||||
|
// and if there is a pubic path from (dynamic_ptr, dynamic_type) to
|
||||||
|
// (static_ptr, static_type) and a public path from (dynamic_ptr, dynamic_type)
|
||||||
|
// to the single dst_type, then return a pointer to that dst_type,
|
||||||
|
// Else return nullptr.
|
||||||
|
// Else if there are no dst_type derived (below) (static_ptr, static_type)
|
||||||
|
// And if there is a single dst_type base of (above)
|
||||||
|
// (dynamic_ptr, dynamic_type), and if that single dst_type has a
|
||||||
|
// public path to it. And if there is a public path
|
||||||
|
// from (dynamic_ptr, dynamic_type) to (static_ptr, static_type)
|
||||||
|
// then return a pointer to that single dst_type, else return nullptr.
|
||||||
|
// Else return nullptr.
|
||||||
extern "C"
|
extern "C"
|
||||||
void*
|
void*
|
||||||
__dynamic_cast(const void* static_ptr,
|
__dynamic_cast(const void* static_ptr,
|
||||||
@ -487,7 +546,13 @@ dynamic_type->display(dynamic_ptr);
|
|||||||
dst_ptr = info.dst_ptr_not_leading_to_static_ptr;
|
dst_ptr = info.dst_ptr_not_leading_to_static_ptr;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
if (info.path_dst_ptr_to_static_ptr == public_path)
|
if (info.path_dst_ptr_to_static_ptr == public_path ||
|
||||||
|
(
|
||||||
|
info.number_to_dst_ptr == 0 &&
|
||||||
|
info.path_dynamic_ptr_to_static_ptr == public_path &&
|
||||||
|
info.path_dynamic_ptr_to_dst_ptr == public_path
|
||||||
|
)
|
||||||
|
)
|
||||||
dst_ptr = info.dst_ptr_leading_to_static_ptr;
|
dst_ptr = info.dst_ptr_leading_to_static_ptr;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
2453
libcxxabi/test/dynamic_cast3.cpp
Normal file
2453
libcxxabi/test/dynamic_cast3.cpp
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user