天天看点

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    

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.

继续阅读