dynamic_cast.cc revision 227983
1#include "typeinfo.h"
2#include <stdio.h>
3
4using namespace ABI_NAMESPACE;
5
6/**
7 * Vtable header.
8 */
9struct vtable_header
10{
11	/** Offset of the leaf object. */
12	ptrdiff_t leaf_offset;
13	/** Type of the object. */
14	const __class_type_info *type;
15};
16
17/**
18 * Simple macro that does pointer arithmetic in bytes but returns a value of
19 * the same type as the original.
20 */
21#define ADD_TO_PTR(x, off) (__typeof__(x))(((char*)x) + off)
22
23bool __class_type_info::can_cast_to(const struct __class_type_info *other) const
24{
25    return this == other;
26}
27
28void *__class_type_info::cast_to(void *obj, const struct __class_type_info *other) const
29{
30	if (this == other)
31	{
32		return obj;
33	}
34	return 0;
35}
36
37
38bool __si_class_type_info::can_cast_to(const struct __class_type_info *other) const
39{
40    return this == other || __base_type->can_cast_to(other);
41}
42
43void *__si_class_type_info::cast_to(void *obj, const struct __class_type_info *other) const
44{
45	if (this == other)
46	{
47		return obj;
48	}
49	return __base_type->cast_to(obj, other);
50}
51
52
53bool __vmi_class_type_info::can_cast_to(const struct __class_type_info *other) const
54{
55	if (this == other)
56	{
57		return true;
58	}
59	for (unsigned int i=0 ; i<__base_count ; i++)
60	{
61		const __base_class_type_info *info = &__base_info[i];
62        if(info->isPublic() && info->__base_type->can_cast_to(other))
63        {
64            return true;
65        }
66	}
67	return false;
68}
69
70void *__vmi_class_type_info::cast_to(void *obj, const struct __class_type_info *other) const
71{
72	if (this == other)
73	{
74		return obj;
75	}
76	for (unsigned int i=0 ; i<__base_count ; i++)
77	{
78		const __base_class_type_info *info = &__base_info[i];
79		ptrdiff_t offset = info->offset();
80		// If this is a virtual superclass, the offset is stored in the
81		// object's vtable at the offset requested; 2.9.5.6.c:
82		//
83		// 'For a non-virtual base, this is the offset in the object of the
84		// base subobject. For a virtual base, this is the offset in the
85		// virtual table of the virtual base offset for the virtual base
86		// referenced (negative).'
87
88		if (info->isVirtual())
89		{
90			// Object's vtable
91			ptrdiff_t *off = *(ptrdiff_t**)obj;
92			// Offset location in vtable
93			off = ADD_TO_PTR(off, offset);
94			offset = *off;
95		}
96		void *cast = ADD_TO_PTR(obj, offset);
97
98		if (info->__base_type == other)
99		{
100			return cast;
101		}
102		if ((cast = info->__base_type->cast_to(cast, other)))
103		{
104			return cast;
105		}
106	}
107	return 0;
108}
109
110/**
111 * ABI function used to implement the dynamic_cast<> operator.  Some cases of
112 * this operator are implemented entirely in the compiler (e.g. to void*).
113 * This function implements the dynamic casts of the form dynamic_cast<T>(v).
114 * This will be translated to a call to this function with the value v as the
115 * first argument.  The type id of the static type of v is the second argument
116 * and the type id of the destination type (T) is the third argument.
117 *
118 * The third argument is a hint about the compiler's guess at the correct
119 * pointer offset.  If this value is negative, then -1 indicates no hint, -2
120 * that src is not a public base of dst, and -3 that src is a multiple public
121 * base type but never a virtual base type
122 */
123extern "C" void* __dynamic_cast(const void *sub,
124                                const __class_type_info *src,
125                                const __class_type_info *dst,
126                                ptrdiff_t src2dst_offset)
127{
128	char *vtable_location = *(char**)sub;
129	const vtable_header *header =
130		(const vtable_header*)(vtable_location - sizeof(vtable_header));
131	void *leaf = ADD_TO_PTR((void*)sub, header->leaf_offset);
132	return header->type->cast_to(leaf, dst);
133}
134