1c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// Copyright (C) 2011 The Android Open Source Project
2c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// All rights reserved.
3c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner//
4c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// Redistribution and use in source and binary forms, with or without
5c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// modification, are permitted provided that the following conditions
6c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// are met:
7c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// 1. Redistributions of source code must retain the above copyright
8c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner//    notice, this list of conditions and the following disclaimer.
9c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// 2. Redistributions in binary form must reproduce the above copyright
10c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner//    notice, this list of conditions and the following disclaimer in the
11c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner//    documentation and/or other materials provided with the distribution.
12c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// 3. Neither the name of the project nor the names of its contributors
13c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner//    may be used to endorse or promote products derived from this software
14c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner//    without specific prior written permission.
15c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner//
16c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
17c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
20c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// SUCH DAMAGE.
27c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner//
28c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// dynamic_cast.cc: RTTI support.
29c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner//
30c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// References:
31c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// Itanium C++ ABI at http://www.codesourcery.com/public/cxx-abi/abi.html
32c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// IHI0041A C++ Application Binary Interface for the ARM architecture.
33c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner//
34c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner
35c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner#include <cxxabi.h>
36c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner
37c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner#include <cstddef>
38c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner#include <cassert>
39c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner
40c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turnernamespace
41c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner{
42c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  // Adjust a pointer by an offset.
43c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner
44c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  const void*
45c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  adjust_pointer(const void* p, std::ptrdiff_t off)
46c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  {
47c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    // FIXME: should we align pointer after adjustment?
48c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    const char *cp = reinterpret_cast<const char*>(p) + off;
49c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    return reinterpret_cast<const void*>(cp);
50c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  }
51c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner
52c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  // Return the vtable pointer of a polymorphic object pointed by p.
53c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner
54c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  inline const void*
55c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  get_vtable(const void* p)
56c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  {
57c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    return *reinterpret_cast<void*const*>(p);
58c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  }
59c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner
60c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  // Return a pointer to a __class_type_info in a vtable.
61c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner
62c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  inline const abi::__class_type_info*
63c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  get_class_type_info(const void* vtable)
64c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  {
65c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    const void* type_info_ptr = adjust_pointer(vtable, -sizeof(void*));
66c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    return *reinterpret_cast<abi::__class_type_info*const*>(type_info_ptr);
67c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  }
68c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner
69c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  // Return offset to object in a vtable.
70c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner
71c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  inline std::ptrdiff_t
72c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  get_offset_to_top(const void* vtable)
73c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  {
74c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    const void* type_info_ptr_address = adjust_pointer(vtable, -sizeof(void*));
75c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    const void* offset_to_top_address =
76c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner      adjust_pointer(type_info_ptr_address, -sizeof(std::ptrdiff_t));
77c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    return *reinterpret_cast<const std::ptrdiff_t*>(offset_to_top_address);
78c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  }
79c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner
80c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  // Return the virtual pointer to the most derived object of referred by a
81c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  // pointer p.
82c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner
83c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  const void*
84c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  get_most_derived_object(const void* p)
85c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  {
86c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    const void* vtable = get_vtable(p);
87c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    std::ptrdiff_t offset_to_top = get_offset_to_top(vtable);
88c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    return adjust_pointer(p, offset_to_top);
89c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  }
90c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner
91c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  // We assume that -1 cannot be a valid pointer to object.
92c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  const void * const ambiguous_object =
93c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    reinterpret_cast<const void*>(-1);
94c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner
95c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  // Return a pointer to the subobject described by base_info.
96c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner
97c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  const void*
98c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  get_subobject(const void* object,
99c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner                const void* vtable,
100c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner                const abi::__base_class_type_info* base_info)
101c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  {
102c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    long offset = base_info->offset();
103c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    if (base_info->is_virtual())
104c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner      {
105c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner        const std::ptrdiff_t* virtual_base_offset_address =
106c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner          static_cast<const std::ptrdiff_t*> (adjust_pointer(vtable, offset));
107c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner        offset = *virtual_base_offset_address;
108c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner      }
109c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    return adjust_pointer(object, offset);
110c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  }
111c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner
112c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  // Helper of __dyanmic_cast to walk the type tree of an object.
113c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner
114c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  const void *
115c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  walk_object(const void *object,
116c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner              const abi::__class_type_info *type,
117c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner              const void *match_object,
118c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner              const abi::__class_type_info *match_type)
119c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  {
120c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    if (*type == *match_type)
121c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner      return (match_object == NULL || object == match_object) ? object : NULL;
122c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner
123c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    switch(type->code())
124c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner      {
125c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner      case abi::__class_type_info::CLASS_TYPE_INFO_CODE:
126c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner        // This isn't not the class you're looking for.
127c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner        return NULL;
128c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner
129c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner      case abi::__class_type_info::SI_CLASS_TYPE_INFO_CODE:
130c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner        // derived type has a single public base at offset 0.
131c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner        {
132c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner          const abi::__si_class_type_info* ti =
133c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner            static_cast<const abi::__si_class_type_info*>(type);
134c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner          return walk_object(object, ti->__base_type, match_object,
135c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner                             match_type);
136c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner        }
137c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner
138c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner      case abi::__class_type_info::VMI_CLASS_TYPE_INFO_CODE:
139c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner        {
140c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner          const void* vtable = get_vtable(object);
141c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner          const abi::__vmi_class_type_info* ti =
142c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner            static_cast<const abi::__vmi_class_type_info*>(type);
143c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner
144c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner          // Look at all direct bases.
145c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner          const void* result = NULL;
146c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner          for (unsigned i = 0; i < ti->__base_count; ++i)
147c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner            {
148c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner              if (!ti->__base_info[i].is_public())
149c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner                continue;
150c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner
151c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner              const void *subobject =
152c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner                get_subobject(object, vtable, &ti->__base_info[i]);
153c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner              const void* walk_subobject_result =
154c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner                walk_object(subobject, ti->__base_info[i].__base_type,
155c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner                            match_object, match_type);
156c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner
157c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner              if (walk_subobject_result == ambiguous_object)
158c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner                return ambiguous_object;
159c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner              else if (walk_subobject_result != NULL)
160c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner                {
161c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner                  if (result == NULL)
162c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner                    {
163c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner                      result = walk_subobject_result;
164c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner                    }
165c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner                  else if (result != walk_subobject_result)
166c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner                    return ambiguous_object;
167c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner                }
168c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner            }
169c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner          return result;
170c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner        }
171c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner
172c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner      default:
173c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner        assert(0);
174c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner      }
175c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    return NULL;
176c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  }
177c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner
178c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  // Bookkeeping structure for derived-to-base cast in the general case.
179c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  struct cast_context
180c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  {
181c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  public:
182c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    const void* object;
183c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    const abi::__class_type_info *src_type;
184c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    const abi::__class_type_info *dst_type;
185c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    std::ptrdiff_t src2dst_offset;
186c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner
187c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    const void* dst_object;
188c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    const void* result;
189c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner
190c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    cast_context(const void* obj, const abi::__class_type_info *src,
191c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner                 const abi::__class_type_info *dst, std::ptrdiff_t offset)
192c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner      : object(obj), src_type(src), dst_type(dst), src2dst_offset(offset),
193c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner        dst_object(NULL), result(NULL)
194c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    { }
195c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  };
196c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner
197c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  // based-to-derive cast in the general case.
198c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner
199c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  void
200c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  base_to_derived_cast(const void *object,
201c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner                       const abi::__class_type_info *type,
202c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner                       cast_context* context)
203c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  {
204c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    const void* saved_dst_object = context->dst_object;
205c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    bool is_dst_type = *type == *context->dst_type;
206c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    if (is_dst_type)
207c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner      context->dst_object = object;
208c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner
209c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    if (object == context->object
210c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner        && context->dst_object != NULL
211c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner        && *type == *context->src_type)
212c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner      {
213c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner        if (context->result == NULL)
214c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner          context->result = context->dst_object;
215c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner        else if (context->result != context->dst_object)
216c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner          context->result = ambiguous_object;
217c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner        context->dst_object = saved_dst_object;
218c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner        return;
219c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner      }
220c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner
221c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    switch(type->code())
222c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner      {
223c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner      case abi::__class_type_info::CLASS_TYPE_INFO_CODE:
224c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner        // This isn't not the class you're looking for.
225c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner        break;
226c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner
227c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner      case abi::__class_type_info::SI_CLASS_TYPE_INFO_CODE:
228c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner        // derived type has a single public base at offset 0.
229c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner        {
230c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner          const abi::__si_class_type_info* ti =
231c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner            static_cast<const abi::__si_class_type_info*>(type);
232c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner          base_to_derived_cast(object, ti->__base_type, context);
233c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner          break;
234c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner        }
235c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner
236c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner      case abi::__class_type_info::VMI_CLASS_TYPE_INFO_CODE:
237c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner        {
238c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner          const void* vtable = get_vtable(object);
239c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner          const abi::__vmi_class_type_info* ti =
240c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner            static_cast<const abi::__vmi_class_type_info*>(type);
241c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner
242c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner          // Look at all direct bases.
243c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner          for (unsigned i = 0; i < ti->__base_count; ++i)
244c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner            {
245c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner              if (!ti->__base_info[i].is_public())
246c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner                continue;
247c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner
248c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner              const void *subobject =
249c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner                get_subobject(object, vtable, &ti->__base_info[i]);
250c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner              base_to_derived_cast(subobject, ti->__base_info[i].__base_type,
251c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner                                   context);
252c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner
253c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner              // FIXME: Use flags in base_info to optimize search.
254c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner              if (context->result == ambiguous_object)
255c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner                break;
256c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner            }
257c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner          break;
258c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner        }
259c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner
260c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner      default:
261c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner        assert(0);
262c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner      }
263c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner     context->dst_object = saved_dst_object;
264c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  }
265c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner} // namespace
266c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner
267c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turnernamespace __cxxabiv1
268c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner{
269c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner#define DYNAMIC_CAST_NO_HINT -1
270c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner#define DYNAMIC_CAST_NOT_PUBLIC_BASE -2
271c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner#define DYNAMIC_CAST_MULTIPLE_PUBLIC_NONVIRTUAL_BASE -3
272c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner
273c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  /* v: source address to be adjusted; nonnull, and since the
274c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner   *    source object is polymorphic, *(void**)v is a virtual pointer.
275c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner   * src: static type of the source object.
276c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner   * dst: destination type (the "T" in "dynamic_cast<T>(v)").
277c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner   * src2dst_offset: a static hint about the location of the
278c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner   *    source subobject with respect to the complete object;
279c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner   *    special negative values are:
280c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner   *       -1: no hint
281c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner   *       -2: src is not a public base of dst
282c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner   *       -3: src is a multiple public base type but never a
283c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner   *           virtual base type
284c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner   *    otherwise, the src type is a unique public nonvirtual
285c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner   *    base type of dst at offset src2dst_offset from the
286c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner   *    origin of dst.
287c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner   */
288c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  extern "C" void*
289c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  __dynamic_cast (const void *v,
290c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner                  const abi::__class_type_info *src,
291c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner                  const abi::__class_type_info *dst,
292c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner                  std::ptrdiff_t src2dst_offset)
293c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  {
294c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    const void* most_derived_object = get_most_derived_object(v);
295c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    const void* vtable = get_vtable(most_derived_object);
296c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    const abi::__class_type_info* most_derived_class_type_info =
297c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner      get_class_type_info(vtable);
298c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner
299c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    // If T is not a public base type of the most derived class referred
300c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    // by v, the cast always fails.
301c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    void* t_object =
302c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner      const_cast<void*>(walk_object(most_derived_object,
303c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner                                    most_derived_class_type_info, NULL, dst));
304c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    if (t_object == NULL)
305c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner      return NULL;
306c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner
307c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    // C++ ABI 2.9.7 The dynamic_cast Algorithm:
308c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    //
309c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    // If, in the most derived object pointed (referred) to by v, v points
310c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    // (refers) to a public base class subobject of a T object [note: this can
311c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    // be checked at compile time], and if only one object of type T is derived
312c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    // from the subobject pointed (referred) to by v, the result is a pointer
313c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    // (an lvalue referring) to that T object.
314c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner
315c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    // We knew that src is not a public base, so base-to-derived cast
316c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    // is not possible.  This works even if there are multiple subobjects
317c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    // of type T in the most derived object.
318c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    if (src2dst_offset != DYNAMIC_CAST_NOT_PUBLIC_BASE)
319c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner      {
320c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner        // If it is known that v points to a public base class subobject
321c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner        // of a T object, simply adjust the pointer by the offset.
322c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner        if (t_object != ambiguous_object && src2dst_offset >= 0)
323b5300299788c51394c7f57b32c7e073605e4e22dDavid 'Digit' Turner          return const_cast<void*>(adjust_pointer(v, -src2dst_offset));
324c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner
325c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner        // If there is only one T type subobject, we only need to look at
326c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner        // there.  Otherwise, look for the subobject referred by v in the
327c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner        // most derived object.
328c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner        cast_context context(v, src, dst, src2dst_offset);
329c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner        if (t_object != ambiguous_object)
330c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner          base_to_derived_cast(t_object, dst, &context);
331c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner        else
332c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner          base_to_derived_cast(most_derived_object,
333c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner                               most_derived_class_type_info, &context);
334c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner
335c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner        if (context.result != NULL && context.result != ambiguous_object)
336c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner          return const_cast<void*>(context.result);
337c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner      }
338c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner
339c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    // C++ ABI 2.9.7 The dynamic_cast Algorithm:
340c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    //
341c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    // Otherwise, if v points (refers) to a public base class subobject of the
342c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    // most derived object, and the type of the most derived object has an
343c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    // unambiguous public base class of type T, the result is a pointer (an
344c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    // lvalue referring) to the T subobject of the most derived object.
345c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    // Otherwise, the run-time check fails.
346c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner
347c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    // Check to see if T is a unambiguous public base class.
348c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    if (t_object == ambiguous_object)
349c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner      return NULL;
350c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner
351c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    // See if v refers to a public base class subobject.
352c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    const void* v_object =
353c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner      walk_object(most_derived_object, most_derived_class_type_info, v, src);
354c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner    return v_object == v ? t_object : NULL;
355c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner  }
356c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner} // namespace __cxxabiv1
357