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.