wordpress整站源码带数据,多语言网站建设推广,怎么做卖卷网站,福田网站建设设计公司哪家好摘要#xff1a;最近在看一个崩溃的过程中详细看了一遍cxxabi的定义#xff0c;就想着看一些llvm中cxxabi的一些实现。本文描述了cxxabi中dynamic_cast的实现以及原理。 关键字#xff1a;cxxabi,dynamic_cast
1 简介 C中#xff0c;dynamic_cast用于有虚函数的继承链… 摘要最近在看一个崩溃的过程中详细看了一遍cxxabi的定义就想着看一些llvm中cxxabi的一些实现。本文描述了cxxabi中dynamic_cast的实现以及原理。 关键字cxxabi,dynamic_cast
1 简介 C中dynamic_cast用于有虚函数的继承链中父类型到子类型的安全转换。比较常见的用法如下
class A{
public:virtual ~A() default;
};class B{
};A *p new B;
B* pp dynamic_castB*(p);dynamic_cast如何识别当前类的类型这依赖于RTTI。C中包含虚函数的对象都有一个虚函数表一般情况下都在首地址多继承和虚继承会有多个有一个指向该虚函数表的虚函数表指针。虚函数表中有以下内容
基类偏移typeinfo如果有虚函数的话会有虚析构函数指针一般情况下有两个 The entries for virtual destructors are actually pairs of entries. The first destructor, called the complete object destructor, performs the destruction without calling delete() on the object. The second destructor, called the deleting destructor, calls delete() after destroying the object. Both destroy any virtual bases; a separate, non-virtual function, called the base object destructor, performs destruction of the object but not its virtual base subobjects, and does not call delete(). 虚函数指针如果是虚继承对应的虚函数指针可能是一个thunk function。 A segment of code associated (in this ABI) with a target function, which is called instead of the target function for the purpose of modifying parameters (e.g. this) or other parts of the environment before transferring control to the target function, and possibly making further modifications after its return. A thunk may contain as little as an instruction to be executed prior to falling through to an immediately following target function, or it may be a full function with its own stack frame that does a full call to the target function. C中就是通过虚函数表携带的typeinfo信息来确认当前类的类型如果是该类型就就可以转换成功否则的话就会转换失败。cxxabi的基本实现思路也是如此。
2 cxxabi实现 先来看一下cxxabi中对应实现函数的声明。
static_ptr期望将进行转换的类地址static_type当前类的类型信息dst_type目标转换类的类型信息src2dst_offset由 Itanium ABI 所规定的 hint 值辅助优化用 是一个非负整数值说明From是To的唯一一个公开非虚基类且From基类子对象在一个To对象中的偏移为src2dst_offset-1表示无hint-2表示From不是To的公开基类-3表示To存在多个公开From基类但是这些公开From基类都不是To的虚基类。
extern C _LIBCXXABI_FUNC_VIS void *
__dynamic_cast(const void *static_ptr, const __class_type_info *static_type, const __class_type_info *dst_type, std::ptrdiff_t src2dst_offset) 首先是从虚函数表中提取出当前类对象相对于子类首地址的offset和typeinfo这两项都是固定存储在虚函数表指针所指向位置的-1和-2位置处。 The offset to top holds the displacement to the top of the object from the location within the object of the virtual table pointer that addresses this virtual table, as a ptrdiff_t. It is always present. The offset provides a way to find the top of the object from any base subobject with a virtual table pointer. This is necessary for dynamic_castvoid* in particular. void **vtable *static_castvoid ** const *(static_ptr);ptrdiff_t offset_to_derived reinterpret_castptrdiff_t(vtable[-2]);const void* dynamic_ptr static_castconst char*(static_ptr) offset_to_derived;const __class_type_info* dynamic_type static_castconst __class_type_info*(vtable[-1]);接下来便是根据期望转换的目标对象的typeinfo和当前获取的typeinfo作对比进而选择是否将进行更进一步的转换。需要注意的是比较两个对象是否相同的方式
static inline bool is_equal(const std::type_info* x, const std::type_info* y, bool use_strcmp){// Use std::type_infos default comparison unless weve explicitly asked// for strcmp.if (!use_strcmp)return *x *y;// Still allow pointer equality to short circut.return x y || strcmp(x-name(), y-name()) 0;
}相同类型 typeinfo是编译器生成的是静态对象用户只能读写这里提供了使用typeinfo的名字和指针来比较的方式是为了避免一些场景下typeinfo不一致导致转换失败虽然ABI中默认是关闭的。 针对typeinfo相同的情况下则需要根据src2dst_offset来辅助优化
src2dst_offset为非负整数时fromt是to的唯一公开非虚基类。但是to类型是有可能有其他非公开基类的因此需要比较vtptr中的偏移和src2dst_offset能够匹配则直接返回偏移后的地址否则返回空指针src2dst_offset为-2表示from不是to的公开基类直接返回空指针 if (src2dst_offset 0){// The static type is a unique public non-virtual base type of// dst_type at offset src2dst_offset from the origin of dst.// Note that there might be other non-public static_type bases. The// hint only guarantees that the public base is non-virtual and// unique. So we have to check whether static_ptr points to that// unique public base sub-object.if (offset_to_derived -src2dst_offset)dst_ptr dynamic_ptr;}else if (src2dst_offset -2){// static_type is not a public base of dst_type.dst_ptr nullptr;}src2dst_offset无法提供帮助时只能所搜继承图来确认是否存在继承关系。此时只能搜索整张继承图搜索出从最派生对象所有的from公开基类子对象。如果from所指向的对象是这些from基类子对象中的某一个那么转换成功转换结果是最派生对象指针否则转换失败。在搜索继承图的过程中可以应用一些剪枝方法降低搜索开销。例如一旦搜索到from指向的对象就停止搜索、不搜索包含私有继承的路径等。
info.number_of_dst_type 1;
// Do the search
dynamic_type-search_above_dst(info, dynamic_ptr, dynamic_ptr, public_path, false);不相同类型 typeinfo不相同时表示源和目标只是在相同的继承图上但是并不存在直接的公开继承关系因此为了确认是否真的存在该关系只能搜索当前源和目标的继承图来确认。 libcxxabi的dynamic_cast实现似乎有性能问题https://reviews.llvm.org/D137315#3910662这个patch修复了该问题。修复完的benchmarkhttps://gist.github.com/Lancern/212a26a3144343f459428dffe202cde0 搜索策略 对于不同继承类型的类的 type info 有不同的搜索策略。例如对于有虚多继承的类的 type info__vmi_class_type_info、单继承的类的 type info__si_class_info等。搜索的方式看起来就是广度优先搜索再加上一些剪枝的优化。