Studying note of GCC-3.4.6 source (141)

    技术2022-06-29  66

    5.12.5.2.2.2.1.3.11.        Finish the derived RECORD_TYPE – finish vtable

    For our example of template instantiation, it contains no vtable as no virtual functions and virtual bases involved (C++ probits template from having virtual function, but can be used as virtual base). However, concept of polymophism is so important, it worths a deep looking here. So following discussion uses example 1 and 2 in previous section.

    At line 5159, CLASSTYPE_VFIELDS is the list of virtual table fields that this type contains (both the primary and secondary). The TREE_VALUE is the class type where the vtable field was introduced. For a vtable field inherited from the primary base, or introduced by this class, the TREE_PURPOSE (aliases by VF_BINFO_VALUE) is NULL. For other vtable fields (those from non-primary bases), the TREE_PURPOSE is the BINFO of the base through which the vtable was inherited. TREE_ADDRESSABLE is set for such vtable fields.

     

    finish_struct_1 (continue)

     

    5129     /* Complete the rtl for any static member objects of the type we're

    5130       working on.  */

    5131     for (x = TYPE_FIELDS (t); x; x = TREE_CHAIN (x))

    5132       if (TREE_CODE (x) == VAR_DECL && TREE_STATIC (x)

    5133          && same_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (x)), t))

    5134         DECL_MODE (x) = TYPE_MODE (t);

    5135  

    5136     /* Done with FIELDS...now decide whether to sort these for

    5137       faster lookups later.

    5138  

    5139       We use a small number because most searches fail (succeeding

    5140       ultimately as the search bores through the inheritance

    5141       hierarchy), and we want this failure to occur quickly.  */

    5142  

    5143     n_fields = count_fields (TYPE_FIELDS (t));

    5144     if (n_fields > 7)

    5145     {

    5146       struct sorted_fields_type *field_vec = ggc_alloc (sizeof (struct sorted_fields_type)

    5147                                                 + n_fields * sizeof (tree));

    5148       field_vec->len = n_fields;

    5149       add_fields_to_record_type (TYPE_FIELDS (t), field_vec, 0);

    5150       qsort (field_vec->elts, n_fields, sizeof (tree),

    5151             field_decl_cmp);

    5152       if (! DECL_LANG_SPECIFIC (TYPE_MAIN_DECL (t)))

    5153         retrofit_lang_decl (TYPE_MAIN_DECL (t));

    5154       DECL_SORTED_FIELDS (TYPE_MAIN_DECL (t)) = field_vec;

    5155     }

    5156  

    5157     if (TYPE_HAS_CONSTRUCTOR (t))

    5158     {

    5159       tree vfields = CLASSTYPE_VFIELDS (t);

    5160  

    5161       for (vfields = CLASSTYPE_VFIELDS (t);

    5162           vfields; vfields = TREE_CHAIN (vfields))

    5163         /* Mark the fact that constructor for T could affect anybody

    5164           inheriting from T who wants to initialize vtables for

    5165           VFIELDS's type.  */

    5166         if (VF_BINFO_VALUE (vfields))

    5167           TREE_ADDRESSABLE (vfields) = 1;

    5168     }

    5169  

    5170     /* Make the rtl for any new vtables we have created, and unmark

    5171       the base types we marked.  */

    5172     finish_vtbls (t);

     

    For class contains vtable, compiler will enlarge this table to include extra entries that necessary for polymorphism and give out the way to initialize this table. It is a very complex procedure and embodies exquisite consideration. Again we use examples in previous section. At first, let’s see the real output generated by GCC.

    Example 1:

    Vtable for A

    A::_ZTV1A: 3u entries

    0     (int (*)(...))0              // vcall offset

    4     (int (*)(...))(& _ZTI1A)

    8     A ::f       // slot for A::f

    Vtable for B1

    B1::_ZTV2B1: 6u entries

    0     0u        // vbase offset

    4     0u        // vcall offset

    8     (int (*)(...))0

    12    (int (*)(...))(& _ZTI2B1)

    16    B1::_ZTcv0_n12_v0_n16_N2B11fEv         // slot for B1::A::f

    20    B1::f     // slot for B1::f

    Vtable for B2

    B2::_ZTV2B2: 6u entries

    0     0u        // vbase offset

    4      0u        // vcall offset

    8     (int (*)(...))0

    12    (int (*)(...))(& _ZTI2B2)

    16    B2::_ZTcv0_n12_v0_n16_N2B21fEv         // slot for B2::A::f

    20    B2::f     // slot for B2::f

    Vtable for C

    C::_ZTV1C: 12u entries

    0     0u        // vbase offset

    4     0u        // vcall offset

    8      (int (*)(...))0

    12    (int (*)(...))(& _ZTI1C)

    16    C ::_ZTcv0_n12_v0_n16_N1C1fEv     // slot for C::B1::A::f

    20    C ::f       // slot for C::f

    24    -4u

    28    -4u

    32    (int (*)(...))-0x000000004

    36    (int (*)(...))(& _ZTI1C)

    40    C ::_ZTcvn4_n12_v0_n16_N1C1fEv   // slot for C::B2::A::f

    44    C ::_ZTchn4_h4_N1C1fEv   // slot for C::B2::f

    In the output “B1::_ZTV2B1: 6u entries”, prefix “_Z” is the common prefix used by GCC, and preifx “TV” is used for vtable, “2” is the size of the name of the class, and “B1” is the name of the class, then “6u” tells the size of the vtable.

    And in “B1::_ZTcv0_n12_v0_n16_N2B11fEv”, prefix “_ZTc” is used for thunk of this-adjustment or/and result-adjustment; “v0_n12_” tells the this-adjustment, which follows the formular “v<fixed offset number>_<virtual offset number>_” and “n12” stands for “-12”, in which “n” stands for negative (this value added to the address of vptr to get the entry of the vtable which contains the value of the real adjustment); then “v0_n16_” is the result-adjustment; next “N2B11fE”, “N…E” means nested name present, and “2B11f” is the nested name “B1::f”; the last part “v” means the the function has parameter of void.

    Next “C::_ZTchn4_h4_N1C1fEv” is a covariant thunk, “hn4_” is the form of “h<fixed offset number>_”, and “h4_” is the nested thunk.

    Then in “_ZTI2B1”, prefix “TI” stands for type-info; in “2B1”, “2” is the length of “B1”, and “B1” is the class the type-info corresponding for.

    Now think why it needs such arrangement? Consider an expression: “p->func();” p is a pointer of base type but points to derived, and func is virtual defined in base and derived. As result of member lookup, func defined in base would be found out because it search the member in base referred by p instead of in derived. However, in runtime the function gotten executed should be that defined in derived. Though in runtime we can use the virutal function defined in derived via vtable, but at point of invocation, in the arguments list, the implicit “this” argument and the returned value are tailored for func in the base, which are not the derived virtual wants and will make code generation later incorrect and lead to unexpected runtime result. So thunks here will do the necessary adjustments to set up the correct environment for the virtual really invoked.

    Below code reveals the detail in constructing vtable above, in which we just focus on the handling of class C.

     

    6762   static void

    6763   finish_vtbls (tree t)                                                                                   in class.c

    6764   {

    6765     tree list;

    6766     tree vbase;

    6767  

    6768     /* We lay out the primary and secondary vtables in one contiguous

    6769       vtable. The primary vtable is first, followed by the non-virtual

    6770       secondary vtables in inheritance graph order.  */

    6771     list = build_tree_list (TYPE_BINFO_VTABLE (t), NULL_TREE);

    6772     accumulate_vtbl_inits (TYPE_BINFO (t), TYPE_BINFO (t),

    6773                        TYPE_BINFO (t), t, list);

    6774    

    6775     /* Then come the virtual bases, also in inheritance graph order.  */

    6776     for (vbase = TYPE_BINFO (t); vbase; vbase = TREE_CHAIN (vbase))

    6777     {

    6778       if (!TREE_VIA_VIRTUAL (vbase))

    6779         continue ;

    6780       accumulate_vtbl_inits (vbase, vbase, TYPE_BINFO (t), t, list);

    6781     }

    6782  

    6783     if (TYPE_BINFO_VTABLE (t))

    6784       initialize_vtable (TYPE_BINFO (t), TREE_VALUE (list));

    6785   }

     

    If it is the handling of class C, then above argument t is the RECORD_TYPE of C ; and TYPE_BINFO_VTABLE(t) is the C’s vtable object. At line 6771, list is a tree_list node, in its TREE_PURPOSE field is this vtable object, while TREE_VALUE field is empty temperarily (dfs_accumulate_vtbl_inits below will fill it). In below function, at line 7167 ctor_vtbl_p is used to control the creation of constructor vtable group (during building VTT), under our circumstance here as rtti_binfo is gotten from TYPE_BINFO (t ), ctor_vtbl_p is 0.

    Pay attention to the order of invocation of accumulate_vtbl_inits , it ensures that the virtual bases are handled in the last.

     

    7159   static void

    7160   accumulate_vtbl_inits (tree binfo,                                                              in class.c

    7161                      tree orig_binfo,

    7162                      tree rtti_binfo,

    7163                      tree t,

    7164                      tree inits)

    7165   {

    7166     int i;

    7167     int ctor_vtbl_p = !same_type_p (BINFO_TYPE (rtti_binfo), t);

    7168  

    7169     my_friendly_assert (same_type_p (BINFO_TYPE (binfo),

    7170                      BINFO_TYPE (orig_binfo)),

    7171                      20000517);

    7172  

    7173     /* If it doesn't have a vptr, we don't do anything.  */

    7174     if (!TYPE_CONTAINS_VPTR_P (BINFO_TYPE (binfo)))

    7175       return ;

    7176    

    7177     /* If we're building a construction vtable, we're not interested in

    7178       subobjects that don't require construction vtables.  */

    7179     if (ctor_vtbl_p

    7180         && !TYPE_USES_VIRTUAL_BASECLASSES (BINFO_TYPE (binfo))

    7181         && !binfo_via_virtual (orig_binfo, BINFO_TYPE (rtti_binfo)))

    7182       return ;

    7183  

    7184     /* Build the initializers for the BINFO-in-T vtable.  */

    7185     TREE_VALUE (inits)

    7186       = chainon (TREE_VALUE (inits),

    7187                dfs_accumulate_vtbl_inits (binfo, orig_binfo,

    7188                                       rtti_binfo, t, inits));

    7189                    

    7190     /* Walk the BINFO and its bases. We walk in preorder so that as we

    7191       initialize each vtable we can figure out at what offset the

    7192       secondary vtable lies from the primary vtable. We can't use

    7193       dfs_walk here because we need to iterate through bases of BINFO

    7194       and RTTI_BINFO simultaneously.  */

    7195     for (i = 0; i < BINFO_N_BASETYPES (binfo); ++i)

    7196     {

    7197       tree base_binfo = BINFO_BASETYPE (binfo, i);

    7198        

    7199       /* Skip virtual bases.   */

    7200       if (TREE_VIA_VIRTUAL (base_binfo))

    7201         continue ;

    7202       accumulate_vtbl_inits (base_binfo,

    7203                          BINFO_BASETYPE (orig_binfo, i),

    7204                          rtti_binfo, t,

    7205                          inits);

    7206     }

    7207   }

     

    See that both binfo and orig_binfo are binfos of the same type, but are not necessarily the same in terms of layout (here they are the strictly same one). Assertion at line 7169 checks for this pre-condition.

    For class C, ctor_vtbl_p below is false. And if predicate BINFO_NEW_VTABLE_MARKED fails, it says that the base hasn’t vtable prepared. Remember that in above inheritance tree walk taken by dfs_modify_vtables , non-virtual primary bases are skipped and haven’t vtables prepared, as result, BINFO_NEW_VTABLE_MARKED fails for these bases, and exits at line 7274.

    Below we display example in former section again:

    class A { virtual A* f (); };

    class B1 : virtual public A { virtual B1* f (); };

    class B2 : virtual public A { virtual B2* f (); };

    class C: public B1, public B2 { virtual C* f (); };

    The processing order will be C, B1 will be skipped by dfs_accumulate_vtbl_inits , then B2, and next A.

     

    7212   static tree

    7213   dfs_accumulate_vtbl_inits (tree binfo,                                                               in class.c

    7214                         tree orig_binfo,

    7215                         tree rtti_binfo,

    7216                         tree t,

    7217                         tree l)

    7218   {

    7219     tree inits = NULL_TREE;

    7220     tree vtbl = NULL_TREE;

    7221     int ctor_vtbl_p = !same_type_p (BINFO_TYPE (rtti_binfo), t);

    7222  

    7223     if (ctor_vtbl_p

    7224         && TREE_VIA_VIRTUAL (orig_binfo) && BINFO_PRIMARY_P (orig_binfo))

    7225     {

              …

    7272     }

    7273     else if (!BINFO_NEW_VTABLE_MARKED (orig_binfo))

    7274       return inits;

    7275  

    7276     if (!vtbl)

    7277     {

    7278       tree index;

    7279       int non_fn_entries;

    7280  

    7281       /* Compute the initializer for this vtable.  */

    7282       inits = build_vtbl_initializer (binfo, orig_binfo, t, rtti_binfo,

    7283                               &non_fn_entries);

     

    The object of C’s vtable is smiliar with common object we declare, needs initialization. This initializer is prepared by build_vtbl_initializer . Below argument non_fn_entries_p is used to record the extra non-function entry of the vtable.

     

    7338   static tree

    7339   build_vtbl_initializer (tree binfo,                                                                in class.c

    7340                     tree orig_binfo,

    7341                     tree t,

    7342                     tree rtti_binfo,

    7343                      int* non_fn_entries_p)

    7344   {

    7345     tree v, b;

    7346     tree vfun_inits;

    7347     tree vbase;

    7348     vtbl_init_data vid;

    7349  

    7350     /* Initialize VID.  */

    7351     memset (&vid, 0, sizeof (vid));

    7352     vid.binfo = binfo;

    7353     vid.derived = t;

    7354     vid.rtti_binfo = rtti_binfo;

    7355     vid.last_init = &vid.inits;

    7356     vid.primary_vtbl_p = (binfo == TYPE_BINFO (t));

    7357     vid.ctor_vtbl_p = !same_type_p (BINFO_TYPE (rtti_binfo), t);

    7358     vid.generate_vcall_entries = true;

    7359     /* The first vbase or vcall offset is at index -3 in the vtable.  */

    7360     vid.index = ssize_int (-3 * TARGET_VTABLE_DATA_ENTRY_DISTANCE);

    7361  

    7362     /* Add entries to the vtable for RTTI.  */

    7363     build_rtti_vtbl_entries (binfo, &vid);

    7364  

    7365     /* Create an array for keeping track of the functions we've

    7366       processed. When we see multiple functions with the same

    7367       signature, we share the vcall offsets.  */

    7368     VARRAY_TREE_INIT (vid.fns, 32, "fns");

    7369     /* Add the vcall and vbase offset entries.  */

    7370     build_vcall_and_vbase_vtbl_entries (binfo, &vid);

    7371     /* Clear BINFO_VTABLE_PATH_MARKED; it's set by

    7372       build_vbase_offset_vtbl_entries.  */

    7373     for (vbase = CLASSTYPE_VBASECLASSES (t);

    7374         vbase;

    7375         vbase = TREE_CHAIN (vbase))

    7376       BINFO_VTABLE_PATH_MARKED (TREE_VALUE (vbase)) = 0;

     

    Type vtbl_init_data_s has below definition.

     

    65      typedef struct vtbl_init_data_s                                                                   in class.c

    66      {

    67        /* The base for which we're building initializers.  */

    68        tree binfo;

    69        /* The type of the most-derived type.  */

    70        tree derived;

    71        /* The binfo for the dynamic type. This will be TYPE_BINFO (derived),

    72          unless ctor_vtbl_p is true.  */

    73        tree rtti_binfo;

    74        /* The negative-index vtable initializers built up so far. These

    75          are in order from least negative index to most negative index.  */

    76        tree inits;

    77        /* The last (i.e., most negative) entry in INITS.  */

    78        tree* last_init;

    79        /* The binfo for the virtual base for which we're building

    80          vcall offset initializers.  */

    81        tree vbase;

    82        /* The functions in vbase for which we have already provided vcall

    83          offsets.  */

    84        varray_type fns;

    85        /* The vtable index of the next vcall or vbase offset.  */

    86        tree index;

    87        /* Nonzero if we are building the initializer for the primary

    88          vtable.  */

    89        int primary_vtbl_p;

    90        /* Nonzero if we are building the initializer for a construction

    91          vtable.  */

    92        int ctor_vtbl_p;

    93        /* True when adding vcall offset entries to the vtable. False when

    94          merely computing the indices.  */

    95        bool generate_vcall_entries;

    96      } vtbl_init_data ;

     

    At line 7355, last_init always points to last node in inits . It will point to negative index vtable initializers (that is the part prior to the part of vtable visible to programmer).

     

    7862   static void

    7863   build_rtti_vtbl_entries (tree binfo, vtbl_init_data * vid)                                  in class.c

    7864   {

    7865     tree b;

    7866     tree t;

    7867     tree basetype;

    7868     tree offset;

    7869     tree decl;

    7870     tree init;

    7871  

    7872     basetype = BINFO_TYPE (binfo);

    7873     t = BINFO_TYPE (vid->rtti_binfo);

    7874  

    7875     /* To find the complete object, we will first convert to our most

    7876       primary base, and then add the offset in the vtbl to that value.  */

    7877     b = binfo;

    7878     while (CLASSTYPE_HAS_PRIMARY_BASE_P (BINFO_TYPE (b))

    7879            && !BINFO_LOST_PRIMARY_P (b))

    7880     {

    7881       tree primary_base;

    7882  

    7883       primary_base = get_primary_binfo (b);

    7884       my_friendly_assert (BINFO_PRIMARY_BASE_OF (primary_base) == b, 20010127);

    7885       b = primary_base;

    7886     }

    7887     offset = size_diffop (BINFO_OFFSET (vid->rtti_binfo), BINFO_OFFSET (b));

    7888  

    7889     /* The second entry is the address of the typeinfo object.  */

    7890     if (flag_rtti )

    7891       decl = build_address (get_tinfo_decl (t));

    7892     else

    7893       decl = integer_zero_node;

    7894    

    7895     /* Convert the declaration to a type that can be stored in the

    7896       vtable.  */

    7897     init = build_nop (vfunc_ptr_type_node , decl);

    7898     *vid->last_init = build_tree_list (NULL_TREE, init);

    7899     vid->last_init = &TREE_CHAIN (*vid->last_init);

    7900  

    7901     /* Add the offset-to-top entry. It comes earlier in the vtable that

    7902       the the typeinfo entry. Convert the offset to look like a

    7903       function pointer, so that we can put it in the vtable.  */

    7904     init = build_nop (vfunc_ptr_type_node , offset);

    7905     *vid->last_init = build_tree_list (NULL_TREE, init);

    7906     vid->last_init = &TREE_CHAIN (*vid->last_init);

    7907   }

     

    The -1 entry of vtable places the tinfo (type information) object of the type. The necessary entities to support tinfo have been initialized in init_rtti_processing . This tinfo will be declared as static data member of the type.

    In build_rtti_vtbl_entries , from the type specified by binfo , stepping down along the primary base path, and finds out the most basic primary base (note that if we encounter base satisifying BINFO_LOST_PRIMARY_P, we are going to step into sub-tree of non-primary base, must stop). The offset from this type to this most basic primary base will be recorded in the -2 entry of the vtable of the class. In our example here, this offset is from C to A.

    Back to build_vtbl_initializer , following function is invoked to handle type of virtual base or type contains virtual base.

     

    7512   static void

    7513   build_vcall_and_vbase_vtbl_entries (tree binfo, vtbl_init_data * vid)               in class.c

    7514   {

    7515     tree b;

    7516  

    7517     /* If this is a derived class, we must first create entries

    7518       corresponding to the primary base class.  */

    7519     b = get_primary_binfo (binfo);

    7520     if (b)

    7521       build_vcall_and_vbase_vtbl_entries (b, vid);

    7522  

    7523     /* Add the vbase entries for this base.  */

    7524     build_vbase_offset_vtbl_entries (binfo, vid);

    7525     /* Add the vcall entries for this base.  */

    7526     build_vcall_offset_vtbl_entries (binfo, vid);

    7527   }

     

    Notice that build_vcall_and_vbase_vtbl_entries is executed bottom up from the most basic primary base for the certain type of binfo . In our example, build_vcall_and_vbase_vtbl_entries stops recurring at meeting virtual base A. As A contains no virtual base, build_vbase_offset_vtbl_entries does nothing. And now, we are within following call stack:

    build_vcall_and_vbase_vtbl_entries:       for C

            build_vcall_and_vbase_vtbl_entries:     for B1

                   build_vcall_and_vbase_vtbl_entries:     for A

                          build_vcall_offset_vtbl_entries:     for A

     

    7632   static void

    7633   build_vcall_offset_vtbl_entries (tree binfo, vtbl_init_data * vid)               in class.c

    7634   {

    7635     /* We only need these entries if this base is a virtual base. We

    7636       compute the indices -- but do not add to the vtable -- when

    7637       building the main vtable for a class.  */

    7638     if (TREE_VIA_VIRTUAL (binfo) || binfo == TYPE_BINFO (vid->derived))

    7639     {

    7640       /* We need a vcall offset for each of the virtual functions in this

    7641         vtable. For example:

    7642  

    7643          class A { virtual void f (); };

    7644          class B1 : virtual public A { virtual void f (); };

    7645          class B2 : virtual public A { virtual void f (); };

    7646          class C: public B1, public B2 { virtual void f (); };

    7647  

    7648          A C object has a primary base of B1, which has a primary base of A. A

    7649          C also has a secondary base of B2, which no longer has a primary base

    7650          of A. So the B2-in-C construction vtable needs a secondary vtable for

    7651          A, which will adjust the A* to a B2* to call f. We have no way of

    7652          knowing what (or even whether) this offset will be when we define B2,

    7653          so we store this "vcall offset" in the A sub-vtable and look it up in

    7654          a "virtual thunk" for B2::f.

    7655  

    7656          We need entries for all the functions in our primary vtable and

    7657          i n our non-virtual bases' secondary vtables.  */

    7658       vid->vbase = binfo;

    7659       /* If we are just computing the vcall indices -- but do not need

    7660          the actual entries -- not that.  */

    7661       if (!TREE_VIA_VIRTUAL (binfo))

    7662         vid->generate_vcall_entries = false;

    7663       /* Now, walk through the non-virtual bases, adding vcall offsets.  */

    7664       add_vcall_offset_vtbl_entries_r (binfo, vid);

    7665     }

    7666   }

     

    For the qualified candidate in add_vcall_offset_vtbl_entries_r , above at line 7658, vbase field of vid is set with the corresponding binfo which is the vritual base for which we are building the vcall offsets. Below condition at line 7680, filters out virtual base not building vcall offset; and above condition at line 7638, only passes virtual bases and the most derived class.

     

    7670   static void

    7671   add_vcall_offset_vtbl_entries_r (tree binfo, vtbl_init_data * vid)                    in class.c

    7672   {

    7673     int i;

    7674     tree primary_binfo;

    7675  

    7676     /* Don't walk into virtual bases -- except, of course, for the

    7677       virtual base for which we are building vcall offsets. Any

    7678       primary virtual base will have already had its offsets generated

    7679       through the recursion in build_vcall_and_vbase_vtbl_entries.  */

    7680     if (TREE_VIA_VIRTUAL (binfo) && vid->vbase != binfo)

    7681       return ;

    7682    

    7683     /* If BINFO has a primary base, process it first.  */

    7684     primary_binfo = get_primary_binfo (binfo);

    7685     if (primary_binfo)

    7686       add_vcall_offset_vtbl_entries_r (primary_binfo, vid);

    7687  

    7688     /* Add BINFO itself to the list.  */

    7689     add_vcall_offset_vtbl_entries_1 (binfo, vid);

    7690  

    7691     /* Scan the non-primary bases of BINFO.  */

    7692     for (i = 0; i < BINFO_N_BASETYPES (binfo); ++i)

    7693     {

    7694       tree base_binfo;

    7695        

    7696       base_binfo = BINFO_BASETYPE (binfo, i);

    7697       if (base_binfo != primary_binfo)

    7698         add_vcall_offset_vtbl_entries_r (base_binfo, vid);

    7699     }

    7700   }

     

    Also here, if binfo is of derived class, it recurs into add_vcall_offset_vtbl_entries_r too, till encountering the bottom primrary base. Note that this primary base can be a derived, except it can has base defining virtual function. Above, in handling the derived (only current class, i.e., C; or virtual base, but its bases can’t have virtual function), first is its primary base, then is itselt, which is followed by non-primary base.

     

    7704   static void

    7705   add_vcall_offset_vtbl_entries_1 (tree binfo, vtbl_init_data * vid)                   in class.c

    7706   {

    7707     /* Make entries for the rest of the virtuals.  */

    7708     if (abi_version_at_least (2))

    7709     {

    7710       tree orig_fn;

    7711  

    7712       /* The ABI requires that the methods be processed in declaration

    7713          order. G++ 3.2 used the order in the vtable.  */

    7714       for (orig_fn = TYPE_METHODS (BINFO_TYPE (binfo));

    7715            orig_fn;

    7716            orig_fn = TREE_CHAIN (orig_fn))

    7717         if (DECL_VINDEX (orig_fn))

    7718            add_vcall_offset (orig_fn, binfo, vid);

    7719     }

    7720     else

    7721     {

              …

    7785     }

    7786   }

     

    We focus on ABI first used in GCC 3.4. In previous section, we have seen that in finish_struct_1 , at line 5123, DECL_VINDEX of virtual functions have been updated by INTEGER_CST, and this field is empty for non-virtual function. Obviously, add_vcall_offset just processes virtual function, and note that the virtual functions come from class specified by binfo .

     

    7790   static void

    7791   add_vcall_offset (tree orig_fn, tree binfo, vtbl_init_data *vid)                             in class.c

    7792   {

    7793     size_t i;

    7794     tree vcall_offset;

    7795  

    7796     /* If there is already an entry for a function with the same

    7797       signature as FN, then we do not need a second vcall offset.

    7798       Check the list of functions already present in the derived

    7799       class vtable.  */

    7800     for (i = 0; i < VARRAY_ACTIVE_SIZE (vid->fns); ++i)

    7801     {

    7802       tree derived_entry;

    7803  

    7804       derived_entry = VARRAY_TREE (vid->fns, i);

    7805       if (same_signature_p (derived_entry, orig_fn)

    7806         /* We only use one vcall offset for virtual destructors,

    7807            even though there are two virtual table entries.  */

    7808         || (DECL_DESTRUCTOR_P (derived_entry)

    7809           && DECL_DESTRUCTOR_P (orig_fn)))

    7810         return ;

    7811     }

    7812  

    7813     /* If we are building these vcall offsets as part of building

    7814       the vtable for the most derived class, remember the vcall

    7815       offset.  */

    7816     if (vid->binfo == TYPE_BINFO (vid->derived))

    7817       CLASSTYPE_VCALL_INDICES (vid->derived)

    7818         = tree_cons (orig_fn, vid->index,

    7819                    CLASSTYPE_VCALL_INDICES (vid->derived));

    7820  

    7821     /* The next vcall offset will be found at a more negative

    7822       offset.  */

    7823     vid->index = size_binop (MINUS_EXPR, vid->index,

    7824                         ssize_int (TARGET_VTABLE_DATA_ENTRY_DISTANCE));

    7825  

    7826     /* Keep track of this function.  */

    7827     VARRAY_PUSH_TREE (vid->fns, orig_fn);

    7828  

    7829     if (vid->generate_vcall_entries)

    7830     {

    7831       tree base;

    7832       tree fn;

    7833  

    7834       /* Find the overriding function.  */

    7835       fn = find_final_overrider (vid->rtti_binfo, binfo, orig_fn);

    7836       if (fn == error_mark_node)

    7837         vcall_offset = build1 (NOP_EXPR, vtable_entry_type ,

    7838                            integer_zero_node);

    7839       else

    7840       {

    7841         base = TREE_VALUE (fn);

    7842  

    7843         /* The vbase we're working on is a primary base of

    7844           vid->binfo. But it might be a lost primary, so its

    7845           BINFO_OFFSET might be wrong, so we just use the

    7846           BINFO_OFFSET from vid->binfo.  */

    7847         vcall_offset = size_diffop (BINFO_OFFSET (base),

    7848                               BINFO_OFFSET (vid->binfo));

    7849         vcall_offset = fold (build1 (NOP_EXPR, vtable_entry_type ,

    7850                               vcall_offset));

    7851       }

    7852       /* Add the initializer to the vtable.  */

    7853       *vid->last_init = build_tree_list (NULL_TREE, vcall_offset);

    7854       vid->last_init = &TREE_CHAIN (*vid->last_init);

    7855     }

    7856   }

     

    At first, vid->fns is an empty arrary, here it is used as a cache to ensure every virtual function can only be handled once. At line 7818, vid->index records the current index (note that it is negative) of vtable of current class (that is class C); if condition at line 7816 is satisfied, it means class C is being handled by dfs_accumulate_vtbl_inits , which is the first processed. It is our scenario now, then CLASSTYPE_VCALL_INDICES records the position of these containing vcall offset functions; at time C being virtual base, it will be set in BV_VCALL_INDEX of the virtual by get_vcall_index (refer to previous section, update_vtable_entry_for_fn ). At line 7827, caches this virtual function. At line 7829, vid->generate_vcall_entries is true for virtual base, which indicates need construct entry in vtable for vcall. Then at line 7835, vid->rtti_binfo is the binfo of current class (binfo of class C), so here found by find_final_overrider is the last overrider (for our example, it is C::f). Note if fn is error_mark_node , it means find_final_overrider detects error (like ambiguity), and here it sets vcall offset as 0. In normal case, fn would be a tree_list node, in its value field is the base defining it. So vcall_offset at line 7847, is the offset from the base preparing vtable entry to the derived last overrides the function. In our current scenario, they are both C.

    Then exitting from build_vcall_and_vbase_vtbl_entries handling A, we back in the function handling B1, in which build_vcall_offset_vtbl_entries does nothing for as B1 is not virutal base. But as it has virtual base A, it undergoes build_vbase_offset_vtbl_entries . Now the call stack is:

    build_vcall_and_vbase_vtbl_entries:       for C

            build_vcall_and_vbase_vtbl_entries:     for B1

                   build_vbase_offset_vtbl_entries:   for B1

    During the processing current class, vid->derived always refers to class C. And line 7543 filters out classes that don’t derive from virtual base.

     

    7534   static void

    7535   build_vbase_offset_vtbl_entries (tree binfo, vtbl_init_data * vid)                    in class.c

    7536   {

    7537     tree vbase;

    7538     tree t;

    7539     tree non_primary_binfo;

    7540  

    7541     /* If there are no virtual baseclasses, then there is nothing to

    7542       do.  */

    7543     if (!TYPE_USES_VIRTUAL_BASECLASSES (BINFO_TYPE (binfo)))

    7544       return ;

    7545  

    7546     t = vid->derived;

    7547    

    7548     /* We might be a primary base class. Go up the inheritance hierarchy

    7549       until we find the most derived class of which we are a primary base:

    7550       it is the offset of that which we need to use.  */

    7551     non_primary_binfo = binfo;

    7552     while (BINFO_INHERITANCE_CHAIN (non_primary_binfo))

    7553     {

    7554       tree b;

    7555  

    7556       /* If we have reached a virtual base, then it must be a primary

    7557          base (possibly multi-level) of vid->binfo, or we wouldn't

    7558          have called build_vcall_and_vbase_vtbl_entries for it. But it

    7559          might be a lost primary, so just skip down to vid->binfo.  */

    7560       if (TREE_VIA_VIRTUAL (non_primary_binfo))

    7561       {

    7562          non_primary_binfo = vid->binfo;

    7563          break ;

    7564       }

    7565  

    7566       b = BINFO_INHERITANCE_CHAIN (non_primary_binfo);

    7567       if (get_primary_binfo (b) != non_primary_binfo)

    7568         break ;

    7569       non_primary_binfo = b;

    7570     }

    7571  

    7572     /* Go through the virtual bases, adding the offsets.  */

    7573     for (vbase = TYPE_BINFO (BINFO_TYPE (binfo));

    7574          vbase;

    7575          vbase = TREE_CHAIN (vbase))

    7576     {

    7577       tree b;

    7578       tree delta;

    7579        

    7580       if (!TREE_VIA_VIRTUAL (vbase))

    7581         continue ;

    7582  

    7583       /* Find the instance of this virtual base in the complete

    7584          object.  */

    7585       b = copied_binfo (vbase, binfo);

    7586  

    7587       /* If we've already got an offset for this virtual base, we

    7588          don't need another one.  */

    7589       if (BINFO_VTABLE_PATH_MARKED (b))

    7590         continue ;

    7591       BINFO_VTABLE_PATH_MARKED (b) = 1;

    7592  

    7593       /* Figure out where we can find this vbase offset.  */

    7594       delta = size_binop (MULT_EXPR,

    7595                        vid->index,

    7596                        convert (ssizetype,

    7597                                TYPE_SIZE_UNIT (vtable_entry_type)));

    7598       if (vid->primary_vtbl_p)

    7599         BINFO_VPTR_FIELD (b) = delta;

    7600  

    7601       if (binfo != TYPE_BINFO (t))

    7602       {

    7603          /* The vbase offset had better be the same.  */

    7604          my_friendly_assert (tree_int_cst_equal (delta,

    7605                                          BINFO_VPTR_FIELD (vbase)),

    7606                          20030202);

    7607       }

    7608  

    7609       /* The next vbase will come at a more negative offset.  */

    7610       vid->index = size_binop (MINUS_EXPR, vid->index,

    7611                          ssize_int (TARGET_VTABLE_DATA_ENTRY_DISTANCE));

    7612  

    7613       /* The initializer is the delta from BINFO to this virtual base.

    7614          The vbase offsets go in reverse inheritance-graph order, and

    7615          we are walking in inheritance graph order so these end up in

    7616          the right order.  */

    7617       delta = size_diffop (BINFO_OFFSET (b), BINFO_OFFSET (non_primary_binfo));

    7618        

    7619       *vid->last_init

    7620             = build_tree_list (NULL_TREE,

    7621                            fold (build1 (NOP_EXPR,

    7622                                       vtable_entry_type ,

    7623                                       delta)));

    7624       vid->last_init = &TREE_CHAIN (*vid->last_init);

    7625     }

    7626   }

     

    WHILE block at line 7552 finds out most derived class which is the non-virtual primary base within the branch of the hierarchy tree, to which binfo belongs. For example, for class B1 in our example, non_primary_binfo refers to C. We find these types, because as we have seen, bases in primary base path that share the vtable ptr are laid at the same offset from the head of the most derived class.

    At line 7598, vid->primary_vtbl_p is true, if we are preparing vtable entry for current class (C). BINFO_VPTR_FIELD of virtual base saves an INTEGER_CST which is an index of vtable, where vcall offset can be found. The significance of this offset is, considering below statements:

    A *pa = new C;

    pa->f();

    Runtime polymorphism must promise C::f get invoked, so offset A à C must be known, which is caculated above.

    Condition at line 7601 and assertion at line 7604 ensure index for vbase offset generated by every class containing virtual base is the same.

     


    最新回复(0)