1232950Stheraven/* 2232950Stheraven * Copyright 2010-2011 PathScale, Inc. All rights reserved. 3232950Stheraven * 4232950Stheraven * Redistribution and use in source and binary forms, with or without 5232950Stheraven * modification, are permitted provided that the following conditions are met: 6232950Stheraven * 7232950Stheraven * 1. Redistributions of source code must retain the above copyright notice, 8232950Stheraven * this list of conditions and the following disclaimer. 9232950Stheraven * 10232950Stheraven * 2. Redistributions in binary form must reproduce the above copyright notice, 11232950Stheraven * this list of conditions and the following disclaimer in the documentation 12232950Stheraven * and/or other materials provided with the distribution. 13232950Stheraven * 14232950Stheraven * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS 15232950Stheraven * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 16232950Stheraven * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17232950Stheraven * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 18232950Stheraven * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19232950Stheraven * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20232950Stheraven * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21232950Stheraven * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22232950Stheraven * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23232950Stheraven * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24232950Stheraven * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25232950Stheraven */ 26232950Stheraven 27227825Stheraven#include "typeinfo.h" 28227825Stheraven#include <stdio.h> 29227825Stheraven 30227825Stheravenusing namespace ABI_NAMESPACE; 31227825Stheraven 32227825Stheraven/** 33227825Stheraven * Vtable header. 34227825Stheraven */ 35227825Stheravenstruct vtable_header 36227825Stheraven{ 37227825Stheraven /** Offset of the leaf object. */ 38227825Stheraven ptrdiff_t leaf_offset; 39227825Stheraven /** Type of the object. */ 40227825Stheraven const __class_type_info *type; 41227825Stheraven}; 42227825Stheraven 43227825Stheraven/** 44227825Stheraven * Simple macro that does pointer arithmetic in bytes but returns a value of 45227825Stheraven * the same type as the original. 46227825Stheraven */ 47227825Stheraven#define ADD_TO_PTR(x, off) (__typeof__(x))(((char*)x) + off) 48227825Stheraven 49233235Stheravenbool std::type_info::__do_catch(std::type_info const *ex_type, 50233235Stheraven void **exception_object, 51233235Stheraven unsigned int outer) const 52227825Stheraven{ 53233235Stheraven const type_info *type = this; 54233235Stheraven 55233235Stheraven if (type == ex_type) 56233235Stheraven { 57233235Stheraven return true; 58233235Stheraven } 59233235Stheraven if (const __class_type_info *cti = dynamic_cast<const __class_type_info *>(type)) 60233235Stheraven { 61233235Stheraven return ex_type->__do_upcast(cti, exception_object); 62233235Stheraven } 63233235Stheraven return false; 64227825Stheraven} 65227825Stheraven 66233235Stheravenbool __pbase_type_info::__do_catch(std::type_info const *ex_type, 67233235Stheraven void **exception_object, 68233235Stheraven unsigned int outer) const 69233235Stheraven{ 70233235Stheraven if (ex_type == this) 71233235Stheraven { 72233235Stheraven return true; 73233235Stheraven } 74233235Stheraven if (!ex_type->__is_pointer_p()) 75233235Stheraven { 76233235Stheraven // Can't catch a non-pointer type in a pointer catch 77233235Stheraven return false; 78233235Stheraven } 79233235Stheraven 80233235Stheraven if (!(outer & 1)) 81233235Stheraven { 82233235Stheraven // If the low bit is cleared on this means that we've gone 83233235Stheraven // through a pointer that is not const qualified. 84233235Stheraven return false; 85233235Stheraven } 86233235Stheraven // Clear the low bit on outer if we're not const qualified. 87233235Stheraven if (!(__flags & __const_mask)) 88233235Stheraven { 89233235Stheraven outer &= ~1; 90233235Stheraven } 91233235Stheraven 92233235Stheraven const __pbase_type_info *ptr_type = 93233235Stheraven static_cast<const __pbase_type_info*>(ex_type); 94233235Stheraven 95233235Stheraven if (ptr_type->__flags & ~__flags) 96233235Stheraven { 97233235Stheraven // Handler pointer is less qualified 98233235Stheraven return false; 99233235Stheraven } 100233235Stheraven 101233235Stheraven // Special case for void* handler. 102233235Stheraven if(*__pointee == typeid(void)) 103233235Stheraven { 104233235Stheraven return true; 105233235Stheraven } 106233235Stheraven 107233235Stheraven return __pointee->__do_catch(ptr_type->__pointee, exception_object, outer); 108233235Stheraven} 109233235Stheraven 110227825Stheravenvoid *__class_type_info::cast_to(void *obj, const struct __class_type_info *other) const 111227825Stheraven{ 112227825Stheraven if (this == other) 113227825Stheraven { 114227825Stheraven return obj; 115227825Stheraven } 116227825Stheraven return 0; 117227825Stheraven} 118227825Stheraven 119227825Stheravenvoid *__si_class_type_info::cast_to(void *obj, const struct __class_type_info *other) const 120227825Stheraven{ 121227825Stheraven if (this == other) 122227825Stheraven { 123227825Stheraven return obj; 124227825Stheraven } 125227825Stheraven return __base_type->cast_to(obj, other); 126227825Stheraven} 127233235Stheravenbool __si_class_type_info::__do_upcast(const __class_type_info *target, 128233235Stheraven void **thrown_object) const 129227825Stheraven{ 130233235Stheraven if (this == target) 131227825Stheraven { 132227825Stheraven return true; 133227825Stheraven } 134233235Stheraven return __base_type->__do_upcast(target, thrown_object); 135227825Stheraven} 136227825Stheraven 137227825Stheravenvoid *__vmi_class_type_info::cast_to(void *obj, const struct __class_type_info *other) const 138227825Stheraven{ 139233235Stheraven if (__do_upcast(other, &obj)) 140227825Stheraven { 141227825Stheraven return obj; 142227825Stheraven } 143233235Stheraven return 0; 144233235Stheraven} 145233235Stheraven 146233235Stheravenbool __vmi_class_type_info::__do_upcast(const __class_type_info *target, 147233235Stheraven void **thrown_object) const 148233235Stheraven{ 149233235Stheraven if (this == target) 150233235Stheraven { 151233235Stheraven return true; 152233235Stheraven } 153227825Stheraven for (unsigned int i=0 ; i<__base_count ; i++) 154227825Stheraven { 155227825Stheraven const __base_class_type_info *info = &__base_info[i]; 156227825Stheraven ptrdiff_t offset = info->offset(); 157227825Stheraven // If this is a virtual superclass, the offset is stored in the 158227825Stheraven // object's vtable at the offset requested; 2.9.5.6.c: 159227825Stheraven // 160227825Stheraven // 'For a non-virtual base, this is the offset in the object of the 161227825Stheraven // base subobject. For a virtual base, this is the offset in the 162227825Stheraven // virtual table of the virtual base offset for the virtual base 163227825Stheraven // referenced (negative).' 164227825Stheraven 165233235Stheraven void *obj = *thrown_object; 166227825Stheraven if (info->isVirtual()) 167227825Stheraven { 168227825Stheraven // Object's vtable 169227825Stheraven ptrdiff_t *off = *(ptrdiff_t**)obj; 170227825Stheraven // Offset location in vtable 171227825Stheraven off = ADD_TO_PTR(off, offset); 172227825Stheraven offset = *off; 173227825Stheraven } 174227825Stheraven void *cast = ADD_TO_PTR(obj, offset); 175227825Stheraven 176233235Stheraven if (info->__base_type == target || 177233235Stheraven (info->__base_type->__do_upcast(target, &cast))) 178227825Stheraven { 179233235Stheraven *thrown_object = cast; 180233235Stheraven return true; 181227825Stheraven } 182227825Stheraven } 183227825Stheraven return 0; 184227825Stheraven} 185227825Stheraven 186233235Stheraven 187227825Stheraven/** 188227825Stheraven * ABI function used to implement the dynamic_cast<> operator. Some cases of 189227825Stheraven * this operator are implemented entirely in the compiler (e.g. to void*). 190227825Stheraven * This function implements the dynamic casts of the form dynamic_cast<T>(v). 191227825Stheraven * This will be translated to a call to this function with the value v as the 192227825Stheraven * first argument. The type id of the static type of v is the second argument 193227825Stheraven * and the type id of the destination type (T) is the third argument. 194227825Stheraven * 195227825Stheraven * The third argument is a hint about the compiler's guess at the correct 196227825Stheraven * pointer offset. If this value is negative, then -1 indicates no hint, -2 197227825Stheraven * that src is not a public base of dst, and -3 that src is a multiple public 198227825Stheraven * base type but never a virtual base type 199227825Stheraven */ 200227825Stheravenextern "C" void* __dynamic_cast(const void *sub, 201227825Stheraven const __class_type_info *src, 202227825Stheraven const __class_type_info *dst, 203227825Stheraven ptrdiff_t src2dst_offset) 204227825Stheraven{ 205227825Stheraven char *vtable_location = *(char**)sub; 206227825Stheraven const vtable_header *header = 207227825Stheraven (const vtable_header*)(vtable_location - sizeof(vtable_header)); 208227825Stheraven void *leaf = ADD_TO_PTR((void*)sub, header->leaf_offset); 209227825Stheraven return header->type->cast_to(leaf, dst); 210227825Stheraven} 211