14684ddb6SLionel Sambuc /*
24684ddb6SLionel Sambuc * Copyright 2010-2011 PathScale, Inc. All rights reserved.
34684ddb6SLionel Sambuc *
44684ddb6SLionel Sambuc * Redistribution and use in source and binary forms, with or without
54684ddb6SLionel Sambuc * modification, are permitted provided that the following conditions are met:
64684ddb6SLionel Sambuc *
74684ddb6SLionel Sambuc * 1. Redistributions of source code must retain the above copyright notice,
84684ddb6SLionel Sambuc * this list of conditions and the following disclaimer.
94684ddb6SLionel Sambuc *
104684ddb6SLionel Sambuc * 2. Redistributions in binary form must reproduce the above copyright notice,
114684ddb6SLionel Sambuc * this list of conditions and the following disclaimer in the documentation
124684ddb6SLionel Sambuc * and/or other materials provided with the distribution.
134684ddb6SLionel Sambuc *
144684ddb6SLionel Sambuc * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
154684ddb6SLionel Sambuc * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
164684ddb6SLionel Sambuc * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
174684ddb6SLionel Sambuc * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
184684ddb6SLionel Sambuc * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
194684ddb6SLionel Sambuc * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
204684ddb6SLionel Sambuc * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
214684ddb6SLionel Sambuc * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
224684ddb6SLionel Sambuc * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
234684ddb6SLionel Sambuc * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
244684ddb6SLionel Sambuc * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
254684ddb6SLionel Sambuc */
264684ddb6SLionel Sambuc
274684ddb6SLionel Sambuc #include "typeinfo.h"
284684ddb6SLionel Sambuc #include <stdio.h>
294684ddb6SLionel Sambuc
304684ddb6SLionel Sambuc using namespace ABI_NAMESPACE;
314684ddb6SLionel Sambuc
324684ddb6SLionel Sambuc /**
334684ddb6SLionel Sambuc * Vtable header.
344684ddb6SLionel Sambuc */
354684ddb6SLionel Sambuc struct vtable_header
364684ddb6SLionel Sambuc {
374684ddb6SLionel Sambuc /** Offset of the leaf object. */
384684ddb6SLionel Sambuc ptrdiff_t leaf_offset;
394684ddb6SLionel Sambuc /** Type of the object. */
404684ddb6SLionel Sambuc const __class_type_info *type;
414684ddb6SLionel Sambuc };
424684ddb6SLionel Sambuc
434684ddb6SLionel Sambuc /**
444684ddb6SLionel Sambuc * Simple macro that does pointer arithmetic in bytes but returns a value of
454684ddb6SLionel Sambuc * the same type as the original.
464684ddb6SLionel Sambuc */
47*0a6a1f1dSLionel Sambuc #define ADD_TO_PTR(x, off) reinterpret_cast<__typeof__(x)>(reinterpret_cast<char*>(x) + off)
484684ddb6SLionel Sambuc
__do_catch(std::type_info const * ex_type,void ** exception_object,unsigned int outer) const494684ddb6SLionel Sambuc bool std::type_info::__do_catch(std::type_info const *ex_type,
504684ddb6SLionel Sambuc void **exception_object,
514684ddb6SLionel Sambuc unsigned int outer) const
524684ddb6SLionel Sambuc {
534684ddb6SLionel Sambuc const type_info *type = this;
544684ddb6SLionel Sambuc
554684ddb6SLionel Sambuc if (type == ex_type)
564684ddb6SLionel Sambuc {
574684ddb6SLionel Sambuc return true;
584684ddb6SLionel Sambuc }
594684ddb6SLionel Sambuc if (const __class_type_info *cti = dynamic_cast<const __class_type_info *>(type))
604684ddb6SLionel Sambuc {
614684ddb6SLionel Sambuc return ex_type->__do_upcast(cti, exception_object);
624684ddb6SLionel Sambuc }
634684ddb6SLionel Sambuc return false;
644684ddb6SLionel Sambuc }
654684ddb6SLionel Sambuc
__do_catch(std::type_info const * ex_type,void ** exception_object,unsigned int outer) const664684ddb6SLionel Sambuc bool __pbase_type_info::__do_catch(std::type_info const *ex_type,
674684ddb6SLionel Sambuc void **exception_object,
684684ddb6SLionel Sambuc unsigned int outer) const
694684ddb6SLionel Sambuc {
704684ddb6SLionel Sambuc if (ex_type == this)
714684ddb6SLionel Sambuc {
724684ddb6SLionel Sambuc return true;
734684ddb6SLionel Sambuc }
744684ddb6SLionel Sambuc if (!ex_type->__is_pointer_p())
754684ddb6SLionel Sambuc {
764684ddb6SLionel Sambuc // Can't catch a non-pointer type in a pointer catch
774684ddb6SLionel Sambuc return false;
784684ddb6SLionel Sambuc }
794684ddb6SLionel Sambuc
804684ddb6SLionel Sambuc if (!(outer & 1))
814684ddb6SLionel Sambuc {
824684ddb6SLionel Sambuc // If the low bit is cleared on this means that we've gone
834684ddb6SLionel Sambuc // through a pointer that is not const qualified.
844684ddb6SLionel Sambuc return false;
854684ddb6SLionel Sambuc }
864684ddb6SLionel Sambuc // Clear the low bit on outer if we're not const qualified.
874684ddb6SLionel Sambuc if (!(__flags & __const_mask))
884684ddb6SLionel Sambuc {
894684ddb6SLionel Sambuc outer &= ~1;
904684ddb6SLionel Sambuc }
914684ddb6SLionel Sambuc
924684ddb6SLionel Sambuc const __pbase_type_info *ptr_type =
934684ddb6SLionel Sambuc static_cast<const __pbase_type_info*>(ex_type);
944684ddb6SLionel Sambuc
954684ddb6SLionel Sambuc if (ptr_type->__flags & ~__flags)
964684ddb6SLionel Sambuc {
974684ddb6SLionel Sambuc // Handler pointer is less qualified
984684ddb6SLionel Sambuc return false;
994684ddb6SLionel Sambuc }
1004684ddb6SLionel Sambuc
1014684ddb6SLionel Sambuc // Special case for void* handler.
1024684ddb6SLionel Sambuc if(*__pointee == typeid(void))
1034684ddb6SLionel Sambuc {
1044684ddb6SLionel Sambuc return true;
1054684ddb6SLionel Sambuc }
1064684ddb6SLionel Sambuc
1074684ddb6SLionel Sambuc return __pointee->__do_catch(ptr_type->__pointee, exception_object, outer);
1084684ddb6SLionel Sambuc }
1094684ddb6SLionel Sambuc
cast_to(void * obj,const struct __class_type_info * other) const1104684ddb6SLionel Sambuc void *__class_type_info::cast_to(void *obj, const struct __class_type_info *other) const
1114684ddb6SLionel Sambuc {
1124684ddb6SLionel Sambuc if (this == other)
1134684ddb6SLionel Sambuc {
1144684ddb6SLionel Sambuc return obj;
1154684ddb6SLionel Sambuc }
1164684ddb6SLionel Sambuc return 0;
1174684ddb6SLionel Sambuc }
1184684ddb6SLionel Sambuc
cast_to(void * obj,const struct __class_type_info * other) const1194684ddb6SLionel Sambuc void *__si_class_type_info::cast_to(void *obj, const struct __class_type_info *other) const
1204684ddb6SLionel Sambuc {
1214684ddb6SLionel Sambuc if (this == other)
1224684ddb6SLionel Sambuc {
1234684ddb6SLionel Sambuc return obj;
1244684ddb6SLionel Sambuc }
1254684ddb6SLionel Sambuc return __base_type->cast_to(obj, other);
1264684ddb6SLionel Sambuc }
__do_upcast(const __class_type_info * target,void ** thrown_object) const1274684ddb6SLionel Sambuc bool __si_class_type_info::__do_upcast(const __class_type_info *target,
1284684ddb6SLionel Sambuc void **thrown_object) const
1294684ddb6SLionel Sambuc {
1304684ddb6SLionel Sambuc if (this == target)
1314684ddb6SLionel Sambuc {
1324684ddb6SLionel Sambuc return true;
1334684ddb6SLionel Sambuc }
1344684ddb6SLionel Sambuc return __base_type->__do_upcast(target, thrown_object);
1354684ddb6SLionel Sambuc }
1364684ddb6SLionel Sambuc
cast_to(void * obj,const struct __class_type_info * other) const1374684ddb6SLionel Sambuc void *__vmi_class_type_info::cast_to(void *obj, const struct __class_type_info *other) const
1384684ddb6SLionel Sambuc {
1394684ddb6SLionel Sambuc if (__do_upcast(other, &obj))
1404684ddb6SLionel Sambuc {
1414684ddb6SLionel Sambuc return obj;
1424684ddb6SLionel Sambuc }
1434684ddb6SLionel Sambuc return 0;
1444684ddb6SLionel Sambuc }
1454684ddb6SLionel Sambuc
__do_upcast(const __class_type_info * target,void ** thrown_object) const1464684ddb6SLionel Sambuc bool __vmi_class_type_info::__do_upcast(const __class_type_info *target,
1474684ddb6SLionel Sambuc void **thrown_object) const
1484684ddb6SLionel Sambuc {
1494684ddb6SLionel Sambuc if (this == target)
1504684ddb6SLionel Sambuc {
1514684ddb6SLionel Sambuc return true;
1524684ddb6SLionel Sambuc }
1534684ddb6SLionel Sambuc for (unsigned int i=0 ; i<__base_count ; i++)
1544684ddb6SLionel Sambuc {
1554684ddb6SLionel Sambuc const __base_class_type_info *info = &__base_info[i];
1564684ddb6SLionel Sambuc ptrdiff_t offset = info->offset();
1574684ddb6SLionel Sambuc // If this is a virtual superclass, the offset is stored in the
1584684ddb6SLionel Sambuc // object's vtable at the offset requested; 2.9.5.6.c:
1594684ddb6SLionel Sambuc //
1604684ddb6SLionel Sambuc // 'For a non-virtual base, this is the offset in the object of the
1614684ddb6SLionel Sambuc // base subobject. For a virtual base, this is the offset in the
1624684ddb6SLionel Sambuc // virtual table of the virtual base offset for the virtual base
1634684ddb6SLionel Sambuc // referenced (negative).'
1644684ddb6SLionel Sambuc
1654684ddb6SLionel Sambuc void *obj = *thrown_object;
1664684ddb6SLionel Sambuc if (info->isVirtual())
1674684ddb6SLionel Sambuc {
1684684ddb6SLionel Sambuc // Object's vtable
169*0a6a1f1dSLionel Sambuc ptrdiff_t *off = *static_cast<ptrdiff_t**>(obj);
1704684ddb6SLionel Sambuc // Offset location in vtable
1714684ddb6SLionel Sambuc off = ADD_TO_PTR(off, offset);
1724684ddb6SLionel Sambuc offset = *off;
1734684ddb6SLionel Sambuc }
1744684ddb6SLionel Sambuc void *cast = ADD_TO_PTR(obj, offset);
1754684ddb6SLionel Sambuc
1764684ddb6SLionel Sambuc if (info->__base_type == target ||
1774684ddb6SLionel Sambuc (info->__base_type->__do_upcast(target, &cast)))
1784684ddb6SLionel Sambuc {
1794684ddb6SLionel Sambuc *thrown_object = cast;
1804684ddb6SLionel Sambuc return true;
1814684ddb6SLionel Sambuc }
1824684ddb6SLionel Sambuc }
1834684ddb6SLionel Sambuc return 0;
1844684ddb6SLionel Sambuc }
1854684ddb6SLionel Sambuc
1864684ddb6SLionel Sambuc
1874684ddb6SLionel Sambuc /**
1884684ddb6SLionel Sambuc * ABI function used to implement the dynamic_cast<> operator. Some cases of
1894684ddb6SLionel Sambuc * this operator are implemented entirely in the compiler (e.g. to void*).
1904684ddb6SLionel Sambuc * This function implements the dynamic casts of the form dynamic_cast<T>(v).
1914684ddb6SLionel Sambuc * This will be translated to a call to this function with the value v as the
1924684ddb6SLionel Sambuc * first argument. The type id of the static type of v is the second argument
1934684ddb6SLionel Sambuc * and the type id of the destination type (T) is the third argument.
1944684ddb6SLionel Sambuc *
1954684ddb6SLionel Sambuc * The third argument is a hint about the compiler's guess at the correct
1964684ddb6SLionel Sambuc * pointer offset. If this value is negative, then -1 indicates no hint, -2
1974684ddb6SLionel Sambuc * that src is not a public base of dst, and -3 that src is a multiple public
1984684ddb6SLionel Sambuc * base type but never a virtual base type
1994684ddb6SLionel Sambuc */
__dynamic_cast(const void * sub,const __class_type_info * src,const __class_type_info * dst,ptrdiff_t src2dst_offset)2004684ddb6SLionel Sambuc extern "C" void* __dynamic_cast(const void *sub,
2014684ddb6SLionel Sambuc const __class_type_info *src,
2024684ddb6SLionel Sambuc const __class_type_info *dst,
2034684ddb6SLionel Sambuc ptrdiff_t src2dst_offset)
2044684ddb6SLionel Sambuc {
205*0a6a1f1dSLionel Sambuc const char *vtable_location = *static_cast<const char * const *>(sub);
2064684ddb6SLionel Sambuc const vtable_header *header =
207*0a6a1f1dSLionel Sambuc reinterpret_cast<const vtable_header*>(vtable_location - sizeof(vtable_header));
208*0a6a1f1dSLionel Sambuc void *leaf = ADD_TO_PTR(const_cast<void *>(sub), header->leaf_offset);
2094684ddb6SLionel Sambuc return header->type->cast_to(leaf, dst);
2104684ddb6SLionel Sambuc }
211