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
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
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
5166 if (VF_BINFO_VALUE (vfields))
5167 TREE_ADDRESSABLE (vfields) = 1;
5168 }
5169
5170
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
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
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
7174 if (!TYPE_CONTAINS_VPTR_P (BINFO_TYPE (binfo)))
7175 return ;
7176
7177
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
7185 TREE_VALUE (inits)
7186 = chainon (TREE_VALUE (inits),
7187 dfs_accumulate_vtbl_inits (binfo, orig_binfo,
7188 rtti_binfo, t, inits));
7189
7190
7195 for (i = 0; i < BINFO_N_BASETYPES (binfo); ++i)
7196 {
7197 tree base_binfo = BINFO_BASETYPE (binfo, i);
7198
7199
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
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
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
7360 vid.index = ssize_int (-3 * TARGET_VTABLE_DATA_ENTRY_DISTANCE);
7361
7362
7363 build_rtti_vtbl_entries (binfo, &vid);
7364
7365
7368 VARRAY_TREE_INIT (vid.fns, 32, "fns");
7369
7370 build_vcall_and_vbase_vtbl_entries (binfo, &vid);
7371
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
68 tree binfo;
69
70 tree derived;
71
73 tree rtti_binfo;
74
76 tree inits;
77
78 tree* last_init;
79
81 tree vbase;
82
84 varray_type fns;
85
86 tree index;
87
89 int primary_vtbl_p;
90
92 int ctor_vtbl_p;
93
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
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
7890 if (flag_rtti )
7891 decl = build_address (get_tinfo_decl (t));
7892 else
7893 decl = integer_zero_node;
7894
7895
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
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
7519 b = get_primary_binfo (binfo);
7520 if (b)
7521 build_vcall_and_vbase_vtbl_entries (b, vid);
7522
7523
7524 build_vbase_offset_vtbl_entries (binfo, vid);
7525
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
7638 if (TREE_VIA_VIRTUAL (binfo) || binfo == TYPE_BINFO (vid->derived))
7639 {
7640
7658 vid->vbase = binfo;
7659
7661 if (!TREE_VIA_VIRTUAL (binfo))
7662 vid->generate_vcall_entries = false;
7663
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
7680 if (TREE_VIA_VIRTUAL (binfo) && vid->vbase != binfo)
7681 return ;
7682
7683
7684 primary_binfo = get_primary_binfo (binfo);
7685 if (primary_binfo)
7686 add_vcall_offset_vtbl_entries_r (primary_binfo, vid);
7687
7688
7689 add_vcall_offset_vtbl_entries_1 (binfo, vid);
7690
7691
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
7708 if (abi_version_at_least (2))
7709 {
7710 tree orig_fn;
7711
7712
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
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
7808 || (DECL_DESTRUCTOR_P (derived_entry)
7809 && DECL_DESTRUCTOR_P (orig_fn)))
7810 return ;
7811 }
7812
7813
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
7823 vid->index = size_binop (MINUS_EXPR, vid->index,
7824 ssize_int (TARGET_VTABLE_DATA_ENTRY_DISTANCE));
7825
7826
7827 VARRAY_PUSH_TREE (vid->fns, orig_fn);
7828
7829 if (vid->generate_vcall_entries)
7830 {
7831 tree base;
7832 tree fn;
7833
7834
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
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
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
7543 if (!TYPE_USES_VIRTUAL_BASECLASSES (BINFO_TYPE (binfo)))
7544 return ;
7545
7546 t = vid->derived;
7547
7548
7551 non_primary_binfo = binfo;
7552 while (BINFO_INHERITANCE_CHAIN (non_primary_binfo))
7553 {
7554 tree b;
7555
7556
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
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
7585 b = copied_binfo (vbase, binfo);
7586
7587
7589 if (BINFO_VTABLE_PATH_MARKED (b))
7590 continue ;
7591 BINFO_VTABLE_PATH_MARKED (b) = 1;
7592
7593
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
7604 my_friendly_assert (tree_int_cst_equal (delta,
7605 BINFO_VPTR_FIELD (vbase)),
7606 20030202);
7607 }
7608
7609
7610 vid->index = size_binop (MINUS_EXPR, vid->index,
7611 ssize_int (TARGET_VTABLE_DATA_ENTRY_DISTANCE));
7612
7613
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.