dynamic_cast.cc revision 232950
1/* 2 * Copyright 2010-2011 PathScale, Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are met: 6 * 7 * 1. Redistributions of source code must retain the above copyright notice, 8 * this list of conditions and the following disclaimer. 9 * 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS 15 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 16 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include "typeinfo.h" 28#include <stdio.h> 29 30using namespace ABI_NAMESPACE; 31 32/** 33 * Vtable header. 34 */ 35struct vtable_header 36{ 37 /** Offset of the leaf object. */ 38 ptrdiff_t leaf_offset; 39 /** Type of the object. */ 40 const __class_type_info *type; 41}; 42 43/** 44 * Simple macro that does pointer arithmetic in bytes but returns a value of 45 * the same type as the original. 46 */ 47#define ADD_TO_PTR(x, off) (__typeof__(x))(((char*)x) + off) 48 49bool __class_type_info::can_cast_to(const struct __class_type_info *other) const 50{ 51 return this == other; 52} 53 54void *__class_type_info::cast_to(void *obj, const struct __class_type_info *other) const 55{ 56 if (this == other) 57 { 58 return obj; 59 } 60 return 0; 61} 62 63 64bool __si_class_type_info::can_cast_to(const struct __class_type_info *other) const 65{ 66 return this == other || __base_type->can_cast_to(other); 67} 68 69void *__si_class_type_info::cast_to(void *obj, const struct __class_type_info *other) const 70{ 71 if (this == other) 72 { 73 return obj; 74 } 75 return __base_type->cast_to(obj, other); 76} 77 78 79bool __vmi_class_type_info::can_cast_to(const struct __class_type_info *other) const 80{ 81 if (this == other) 82 { 83 return true; 84 } 85 for (unsigned int i=0 ; i<__base_count ; i++) 86 { 87 const __base_class_type_info *info = &__base_info[i]; 88 if(info->isPublic() && info->__base_type->can_cast_to(other)) 89 { 90 return true; 91 } 92 } 93 return false; 94} 95 96void *__vmi_class_type_info::cast_to(void *obj, const struct __class_type_info *other) const 97{ 98 if (this == other) 99 { 100 return obj; 101 } 102 for (unsigned int i=0 ; i<__base_count ; i++) 103 { 104 const __base_class_type_info *info = &__base_info[i]; 105 ptrdiff_t offset = info->offset(); 106 // If this is a virtual superclass, the offset is stored in the 107 // object's vtable at the offset requested; 2.9.5.6.c: 108 // 109 // 'For a non-virtual base, this is the offset in the object of the 110 // base subobject. For a virtual base, this is the offset in the 111 // virtual table of the virtual base offset for the virtual base 112 // referenced (negative).' 113 114 if (info->isVirtual()) 115 { 116 // Object's vtable 117 ptrdiff_t *off = *(ptrdiff_t**)obj; 118 // Offset location in vtable 119 off = ADD_TO_PTR(off, offset); 120 offset = *off; 121 } 122 void *cast = ADD_TO_PTR(obj, offset); 123 124 if (info->__base_type == other) 125 { 126 return cast; 127 } 128 if ((cast = info->__base_type->cast_to(cast, other))) 129 { 130 return cast; 131 } 132 } 133 return 0; 134} 135 136/** 137 * ABI function used to implement the dynamic_cast<> operator. Some cases of 138 * this operator are implemented entirely in the compiler (e.g. to void*). 139 * This function implements the dynamic casts of the form dynamic_cast<T>(v). 140 * This will be translated to a call to this function with the value v as the 141 * first argument. The type id of the static type of v is the second argument 142 * and the type id of the destination type (T) is the third argument. 143 * 144 * The third argument is a hint about the compiler's guess at the correct 145 * pointer offset. If this value is negative, then -1 indicates no hint, -2 146 * that src is not a public base of dst, and -3 that src is a multiple public 147 * base type but never a virtual base type 148 */ 149extern "C" void* __dynamic_cast(const void *sub, 150 const __class_type_info *src, 151 const __class_type_info *dst, 152 ptrdiff_t src2dst_offset) 153{ 154 char *vtable_location = *(char**)sub; 155 const vtable_header *header = 156 (const vtable_header*)(vtable_location - sizeof(vtable_header)); 157 void *leaf = ADD_TO_PTR((void*)sub, header->leaf_offset); 158 return header->type->cast_to(leaf, dst); 159} 160