dynamic_cast.cc revision 232950
1255736Sdavidch/*
2265797Sdavidcs * Copyright 2010-2011 PathScale, Inc. All rights reserved.
3255736Sdavidch *
4255736Sdavidch * Redistribution and use in source and binary forms, with or without
5255736Sdavidch * modification, are permitted provided that the following conditions are met:
6255736Sdavidch *
7255736Sdavidch * 1. Redistributions of source code must retain the above copyright notice,
8255736Sdavidch *    this list of conditions and the following disclaimer.
9255736Sdavidch *
10255736Sdavidch * 2. Redistributions in binary form must reproduce the above copyright notice,
11255736Sdavidch *    this list of conditions and the following disclaimer in the documentation
12255736Sdavidch *    and/or other materials provided with the distribution.
13255736Sdavidch *
14255736Sdavidch * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
15255736Sdavidch * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16255736Sdavidch * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17255736Sdavidch * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
18255736Sdavidch * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19255736Sdavidch * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20255736Sdavidch * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21255736Sdavidch * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22255736Sdavidch * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23255736Sdavidch * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24255736Sdavidch * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25255736Sdavidch */
26255736Sdavidch
27255736Sdavidch#include "typeinfo.h"
28255736Sdavidch#include <stdio.h>
29255736Sdavidch
30255736Sdavidchusing namespace ABI_NAMESPACE;
31255736Sdavidch
32255736Sdavidch/**
33255736Sdavidch * Vtable header.
34255736Sdavidch */
35255736Sdavidchstruct vtable_header
36255736Sdavidch{
37255736Sdavidch	/** Offset of the leaf object. */
38255736Sdavidch	ptrdiff_t leaf_offset;
39255736Sdavidch	/** Type of the object. */
40255736Sdavidch	const __class_type_info *type;
41255736Sdavidch};
42255736Sdavidch
43255736Sdavidch/**
44255736Sdavidch * Simple macro that does pointer arithmetic in bytes but returns a value of
45255736Sdavidch * the same type as the original.
46255736Sdavidch */
47255736Sdavidch#define ADD_TO_PTR(x, off) (__typeof__(x))(((char*)x) + off)
48255736Sdavidch
49255736Sdavidchbool __class_type_info::can_cast_to(const struct __class_type_info *other) const
50255736Sdavidch{
51255736Sdavidch    return this == other;
52255736Sdavidch}
53255736Sdavidch
54255736Sdavidchvoid *__class_type_info::cast_to(void *obj, const struct __class_type_info *other) const
55255736Sdavidch{
56255736Sdavidch	if (this == other)
57255736Sdavidch	{
58255736Sdavidch		return obj;
59255736Sdavidch	}
60255736Sdavidch	return 0;
61255736Sdavidch}
62255736Sdavidch
63255736Sdavidch
64255736Sdavidchbool __si_class_type_info::can_cast_to(const struct __class_type_info *other) const
65255736Sdavidch{
66255736Sdavidch    return this == other || __base_type->can_cast_to(other);
67255736Sdavidch}
68255736Sdavidch
69255736Sdavidchvoid *__si_class_type_info::cast_to(void *obj, const struct __class_type_info *other) const
70255736Sdavidch{
71255736Sdavidch	if (this == other)
72255736Sdavidch	{
73255736Sdavidch		return obj;
74255736Sdavidch	}
75255736Sdavidch	return __base_type->cast_to(obj, other);
76255736Sdavidch}
77255736Sdavidch
78255736Sdavidch
79255736Sdavidchbool __vmi_class_type_info::can_cast_to(const struct __class_type_info *other) const
80255736Sdavidch{
81255736Sdavidch	if (this == other)
82255736Sdavidch	{
83255736Sdavidch		return true;
84255736Sdavidch	}
85255736Sdavidch	for (unsigned int i=0 ; i<__base_count ; i++)
86255736Sdavidch	{
87255736Sdavidch		const __base_class_type_info *info = &__base_info[i];
88255736Sdavidch        if(info->isPublic() && info->__base_type->can_cast_to(other))
89255736Sdavidch        {
90255736Sdavidch            return true;
91255736Sdavidch        }
92255736Sdavidch	}
93255736Sdavidch	return false;
94255736Sdavidch}
95255736Sdavidch
96255736Sdavidchvoid *__vmi_class_type_info::cast_to(void *obj, const struct __class_type_info *other) const
97255736Sdavidch{
98255736Sdavidch	if (this == other)
99255736Sdavidch	{
100255736Sdavidch		return obj;
101255736Sdavidch	}
102255736Sdavidch	for (unsigned int i=0 ; i<__base_count ; i++)
103255736Sdavidch	{
104255736Sdavidch		const __base_class_type_info *info = &__base_info[i];
105255736Sdavidch		ptrdiff_t offset = info->offset();
106255736Sdavidch		// If this is a virtual superclass, the offset is stored in the
107255736Sdavidch		// object's vtable at the offset requested; 2.9.5.6.c:
108255736Sdavidch		//
109255736Sdavidch		// 'For a non-virtual base, this is the offset in the object of the
110255736Sdavidch		// base subobject. For a virtual base, this is the offset in the
111255736Sdavidch		// virtual table of the virtual base offset for the virtual base
112255736Sdavidch		// referenced (negative).'
113255736Sdavidch
114255736Sdavidch		if (info->isVirtual())
115255736Sdavidch		{
116255736Sdavidch			// Object's vtable
117255736Sdavidch			ptrdiff_t *off = *(ptrdiff_t**)obj;
118255736Sdavidch			// Offset location in vtable
119255736Sdavidch			off = ADD_TO_PTR(off, offset);
120255736Sdavidch			offset = *off;
121255736Sdavidch		}
122255736Sdavidch		void *cast = ADD_TO_PTR(obj, offset);
123255736Sdavidch
124255736Sdavidch		if (info->__base_type == other)
125255736Sdavidch		{
126255736Sdavidch			return cast;
127255736Sdavidch		}
128255736Sdavidch		if ((cast = info->__base_type->cast_to(cast, other)))
129255736Sdavidch		{
130255736Sdavidch			return cast;
131255736Sdavidch		}
132255736Sdavidch	}
133255736Sdavidch	return 0;
134255736Sdavidch}
135255736Sdavidch
136255736Sdavidch/**
137255736Sdavidch * ABI function used to implement the dynamic_cast<> operator.  Some cases of
138255736Sdavidch * this operator are implemented entirely in the compiler (e.g. to void*).
139255736Sdavidch * This function implements the dynamic casts of the form dynamic_cast<T>(v).
140255736Sdavidch * This will be translated to a call to this function with the value v as the
141255736Sdavidch * first argument.  The type id of the static type of v is the second argument
142255736Sdavidch * and the type id of the destination type (T) is the third argument.
143255736Sdavidch *
144255736Sdavidch * The third argument is a hint about the compiler's guess at the correct
145255736Sdavidch * pointer offset.  If this value is negative, then -1 indicates no hint, -2
146255736Sdavidch * that src is not a public base of dst, and -3 that src is a multiple public
147255736Sdavidch * base type but never a virtual base type
148255736Sdavidch */
149255736Sdavidchextern "C" void* __dynamic_cast(const void *sub,
150255736Sdavidch                                const __class_type_info *src,
151255736Sdavidch                                const __class_type_info *dst,
152255736Sdavidch                                ptrdiff_t src2dst_offset)
153255736Sdavidch{
154255736Sdavidch	char *vtable_location = *(char**)sub;
155255736Sdavidch	const vtable_header *header =
156255736Sdavidch		(const vtable_header*)(vtable_location - sizeof(vtable_header));
157255736Sdavidch	void *leaf = ADD_TO_PTR((void*)sub, header->leaf_offset);
158255736Sdavidch	return header->type->cast_to(leaf, dst);
159255736Sdavidch}
160255736Sdavidch