dynamic_cast.cc revision 227825
1227825Stheraven#include "typeinfo.h" 2227825Stheraven#include <stdio.h> 3227825Stheraven 4227825Stheravenusing namespace ABI_NAMESPACE; 5227825Stheraven 6227825Stheraven/** 7227825Stheraven * Vtable header. 8227825Stheraven */ 9227825Stheravenstruct vtable_header 10227825Stheraven{ 11227825Stheraven /** Offset of the leaf object. */ 12227825Stheraven ptrdiff_t leaf_offset; 13227825Stheraven /** Type of the object. */ 14227825Stheraven const __class_type_info *type; 15227825Stheraven}; 16227825Stheraven 17227825Stheraven/** 18227825Stheraven * Simple macro that does pointer arithmetic in bytes but returns a value of 19227825Stheraven * the same type as the original. 20227825Stheraven */ 21227825Stheraven#define ADD_TO_PTR(x, off) (__typeof__(x))(((char*)x) + off) 22227825Stheraven 23227825Stheravenbool __class_type_info::can_cast_to(const struct __class_type_info *other) const 24227825Stheraven{ 25227825Stheraven return this == other; 26227825Stheraven} 27227825Stheraven 28227825Stheravenvoid *__class_type_info::cast_to(void *obj, const struct __class_type_info *other) const 29227825Stheraven{ 30227825Stheraven if (this == other) 31227825Stheraven { 32227825Stheraven return obj; 33227825Stheraven } 34227825Stheraven return 0; 35227825Stheraven} 36227825Stheraven 37227825Stheraven 38227825Stheravenbool __si_class_type_info::can_cast_to(const struct __class_type_info *other) const 39227825Stheraven{ 40227825Stheraven return this == other || __base_type->can_cast_to(other); 41227825Stheraven} 42227825Stheraven 43227825Stheravenvoid *__si_class_type_info::cast_to(void *obj, const struct __class_type_info *other) const 44227825Stheraven{ 45227825Stheraven if (this == other) 46227825Stheraven { 47227825Stheraven return obj; 48227825Stheraven } 49227825Stheraven return __base_type->cast_to(obj, other); 50227825Stheraven} 51227825Stheraven 52227825Stheraven 53227825Stheravenbool __vmi_class_type_info::can_cast_to(const struct __class_type_info *other) const 54227825Stheraven{ 55227825Stheraven if (this == other) 56227825Stheraven { 57227825Stheraven return true; 58227825Stheraven } 59227825Stheraven for (unsigned int i=0 ; i<__base_count ; i++) 60227825Stheraven { 61227825Stheraven const __base_class_type_info *info = &__base_info[i]; 62227825Stheraven if(info->isPublic() && info->__base_type->can_cast_to(other)) 63227825Stheraven { 64227825Stheraven return true; 65227825Stheraven } 66227825Stheraven } 67227825Stheraven return false; 68227825Stheraven} 69227825Stheraven 70227825Stheravenvoid *__vmi_class_type_info::cast_to(void *obj, const struct __class_type_info *other) const 71227825Stheraven{ 72227825Stheraven if (this == other) 73227825Stheraven { 74227825Stheraven return obj; 75227825Stheraven } 76227825Stheraven for (unsigned int i=0 ; i<__base_count ; i++) 77227825Stheraven { 78227825Stheraven const __base_class_type_info *info = &__base_info[i]; 79227825Stheraven ptrdiff_t offset = info->offset(); 80227825Stheraven // If this is a virtual superclass, the offset is stored in the 81227825Stheraven // object's vtable at the offset requested; 2.9.5.6.c: 82227825Stheraven // 83227825Stheraven // 'For a non-virtual base, this is the offset in the object of the 84227825Stheraven // base subobject. For a virtual base, this is the offset in the 85227825Stheraven // virtual table of the virtual base offset for the virtual base 86227825Stheraven // referenced (negative).' 87227825Stheraven 88227825Stheraven if (info->isVirtual()) 89227825Stheraven { 90227825Stheraven // Object's vtable 91227825Stheraven ptrdiff_t *off = *(ptrdiff_t**)obj; 92227825Stheraven // Offset location in vtable 93227825Stheraven off = ADD_TO_PTR(off, offset); 94227825Stheraven offset = *off; 95227825Stheraven } 96227825Stheraven void *cast = ADD_TO_PTR(obj, offset); 97227825Stheraven 98227825Stheraven if (info->__base_type == other) 99227825Stheraven { 100227825Stheraven return cast; 101227825Stheraven } 102227825Stheraven if ((cast = info->__base_type->cast_to(cast, other))) 103227825Stheraven { 104227825Stheraven return cast; 105227825Stheraven } 106227825Stheraven } 107227825Stheraven return 0; 108227825Stheraven} 109227825Stheraven 110227825Stheraven/** 111227825Stheraven * ABI function used to implement the dynamic_cast<> operator. Some cases of 112227825Stheraven * this operator are implemented entirely in the compiler (e.g. to void*). 113227825Stheraven * This function implements the dynamic casts of the form dynamic_cast<T>(v). 114227825Stheraven * This will be translated to a call to this function with the value v as the 115227825Stheraven * first argument. The type id of the static type of v is the second argument 116227825Stheraven * and the type id of the destination type (T) is the third argument. 117227825Stheraven * 118227825Stheraven * The third argument is a hint about the compiler's guess at the correct 119227825Stheraven * pointer offset. If this value is negative, then -1 indicates no hint, -2 120227825Stheraven * that src is not a public base of dst, and -3 that src is a multiple public 121227825Stheraven * base type but never a virtual base type 122227825Stheraven */ 123227825Stheravenextern "C" void* __dynamic_cast(const void *sub, 124227825Stheraven const __class_type_info *src, 125227825Stheraven const __class_type_info *dst, 126227825Stheraven ptrdiff_t src2dst_offset) 127227825Stheraven{ 128227825Stheraven char *vtable_location = *(char**)sub; 129227825Stheraven const vtable_header *header = 130227825Stheraven (const vtable_header*)(vtable_location - sizeof(vtable_header)); 131227825Stheraven void *leaf = ADD_TO_PTR((void*)sub, header->leaf_offset); 132227825Stheraven return header->type->cast_to(leaf, dst); 133227825Stheraven} 134