dynamic_cast.cc revision 232950
1255736Sdavidch/* 2265797Sdavidcs * Copyright 2010-2011 PathScale, Inc. All rights reserved. 3255736Sdavidch * 4255736Sdavidch * Redistribution and use in source and binary forms, with or without 5255736Sdavidch * modification, are permitted provided that the following conditions are met: 6255736Sdavidch * 7255736Sdavidch * 1. Redistributions of source code must retain the above copyright notice, 8255736Sdavidch * this list of conditions and the following disclaimer. 9255736Sdavidch * 10255736Sdavidch * 2. Redistributions in binary form must reproduce the above copyright notice, 11255736Sdavidch * this list of conditions and the following disclaimer in the documentation 12255736Sdavidch * and/or other materials provided with the distribution. 13255736Sdavidch * 14255736Sdavidch * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS 15255736Sdavidch * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 16255736Sdavidch * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17255736Sdavidch * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 18255736Sdavidch * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19255736Sdavidch * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20255736Sdavidch * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21255736Sdavidch * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22255736Sdavidch * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23255736Sdavidch * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24255736Sdavidch * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25255736Sdavidch */ 26255736Sdavidch 27255736Sdavidch#include "typeinfo.h" 28255736Sdavidch#include <stdio.h> 29255736Sdavidch 30255736Sdavidchusing namespace ABI_NAMESPACE; 31255736Sdavidch 32255736Sdavidch/** 33255736Sdavidch * Vtable header. 34255736Sdavidch */ 35255736Sdavidchstruct vtable_header 36255736Sdavidch{ 37255736Sdavidch /** Offset of the leaf object. */ 38255736Sdavidch ptrdiff_t leaf_offset; 39255736Sdavidch /** Type of the object. */ 40255736Sdavidch const __class_type_info *type; 41255736Sdavidch}; 42255736Sdavidch 43255736Sdavidch/** 44255736Sdavidch * Simple macro that does pointer arithmetic in bytes but returns a value of 45255736Sdavidch * the same type as the original. 46255736Sdavidch */ 47255736Sdavidch#define ADD_TO_PTR(x, off) (__typeof__(x))(((char*)x) + off) 48255736Sdavidch 49255736Sdavidchbool __class_type_info::can_cast_to(const struct __class_type_info *other) const 50255736Sdavidch{ 51255736Sdavidch return this == other; 52255736Sdavidch} 53255736Sdavidch 54255736Sdavidchvoid *__class_type_info::cast_to(void *obj, const struct __class_type_info *other) const 55255736Sdavidch{ 56255736Sdavidch if (this == other) 57255736Sdavidch { 58255736Sdavidch return obj; 59255736Sdavidch } 60255736Sdavidch return 0; 61255736Sdavidch} 62255736Sdavidch 63255736Sdavidch 64255736Sdavidchbool __si_class_type_info::can_cast_to(const struct __class_type_info *other) const 65255736Sdavidch{ 66255736Sdavidch return this == other || __base_type->can_cast_to(other); 67255736Sdavidch} 68255736Sdavidch 69255736Sdavidchvoid *__si_class_type_info::cast_to(void *obj, const struct __class_type_info *other) const 70255736Sdavidch{ 71255736Sdavidch if (this == other) 72255736Sdavidch { 73255736Sdavidch return obj; 74255736Sdavidch } 75255736Sdavidch return __base_type->cast_to(obj, other); 76255736Sdavidch} 77255736Sdavidch 78255736Sdavidch 79255736Sdavidchbool __vmi_class_type_info::can_cast_to(const struct __class_type_info *other) const 80255736Sdavidch{ 81255736Sdavidch if (this == other) 82255736Sdavidch { 83255736Sdavidch return true; 84255736Sdavidch } 85255736Sdavidch for (unsigned int i=0 ; i<__base_count ; i++) 86255736Sdavidch { 87255736Sdavidch const __base_class_type_info *info = &__base_info[i]; 88255736Sdavidch if(info->isPublic() && info->__base_type->can_cast_to(other)) 89255736Sdavidch { 90255736Sdavidch return true; 91255736Sdavidch } 92255736Sdavidch } 93255736Sdavidch return false; 94255736Sdavidch} 95255736Sdavidch 96255736Sdavidchvoid *__vmi_class_type_info::cast_to(void *obj, const struct __class_type_info *other) const 97255736Sdavidch{ 98255736Sdavidch if (this == other) 99255736Sdavidch { 100255736Sdavidch return obj; 101255736Sdavidch } 102255736Sdavidch for (unsigned int i=0 ; i<__base_count ; i++) 103255736Sdavidch { 104255736Sdavidch const __base_class_type_info *info = &__base_info[i]; 105255736Sdavidch ptrdiff_t offset = info->offset(); 106255736Sdavidch // If this is a virtual superclass, the offset is stored in the 107255736Sdavidch // object's vtable at the offset requested; 2.9.5.6.c: 108255736Sdavidch // 109255736Sdavidch // 'For a non-virtual base, this is the offset in the object of the 110255736Sdavidch // base subobject. For a virtual base, this is the offset in the 111255736Sdavidch // virtual table of the virtual base offset for the virtual base 112255736Sdavidch // referenced (negative).' 113255736Sdavidch 114255736Sdavidch if (info->isVirtual()) 115255736Sdavidch { 116255736Sdavidch // Object's vtable 117255736Sdavidch ptrdiff_t *off = *(ptrdiff_t**)obj; 118255736Sdavidch // Offset location in vtable 119255736Sdavidch off = ADD_TO_PTR(off, offset); 120255736Sdavidch offset = *off; 121255736Sdavidch } 122255736Sdavidch void *cast = ADD_TO_PTR(obj, offset); 123255736Sdavidch 124255736Sdavidch if (info->__base_type == other) 125255736Sdavidch { 126255736Sdavidch return cast; 127255736Sdavidch } 128255736Sdavidch if ((cast = info->__base_type->cast_to(cast, other))) 129255736Sdavidch { 130255736Sdavidch return cast; 131255736Sdavidch } 132255736Sdavidch } 133255736Sdavidch return 0; 134255736Sdavidch} 135255736Sdavidch 136255736Sdavidch/** 137255736Sdavidch * ABI function used to implement the dynamic_cast<> operator. Some cases of 138255736Sdavidch * this operator are implemented entirely in the compiler (e.g. to void*). 139255736Sdavidch * This function implements the dynamic casts of the form dynamic_cast<T>(v). 140255736Sdavidch * This will be translated to a call to this function with the value v as the 141255736Sdavidch * first argument. The type id of the static type of v is the second argument 142255736Sdavidch * and the type id of the destination type (T) is the third argument. 143255736Sdavidch * 144255736Sdavidch * The third argument is a hint about the compiler's guess at the correct 145255736Sdavidch * pointer offset. If this value is negative, then -1 indicates no hint, -2 146255736Sdavidch * that src is not a public base of dst, and -3 that src is a multiple public 147255736Sdavidch * base type but never a virtual base type 148255736Sdavidch */ 149255736Sdavidchextern "C" void* __dynamic_cast(const void *sub, 150255736Sdavidch const __class_type_info *src, 151255736Sdavidch const __class_type_info *dst, 152255736Sdavidch ptrdiff_t src2dst_offset) 153255736Sdavidch{ 154255736Sdavidch char *vtable_location = *(char**)sub; 155255736Sdavidch const vtable_header *header = 156255736Sdavidch (const vtable_header*)(vtable_location - sizeof(vtable_header)); 157255736Sdavidch void *leaf = ADD_TO_PTR((void*)sub, header->leaf_offset); 158255736Sdavidch return header->type->cast_to(leaf, dst); 159255736Sdavidch} 160255736Sdavidch