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