dynamic_cast.cc revision 272461
119304Speter/* 219304Speter * Copyright 2010-2011 PathScale, Inc. All rights reserved. 319304Speter * 419304Speter * Redistribution and use in source and binary forms, with or without 519304Speter * modification, are permitted provided that the following conditions are met: 619304Speter * 719304Speter * 1. Redistributions of source code must retain the above copyright notice, 819304Speter * this list of conditions and the following disclaimer. 919304Speter * 1019304Speter * 2. Redistributions in binary form must reproduce the above copyright notice, 1119304Speter * this list of conditions and the following disclaimer in the documentation 1219304Speter * and/or other materials provided with the distribution. 1319304Speter * 1419304Speter * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS 1519304Speter * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 1619304Speter * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 1719304Speter * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 1819304Speter * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 1919304Speter * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 2019304Speter * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 2119304Speter * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 2219304Speter * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 2319304Speter * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 2419304Speter * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2519304Speter */ 2619304Speter 2719304Speter#include "typeinfo.h" 2819304Speter#include <stdio.h> 2919304Speter 3019304Speterusing namespace ABI_NAMESPACE; 3119304Speter 3219304Speter/** 3319304Speter * Vtable header. 3419304Speter */ 3519304Speterstruct vtable_header 3619304Speter{ 3719304Speter /** Offset of the leaf object. */ 3819304Speter ptrdiff_t leaf_offset; 3919304Speter /** Type of the object. */ 4019304Speter const __class_type_info *type; 4119304Speter}; 4219304Speter 4319304Speter/** 4419304Speter * Simple macro that does pointer arithmetic in bytes but returns a value of 4519304Speter * the same type as the original. 4619304Speter */ 4719304Speter#define ADD_TO_PTR(x, off) (__typeof__(x))(((char*)x) + off) 4819304Speter 4919304Speterbool std::type_info::__do_catch(std::type_info const *ex_type, 5019304Speter void **exception_object, 5119304Speter unsigned int outer) const 5219304Speter{ 5319304Speter const type_info *type = this; 5419304Speter 5519304Speter if (type == ex_type) 5619304Speter { 5719304Speter return true; 5819304Speter } 5919304Speter if (const __class_type_info *cti = dynamic_cast<const __class_type_info *>(type)) 6019304Speter { 6119304Speter return ex_type->__do_upcast(cti, exception_object); 6219304Speter } 6319304Speter return false; 6419304Speter} 6519304Speter 6619304Speterbool __pbase_type_info::__do_catch(std::type_info const *ex_type, 6719304Speter void **exception_object, 6819304Speter unsigned int outer) const 6919304Speter{ 7019304Speter if (ex_type == this) 7119304Speter { 7219304Speter return true; 7319304Speter } 7419304Speter if (!ex_type->__is_pointer_p()) 7519304Speter { 7619304Speter // Can't catch a non-pointer type in a pointer catch 7719304Speter return false; 7819304Speter } 7919304Speter 8019304Speter if (!(outer & 1)) 8119304Speter { 8219304Speter // If the low bit is cleared on this means that we've gone 8319304Speter // through a pointer that is not const qualified. 8419304Speter return false; 8519304Speter } 8619304Speter // Clear the low bit on outer if we're not const qualified. 8719304Speter if (!(__flags & __const_mask)) 8819304Speter { 8919304Speter outer &= ~1; 9019304Speter } 9119304Speter 9219304Speter const __pbase_type_info *ptr_type = 9319304Speter static_cast<const __pbase_type_info*>(ex_type); 9419304Speter 9519304Speter if (ptr_type->__flags & ~__flags) 9619304Speter { 9719304Speter // Handler pointer is less qualified 9819304Speter return false; 9919304Speter } 10019304Speter 10119304Speter // Special case for void* handler. 10219304Speter if(*__pointee == typeid(void)) 10319304Speter { 10419304Speter return true; 10519304Speter } 10619304Speter 10719304Speter return __pointee->__do_catch(ptr_type->__pointee, exception_object, outer); 10819304Speter} 10919304Speter 11019304Spetervoid *__class_type_info::cast_to(void *obj, const struct __class_type_info *other) const 11119304Speter{ 11219304Speter if (this == other) 11319304Speter { 11419304Speter return obj; 11519304Speter } 11619304Speter return 0; 11719304Speter} 11819304Speter 11919304Spetervoid *__si_class_type_info::cast_to(void *obj, const struct __class_type_info *other) const 12019304Speter{ 12119304Speter if (this == other) 12219304Speter { 12319304Speter return obj; 12419304Speter } 12519304Speter return __base_type->cast_to(obj, other); 12619304Speter} 12719304Speterbool __si_class_type_info::__do_upcast(const __class_type_info *target, 12819304Speter void **thrown_object) const 12919304Speter{ 13019304Speter if (this == target) 13119304Speter { 132208611Sjh return true; 13319304Speter } 13419304Speter return __base_type->__do_upcast(target, thrown_object); 13519304Speter} 13619304Speter 13719304Spetervoid *__vmi_class_type_info::cast_to(void *obj, const struct __class_type_info *other) const 13819304Speter{ 13919304Speter if (__do_upcast(other, &obj)) 14019304Speter { 14119304Speter return obj; 14219304Speter } 14319304Speter return 0; 14419304Speter} 14519304Speter 14619304Speterbool __vmi_class_type_info::__do_upcast(const __class_type_info *target, 14719304Speter void **thrown_object) const 14819304Speter{ 14919304Speter if (this == target) 15019304Speter { 15119304Speter return true; 15219304Speter } 15319304Speter for (unsigned int i=0 ; i<__base_count ; i++) 15419304Speter { 15519304Speter const __base_class_type_info *info = &__base_info[i]; 15619304Speter ptrdiff_t offset = info->offset(); 15719304Speter // If this is a virtual superclass, the offset is stored in the 15819304Speter // object's vtable at the offset requested; 2.9.5.6.c: 15919304Speter // 16019304Speter // 'For a non-virtual base, this is the offset in the object of the 16119304Speter // base subobject. For a virtual base, this is the offset in the 16219304Speter // virtual table of the virtual base offset for the virtual base 16319304Speter // referenced (negative).' 16419304Speter 16519304Speter void *obj = *thrown_object; 16619304Speter if (info->isVirtual()) 16719304Speter { 16819304Speter // Object's vtable 16919304Speter ptrdiff_t *off = *(ptrdiff_t**)obj; 17019304Speter // Offset location in vtable 17119304Speter off = ADD_TO_PTR(off, offset); 17219304Speter offset = *off; 17319304Speter } 17419304Speter void *cast = ADD_TO_PTR(obj, offset); 17519304Speter 17619304Speter if (info->__base_type == target || 17719304Speter (info->__base_type->__do_upcast(target, &cast))) 17819304Speter { 17919304Speter *thrown_object = cast; 18019304Speter return true; 18119304Speter } 18219304Speter } 18319304Speter return 0; 18419304Speter} 18519304Speter 18619304Speter 18719304Speter/** 18819304Speter * ABI function used to implement the dynamic_cast<> operator. Some cases of 18919304Speter * this operator are implemented entirely in the compiler (e.g. to void*). 19019304Speter * This function implements the dynamic casts of the form dynamic_cast<T>(v). 19119304Speter * This will be translated to a call to this function with the value v as the 19219304Speter * first argument. The type id of the static type of v is the second argument 19319304Speter * and the type id of the destination type (T) is the third argument. 19419304Speter * 19519304Speter * The third argument is a hint about the compiler's guess at the correct 19619304Speter * pointer offset. If this value is negative, then -1 indicates no hint, -2 19719304Speter * that src is not a public base of dst, and -3 that src is a multiple public 19819304Speter * base type but never a virtual base type 19919304Speter */ 20019304Speterextern "C" void* __dynamic_cast(const void *sub, 20119304Speter const __class_type_info *src, 20219304Speter const __class_type_info *dst, 20319304Speter ptrdiff_t src2dst_offset) 20419304Speter{ 20519304Speter char *vtable_location = *(char**)sub; 20619304Speter const vtable_header *header = 20719304Speter (const vtable_header*)(vtable_location - sizeof(vtable_header)); 20819304Speter void *leaf = ADD_TO_PTR((void*)sub, header->leaf_offset); 20919304Speter return header->type->cast_to(leaf, dst); 21019304Speter} 21119304Speter