/*1* Copyright 2010-2011 PathScale, Inc. All rights reserved.2*3* Redistribution and use in source and binary forms, with or without4* modification, are permitted provided that the following conditions are met:5*6* 1. Redistributions of source code must retain the above copyright notice,7* this list of conditions and the following disclaimer.8*9* 2. Redistributions in binary form must reproduce the above copyright notice,10* this list of conditions and the following disclaimer in the documentation11* and/or other materials provided with the distribution.12*13* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS14* IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,15* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR16* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR17* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,18* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,19* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;20* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,21* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR22* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF23* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.24*/2526#include "typeinfo.h"27#include <stdio.h>2829using namespace ABI_NAMESPACE;3031/**32* Vtable header.33*/34struct vtable_header35{36/** Offset of the leaf object. */37ptrdiff_t leaf_offset;38/** Type of the object. */39const __class_type_info *type;40};4142/**43* Simple macro that does pointer arithmetic in bytes but returns a value of44* the same type as the original.45*/46#define ADD_TO_PTR(x, off) reinterpret_cast<__typeof__(x)>(reinterpret_cast<char*>(x) + off)4748bool std::type_info::__do_catch(std::type_info const *ex_type,49void **exception_object,50unsigned int outer) const51{52const type_info *type = this;5354if (type == ex_type)55{56return true;57}58if (const __class_type_info *cti = dynamic_cast<const __class_type_info *>(type))59{60return ex_type->__do_upcast(cti, exception_object);61}62return false;63}6465bool __pbase_type_info::__do_catch(std::type_info const *ex_type,66void **exception_object,67unsigned int outer) const68{69if (ex_type == this)70{71return true;72}73if (!ex_type->__is_pointer_p())74{75// Can't catch a non-pointer type in a pointer catch76return false;77}7879if (!(outer & 1))80{81// If the low bit is cleared on this means that we've gone82// through a pointer that is not const qualified.83return false;84}85// Clear the low bit on outer if we're not const qualified.86if (!(__flags & __const_mask))87{88outer &= ~1;89}9091const __pbase_type_info *ptr_type =92static_cast<const __pbase_type_info*>(ex_type);9394if (ptr_type->__flags & ~__flags)95{96// Handler pointer is less qualified97return false;98}99100// Special case for void* handler.101if(*__pointee == typeid(void))102{103return true;104}105106return __pointee->__do_catch(ptr_type->__pointee, exception_object, outer);107}108109void *__class_type_info::cast_to(void *obj, const struct __class_type_info *other) const110{111if (this == other)112{113return obj;114}115return 0;116}117118void *__si_class_type_info::cast_to(void *obj, const struct __class_type_info *other) const119{120if (this == other)121{122return obj;123}124return __base_type->cast_to(obj, other);125}126bool __si_class_type_info::__do_upcast(const __class_type_info *target,127void **thrown_object) const128{129if (this == target)130{131return true;132}133return __base_type->__do_upcast(target, thrown_object);134}135136void *__vmi_class_type_info::cast_to(void *obj, const struct __class_type_info *other) const137{138if (__do_upcast(other, &obj))139{140return obj;141}142return 0;143}144145bool __vmi_class_type_info::__do_upcast(const __class_type_info *target,146void **thrown_object) const147{148if (this == target)149{150return true;151}152for (unsigned int i=0 ; i<__base_count ; i++)153{154const __base_class_type_info *info = &__base_info[i];155ptrdiff_t offset = info->offset();156// If this is a virtual superclass, the offset is stored in the157// object's vtable at the offset requested; 2.9.5.6.c:158//159// 'For a non-virtual base, this is the offset in the object of the160// base subobject. For a virtual base, this is the offset in the161// virtual table of the virtual base offset for the virtual base162// referenced (negative).'163164void *obj = *thrown_object;165if (info->isVirtual())166{167// Object's vtable168ptrdiff_t *off = *static_cast<ptrdiff_t**>(obj);169// Offset location in vtable170off = ADD_TO_PTR(off, offset);171offset = *off;172}173void *cast = ADD_TO_PTR(obj, offset);174175if (info->__base_type == target ||176(info->__base_type->__do_upcast(target, &cast)))177{178*thrown_object = cast;179return true;180}181}182return 0;183}184185186/**187* ABI function used to implement the dynamic_cast<> operator. Some cases of188* this operator are implemented entirely in the compiler (e.g. to void*).189* This function implements the dynamic casts of the form dynamic_cast<T>(v).190* This will be translated to a call to this function with the value v as the191* first argument. The type id of the static type of v is the second argument192* and the type id of the destination type (T) is the third argument.193*194* The third argument is a hint about the compiler's guess at the correct195* pointer offset. If this value is negative, then -1 indicates no hint, -2196* that src is not a public base of dst, and -3 that src is a multiple public197* base type but never a virtual base type198*/199extern "C" void* __dynamic_cast(const void *sub,200const __class_type_info *src,201const __class_type_info *dst,202ptrdiff_t src2dst_offset)203{204const char *vtable_location = *static_cast<const char * const *>(sub);205const vtable_header *header =206reinterpret_cast<const vtable_header*>(vtable_location - sizeof(vtable_header));207void *leaf = ADD_TO_PTR(const_cast<void *>(sub), header->leaf_offset);208return header->type->cast_to(leaf, dst);209}210211212