| // Copyright (C) 2011 The Android Open Source Project |
| // All rights reserved. |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions |
| // are met: |
| // 1. Redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer. |
| // 2. Redistributions in binary form must reproduce the above copyright |
| // notice, this list of conditions and the following disclaimer in the |
| // documentation and/or other materials provided with the distribution. |
| // 3. Neither the name of the project nor the names of its contributors |
| // may be used to endorse or promote products derived from this software |
| // without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND |
| // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| // ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE |
| // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| // SUCH DAMAGE. |
| // |
| // vmi_class_type_info.cc: Methods for __vmi_class_type_info. |
| |
| #include <cassert> |
| #include <cxxabi.h> |
| |
| namespace __cxxabiv1 |
| { |
| __vmi_class_type_info::~__vmi_class_type_info() |
| { |
| } |
| |
| bool __vmi_class_type_info::walk_to(const __class_type_info* base_type, |
| void*& adjustedPtr, |
| __UpcastInfo& info) const { |
| if (self_class_type_match(base_type, adjustedPtr, info)) { |
| return true; |
| } |
| |
| for (size_t i = 0, e = __base_count; i != e; ++i) { |
| __UpcastInfo cur_base_info(this); |
| void* cur_base_ptr = adjustedPtr; |
| const __class_type_info* cur_base_type = __base_info[i].__base_type; |
| long cur_base_offset = __base_info[i].offset(); |
| bool cur_base_is_virtual = __base_info[i].is_virtual(); |
| bool cur_base_is_public = __base_info[i].is_public(); |
| |
| // Adjust cur_base_ptr to correct position |
| if (cur_base_ptr) { |
| if (cur_base_is_virtual) { |
| void* vtable = *reinterpret_cast<void**>(cur_base_ptr); |
| cur_base_offset = *reinterpret_cast<long*>( |
| static_cast<uint8_t*>(vtable) + cur_base_offset); |
| } |
| cur_base_ptr = static_cast<uint8_t*>(cur_base_ptr) + cur_base_offset; |
| } |
| |
| |
| if (!cur_base_is_public && |
| (info.premier_flags & __non_diamond_repeat_mask) == 0) { |
| continue; |
| } |
| |
| |
| /*** Body ***/ |
| |
| |
| if (!cur_base_type->walk_to(base_type, cur_base_ptr, cur_base_info)) { |
| continue; |
| } |
| |
| |
| /*** Post ***/ |
| |
| |
| if (!cur_base_is_public) { // Narrow public attribute |
| cur_base_info.status = __UpcastInfo::has_ambig_or_not_public; |
| } |
| |
| if (cur_base_is_virtual) { |
| // We can make sure it may not conflict from now. |
| cur_base_info.nullobj_may_conflict = false; |
| } |
| |
| // First time found |
| if (info.base_type == NULL && cur_base_info.base_type != NULL) { |
| info = cur_base_info; |
| if (info.status == __UpcastInfo::has_public_contained && |
| (__flags & __non_diamond_repeat_mask) == 0) { |
| // Don't need to call deeper recursively since |
| // it has no non-diamond repeat superclass |
| |
| // Return true only means we found one. |
| // It didn't guarantee it is the unique public one. We need to check |
| // publicity in the recursive caller-side. |
| // |
| // Why we don't just return false? No, we can't. |
| // Return false will make the caller ignore this base class directly, |
| // but we need some information kept in the info. |
| return true; |
| } |
| continue; |
| } |
| |
| assert (info.base_type != NULL && cur_base_info.base_type != NULL); |
| |
| // Found twice, but different types |
| if (*cur_base_info.base_type != *info.base_type) { |
| info.status = __UpcastInfo::has_ambig_or_not_public; |
| return true; |
| } |
| |
| // Found twice, but null object |
| if (!info.adjustedPtr && !cur_base_info.adjustedPtr) { |
| if (info.nullobj_may_conflict || cur_base_info.nullobj_may_conflict) { |
| info.status = __UpcastInfo::has_ambig_or_not_public; |
| return true; |
| } |
| |
| if (*info.base_type == *cur_base_info.base_type) { |
| // The two ptr definitely not point to the same object, although |
| // their base_type are the same. |
| // Otherwise, It will immediately return back at the statement before: |
| // |
| // if (info.status == __UpcastInfo::has_public_contained && |
| // (__flags & __non_diamond_repeat_mask) == 0) { return true; } |
| info.status = __UpcastInfo::has_ambig_or_not_public; |
| return true; |
| } |
| } |
| |
| assert (*info.base_type == *cur_base_info.base_type); |
| |
| // Logically, this should be: |
| // assert (info.adjustedPtr || cur_base_info.adjustedPtr); |
| // But in reality, this will be: |
| assert (info.adjustedPtr && cur_base_info.adjustedPtr); |
| |
| // Found twice, but different real objects |
| if (info.adjustedPtr != cur_base_info.adjustedPtr) { |
| info.status = __UpcastInfo::has_ambig_or_not_public; |
| return true; |
| } |
| |
| // Found twice, but the same real object (virtual base) |
| continue; |
| } |
| |
| // We need information in info unless we know nothing |
| return info.status != __UpcastInfo::unknown; |
| } |
| } // namespace __cxxabiv1 |