GCC-3.4.6源代码学习笔记(142-续1)

好了,现在让我们看一下 GCC 对我们例 1 的输出。

1

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

 

// no VTT for A

VTT for B1

B1::_ZTT2B1: 2u entries

0     ((& B1::_ZTV2B1) + 16u)

4     ((& B1::_ZTV2B1) + 16u)

VTT for B2

B2::_ZTT2B2: 2u entries

0     ((& B2::_ZTV2B2) + 16u)

4     ((& B2::_ZTV2B2) + 16u)

Construction vtable for B1 (0xb7f2d980 instance) in C

C::_ZTC1C0_2B1: 6u entries

0     0u

4     0u

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

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

16    B1::_ZTcv0_n12_v0_n16_N2B11fEv         // C::B1::f

20    B1::f

 

Construction vtable for B2 (0xb7f2da00 instance) in C

C::_ZTC1C4_2B2: 10u entries

0      -4u

4     0u

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

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

16    B2::_ZTcv0_n12_v0_n16_N2B21fEv         // C::B2::f

20    B2::f

24    4u

28    (int (*)(...))4

32    (int (*)(...))(& _ZTI2B2)

36    B2::_ZTcv0_n12_v0_n16_N2B21fEv         // C::B2::f

 

VTT for C

C::_ZTT1C: 7u entries

0     ((& C::_ZTV1C) + 16u)             // vptr for C

4     ((& C::_ZTC1C0_2B1) + 16u)    // construction vtable used for B1

8     ((& C::_ZTC1C0_2B1) + 16u)    // construction vtable used for B1::A

12    ((& C::_ZTC1C4_2B2) + 16u)    // construction vtable used for B2

16    ((& C::_ZTC1C4_2B2) + 36u)    // construction vtable used for B2::A

20    ((& C::_ZTV1C) + 16u)             // vptr for secondary vtable of B2

24    ((& C::_ZTV1C) + 40u)             // vptr for secondary vtable of A

VTT 的构造由下面的函数完成。

 

6829   static void

6830   build_vtt (tree t)                                                                                      in class.c

6831   {

6832     tree inits;

6833     tree type;

6834     tree vtt;

6835     tree index;

6836  

6837     /* Build up the initializers for the VTT.  */

6838     inits = NULL_TREE;

6839     index = size_zero_node;

6840     build_vtt_inits (TYPE_BINFO (t), t, &inits, &index);

6841  

6842     /* If we didn't need a VTT, we're done.  */

6843     if (!inits)

6844       return ;

6845  

6846     /* Figure out the type of the VTT.  */

6847     type = build_index_type (size_int (list_length (inits) - 1));

6848     type = build_cplus_array_type (const_ptr_type_node, type);

6849                            

6850     /* Now, build the VTT object itself.  */

6851     vtt = build_vtable (t, get_vtt_name (t), type);

6852     initialize_array (vtt, inits);

6853     /* Add the VTT to the vtables list.  */

6854     TREE_CHAIN (vtt) = TREE_CHAIN (CLASSTYPE_VTABLES (t));

6855     TREE_CHAIN (CLASSTYPE_VTABLES (t)) = vtt;

6856  

6857     dump_vtt (t, vtt);

6858   }

 

在我们的例子中 对于类 B1 B2 C VTT 是期望的 其主体由下面的 build_vtt_init 构建。其中参数 binfo 是最后派生类的 binfo t 是最后派生类 index 是在 VTT 中最后占用的索引。

 

6892   static tree *

6893   build_vtt_inits (tree binfo, tree t, tree* inits, tree* index)                              in class.c

6894   {

6895     int i;

6896     tree b;

6897     tree init;

6898     tree secondary_vptrs;

6899     int top_level_p = same_type_p (TREE_TYPE (binfo), t);

6900  

6901     /* We only need VTTs for subobjects with virtual bases.  */

6902     if (!TYPE_USES_VIRTUAL_BASECLASSES (BINFO_TYPE (binfo)))

6903       return inits;

6904  

6905     /* We need to use a construction vtable if this is not the primary

6906        VTT.  */

6907     if (!top_level_p)

6908     {

6909       build_ctor_vtbl_group (binfo, t);

6910  

6911       /* Record the offset in the VTT where this sub-VTT can be found.  */

6912       BINFO_SUBVTT_INDEX (binfo) = *index;

6913     }

6914  

6915     /* Add the address of the primary vtable for the complete object.  */

6916     init = binfo_ctor_vtable (binfo);

6917     *inits = build_tree_list (NULL_TREE, init);

6918     inits = &TREE_CHAIN (*inits);

6919     if (top_level_p)

6920     {

6921       my_friendly_assert (!BINFO_VPTR_INDEX (binfo), 20010129);

6922       BINFO_VPTR_INDEX (binfo) = *index;

6923     }

6924     *index = size_binop (PLUS_EXPR, *index, TYPE_SIZE_UNIT (ptr_type_node));

6925                     

6926     /* Recursively add the secondary VTTs for non-virtual bases.  */

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

6928     {

6929       b = BINFO_BASETYPE (binfo, i);

6930       if (!TREE_VIA_VIRTUAL (b))

6931         inits = build_vtt_inits (BINFO_BASETYPE (binfo, i), t,

6932                            inits, index);

6933     }

 

在前一节中,类的 BINFO_VTABLE dfs_accumulate_vtbl_inits 中设置了 vtable 初始值。它是一个 PLUS_EXPR ,指定了作为 vtable 开头的初始值的位置。在上面的 6916 行, binfo_ctor_vtable 从类得到这个表达式。

 

6865   static tree

6866   binfo_ctor_vtable (tree binfo)                                                                    in class.c

6867   {

6868     tree vt;

6869  

6870     while (1)

6871     {

6872       vt = BINFO_VTABLE (binfo);

6873       if (TREE_CODE (vt) == TREE_LIST)

6874         vt = TREE_VALUE (vt);

6875       if (TREE_CODE (vt) == TREE_VEC)

6876         binfo = vt;

6877       else

6878         break ;

6879     }

6880  

6881     return vt;

6882   }

 

在上面的 6917 行,由 binfo_ctor_vtable 返回的 init 被构建入一个 tree_list ;而在 6918 行, inits 又指向了这个 tree_list chain 域的地址,那么在 6931 行递归进入这个函数时,将继续往这个链表上添加节点。上面的参数 index VTT 中下一个成员的索引(它也是字节数),一开始它为 size_zero_node

6922 行的 BINFO_VPTR_INDEX 保存了 VTT 的索引,在那里可以找到该子对象的虚指针。对于最后派生类 C ,其虚指针在 VTT 索引为 0 的地方。首先,对非虚拟基类, build_ctor_vtbl_group 执行以下的处理。

 

7098   static void

7099   build_ctor_vtbl_group (tree binfo, tree t)                                                    in class.c

7100   {

7101     tree list;

7102     tree type;

7103     tree vtbl;

7104     tree inits;

7105     tree id;

7106     tree vbase;

7107  

7108     /* See if we've already created this construction vtable group.  */

7109     id = mangle_ctor_vtbl_for_type (t, binfo);

7110     if (IDENTIFIER_GLOBAL_VALUE (id))

7111       return ;

7112  

7113     my_friendly_assert (!same_type_p (BINFO_TYPE (binfo), t), 20010124);

7114     /* Build a version of VTBL (with the wrong type) for use in

7115       constructing the addresses of secondary vtables in the

7116       construction vtable group.  */

7117     vtbl = build_vtable (t, id, ptr_type_node);

7118     list = build_tree_list (vtbl, NULL_TREE);

7119     accumulate_vtbl_inits (binfo, TYPE_BINFO (TREE_TYPE (binfo)),

7120                         binfo, t, list);

7121  

7122     /* Add the vtables for each of our virtual bases using the vbase in T

7123       binfo.  */

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

7125         vbase;

7126         vbase = TREE_CHAIN (vbase))

7127     {

7128       tree b;

7129  

7130       if (!TREE_VIA_VIRTUAL (vbase))

7131         continue ;

7132       b = copied_binfo (vbase, binfo);

7133        

7134       accumulate_vtbl_inits (b, vbase, binfo, t, list);

7135     }

7136     inits = TREE_VALUE (list);

7137  

7138     /* Figure out the type of the construction vtable.  */

7139     type = build_index_type (size_int (list_length (inits) - 1));

7140     type = build_cplus_array_type (vtable_entry_type, type);

7141     TREE_TYPE (vtbl) = type;

7142  

7143     /* Initialize the construction vtable.  */

7144     CLASSTYPE_VTABLES (t) = chainon (CLASSTYPE_VTABLES (t), vtbl);

7145     initialize_array (vtbl, inits);

7146     dump_vtable (t, binfo, vtbl);

7147   }

 

在上面的 7109 mangle_ctor_vtbl_for_type 返回用于链接目的的 vtable 修饰名。接着的断言确保只有基类才会进入这个函数。然后一个新构建的 vtable 对象被封装入一个 tree_list 节点,并在 7119 行作为最后的参数传给下面的函数。注意 rtti_binfo 是合资格直接基类的 binfo ,该函数将为这个基类准备初始值。

这里, accumulate_vtbl_inits 按前序的次序处理感兴趣的基类及它的非虚拟基类,然后在 build_ctor_vblt_group 中,以在派生树中出现的次序,调用该函数处理基类的虚拟基类。出于方便,我们在下面重新显示相关的函数。

 

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   }

 

这一次 上面 7167 行的 ctor_vtbl_p true 因为参数 t 总是指向最后派生类 rtti_binfo 总是其基类。 7179 行的条件滤除不从虚拟基类派生的非虚拟基类。

 

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     {

7226       /* In the hierarchy of BINFO_TYPE (RTTI_BINFO), this is a

7227          primary virtual base. If it is not the same primary in

7228          the hierarchy of T, we'll need to generate a ctor vtable

7229          for it, to place at its location in T. If it is the same

7230          primary, we still need a VTT entry for the vtable, but it

7231          should point to the ctor vtable for the base it is a

7232          primary for within the sub-hierarchy of RTTI_BINFO.

7233             

7234          There are three possible cases:

7235             

7236          1) We are in the same place.

7237          2) We are a primary base within a lost primary virtual base of

7238           RTTI_BINFO.

7239          3) We are primary to something not a base of RTTI_BINFO.  */

7240         

7241       tree b = BINFO_PRIMARY_BASE_OF (binfo);

7242       tree last = NULL_TREE;

7243  

7244       /* First, look through the bases we are primary to for RTTI_BINFO

7245          or a virtual base.  */

7246       for (; b; b = BINFO_PRIMARY_BASE_OF (b))

7247       {

7248          last = b;

7249          if (TREE_VIA_VIRTUAL (b) || b == rtti_binfo)

7250            break ;

7251       }

7252       /* If we run out of primary links, keep looking down our

7253          inheritance chain; we might be an indirect primary.  */

7254       if (b == NULL_TREE)

7255         for (b = last; b; b = BINFO_INHERITANCE_CHAIN (b))

7256            if (TREE_VIA_VIRTUAL (b) || b == rtti_binfo)

7257              break ;

7258  

7259        /* If we found RTTI_BINFO, this is case 1. If we found a virtual

7260         base B and it is a base of RTTI_BINFO, this is case 2. In

7261          either case, we share our vtable with LAST, i.e. the

7262          derived-most base within B of which we are a primary.  */

7263       if (b == rtti_binfo

7264           || (b && purpose_member (BINFO_TYPE (b),

7265                  CLASSTYPE_VBASECLASSES (BINFO_TYPE (rtti_binfo)))))

7266         /* Just set our BINFO_VTABLE to point to LAST, as we may not have

7267            set LAST's BINFO_VTABLE yet. We'll extract the actual vptr in

7268            binfo_ctor_vtable after everything's been set up.  */

7269         vtbl = last;

7270  

7271        /* Otherwise, this is case 3 and we get our own.  */

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);

7284  

7285       /* Figure out the position to which the VPTR should point.  */

7286       vtbl = TREE_PURPOSE (l);

7287       vtbl = build1 (ADDR_EXPR,

7288                   vtbl_ptr_type_node,

7289                   vtbl);

7290       TREE_CONSTANT (vtbl) = 1;

7291       index = size_binop (PLUS_EXPR,

7292                        size_int (non_fn_entries),

7293                        size_int (list_length (TREE_VALUE (l))));

7294       index = size_binop (MULT_EXPR,

7295                        TYPE_SIZE_UNIT (vtable_entry_type),

7296                        index);

7297       vtbl = build (PLUS_EXPR, TREE_TYPE (vtbl), vtbl, index);

7298       TREE_CONSTANT (vtbl) = 1;

7299     }

7300  

7301     if (ctor_vtbl_p)

7302       /* For a construction vtable, we can't overwrite BINFO_VTABLE.

7303         So, we make a TREE_LIST. Later, dfs_fixup_binfo_vtbls will

7304         straighten this out.  */

7305       BINFO_VTABLE (binfo) = tree_cons (rtti_binfo, vtbl, BINFO_VTABLE (binfo));

7306     else if (BINFO_PRIMARY_P (binfo) && TREE_VIA_VIRTUAL (binfo))

7307       inits = NULL_TREE;

7308     else

7309       /* For an ordinary vtable, set BINFO_VTABLE.  */

7310       BINFO_VTABLE (binfo) = vtbl;

7311  

7312     return inits;

7313   }

 

参数 orig_binfo 应该总是指向感兴趣基类类型的 binfo 。而在 7273 行的断言 BINFO_NEW_VTABLE_MARKED 返回 true ,如果类型有属于自己的 vtable 。现在 rtti_binfo 是感兴趣直接基类的 binfo 。在我们的例子里,当处理 C 时, B1 B2 就是这样的基类。而 t 指向最后派生类的 binfo ,在我们的例子中,它是类 C 。另外 binfo 是正在处理的基类的 binfo

这里当 accumulate_vtbl_inits 处理 B1 时,在 dfs_accumulate_vtbl_inits 7224 行条件, TREE_VIA_VIRTUAL BINFO_PRIMARY_P 对于 orig_binfo 都是不成立的(这里是 B1 binfo );而在 7273 行的条件, orig_binfo 显然具有自己的 vtable ,该条件亦不成立。因此将进入 7276 行的 IF 块,这里面的处理在前一节已经看过,大同小异。因为 ctor_vtbl_p true ,因而 7305 行得到执行,注意 binfo B1-in-C binfo ,它的 BINFO_VTABLE NULL 。因为这里得到的 vtable 是构造( construction vtable ,它只能暂时借用 BINFO_VTABLE ,所以把它构建入一个 tree_list 。为之配合的函数有: binfo_ctor_vtable dfs_fixup_binfo_vtbls

7119 行,当从 accumulate_vtbl_inits 退出时,例 1 B1-in-C 应该在其构造( construction vtable 里,具有如下的项(保存在 build_ctor_vtbl_group 7118 行的 list TREE_PURPOSE 域,及 BINFO_VTABLE (B1-in-C binfo) )。

Construction vtable for B1 (0xb7f2d980 instance) in C

C::_ZTC1C0_2B1: 6u entries

0     0u

4     0u

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

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

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

20    B1::f     // slot of B1::f

接着在 7134 行对 accumulate_vtbl_inits 的调用中, binfo C::B1 binfo ,而 7124 行获得了类型 B1 binfo ,因此 vbase B1::A binfo ,而 b C::B1::A binfo ,而 t 仍然是类型 C 。它们被传递给 dfs_accumulate_vtbl_inits ,按如下的映射关系: binfo b ), orig_binfo vbase ), rtti_binfo binfo )及 t t )。

那么 7223 行条件满足。在 7241 行, b C::B1 binfo ;而 last 7248 行得到 C::B1 binfo 。结果 vtbl 7269 行被设置为 C::B1 binfo 。最后,在 7305 行, BINFO_VTABLE (C::B1::A binfo) 被加入一个包含 C::B1 binfo tree_list 节点。并且为 NULL inits 被返回。

不过对于 B2-in-C ,事情稍有不同。同样在 7119 行退出 accumulate_vtbl_inits 时,例 1 中的 B2-in-C 应该在其构造( construction vtable 里,具有如下的项(保存在 build_ctor_vtbl_group 7118 行的 list TREE_PURPOSE 域)。

Construction vtable for B2 (0xb7f2da00 instance) in C

C::_ZTC1C4_2B2: 10u entries

0     -4u

4     0u

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

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

16    B2::_ZTcv0_n12_v0_n16_N2B21fEv

20    B2::f     // slot of B2::f

但在为 B2::A 调用的 dfs_accumulate_vtbl_inits 中, binfo C::B2 binfo (参数: rtti_binfo ), vbase B2::A binfo (参数: orig_binfo ), b C::B2::A binfo (参数: binfo ), t C (参数: t )。

那么在 7241 行, b 这次是 C::B2 binfo ;而在 7248 行的 last 得到 NULL ,因为它沿着路径 A à B1 à C 攀升。因此在 7276 行的条件中, vtbl 保持为 NULL 。因而为 B2::A 产生的构造( construction vtable 具有如下的项:

24    4u        // part of A in B2 - begin

28    (int (*)(...))4

32    (int (*)(...))(& _ZTI2B2)

36    B2::_ZTcv0_n12_v0_n16_N2B21fEv         // part of A in B2 - end

build_ctor_vtbl_group 7140 行为这些构造( construction vtable 重新构建了数组类型。接着在 7144 行,这个用于基类构造的 vtable 串接入最后派生类的 CLASSTYPE_VTABLES 。而在 7145 行的 initialize_array vtable 项确切的类型准备初始值。

build_ctor_vtbl_group 回到 build_vtt_inits 时, 6916 行的 binfo_ctor_vtable C::B1 得到 C::B1 的构造( construction vtable index 1 )。

6927 行的 FOR 循环对于 B1 B2 不做任何事,那么我们来到下面的代码。

 

build_vtt_inits (continue)

 

6935     /* Add secondary virtual pointers for all subobjects of BINFO with

6936       either virtual bases or reachable along a virtual path, except

6937       subobjects that are non-virtual primary bases.  */

6938     secondary_vptrs = tree_cons (t, NULL_TREE, BINFO_TYPE (binfo));

6939     TREE_TYPE (secondary_vptrs) = *index;

6940     VTT_TOP_LEVEL_P (secondary_vptrs) = top_level_p;

6941     VTT_MARKED_BINFO_P (secondary_vptrs) = 0;

6942    

6943     dfs_walk_real (binfo,

6944                   dfs_build_secondary_vptr_vtt_inits ,

6945                   NULL,

6946                   dfs_ctor_vtable_bases_queue_p,

6947                   secondary_vptrs);

6948     VTT_MARKED_BINFO_P (secondary_vptrs) = 1;

6949     dfs_walk (binfo, dfs_unmark, dfs_ctor_vtable_bases_queue_p,

6950              secondary_vptrs);

6951  

6952     *index = TREE_TYPE (secondary_vptrs);

6953  

6954     /* The secondary vptrs come back in reverse order. After we reverse

6955       them, and add the INITS, the last init will be the first element

6956       of the chain.  */

6957     secondary_vptrs = TREE_VALUE (secondary_vptrs);

6958     if (secondary_vptrs)

6959     {

6960       *inits = nreverse (secondary_vptrs);

6961       inits = &TREE_CHAIN (secondary_vptrs);

6962       my_friendly_assert (*inits == NULL_TREE, 20000517);

6963     }

6964  

6965     /* Add the secondary VTTs for virtual bases.  */

6966     if (top_level_p)

6967       for (b = TYPE_BINFO (BINFO_TYPE (binfo)); b; b = TREE_CHAIN (b))

6968       {

6969         if (!TREE_VIA_VIRTUAL (b))

6970            continue ;

6971       

6972         inits = build_vtt_inits (b, t, inits, index);

6973       }

6974  

6975     if (!top_level_p)

6976     {

6977       tree data = tree_cons (t, binfo, NULL_TREE);

6978       VTT_TOP_LEVEL_P (data) = 0;

6979       VTT_MARKED_BINFO_P (data) = 0;

6980        

6981       dfs_walk (binfo, dfs_fixup_binfo_vtbls ,

6982                dfs_ctor_vtable_bases_queue_p,

6983                data);

6984     }

6985  

6986     return inits;

6987   }

 

上面的 secondary_vptrs 正如其名字所表示的,是在最后派生类的 VTT 中指向次要 vtable 的指针;而 index 指出这个指针所在的 VTT 的项。在 6943 行的遍历从 binfo 所指定的基类 binfo 开始(这里,即是 C::B1 binfo C::B2 binfo ),并步入这个节点。下面的函数则以前序的次序处理访问的节点,看到参数 data secondary_vptrs

 

6996   static tree

6997   dfs_build_secondary_vptr_vtt_inits (tree binfo, void* data)                          in class.c

6998   {

6999     tree l;

7000     tree t;

7001     tree init;

7002     tree index;

7003     int top_level_p;

7004  

7005     l = (tree) data;

7006     t = TREE_CHAIN (l);

7007     top_level_p = VTT_TOP_LEVEL_P (l);

7008    

7009     BINFO_MARKED (binfo) = 1;

7010  

7011     /* We don't care about bases that don't have vtables.  */

7012     if (!TYPE_VFIELD (BINFO_TYPE (binfo)))

7013       return NULL_TREE;

7014  

7015     /* We're only interested in proper subobjects of T.  */

7016     if (same_type_p (BINFO_TYPE (binfo), t))

7017       return NULL_TREE;

7018  

7019     /* We're not interested in non-virtual primary bases.  */

7020     if (!TREE_VIA_VIRTUAL (binfo) && BINFO_PRIMARY_P (binfo))

7021       return NULL_TREE;

7022  

7023     /* If BINFO has virtual bases or is reachable via a virtual path

7024        from T, it'll have a secondary vptr.  */

7025     if (!TYPE_USES_VIRTUAL_BASECLASSES (BINFO_TYPE (binfo))

7026         && !binfo_via_virtual (binfo, t))

7027       return NULL_TREE;

7028  

7029     /* Record the index where this secondary vptr can be found.  */

7030     index = TREE_TYPE (l);

7031     if (top_level_p)

7032     {

7033       my_friendly_assert (!BINFO_VPTR_INDEX (binfo), 20010129);

7034       BINFO_VPTR_INDEX (binfo) = index;

7035     }

7036     TREE_TYPE (l) = size_binop (PLUS_EXPR, index,

7037                               TYPE_SIZE_UNIT (ptr_type_node));

7038  

7039     /* Add the initializer for the secondary vptr itself.  */

7040     if (top_level_p && TREE_VIA_VIRTUAL (binfo))

7041     {

7042        /* It's a primary virtual base, and this is not the construction

7043         vtable. Find the base this is primary of in the inheritance graph,

7044         and use that base's vtable now.  */

7045       while (BINFO_PRIMARY_BASE_OF (binfo))

7046         binfo = BINFO_PRIMARY_BASE_OF (binfo);

7047     }

7048     init = binfo_ctor_vtable (binfo);

7049     TREE_VALUE (l) = tree_cons (NULL_TREE, init, TREE_VALUE (l));

7050  

7051     return NULL_TREE;

7052   }

 

当遍历以 C::B1 binfo 为根的子树时,上面的 top_level_p false 7006 行的 t 是类型 B1 。这个节点被跳过,因为满足 7016 行的条件;在访问 C::B1::A binfo 时,在 7048 行,因为 C::B1::A binfo BINFO_VTABLE 中保存的是 C::B1 binfo binfo_ctor_vtable 辗转地再一次获得了 C::B1 的构造( construction vtable (保存在 index 2 的位置)。注意到这个函数总是返回 NULL ,它将强制进行整棵子树的遍历。

记得在 dfs_accumulate_vtbl_inits 7305 行,构造( construction vtable 暂时栖身在 BINFO_VTABLE 中。现在构造( construction vtable 已经记录在 VTT 中,不再需要在 BINFO_VTABLE 里混了。现在要通过尝试把 BINFO_VTABLE 恢复过来。注意其参数 data 的构成,在我们这里,上面由 C::B1::A 暂存的节点被移走了(对 C::B2 则是 C::B2::A )。

 

7075   static tree

7076   dfs_fixup_binfo_vtbls (tree binfo, void* data)                                            in class.c

7077   {

7078     BINFO_MARKED (binfo) = 0;

7079  

7080     /* We don't care about bases that don't have vtables.  */

7081     if (!TYPE_VFIELD (BINFO_TYPE (binfo)))

7082       return NULL_TREE;

7083  

7084     /* If we scribbled the construction vtable vptr into BINFO, clear it

7085       out now.  */

7086     if (BINFO_VTABLE (binfo)

7087         && TREE_CODE (BINFO_VTABLE (binfo)) == TREE_LIST

7088         && (TREE_PURPOSE (BINFO_VTABLE (binfo))

7089               == TREE_VALUE ((tree) data)))

7090       BINFO_VTABLE (binfo) = TREE_CHAIN (BINFO_VTABLE (binfo));

7091  

7092     return NULL_TREE;

7093   }

 

回过去看上面提到的 C::B2 的处理,在其 build_ctor_vtbl_group 返回到 build_vtt_inits 时,其构造( construction vtable 被保存在 VTT index 3 的地方。而在其后对 C::B2 dfs_build_secondary_vptr_vtt_inits 的调用中,在 7048 行, binfo_ctor_vtable 得到了 B2::A 的构造( construction vtable index 4 )。

当完成了 B1 B2 的处理后,在 build_vtt_inits 6938 行,继续处理 C 。在 6943 行,开始遍历以 C 为根节点的派生树。那么在 dfs_build_secondary_vptr_vtt_inits 中, top_level_p true t 是最后派生类 C 。在这个前序遍历中, C 满足 7016 行条件, C::B1 满足 7020 行条件,退出该函数。对于 C::B2 VTT 的索引 5 被置为 C::B2 vptr ,而其 vtable (这是个次要 vtable )的初始值则是上一节中得到的 BINFO_VTABLE(C::B2) ;同样对于 C::B1::A ,它的 vptr VTT 索引为 6 的地方,其 vtable (也是次要 vtable )的初始值也是前一节中保存在 BINFO_VTABLE(A-in-C) 的内容。 C::B2::A 跳过,因为 A 已经在 C::B1::A 中访问了。

build_vtt_inits 6972 行,最后处理 A ,不过因为 A 不包含虚拟基类, build_vtt_inits 对它不做处理。

回到 build_vtt ,如果处理成功, inits 不为 NULL 。接下来就是为 VTT 构建正确的类型,及 VTT 类型的静态成员对象,并且把这个 VTT 对象置入最后派生类 CLASSTYPE_VTABLES 的链头。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值