Studying note of GCC-3.4.6 source (66)

4.3.1.7.8.2.3.2.        Post-processing of type_info

4.3.1.7.8.2.3.2.1.  Install type_info for fundamental types

The front-end invokes function finish_file to close it work, and generate RTL code tree for the back-end. The function also constructs real objects for the pseduo type_infos cached within unemitted_tinfo_decls one by one. But before the creation, it first installs type_info for fundamental types as below.

 

1353   void

1354   emit_support_tinfos (void)                                                                                     in rtti.c

1355   {

1356     static tree *const fundamentals[] =

1357     {

1358       &void_type_node,

1359       &boolean_type_node,

1360       &wchar_type_node,

1361       &char_type_node, &signed_char_type_node, &unsigned_char_type_node,

1362       &short_integer_type_node, &short_unsigned_type_node,

1363       &integer_type_node, &unsigned_type_node,

1364       &long_integer_type_node, &long_unsigned_type_node,

1365       &long_long_integer_type_node, &long_long_unsigned_type_node,

1366       &float_type_node, &double_type_node, &long_double_type_node,

1367       0

1368     };

1369     int ix;

1370     tree bltn_type, dtor;

1371    

1372     push_nested_namespace (abi_node);

1373     bltn_type = xref_tag (class_type,

1374                      get_identifier ("__fundamental_type_info"),

1375                       true, false);

1376     pop_nested_namespace (abi_node);

1377     if (!COMPLETE_TYPE_P (bltn_type))

1378       return;

1379     dtor = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (bltn_type), 1);

1380     if (DECL_EXTERNAL (dtor))

1381       return;

1382     doing_runtime = 1;

1383     for (ix = 0; fundamentals[ix]; ix++)

1384     {

1385       tree bltn = *fundamentals[ix];

1386       tree bltn_ptr = build_pointer_type (bltn);

1387       tree bltn_const_ptr = build_pointer_type

1388                                (build_qualified_type (bltn, TYPE_QUAL_CONST));

1389       tree tinfo;

1390        

1391       tinfo = get_tinfo_decl (bltn);

1392       TREE_USED (tinfo) = 1;

1393       TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (tinfo)) = 1;

1394        

1395       tinfo = get_tinfo_decl (bltn_ptr);

1396       TREE_USED (tinfo) = 1;

1397       TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (tinfo)) = 1;

1398        

1399       tinfo = get_tinfo_decl (bltn_const_ptr);

1400       TREE_USED (tinfo) = 1;

1401       TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (tinfo)) = 1;

1402     }

1403   }

 

type_info for fundamental types, has type __fundamental_type_info, which is declared within cxxabiv1 namespace, and defined in file tinfo2.cc. If in building GCC, includes tinfo2.cc but not just cxxabi.h, then at line 1373 above, bltn_type would be a done RECORD_TYPE node, and would pass condition at line 1377 and 1380 to build type_info object for all fundamentals members. Note the objects created here are still pseduo ones. And at line 1382, doing_runtime would be set as 1 to indicate there is runtime library support.

4.3.1.7.8.2.3.2.2.  Construct real type_info

In below function, parameter decl is the cached pseduo type_info.

 

1433   bool

1434   emit_tinfo_decl (tree decl)                                                                               in rtti.c

1435   {

1436     tree type = TREE_TYPE (DECL_NAME (decl));

1437     bool non_public;

1438     int in_library = typeinfo_in_lib_p (type);

1439     tree var_desc, var_init;

1440  

1441     my_friendly_assert (unemitted_tinfo_decl_p (decl), 20030307);

1442    

1443     import_export_tinfo (decl, type, in_library);

1444     if (DECL_REALLY_EXTERN (decl) || !DECL_NEEDED_P (decl))

1445       return false;

1446  

1447     if (!doing_runtime && in_library)

1448       return false;

1449  

1450     non_public = false;

1451     var_desc = get_pseudo_ti_desc (type);

1452     var_init = get_pseudo_ti_init (type, var_desc, &non_public);

1453    

1454     DECL_EXTERNAL (decl) = 0;

1455     TREE_PUBLIC (decl) = !non_public;

1456     if (non_public)

1457       DECL_COMDAT (decl) = 0;

1458  

1459     DECL_INITIAL (decl) = var_init;

1460     mark_used (decl);

1461     cp_finish_decl (decl, var_init, NULL_TREE, 0);

1462     /* cp_finish_decl will have dealt with linkage.  */

1463    

1464    /* Say we've dealt with it.  */

1465     TREE_TYPE (DECL_NAME (decl)) = NULL_TREE;

1466  

1467     return true;

1468   }

 

Before constructing the real type_info object, the compiler needs to judge whether the object is really needed or not. Unneccessary construction not only reduces compiling efficiency, but bloats the code generated.

Below function in fact check if the type_info is for fundamental type. As these type_infos have been constructed by compiler automatically, there is no question of construct or not.

 

965    static bool

966    typeinfo_in_lib_p (tree type)                                                                            in rtti.c

967    {

968      /* The typeinfo objects for `T*' and `const T*' are in the runtime

969        library for simple types T.  */

970      if (TREE_CODE (type) == POINTER_TYPE

971          && (cp_type_quals (TREE_TYPE (type)) == TYPE_QUAL_CONST

972              || cp_type_quals (TREE_TYPE (type)) == TYPE_UNQUALIFIED))

973        type = TREE_TYPE (type);

974   

975      switch (TREE_CODE (type))

976      {

977        case INTEGER_TYPE:

978        case BOOLEAN_TYPE:

979        case CHAR_TYPE:

980        case REAL_TYPE:

981        case VOID_TYPE:

982          return true;

983       

984        default:

985          return false;

986      }

987    }

 

Function below judges if the type emitting the type_info is internal or external. If it is external, it is possible that this type_info object (note this is a global object) would be generated in other compilation unit. Then the front-end tells the back-end just to generate neccessary object. Linker can solve rest references.

 

1729   void

1730   import_export_tinfo (tree decl, tree type, bool is_in_library)                        in decl2.c

1731   {

1732     if (DECL_INTERFACE_KNOWN (decl))

1733       return;

1734    

1735     if (IS_AGGR_TYPE (type))

1736       import_export_class (type);

1737        

1738     if (IS_AGGR_TYPE (type) && CLASSTYPE_INTERFACE_KNOWN (type)

1739         && TYPE_POLYMORPHIC_P (type)

1740         /* If -fno-rtti, we're not necessarily emitting this stuff with

1741           the class, so go ahead and emit it now. This can happen when

1742           a class is used in exception handling.  */

1743         && flag_rtti)

1744     {

1745       DECL_NOT_REALLY_EXTERN (decl) = !CLASSTYPE_INTERFACE_ONLY (type);

1746       DECL_COMDAT (decl) = 0;

1747     }

1748     else

1749     {

1750       DECL_NOT_REALLY_EXTERN (decl) = 1;

1751       DECL_COMDAT (decl) = 1;

1752     }

1753  

1754     /* Now override some cases.  */

1755     if (flag_weak)

1756       DECL_COMDAT (decl) = 1;

1757     else if (is_in_library)

1758       DECL_COMDAT (decl) = 0;

1759    

1760     DECL_INTERFACE_KNOWN (decl) = 1;

1761   }

 

If the type emitting type_info is a class, then it needs below function to handle it. The function may set CLASSTYPE_INTERFACE_KNOWN for the class, which if is true, indicates we have already determined whether or not vtables, VTTs, typeinfo, and other similar per-class data should be emitted in this translation unit. For class defining virtual function, its type_info would be saved into vtable (only for this kind class, the compiler will initiatively generate type_info; otherwise, it needs triggered by dynamic_cast, and the generated tinfo is only held by dynamic_cast).

 

1484   static void

1485   import_export_class (tree ctype)                                                               in decl2.c

1486   {

1487    /* -1 for imported, 1 for exported.  */

1488     int import_export = 0;

1489  

1490     /* It only makes sense to call this function at EOF. The reason is

1491       that this function looks at whether or not the first non-inline

1492       non-abstract virtual member function has been defined in this

1493       translation unit. But, we can't possibly know that until we've

1494       seen the entire translation unit.  */

1495     my_friendly_assert (at_eof, 20000226);

1496  

1497     if (CLASSTYPE_INTERFACE_KNOWN (ctype))

1498       return;

1499  

1500     /* If MULTIPLE_SYMBOL_SPACES is defined and we saw a #pragma interface,

1501       we will have CLASSTYPE_INTERFACE_ONLY set but not

1502       CLASSTYPE_INTERFACE_KNOWN. In that case, we don't want to use this

1503       heuristic because someone will supply a #pragma implementation

1504       elsewhere, and deducing it here would produce a conflict.  */

1505     if (CLASSTYPE_INTERFACE_ONLY (ctype))

1506       return;

1507  

1508     if (lookup_attribute ("dllimport", TYPE_ATTRIBUTES (ctype)))

1509       import_export = -1;

1510     else if (lookup_attribute ("dllexport", TYPE_ATTRIBUTES (ctype)))

1511       import_export = 1;

1512  

1513     /* If we got -fno-implicit-templates, we import template classes that

1514       weren't explicitly instantiated.  */

1515     if (import_export == 0

1516         && CLASSTYPE_IMPLICIT_INSTANTIATION (ctype)

1517         && ! flag_implicit_templates)

1518       import_export = -1;

1519  

1520     /* Base our import/export status on that of the first non-inline,

1521       non-pure virtual function, if any.  */

1522     if (import_export == 0

1523         && TYPE_POLYMORPHIC_P (ctype))

1524     {

1525       tree method = CLASSTYPE_KEY_METHOD (ctype);

1526       if (method)

1527         import_export = (DECL_REALLY_EXTERN (method) ? -1 : 1);

1528     }

1529  

1530   #ifdef MULTIPLE_SYMBOL_SPACES

1531     if (import_export == -1)

1532       import_export = 0;

1533   #endif

1534  

1535     if (import_export)

1536     {

1537       SET_CLASSTYPE_INTERFACE_KNOWN (ctype);

1538       CLASSTYPE_INTERFACE_ONLY (ctype) = (import_export < 0);

1539     }

1540   }

 

Above at line 1523, TYPE_POLYMORPHIC_P if nonzero, means the class has virtual function. And CLASSTYPE_KEY_METHOD at line 1525, returns the first, non-inline, non-pure-virtual function. So if we have seen the class’s definition, no doubt, vtable, typeinfo, and other similar per-class data should be emitted in this translation unit. Further, class declared with “dllexport” attribute, as explicitly declared as exported, the per-class data if needed, should be emitted here.

For common class, it has neither vtable, nor saves tinfo, the compiler tries to make the tinfo shared across translation units. So, in import_export_class at line 1751, sets DECL_COMDAT.

Back emit_tinfo_decl, at line 1444, DECL_REALLY_EXTERN has following definition:

 

2856   #define DECL_REALLY_EXTERN(NODE) /                                            in cp-tree.h

2857     (DECL_EXTERNAL (NODE) && ! DECL_NOT_REALLY_EXTERN (NODE))

 

When tinfo is decided as external, or it is for fundamental type but runtime support is absent (condition at line 1447), then we abort the generation. Otherwise, needs going on to emit the code to initialize the real tinfo object. Note parameter var_desc of below function is the pseudo tinfo object fetched by get_pseudo_ti_desc at line 1451.

 

995    static tree

996    get_pseudo_ti_init (tree type, tree var_desc, bool *non_public_p)                       in rtti.c

997    {

998      my_friendly_assert (at_eof, 20021120);

999      switch (TREE_CODE (type))

1000     {

1001       case OFFSET_TYPE:

1002         return ptm_initializer (var_desc, type, non_public_p);

1003       case POINTER_TYPE:

1004         return ptr_initializer (var_desc, type, non_public_p);

1005       case ENUMERAL_TYPE:

1006         return generic_initializer (var_desc, type);

1007         break;

1008       case FUNCTION_TYPE:

1009         return generic_initializer (var_desc, type);

1010         break;

1011       case ARRAY_TYPE:

1012         return generic_initializer (var_desc, type);

1013         break;

1014       case UNION_TYPE:

1015       case RECORD_TYPE:

1016         if (TYPE_PTRMEMFUNC_P (type))

1017           return ptm_initializer (var_desc, type, non_public_p);

1018         else if (var_desc == class_desc_type_node)

1019         {

1020           if (!COMPLETE_TYPE_P (type))

1021             /* Emit a non-public class_type_info.  */

1022             *non_public_p = true;

1023             return class_initializer (var_desc, type, NULL_TREE);

1024         }

1025         else if (var_desc == si_class_desc_type_node)

1026         {

1027           tree base_binfos = BINFO_BASETYPES (TYPE_BINFO (type));

1028           tree base_binfo = TREE_VEC_ELT (base_binfos, 0);

1029           tree tinfo = get_tinfo_ptr (BINFO_TYPE (base_binfo));

1030           tree base_inits = tree_cons (NULL_TREE, tinfo, NULL_TREE);

1031         

1032           return class_initializer (var_desc, type, base_inits);

1033         }

1034         else

1035         {

1036           int hint = class_hint_flags (type);

1037           tree binfo = TYPE_BINFO (type);

1038           int nbases = BINFO_N_BASETYPES (binfo);

1039           tree base_binfos = BINFO_BASETYPES (binfo);

1040           tree base_accesses = BINFO_BASEACCESSES (binfo);

1041           tree base_inits = NULL_TREE;

1042           int ix;

1043            

1044           /* Generate the base information initializer.  */

1045           for (ix = nbases; ix--;)

1046           {

1047             tree base_binfo = TREE_VEC_ELT (base_binfos, ix);

1048             tree base_init = NULL_TREE;

1049             int flags = 0;

1050             tree tinfo;

1051             tree offset;

1052                

1053             if (TREE_VEC_ELT (base_accesses, ix) == access_public_node)

1054                flags |= 2;

1055             tinfo = get_tinfo_ptr (BINFO_TYPE (base_binfo));

1056             if (TREE_VIA_VIRTUAL (base_binfo))

1057             {

1058               /* We store the vtable offset at which the virtual

1059                 base offset can be found.  */

1060               offset = BINFO_VPTR_FIELD (base_binfo);

1061               offset = convert (sizetype, offset);

1062               flags |= 1;

1063            }

1064             else

1065               offset = BINFO_OFFSET (base_binfo);

1066                 

1067             /* Combine offset and flags into one field.  */

1068             offset = cp_build_binary_op (LSHIFT_EXPR, offset,

1069                                     build_int_2 (8, 0));

1070             offset = cp_build_binary_op (BIT_IOR_EXPR, offset,

1071                                     build_int_2 (flags, 0));

1072             base_init = tree_cons (NULL_TREE, offset, base_init);

1073             base_init = tree_cons (NULL_TREE, tinfo, base_init);

1074             base_init = build_constructor (NULL_TREE, base_init);

1075             TREE_HAS_CONSTRUCTOR (base_init) = 1;

1076             base_inits = tree_cons (NULL_TREE, base_init, base_inits);

1077           }

1078           base_inits = build_constructor (NULL_TREE, base_inits);

1079           TREE_HAS_CONSTRUCTOR (base_inits) = 1;

1080           base_inits = tree_cons (NULL_TREE, base_inits, NULL_TREE);

1081           /* Prepend the number of bases.  */

1082           base_inits = tree_cons (NULL_TREE,

1083                              build_int_2 (nbases, 0), base_inits);

1084           /* Prepend the hint flags.  */

1085           base_inits = tree_cons (NULL_TREE,

1086                              build_int_2 (hint, 0), base_inits);

1087  

1088           return class_initializer (var_desc, type, base_inits);

1089         }

1090         break;

1091  

1092       default:

1093         return generic_initializer (var_desc, type);

1094     }

1095   }

 

Using multi-derived class as example to see the creation of real tinfo, below function determines the hint flags describing the features of a class's hierarchy.

 

936    static int

937    class_hint_flags (tree type)                                                                               in rtti.c

938    {

939      int hint_flags = 0;

940     

941      dfs_walk (TYPE_BINFO (type), dfs_class_hint_mark, NULL, &hint_flags);

942      dfs_walk (TYPE_BINFO (type), dfs_class_hint_unmark, NULL, NULL);

943     

944      return hint_flags;

945    }  

 

Function dfs_walk performs depth-first post-order traversal upon the class derivation tree, whose detail we will see later. For every base of the class, dfs_class_hint_mark is performed i from most basic to most derived. See that hint is 1 for non-virtual derived class, and 3 for class containing virtual base.

 

899    static tree

900    dfs_class_hint_mark (tree binfo, void *data)                                                     in rtti.c

901    {

902      tree basetype = BINFO_TYPE (binfo);

903      int *hint = (int *) data;

904     

905      if (TREE_VIA_VIRTUAL (binfo))

906      {

907        if (CLASSTYPE_MARKED (basetype))

908          *hint |= 1;

909        if (CLASSTYPE_MARKED2 (basetype))

910          *hint |= 2;

911         SET_CLASSTYPE_MARKED2 (basetype);

912      }

913      else

914      {

915        if (CLASSTYPE_MARKED (basetype) || CLASSTYPE_MARKED2 (basetype))

916          *hint |= 1;

917        SET_CLASSTYPE_MARKED (basetype);

918      }

919      return NULL_TREE;

920    }

 

The type_info object of multi-derived class has type __vmi_class_type_info. In cxxabi.h, can see that the class has an array of type __base_class_type_info to describe the bases. FOR loop at line 1045 initializes this array. And base_init is the initializers in constructing the object, see that the nodes of the list have the reverse order as members’ initialization. In addition, in the constructor of __vmi_class_type_info defined in cxxabi.h, it doesn’t initialize this __base_class_type_info array. But here, the compiler bypasses the constructor to initialize the array. Of course, the precondition is the initializers must strictly match the order of members appearance.

Class __base_class_type_info has two data members, one is pointer points to tinfo of the base, the other is a flag combining offset and information (__offset_flags). For pointer pointing to the base tinfo, its initial value is fetched by below function, it is the address of base tinfo.

 

380    static tree

381    get_tinfo_ptr (tree type)                                                                                  in rtti.c

382    {

383      tree decl = get_tinfo_decl (type);

384   

385      mark_used (decl);

386      return build_nop (type_info_ptr_type,

387                     build_address (decl));

388    }

 

For base binfo, field BINFO_OFFSET or BINFO_VPTR_FIELD (in terms of virtual base) records the offset from the derived in consideration. Thus, obviously, in __offset_flags, its high 24bits keeps this offset, and its low 8bits tells if it’s public base or virtual base. From above code, it can tell that the first data member of class __vmi_class_type_info is the flag class_hint_flags points out, the second is the number of bases, and the third is the __base_class_type_info array. As soon as the initializers ready, function class_initializer constructs node of CONSTRUCTOR to indicate the invocation of this constructor.

 

951    static tree

952    class_initializer (tree desc, tree target, tree trail)                                                        in rtti.c

953    {

954      tree init = tinfo_base_init (desc, target);

955     

956      TREE_CHAIN (init) = trail;

957      init = build_constructor (NULL_TREE, init);

958      TREE_HAS_CONSTRUCTOR (init) = TREE_CONSTANT (init) = TREE_STATIC (init) = 1;

959      return init; 

960    }

 

However, here, the initializers isn’t finished yet. Because tinfo of classes all are derived from __class_type_info. Under C++ standard, the base initialization should be before the data member of the derived, and for class hasing virtual function, it is also problem of initializing vtable. Types of tinfo just has virtual function. The initialization of bases must begin with the bottom one, here the bottom base type_info has a member of type “const char*”, block at line 745 constructs subtrees of its definition and initializer.

 

738    static tree

739    tinfo_base_init (tree desc, tree target)                                                                in rtti.c

740    {

741      tree init = NULL_TREE;

742      tree name_decl;

743      tree vtable_ptr;

744     

745      {

746        tree name_name;

747       

748        /* Generate the NTBS array variable.  */

749        tree name_type = build_cplus_array_type

750                       (build_qualified_type (char_type_node, TYPE_QUAL_CONST),

751                        NULL_TREE);

752        tree name_string = tinfo_name (target);

753   

754        name_name = mangle_typeinfo_string_for_type (target);

755        name_decl = build_lang_decl (VAR_DECL, name_name, name_type);

756       

757        DECL_ARTIFICIAL (name_decl) = 1;

758        TREE_READONLY (name_decl) = 1;

759        TREE_STATIC (name_decl) = 1;

760        DECL_EXTERNAL (name_decl) = 0;

761        TREE_PUBLIC (name_decl) = 1;

762        import_export_tinfo (name_decl, target, typeinfo_in_lib_p (target));

763        /* External name of the string containing the type's name has a

764          special name.  */

765        SET_DECL_ASSEMBLER_NAME (name_decl,

766                                       mangle_typeinfo_string_for_type (target));

767        DECL_INITIAL (name_decl) = name_string;

768        mark_used (name_decl);

769        pushdecl_top_level_and_finish (name_decl, name_string);

770      }

771   

772      vtable_ptr = TINFO_VTABLE_DECL (desc);

773      if (!vtable_ptr)

774      {

775        tree real_type;

776     

777        push_nested_namespace (abi_node);

778        real_type = xref_tag (class_type, TINFO_REAL_NAME (desc),

779                          true, false);

780        pop_nested_namespace (abi_node);

781     

782        if (!COMPLETE_TYPE_P (real_type))

783        {

784          /* We never saw a definition of this type, so we need to

785            tell the compiler that this is an exported class, as

786            indeed all of the __*_type_info classes are.  */

787          SET_CLASSTYPE_INTERFACE_KNOWN (real_type);

788          CLASSTYPE_INTERFACE_ONLY (real_type) = 1;

789        }

790   

791        vtable_ptr = get_vtable_decl (real_type, /*complete=*/1);

792        vtable_ptr = build_unary_op (ADDR_EXPR, vtable_ptr, 0);

793   

794        /* We need to point into the middle of the vtable.  */

795        vtable_ptr = build

796                   (PLUS_EXPR, TREE_TYPE (vtable_ptr), vtable_ptr,

797                    size_binop (MULT_EXPR,

798                        size_int (2 * TARGET_VTABLE_DATA_ENTRY_DISTANCE),

799                        TYPE_SIZE_UNIT (vtable_entry_type)));

800        TREE_CONSTANT (vtable_ptr) = 1;

801   

802        TINFO_VTABLE_DECL (desc) = vtable_ptr;

803      }

804   

805      init = tree_cons (NULL_TREE, vtable_ptr, init);

806     

807      init = tree_cons (NULL_TREE, decay_conversion (name_decl), init);

808     

809      init = build_constructor (NULL_TREE, nreverse (init));

810      TREE_HAS_CONSTRUCTOR (init) = TREE_CONSTANT (init) = TREE_STATIC (init) = 1;

811       init = tree_cons (NULL_TREE, init, NULL_TREE);

812     

813      return init;

814    }

 

Before we have seen that pseudo tinfo hasn’t vatble. So if there is no vtable, means real tinfo object hasn’t been created. Note at line 778, TINFO_REAL_NAME saves the name of real tinfo. And the third parameter of xref_tag is true, which makes the function searching the specified type within __cxxabiv1 namespace. Constructing vtable is quite complex, we will look at it in later. Here, just know that the index of vtable doesn’t begin at 0, the compiler needs the first 2 entries for placing tinfo object, and the offset of the class being base from the derived now considering. Thus vtable_ptr points to the third entry. Further, as tinfo is static member of the class, so at line 810 sets TREE_STATIC, to tell the back-end to allocate static storage.

 

你可能感兴趣的:(Studying note of GCC-3.4.6 source (66))