Studying note of GCC-3.4.6 source (141)

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.

 

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看READme.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值