GCC-3.4.6源代码学习笔记(65)

4.3.1.7.8.2.2.              构建type­_info的定义

下面就是构建这个type_info类型系列。首先是基类。

 

1251   static void

1252   create_tinfo_types (void)                                                                                 in rtti.c

1253   {

1254     my_friendly_assert (!ti_desc_type_node, 20020609);

1255  

1256     push_nested_namespace (abi_node);

 

如果我们需要将不是被当前名字空间所包含的名字空间,作为当前名字空间(例如,当前是A::B,现在我们需要A::D),那么我们应该使用push_nested_namespace,而不是push_namespace。这个函数通过递归,首先回溯到全局名字空间,由push_to_top_level将当前名字空间到全局名字空间之间的内容缓存,然后由push_namespace逐个加入从全局名字空间到所希望名字空间之间的内容(参考进入全局名字空间)。

 

3143   void

3144   push_nested_namespace (tree ns)                                                       in name-lookup.c

3145   {

3146     if (ns == global_namespace)

3147       push_to_top_level ();

3148     else

3149     {

3150       push_nested_namespace (CP_DECL_CONTEXT (ns));

3151       push_namespace (DECL_NAME (ns));

3152     }

3153   }

 

push_nested_namespace的反向操作是pop_nested_namespace。它恢复所有被缓存的内容(参考从全局名字空间返回)。

 

3158   void

3159   pop_nested_namespace (tree ns)                                                         in name-lookup.c

3160   {

3161     timevar_push (TV_NAME_LOOKUP);

3162     while (ns != global_namespace)

3163     {

3164       pop_namespace ();

3165       ns = CP_DECL_CONTEXT (ns);

3166     }

3167  

3168     pop_from_top_level ();

3169     timevar_pop (TV_NAME_LOOKUP);

3170   }

 

现在我们在名字空间__cxxabiv1里了。在“gcc-3.4.6/libstdc++-v3/libsupc++”目录下,GCC有文件cxxabi.h。这个文件就是Linux系统include目录中的“c++/`version`/cxxabi.h”,而其代码生成在libstdc++.so.`ver`库文件里。编译器将按这个文件的内容来生成类定义。

__cxxabiv1名字空间里的类定义都是std::type_info的派生类。因此,首先应该构建这个基类。但是注意下面,这个基类构建在__cxxabiv1名字空间里,且名字是“type_info_pseduo”。事实上,在GCC内部并没有生成std::type_info的定义。在下面std::type_info的定义中,我们可以看到这个类不能单独使用,只能作为基类,而且它具有平凡析构函数(虽然是虚函数)。真正被使用的是__cxxabiv1中的type_info派生类。那么我们偷梁换柱,用type_info_pseduo来替换std::type_info亦无不可,只要我们用到方法、成员都一样的声明,并且不使用基类指针(编译器保证这一点)。下面可以看到type_info_pseduo类是被大大简化了的。

 

create_tinfo_types (continue)

 

1258     /* Create the internal type_info structure. This is used as a base for

1259       the other structures.  */

1260     {

1261       tree field, fields;

1262  

1263       ti_desc_type_node = make_aggr_type (RECORD_TYPE);

1264       field = build_decl (FIELD_DECL, NULL_TREE, const_ptr_type_node);

1265       fields = field;

1266      

1267       field = build_decl (FIELD_DECL, NULL_TREE, const_string_type_node);

1268       TREE_CHAIN (field) = fields;

1269       fields = field;

1270      

1271       finish_builtin_struct (ti_desc_type_node, "__type_info_pseudo",

1272                        fields, NULL_TREE);

1273       TYPE_HAS_CONSTRUCTOR (ti_desc_type_node) = 1;

1274     }

 

type_info_pseduo具有2个匿名成员,一个具有类型“const void*”,另一个是类型“const char*”。这是为了让type_info_pseduostd::type_info具有相同的大小(注意std::type_info有虚函数表,其大小就是const void*)。函数finish_builtin_struct完成这个结构体。

 

1476   void

1477   finish_builtin_struct (tree type, const char *name, tree fields,                      in stor-layout.c

1478                      tree align_type)

1479   {

1480     tree tail, next;

1481  

1482     for (tail = NULL_TREE; fields; tail = fields, fields = next)

1483     {

1484       DECL_FIELD_CONTEXT (fields) = type;

1485       next = TREE_CHAIN (fields);

1486       TREE_CHAIN (fields) = tail;

1487     }

1488     TYPE_FIELDS (type) = tail;

1489  

1490     if (align_type)

1491     {

1492       TYPE_ALIGN (type) = TYPE_ALIGN (align_type);

1493       TYPE_USER_ALIGN (type) = TYPE_USER_ALIGN (align_type);

1494     }

1495  

1496     layout_type (type);

1497   #if 0 /* not yet, should get fixed properly later */

1498     TYPE_NAME (type) = make_type_decl (get_identifier (name), type);

1499   #else

1500     TYPE_NAME (type) = build_decl (TYPE_DECL, get_identifier (name), type);

1501   #endif

1502     TYPE_STUB_DECL (type) = TYPE_NAME (type);

1503     layout_decl (TYPE_NAME (type), 0);

1504   }

 

下面将std::type_info的定义列出。作为对比,type_info_pseduo没有定义任何方法,而且只有不可用的匿名成员。为什么会这样呢?

 

63      class type_info                                                                                        in typeinfo

64      {

65        public:

66          /** Destructor. Being the first non-inline virtual function, this

67           *  controls in which translation unit the vtable is emitted. The

68           *  compiler makes use of that information to know where to emit

69           *  the runtime-mandated type_info structures in the new-abi.  */

70          virtual ~type_info();

71     

72       private:

73          /// Assigning type_info is not supported. Made private.

74          type_info& operator=(const type_info&);

75          type_info(const type_info&);

76         

77       protected:

78          const char *__name;

79         

80        protected:

81          explicit type_info(const char *__n): __name(__n) { }

82         

83       public:

84          // the public interface

85          /** Returns an @e implementation-defined byte string; this is not

86           * portable between compilers!  */

87          const char* name() const

88          { return __name; }

89     

90      #if !__GXX_MERGED_TYPEINFO_NAMES

91          bool before(const type_info& __arg) const;

92          // In old abi, or when weak symbols are not supported, there can

93          // be multiple instances of a type_info object for one

94          // type. Uniqueness must use the _name value, not object address.

95          bool operator==(const type_info& __arg) const;

96      #else

97          /** Returns true if @c *this precedes @c __arg in the implementation's

98           * collation order.  */

99          // In new abi we can rely on type_info's NTBS being unique,

100        // and therefore address comparisons are sufficient.

101        bool before(const type_info& __arg) const

102        { return __name < __arg.__name; }

103        bool operator==(const type_info& __arg) const

104        { return __name == __arg.__name; }

105    #endif

106        bool operator!=(const type_info& __arg) const

107        { return !operator==(__arg); }

108       

109        // the internal interface

110       public:

111         // return true if this is a pointer type of some kind

112         virtual bool __is_pointer_p() const;

113         // return true if this is a function type

114         virtual bool __is_function_p() const;

115    

116         // Try and catch a thrown type. Store an adjusted pointer to the

117         // caught type in THR_OBJ. If THR_TYPE is not a pointer type, then

118         // THR_OBJ points to the thrown object. If THR_TYPE is a pointer

119         // type, then THR_OBJ is the pointer itself. OUTER indicates the

120        // number of outer pointers, and whether they were const

121        // qualified.

122        virtual bool __do_catch(const type_info *__thr_type, void **__thr_obj,

123                           unsigned __outer) const;

124   

125        // internally used during catch matching

126        virtual bool __do_upcast(const __cxxabiv1::__class_type_info *__target,

127                            void **__obj_ptr) const;

128    };

 

首先,派生类指针向基类指针的向下类型转换(downcast),是不需要运行时类型信息的。派生类本身就有足够的信息,这一点我们后面会看到。而对于基类指针向派生类指针的类型提升(upcast),在C++中,有2种方法,一是通过C形式的强制转换,这一过程不会有任何类型检查;二是通过dynamic_cast操作符,这是库函数,它接受type_info对象。另外,C++会执行类型提升的地方,是catch表达式中的捕捉对象,编译器会自动调用dynamic_cast。那么,前端只要保证在交给后端生成汇编代码之前,dynamic_cast函数的实参是真实的type_info对象,而不是这里的伪type_info对象,就没有问题(因为真正的type_info方法也在库里)。后面可以看到,编译器就是这样做的,在前端编译的最后阶段,它将伪type_info对象替换为真实对象(因此,2者大小相同非常重要)。

接下来,继续定义对应于__cxxabiv1名字空间中的伪type_info派生类及辅助类。同样,这里的唯一准则就是,必须和真正的类型大小一样。

 

create_tinfo_types (continue)

 

1276     /* Fundamental type_info */

1277     bltn_desc_type_node = create_pseudo_type_info

1278         ("__fundamental_type_info", 0,

1279          NULL);

1280  

1281     /* Array, function and enum type_info. No additional fields.  */

1282     ary_desc_type_node = create_pseudo_type_info

1283         ("__array_type_info", 0,

1284          NULL);

1285     func_desc_type_node = create_pseudo_type_info

1286          ("__function_type_info", 0,

1287           NULL);

1288     enum_desc_type_node = create_pseudo_type_info

1289          ("__enum_type_info", 0,

1290           NULL);

1291    

1292    /* Class type_info. Add a flags field.  */

1293     class_desc_type_node = create_pseudo_type_info

1294           ("__class_type_info", 0,

1295            NULL);

1296    

1297     /* Single public non-virtual base class. Add pointer to base class.

1298       This is really a descendant of __class_type_info.  */

1299     si_class_desc_type_node = create_pseudo_type_info

1300              ("__si_class_type_info", 0,

1301               build_decl (FIELD_DECL, NULL_TREE, type_info_ptr_type),

1302               NULL);

1303    

1304     /* Base class internal helper. Pointer to base type, offset to base,

1305       flags.  */

1306     {

1307       tree field, fields;

1308      

1309       field = build_decl (FIELD_DECL, NULL_TREE, type_info_ptr_type);

1310       fields = field;

1311      

1312       field = build_decl (FIELD_DECL, NULL_TREE, integer_types[itk_long]);

1313       TREE_CHAIN (field) = fields;

1314       fields = field;

1315    

1316       base_desc_type_node = make_aggr_type (RECORD_TYPE);

1317       finish_builtin_struct (base_desc_type_node, "__base_class_type_info_pseudo",

1318                         fields, NULL_TREE);

1319       TYPE_HAS_CONSTRUCTOR (base_desc_type_node) = 1;

1320     }

1321    

1322     /* General hierarchy is created as necessary in this vector.  */

1323     vmi_class_desc_type_node = make_tree_vec (10);

1324    

1325    /* Pointer type_info. Adds two fields, qualification mask

1326       and pointer to the pointed to type. This is really a descendant of

1327       __pbase_type_info.  */

1328     ptr_desc_type_node = create_pseudo_type_info

1329         ("__pointer_type_info", 0,

1330          build_decl (FIELD_DECL, NULL_TREE, integer_type_node),

1331          build_decl (FIELD_DECL, NULL_TREE, type_info_ptr_type),

1332          NULL);

1333  

1334     /* Pointer to member data type_info. Add qualifications flags,

1335       pointer to the member's type info and pointer to the class.

1336       This is really a descendant of __pbase_type_info.  */

1337     ptm_desc_type_node = create_pseudo_type_info

1338          ("__pointer_to_member_type_info", 0,

1339           build_decl (FIELD_DECL, NULL_TREE, integer_type_node),

1340           build_decl (FIELD_DECL, NULL_TREE, type_info_ptr_type),

1341           build_decl (FIELD_DECL, NULL_TREE, type_info_ptr_type),

1342           NULL);

1343  

1344     pop_nested_namespace (abi_node);

1345   }

 

这些派生类的构建由下面的create_pseduo_type_info完成。在C++中,非虚基类于派生类,就如同一个数据成员。在编译器的实现中亦是这样处理。下面的1132行,伪type_info类型被加入派生类中,作为基类。

 

1112   static tree

1113   create_pseudo_type_info (const char *real_name, int ident, ...)                           in rtti.c

1114   {

1115     tree pseudo_type;

1116     char *pseudo_name;

1117     tree fields;

1118     tree field_decl;

1119     tree result;

1120     va_list ap;

1121  

1122     va_start (ap, ident);

1123  

1124    /* Generate the pseudo type name.  */

1125     pseudo_name = alloca (strlen (real_name) + 30);

1126     strcpy (pseudo_name, real_name);

1127     strcat (pseudo_name, "_pseudo");

1128     if (ident)

1129       sprintf (pseudo_name + strlen (pseudo_name), "%d", ident);

1130    

1131    /* First field is the pseudo type_info base class.  */

1132     fields = build_decl (FIELD_DECL, NULL_TREE, ti_desc_type_node);

1133    

1134    /* Now add the derived fields.  */

1135     while ((field_decl = va_arg (ap, tree)))

1136     {

1137       TREE_CHAIN (field_decl) = fields;

1138       fields = field_decl;

1139     }

1140    

1141     /* Create the pseudo type.  */

1142     pseudo_type = make_aggr_type (RECORD_TYPE);

1143     finish_builtin_struct (pseudo_type, pseudo_name, fields, NULL_TREE);

1144     CLASSTYPE_AS_BASE (pseudo_type) = pseudo_type;

1145  

1146     result = tree_cons (NULL_TREE, NULL_TREE, NULL_TREE);

1147     TINFO_REAL_NAME (result) = get_identifier (real_name);

1148     TINFO_PSEUDO_TYPE (result) =

1149       cp_build_qualified_type (pseudo_type, TYPE_QUAL_CONST);

1150    

1151     va_end (ap);

1152     return result;

1153   }

 

注意在这里传入create_pseduo_type_info的参数real_name是真实type_info派生类型的名字。这个名字,在1147行,亦被设置在伪type_info派生类的TINFO_REAL_NAME域。它将指引编译器产生dynamic_cast函数所需要的对象。

4.3.1.7.8.2.3.              RTTI的使用

4.3.1.7.8.2.3.1.            为类型生成RTTI

只有用户定义了包含虚函数的类,编译器才为之创建type_info对象。或者,编译器在看到dynamic_cast时,编译器也会为dynamic_cast两边的类型创建type_info对象。这创建过程由函数get_tinfo_decl完成。这里的参数type是需要type_info对象的类(type_info与下面tinfo互用)。

 

317    tree

318    get_tinfo_decl (tree type)                                                                          in class.c

319    {

320      tree name;

321      tree d;

322   

323      if (COMPLETE_TYPE_P (type)

324         && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)

325      {

326        error ("cannot create type information for type `%T' because its size is variable",

327             type);

328        return error_mark_node;

329      }

330   

331      if (TREE_CODE (type) == METHOD_TYPE)

332        type = build_function_type (TREE_TYPE (type),

333                               TREE_CHAIN (TYPE_ARG_TYPES (type)));

334   

335      /* For a class type, the variable is cached in the type node

336        itself.  */

337      if (CLASS_TYPE_P (type))

338      {

339        d = CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (type));

340        if (d)

341          return d;

342      }

343       

344      name = mangle_typeinfo_for_type (type);

345   

346      d = IDENTIFIER_GLOBAL_VALUE (name);

347      if (!d)

348      {

349        tree var_desc = get_pseudo_ti_desc (type);

350   

351        d = build_lang_decl (VAR_DECL, name, TINFO_PSEUDO_TYPE (var_desc));

352         

353        DECL_ARTIFICIAL (d) = 1;

354        TREE_READONLY (d) = 1;

355        TREE_STATIC (d) = 1;

356        DECL_EXTERNAL (d) = 1;

357        DECL_COMDAT (d) = 1;

358        TREE_PUBLIC (d) = 1;

359        SET_DECL_ASSEMBLER_NAME (d, name);

360   

361        pushdecl_top_level_and_finish (d, NULL_TREE);

362   

363        if (CLASS_TYPE_P (type))

364          CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (type)) = d;

365   

366        /* Remember the type it is for.  */

367        TREE_TYPE (name) = type;

368   

369        /* Add decl to the global array of tinfo decls.  */

370        my_friendly_assert (unemitted_tinfo_decls != 0, 20030312);

371        VARRAY_PUSH_TREE (unemitted_tinfo_decls, d);

372      }

373   

374      return d;

375    }

 

344行,mangle_typeinfo_for_type返回类的,具有修饰名的,代表tinfo对象的,唯一的标识符(tinfo的修饰名和普通项没有不同,除了有一个领头的“TI”字串)。Tinfo对象是类的公有静态成员,而且使用的是修饰名。因此,它一旦构建了,将在361行加入到全局名字空间,而不会有名字冲突的问题。这样大大简化了对tinfo对象的查找,只需346行的代码就够了;否则要一个个类那样查找,效率低得多。

如果类还没有tinfo对象,首先需要get_pseudo_ti_desc找出其对应的类型。

 

1159   static tree

1160   get_pseudo_ti_desc (tree type)                                                                          in rtti.c

1161   {

1162     switch (TREE_CODE (type))

1163     {

1164       case OFFSET_TYPE:

1165         return ptm_desc_type_node;

1166       case POINTER_TYPE:

1167         return ptr_desc_type_node;

1168       case ENUMERAL_TYPE:

1169         return enum_desc_type_node;

1170       case FUNCTION_TYPE:

1171         return func_desc_type_node;

1172       case ARRAY_TYPE:

1173         return ary_desc_type_node;

1174       case UNION_TYPE:

1175       case RECORD_TYPE:

1176         if (TYPE_PTRMEMFUNC_P (type))

1177           return ptm_desc_type_node;

1178         else if (!COMPLETE_TYPE_P (type))

1179         {

1180           if (!at_eof)

1181             cxx_incomplete_type_error (NULL_TREE, type);

1182           return class_desc_type_node;

1183         }

1184         else if (!CLASSTYPE_N_BASECLASSES (type))

1185           return class_desc_type_node;

1186         else

1187         {

1188           tree binfo = TYPE_BINFO (type);

1189           tree base_binfos = BINFO_BASETYPES (binfo);

1190           tree base_accesses = BINFO_BASEACCESSES (binfo);

1191           tree base_binfo = TREE_VEC_ELT (base_binfos, 0);

1192           int num_bases = TREE_VEC_LENGTH (base_binfos);

1193         

1194           if (num_bases == 1

1195              && TREE_VEC_ELT (base_accesses, 0) == access_public_node

1196              && !TREE_VIA_VIRTUAL (base_binfo)

1197              && integer_zerop (BINFO_OFFSET (base_binfo)))

1198             /* single non-virtual public.  */

1199             return si_class_desc_type_node;

1200           else

1201           {

1202             tree var_desc;

1203             tree array_domain, base_array;

1204             

1205             if (TREE_VEC_LENGTH (vmi_class_desc_type_node) <= num_bases)

1206             {

1207               int ix;

1208               tree extend = make_tree_vec (num_bases + 5);

1209                

1210               for (ix = TREE_VEC_LENGTH (vmi_class_desc_type_node); ix--;)

1211                 TREE_VEC_ELT (extend, ix)

1212                     = TREE_VEC_ELT (vmi_class_desc_type_node, ix);

1213               vmi_class_desc_type_node = extend;

1214             }

1215             var_desc = TREE_VEC_ELT (vmi_class_desc_type_node, num_bases);

1216             if (var_desc)

1217               return var_desc;

1218    

1219             /* Create the array of __base_class_type_info entries.

1220               G++ 3.2 allocated an array that had one too many

1221               entries, and then filled that extra entries with

1222               zeros.  */

1223             if (abi_version_at_least (2))

1224               array_domain = build_index_type (size_int (num_bases - 1));

1225             else

1226               array_domain = build_index_type (size_int (num_bases));

1227             base_array =

1228                    build_array_type (base_desc_type_node, array_domain);

1229  

1230             push_nested_namespace (abi_node);

1231             var_desc = create_pseudo_type_info

1232                        ("__vmi_class_type_info", num_bases,

1233                         build_decl (FIELD_DECL, NULL_TREE, integer_type_node),

1234                         build_decl (FIELD_DECL, NULL_TREE, integer_type_node),

1235                         build_decl (FIELD_DECL, NULL_TREE, base_array),

1236                         NULL);

1237             pop_nested_namespace (abi_node);

1238  

1239             TREE_VEC_ELT (vmi_class_desc_type_node, num_bases) = var_desc;

1240             return var_desc;

1241           }

1242         }

1243       default:

1244         return bltn_desc_type_node;

1245     }

1246   }

 

vmi_class_desc_type_node最初定义为大小为10的空数组,它用于多继承的类。实际上这是数组中,第一项用于虚继承,剩下的则分别设置着__vmi_class_type_info2__vmi_class_type_info3等,用于有多个基类的派生类。

VAR_DECL节点,在RECORD_TYPE节点中,代表类的静态成员。一旦它被创建出来,tinfo对象就算准备好了,并由pushdecl_top_level_and_finish 加到全局名字空间。不过我们已经知道,这里构建的tinfo是伪对象,它还需要编译器的后处理,为此它被缓存入unemitted_tinfo_decls

你可能感兴趣的:(GCC-3.4.6源代码学习笔记(65))