[cfe-commits] [libcxxabi] r148241 - in /libcxxabi/trunk: src/private_typeinfo.cpp src/private_typeinfo.h test/dynamic_cast14.cpp test/dynamic_cast3.cpp test/dynamic_cast5.cpp
Howard Hinnant
hhinnant at apple.com
Mon Jan 16 09:06:52 PST 2012
Author: hhinnant
Date: Mon Jan 16 11:06:51 2012
New Revision: 148241
URL: http://llvm.org/viewvc/llvm-project?rev=148241&view=rev
Log:
Comment smithing. Changed some casts from C-style to C++. And added timings to all of the tests.
Modified:
libcxxabi/trunk/src/private_typeinfo.cpp
libcxxabi/trunk/src/private_typeinfo.h
libcxxabi/trunk/test/dynamic_cast14.cpp
libcxxabi/trunk/test/dynamic_cast3.cpp
libcxxabi/trunk/test/dynamic_cast5.cpp
Modified: libcxxabi/trunk/src/private_typeinfo.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/private_typeinfo.cpp?rev=148241&r1=148240&r2=148241&view=diff
==============================================================================
--- libcxxabi/trunk/src/private_typeinfo.cpp (original)
+++ libcxxabi/trunk/src/private_typeinfo.cpp Mon Jan 16 11:06:51 2012
@@ -87,10 +87,11 @@
// __dynamic_cast
-// static_ptr: source address to be adjusted; nonnull, and since the
-// source object is polymorphic, *(void**)static_ptr is a virtual table pointer.
-// static_type: static type of the source object.
-// dst_type: destination type (the "T" in "dynamic_cast<T>(v)").
+// static_ptr: pointer to an object of type static_type; nonnull, and since the
+// object is polymorphic, *(void**)static_ptr is a virtual table pointer.
+// static_ptr is &v in the expression dynamic_cast<T>(v).
+// static_type: static type of the object pointed to by static_ptr.
+// dst_type: destination type of the cast (the "T" in "dynamic_cast<T>(v)").
// src2dst_offset: a static hint about the location of the
// source subobject with respect to the complete object;
// special negative values are:
@@ -102,20 +103,50 @@
// base type of dst_type at offset src2dst_offset from the
// origin of dst_type.
//
-// (dynamic_ptr, dynamic_type) are the run time type of the complete object and
-// a pointer to it. These can be found from static_ptr for polymorphic types.
+// (dynamic_ptr, dynamic_type) are the run time type of the complete object
+// referred to by static_ptr and a pointer to it. These can be found from
+// static_ptr for polymorphic types.
// static_type is guaranteed to be a polymorphic type.
//
-// There are two classes of dst_types:
-// 1. Those that lead to (static_ptr, static_type).
-// 2. Those that do not lead to (static_ptr, static_type).
-// If there is exactly one dst_type of type 1, and
+// (dynamic_ptr, dynamic_type) is the root of a DAG that grows upward. Each
+// node of the tree represents a base class/object of its parent (or parents) below.
+// Each node is uniquely represented by a pointer to the object, and a pointer
+// to a type_info - its type. Different nodes may have the same pointer and
+// different nodes may have the same type. But only one node has a specific
+// (pointer-value, type) pair. In C++ two objects of the same type can not
+// share the same address.
+//
+// There are two flavors of nodes which have the type dst_type:
+// 1. Those that are derived from (below) (static_ptr, static_type).
+// 2. Those that are not derived from (below) (static_ptr, static_type).
+//
+// Invariants of the DAG:
+//
+// There is at least one path from the root (dynamic_ptr, dynamic_type) to
+// the node (static_ptr, static_type). This path may or may not be public.
+// There may be more than one such path (some public some not). Such a path may
+// or may not go through a node having type dst_type.
+//
+// No node of type T appears above a node of the same type. That means that
+// there is only one node with dynamic_type. And if dynamic_type == dst_type,
+// then there is only one dst_type in the DAG.
+//
+// No node of type dst_type appears above a node of type static_type. Such
+// DAG's are possible in C++, but the compiler computes those dynamic_casts at
+// compile time, and only calls __dynamic_cast when dst_type lies below
+// static_type in the DAG.
+//
+// dst_type != static_type: The compiler computes the dynamic_cast in this case too.
+//
+// Returns:
+//
+// If there is exactly one dst_type of flavor 1, and
// If there is a public path from that dst_type to (static_ptr, static_type), or
-// If there are 0 dst_types of type 2, and there is a public path from
+// If there are 0 dst_types of flavor 2, and there is a public path from
// (dynamic_ptr, dynamic_type) to (static_ptr, static_type) and a public
// path from (dynamic_ptr, dynamic_type) to the one dst_type, then return
// a pointer to that dst_type.
-// Else if there are 0 dst_types of type 1 and exactly 1 dst_type of type 2, and
+// Else if there are 0 dst_types of flavor 1 and exactly 1 dst_type of flavor 2, and
// if there is a public path (dynamic_ptr, dynamic_type) to
// (static_ptr, static_type) and a public path from (dynamic_ptr, dynamic_type)
// to the one dst_type, then return a pointer to that one dst_type.
@@ -135,22 +166,36 @@
std::ptrdiff_t src2dst_offset)
{
// TODO: Take advantage of src2dst_offset
+
+ // Get (dynamic_ptr, dynamic_type) from static_ptr
void** vtable = *(void***)static_ptr;
- ptrdiff_t offset_to_derived = (ptrdiff_t)vtable[-2];
- const void* dynamic_ptr = (const char*)static_ptr + offset_to_derived;
- const __class_type_info* dynamic_type = (const __class_type_info*)vtable[-1];
+ ptrdiff_t offset_to_derived = reinterpret_cast<ptrdiff_t>(vtable[-2]);
+ const void* dynamic_ptr = static_cast<const char*>(static_ptr) + offset_to_derived;
+ const __class_type_info* dynamic_type = static_cast<const __class_type_info*>(vtable[-1]);
+
+ // Initialize answer to nullptr. This will be changed from the search
+ // results if a non-null answer is found. Regardless, this is what will
+ // be returned.
const void* dst_ptr = 0;
+ // Initialize info struct for this search.
__dynamic_cast_info info = {dst_type, static_ptr, static_type, src2dst_offset, 0};
+
+ // Find out if we can use a giant short cut in the search
if (dynamic_type == dst_type)
{
+ // Using giant short cut. Add that information to info.
info.number_of_dst_type = 1;
+ // Do the search
dynamic_type->search_above_dst(&info, dynamic_ptr, dynamic_ptr, public_path);
+ // Query the search.
if (info.path_dst_ptr_to_static_ptr == public_path)
dst_ptr = dynamic_ptr;
}
else
{
+ // Not using giant short cut. Do the search
dynamic_type->search_below_dst(&info, dynamic_ptr, public_path);
+ // Query the search.
switch (info.number_to_static_ptr)
{
case 0:
@@ -256,12 +301,23 @@
// above.
// If it finds a dst_type node it should search base classes using search_above_dst
// to find out if this dst_type points to (static_ptr, static_type) or not.
-// Either way, the dst_type is recorded as one of two "classes": one that does
+// Either way, the dst_type is recorded as one of two "flavors": one that does
// or does not point to (static_ptr, static_type).
// If this is neither a static_type nor a dst_type node, continue searching
// base classes above.
// All the hoopla surrounding the search code is doing nothing but looking for
-// excuses to stop the search prematurely (break out of the for-loop).
+// excuses to stop the search prematurely (break out of the for-loop):
+//
+// const Iter e = __base_info + __base_count;
+// for (Iter p = __base_info; p < e; ++p)
+// p->search_above_dst(info, current_ptr, current_ptr, path_below);
+//
+// or:
+//
+// const Iter e = __base_info + __base_count;
+// for (Iter p = __base_info; p < e; ++p)
+// p->search_below_dst(info, current_ptr, path_below);
+//
void
__vmi_class_type_info::search_below_dst(__dynamic_cast_info* info,
const void* current_ptr,
@@ -311,7 +367,7 @@
info->found_our_static_ptr = false;
info->found_any_static_type = false;
p->search_above_dst(info, current_ptr, current_ptr, public_path);
- if (info->search_done)
+ if (info->search_done)
break;
if (info->found_any_static_type)
{
@@ -657,11 +713,11 @@
ptrdiff_t offset_to_base = __offset_flags >> __offset_shift;
if (__offset_flags & __virtual_mask)
{
- char* vtable = *(char**)current_ptr;
- offset_to_base = *(ptrdiff_t*)(vtable + offset_to_base);
+ const char* vtable = *static_cast<const char*const*>(current_ptr);
+ offset_to_base = *reinterpret_cast<const ptrdiff_t*>(vtable + offset_to_base);
}
__base_type->search_above_dst(info, dst_ptr,
- (char*)current_ptr + offset_to_base,
+ static_cast<const char*>(current_ptr) + offset_to_base,
(__offset_flags & __public_mask) ?
path_below :
not_public_path);
@@ -675,11 +731,11 @@
ptrdiff_t offset_to_base = __offset_flags >> __offset_shift;
if (__offset_flags & __virtual_mask)
{
- char* vtable = *(char**)current_ptr;
- offset_to_base = *(ptrdiff_t*)(vtable + offset_to_base);
+ const char* vtable = *static_cast<const char*const*>(current_ptr);
+ offset_to_base = *reinterpret_cast<const ptrdiff_t*>(vtable + offset_to_base);
}
__base_type->search_below_dst(info,
- (char*)current_ptr + offset_to_base,
+ static_cast<const char*>(current_ptr) + offset_to_base,
(__offset_flags & __public_mask) ?
path_below :
not_public_path);
Modified: libcxxabi/trunk/src/private_typeinfo.h
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/private_typeinfo.h?rev=148241&r1=148240&r2=148241&view=diff
==============================================================================
--- libcxxabi/trunk/src/private_typeinfo.h (original)
+++ libcxxabi/trunk/src/private_typeinfo.h Mon Jan 16 11:06:51 2012
@@ -57,19 +57,21 @@
struct __dynamic_cast_info
{
- // const data supplied to the search
+// 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
+// Data that represents the answer:
// 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;
+
+ // The following three paths are either unknown, public_path or not_public_path.
// 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)
@@ -78,11 +80,15 @@
// 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;
- //
+
+// Data that helps stop the search before the entire tree is searched:
+
+ // is_dst_type_derived_from_static_type is either unknown, yes or no.
int is_dst_type_derived_from_static_type;
// Number of dst_type in tree. If 0, then that means unknown.
int number_of_dst_type;
Modified: libcxxabi/trunk/test/dynamic_cast14.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/test/dynamic_cast14.cpp?rev=148241&r1=148240&r2=148241&view=diff
==============================================================================
--- libcxxabi/trunk/test/dynamic_cast14.cpp (original)
+++ libcxxabi/trunk/test/dynamic_cast14.cpp Mon Jan 16 11:06:51 2012
@@ -2172,9 +2172,18 @@
} // t3
+#include <chrono>
+#include <iostream>
+
int main()
{
+ typedef std::chrono::high_resolution_clock Clock;
+ typedef Clock::time_point time_point;
+ typedef std::chrono::duration<double, std::micro> NS;
+ time_point t0 = Clock::now();
t1::test();
t2::test();
t3::test();
+ time_point t1 = Clock::now();
+ std::cout << NS(t1-t0).count() << " microseconds\n";
}
Modified: libcxxabi/trunk/test/dynamic_cast3.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/test/dynamic_cast3.cpp?rev=148241&r1=148240&r2=148241&view=diff
==============================================================================
--- libcxxabi/trunk/test/dynamic_cast3.cpp (original)
+++ libcxxabi/trunk/test/dynamic_cast3.cpp Mon Jan 16 11:06:51 2012
@@ -2406,8 +2406,15 @@
} // t41
+#include <chrono>
+#include <iostream>
+
int main()
{
+ typedef std::chrono::high_resolution_clock Clock;
+ typedef Clock::time_point time_point;
+ typedef std::chrono::duration<double, std::micro> NS;
+ time_point t0 = Clock::now();
t1::test();
t2::test();
t3::test();
@@ -2449,4 +2456,6 @@
t39::test();
t40::test();
t41::test();
+ time_point t1 = Clock::now();
+ std::cout << NS(t1-t0).count() << " microseconds\n";
}
Modified: libcxxabi/trunk/test/dynamic_cast5.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/test/dynamic_cast5.cpp?rev=148241&r1=148240&r2=148241&view=diff
==============================================================================
--- libcxxabi/trunk/test/dynamic_cast5.cpp (original)
+++ libcxxabi/trunk/test/dynamic_cast5.cpp Mon Jan 16 11:06:51 2012
@@ -1298,8 +1298,15 @@
} // t9
+#include <chrono>
+#include <iostream>
+
int main()
{
+ typedef std::chrono::high_resolution_clock Clock;
+ typedef Clock::time_point time_point;
+ typedef std::chrono::duration<double, std::micro> NS;
+ time_point t0 = Clock::now();
t1::test();
t2::test();
t3::test();
@@ -1309,4 +1316,6 @@
t7::test();
t8::test();
t9::test();
+ time_point t1 = Clock::now();
+ std::cout << NS(t1-t0).count() << " microseconds\n";
}
More information about the cfe-commits
mailing list