GCC-3.4.6源代码学习笔记(140)

5.12.5.2.2.2.1.3.10.        完成派生类的 RECORD_TYPE 构建 vtable

记得在 determine_primary_base 中,如果我们找到一个主要基类,我们只是记住它的 vtable (记住它必须有 vtable ,否则我们不会有主要基类),现在我们需要属于自己的 vtable 。注意 5057 5064 行的断言,它们可以帮助我们尽早地发现不一致的情况。

 

finish_struct_1 (continue)

 

5051     /* Make sure that we get our own copy of the vfield FIELD_DECL.  */

5052     vfield = TYPE_VFIELD (t);

5053     if (vfield && CLASSTYPE_HAS_PRIMARY_BASE_P (t))

5054     {

5055       tree primary = CLASSTYPE_PRIMARY_BINFO (t);

5056  

5057       my_friendly_assert (same_type_p (DECL_FIELD_CONTEXT (vfield),

5058                        BINFO_TYPE (primary)),

5059                        20010726);

5060       /* The vtable better be at the start.  */

5061       my_friendly_assert (integer_zerop (DECL_FIELD_OFFSET (vfield)),

5062                        20010726);

5063       my_friendly_assert (integer_zerop (BINFO_OFFSET (primary)),

5064                        20010726);

5065        

5066       vfield = copy_decl (vfield);

5067       DECL_FIELD_CONTEXT (vfield) = t;

5068       TYPE_VFIELD (t) = vfield;

5069     }

5070     else

5071       my_friendly_assert (!vfield || DECL_FIELD_CONTEXT (vfield) == t, 20010726);

5072  

5073     virtuals = modify_all_vtables (t, nreverse (virtuals));

5074  

5075     /* If we created a new vtbl pointer for this class, add it to the

5076       list.  */

5077     if (TYPE_VFIELD (t) && !CLASSTYPE_HAS_PRIMARY_BASE_P (t))

5078       CLASSTYPE_VFIELDS (t)

5079         = chainon (CLASSTYPE_VFIELDS (t), build_tree_list (NULL_TREE, t));

 

记得上面的 virtuals 记录了 t 中的虚函数,如果有的话。但它是倒序的,所以用 nreverse 先恢复次序。注意到 t 是当前类,而且在调用 dfs_walk 时,它被传作 data 。而 virtuals 通过遍历 TYPE_METHOD 链选出虚函数来构建其内容(参见 create_vtable_ptr ),那么当前类的 binfo BINFO_VIRTUAL 是什么呢?在 set_primary_base 里,当确定了主要基类时,当前类的 TYPE_BINFO_VIRTUALS 被设置为主要基类的 TYPE_BINFO_VIRTUALS TYPE_BINFO_VIRTUALS (t) 被定义为 BINFO_VIRTUALS (TYPE_BINFO (t)) )。那么, B1 (主要基类)的 TYPE_BINFO_VIRTUALS 又是什么呢?一开始,它从 A (参见这一节开头的例 1 和例 2 )的 TYPE_BINFO_VIRTUALS 得到其内容。

让我们回到更早一些时候,在那时类 A 正在完成。毫无疑问,一开始, A 具有空的 TYPE_BINFO_VIRTUALS 。对这个类型,下面的 dfs_modify_vtables 不做任何事,而接着 modify_all_vtables A::f 返回作 virtuals 。接着回到下面的 finish_struct_1 部分,在 5086 行,通过 build_primary_vtable A 构建了主 vtable ,在 5106 行其 TYPE_BINFO_VIRTUALS 包含了 A::f

因此,在完成 B1 时,其 TYPE_BINFO_VIRTUALS 也是包含了 A 的部分,即 A::f 。然后在下面的 dfs_modify_vtables 中的 2314 行,为 A 准备了次要的( secondary )。注意到 dfs_modify_vtables 在派生树中( B1 为根),由下至上地访问基类的 binfo ,因此第一个得到处理的是 B1 中的 A 。在后面可以看到, A::f B1::f 所替代,并且带有一个 thunk 。接着处理 B1 本身, B1 A::f 同样被带有一个 thunk B1::f 所替代( 2 个替代的地点不同,前者在 A 的次要 vtable ,后者在 B1 的主 vtable )。在下面的 modify_all_vtables ,因为 vrituals B1::f DECL_VINDEX 不是 error_mark_node (参见 check_for_override error_mark_node 表示该函数不是一个重载),而现在 BINFO_VIRTUALS (B1) 包含了带 thunk B1::f ,而且因为 value_member 当且仅当 fn 与链中某个实体的地址相同时返回 true ,因此在 virutals 中的 B1::f 被保留,并在 5106 添加到 B1 TYPE_BINFO_VIRTUALS 末尾。从而该链表中包含了带 thunk B1::f ,其后是 B1::f (不带 thunk )。

现在轮到处理 C ,我们知道在 C TYPE_BINFO_VIRTUALS 中,包含了带有结果指针调整 thunk B1::f ,其后是 B1::f ;同样 C 持有 B1 binfo 的拷贝。下面我们将结合代码,仔细地查看这一过程。

 

2344   static tree

2345   modify_all_vtables (tree t, tree virtuals)                                                     in class.c

2346   {

2347     tree binfo = TYPE_BINFO (t);

2348     tree *fnsp;

2349  

2350     /* Update all of the vtables.  */

2351     dfs_walk (binfo, dfs_modify_vtables , unmarkedp , t);

2352     dfs_walk (binfo, dfs_unmark, markedp, t);

2353  

2354     /* Add virtual functions not already in our primary vtable. These

2355       will be both those introduced by this class, and those overridden

2356       from secondary bases. It does not include virtuals merely

2357       inherited from secondary bases.  */

2358     for (fnsp = &virtuals; *fnsp; )

2359     {

2360       tree fn = TREE_VALUE (*fnsp);

2361  

2362       if (!value_member (fn, BINFO_VIRTUALS (binfo))

2363           || DECL_VINDEX (fn) == error_mark_node)

2364       {

2365          /* We don't need to adjust the `this' pointer when

2366            calling this function.  */

2367          BV_DELTA (*fnsp) = integer_zero_node;

2368          BV_VCALL_INDEX (*fnsp) = NULL_TREE;

2369  

2370          /* This is a function not already in our vtable. Keep it.  */

2371          fnsp = &TREE_CHAIN (*fnsp);

2372       }

2373       else

2374         /* We've already got an entry for this function. Skip it.  */

2375         *fnsp = TREE_CHAIN (*fnsp);

2376     }

2377  

2378     return virtuals;

2379   }

 

函数 dfs_modfiy_vtables dfs_walk 遍历派生树时,以后序次序执行。注意到该函数总是返回 NULL 来强制完整的遍历,并且在遍历过程中得到处理的是虚拟基类或非主要基类,如果当前类没有 vtable CLASSTYPE_VFIELDS ,它可能由 determine_primary_base 设置)也不在处理之列。对于例 1 和例 2 ,类 C B2 A 在这里将被以 A B2 ,然后 C 的次序处理。同样需要强调的是,当处理 A 时,所有的改变都发生在 C A binfo 拷贝中;而当处理 B2 时,改变也仅限于 C B2 binfo 拷贝中;两者的处理实际上与 B1 的处理十分类似。下面我们只看 C 的处理过程,记住在 2319 行, C BINFO_VIRTUALS 包含了带有 thunk (从 A B1 this 指针调整( this-adjustment )及结果调整( result-adjustment ))的 B::f

 

2298   static tree

2299   dfs_modify_vtables (tree binfo, void* data)                                                in class.c

2300   {

2301     if (/* There's no need to modify the vtable for a non-virtual

2302          primary base; we're not going to use that vtable anyhow.

2303           We do still need to do this for virtual primary bases, as they

2304           could become non-primary in a construction vtable.  */

2305        (!BINFO_PRIMARY_P (binfo) || TREE_VIA_VIRTUAL (binfo))

2306        /* Similarly, a base without a vtable needs no modification.  */

2307        && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo)))

2308     {

2309       tree t = (tree) data;

2310       tree virtuals;

2311       tree old_virtuals;

2312       unsigned ix;

2313        

2314       make_new_vtable (t, binfo);

2315        

2316       /* Now, go through each of the virtual functions in the virtual

2317          function table for BINFO. Find the final overrider, and

2318          update the BINFO_VIRTUALS list appropriately.  */

2319       for (ix = 0, virtuals = BINFO_VIRTUALS (binfo),

2320              old_virtuals = BINFO_VIRTUALS (TYPE_BINFO (BINFO_TYPE (binfo)));

2321             virtuals;

2322            ix++, virtuals = TREE_CHAIN (virtuals),

2323                old_virtuals = TREE_CHAIN (old_virtuals))

2324         update_vtable_entry_for_fn (t,

2325                                 binfo,

2326                                 BV_FN (old_virtuals),

2327                                 &virtuals, ix);

2328     }

2329  

2330     BINFO_MARKED (binfo) = 1;

2331  

2332     return NULL_TREE;

2333   }

 

注意到参数 t 在过程不改变,总是指向正在完成的当前类。而 binfo 是当前访问的基类。首先,根据需要构建 vtable 。在这里为 A B2 C 构建 vtable

 

658    static int

659    make_new_vtable (tree t, tree binfo)                                                                in class.c

660    {

661      if (binfo == TYPE_BINFO (t))

662        /* In this case, it is *type*'s vtable we are modifying. We start

663          with the approximation that its vtable is that of the

664          immediate base class.  */

665        /* ??? This actually passes TYPE_BINFO (t), not the primary base binfo,

666          since we've updated DECL_CONTEXT (TYPE_VFIELD (t)) by now.  */

667        return build_primary_vtable (TYPE_BINFO (DECL_CONTEXT (TYPE_VFIELD (t))),

668                                 t);

669      else

670        /* This is our very own copy of `basetype' to play with. Later,

671          we will fill in all the virtual functions that override the

672          virtual functions in these base classes which are not defined

673          by the current type.  */

674        return build_secondary_vtable (binfo);

675    }

 

对于 A B2 ,因为它们的 binfo 不同于 TYPE_BINFO (C) build_secondary_vtable 被调用。并且因为这些 binfo 中的虚函数是从对应类的 binfo 中借来的(参见 xref_basetypes 中的 copy_base_binfos )。现在是时候拥有自己那一份了。

 

634    static int

635    build_secondary_vtable (tree binfo)                                                            in class.c

636    {

637      if (BINFO_NEW_VTABLE_MARKED (binfo))

638        /* We already created a vtable for this base. There's no need to

639          do it again.  */

640        return 0;

641   

642      /* Remember that we've created a vtable for this BINFO, so that we

643        don't try to do so again.  */

644      SET_BINFO_NEW_VTABLE_MARKED (binfo);

645     

646      /* Make fresh virtual list, so we can smash it later.  */

647      BINFO_VIRTUALS (binfo) = copy_virtuals (binfo);

648   

649      /* Secondary vtables are laid out as part of the same structure as

650        the primary vtable.  */

651      BINFO_VTABLE (binfo) = NULL_TREE;

652      return 1;

653    }

 

BV_VCALL_INDEX 如果不是 NULL ,保存了 vtable 的索引,在该位置是调用这个虚函数时所需要的 vcall 偏移量(通过把这个值加到 this 指针上)。它需要被清除以准备重新索引。

 

562    static tree

563    copy_virtuals (tree binfo)                                                                         in class.c

564    {

565      tree copies;

566      tree t;

567   

568      copies = copy_list (BINFO_VIRTUALS (binfo));

569      for (t = copies; t; t = TREE_CHAIN (t))

570        BV_VCALL_INDEX (t) = NULL_TREE;

571   

572      return copies;

573    }

 

而对于类 C build_primary_vtable 被调用,因为此处的参数 binfo 就是 C binfo 。记得 C 现在仍然使用其主要基类的 TYPE_BINFO_VTABLE TYPE_BINFO_VIRTUALS ,现在它需要属于自己的那一份。

 

581    static int

582    build_primary_vtable (tree binfo, tree type)                                                in class.c

583    {

584      tree decl;

585      tree virtuals;

586   

587      decl = get_vtable_decl (type, /*complete=*/ 0);

588     

589      if (binfo)

590      {

591        if (BINFO_NEW_VTABLE_MARKED (binfo))

592          /* We have already created a vtable for this base, so there's

593             no need to do it again.  */

594          return 0;

595         

596        virtuals = copy_virtuals (binfo);

597        TREE_TYPE (decl) = TREE_TYPE (get_vtbl_decl_for_binfo (binfo));

598        DECL_SIZE (decl) = TYPE_SIZE (TREE_TYPE (decl));

599        DECL_SIZE_UNIT (decl) = TYPE_SIZE_UNIT (TREE_TYPE (decl));

600      }

601      else

602      {

603        my_friendly_assert (TREE_TYPE (decl) == vtbl_type_node, 20000118);

604        virtuals = NULL_TREE;

605      }

606   

607    #ifdef GATHER_STATISTICS

608      n_vtables += 1;

609      n_vtable_elems += list_length (virtuals);

610    #endif

611    

612      /* Initialize the association list for this type, based

613        on our first approximation.  */

614      TYPE_BINFO_VTABLE (type) = decl;

615      TYPE_BINFO_VIRTUALS (type) = virtuals;

616      SET_BINFO_NEW_VTABLE_MARKED (TYPE_BINFO (type));

617      return 1;

618    }

 

如果 vtable 已经被创建,它保存在 CLASSTYPE_VTABLES 域;否则这个域就是空的。参数 complete 如果是非 0 值,则表示完成在这个函数中创建的 vtable 的定义——通过调用 cp_finish_decl ,我们当前正在这个函数中完成模板类“ SmallObject ”具现。

 

539    tree

540    get_vtable_decl (tree type, int complete)                                                     in class.c

541    {

542      tree decl;

543   

544      if (CLASSTYPE_VTABLES (type))

545        return CLASSTYPE_VTABLES (type);

546     

547      decl = build_vtable (type, get_vtable_name (type), vtbl_type_node );

548      CLASSTYPE_VTABLES (type) = decl;

549   

550      if (complete)

551      {

552        DECL_EXTERNAL (decl) = 1;

553        cp_finish_decl (decl, NULL_TREE, NULL_TREE, 0);

554      }

555   

556      return decl;

557    }

 

Vtable 应该为该类型的所有实例共享(基类是例外,看到其 BINFO_VTABLE build_secondary_vtable 中创建),因此它应该被创建为静态数据成员。上面的 get_vtable_name 获取 vtable 的修饰名(例 1 及例 2 GCC 的输出给出了修饰名的一些例子),而 vtbl_type_node 具有 vtable_entry_type 类型的数组常量类型(在 cxx_init_decl_processing 中构建)。

 

506    static tree

507    build_vtable (tree class_type, tree name, tree vtable_type)                            in class.c

508    {

509      tree decl;

510   

511       decl = build_lang_decl (VAR_DECL, name, vtable_type);

512      /* vtable names are already mangled; give them their DECL_ASSEMBLER_NAME

513        now to avoid confusion in mangle_decl.  */

514      SET_DECL_ASSEMBLER_NAME (decl, name);

515      DECL_CONTEXT (decl) = class_type;

516      DECL_ARTIFICIAL (decl) = 1;

517      TREE_STATIC (decl) = 1;

518      TREE_READONLY (decl) = 1;

519      DECL_VIRTUAL_P (decl) = 1;

520      DECL_ALIGN (decl) = TARGET_VTABLE_ENTRY_ALIGN;

521      DECL_VTABLE_OR_VTT_P (decl) = 1;

522   

523      /* At one time the vtable info was grabbed 2 words at a time. This

524        fails on sparc unless you have 8-byte alignment. (tiemann) */

525      DECL_ALIGN (decl) = MAX (TYPE_ALIGN (double_type_node),

526                                 DECL_ALIGN (decl));

527   

528      import_export_vtable (decl, class_type, 0);

529   

530      return decl;

531    }

 

528 行, import_export_vtable 为构建的 VARL_DECL 设置了 TREE_PUBLIC DECL_EXTERNAL 。注意到在 build_primary_vtable 614 行, TYPE_BINFO_VIRTUALS 获取作为其参数的类的 binfo BINFO_VIRTUALS

build_primary_vtabl 597 行, get_vtbl_decl_for_binfo 获取对应 binfo vtable VAR_DECL

 

6446   tree

6447   get_vtbl_decl_for_binfo (tree binfo)                                                           in class.c

6448   {

6449     tree decl;

6450  

6451     decl = BINFO_VTABLE (binfo);

6452     if (decl && TREE_CODE (decl) == PLUS_EXPR)

6453     {

6454       my_friendly_assert (TREE_CODE (TREE_OPERAND (decl, 0)) == ADDR_EXPR,

6455                        2000403);

6456       decl = TREE_OPERAND (TREE_OPERAND (decl, 0), 0);

6457     }

6458     if (decl)

6459       my_friendly_assert (TREE_CODE (decl) == VAR_DECL, 20000403);

6460     return decl;

6461   }

 

现在回到 dfs_modify_vtables ,注意 virtuals orig_virtuals virtuals 来自当前类派生树中的 binfo ,而 orig_virtuals 来自基类对应类型中的 binfo 。现在它们是不同的,因为相应的 BINFO_VIRTUALS 在上面已经被拷贝了。

那么对于每个定义在该类中的虚函数,必需的 thunk 及其所携带的调整信息将被在 update_vtable_entry_for_fn 中计算并记录。

 

2071   static void

2072   update_vtable_entry_for_fn (tree t, tree binfo, tree fn, tree* virtuals,            in class.c

2073                           unsigned ix)

2074   {

2075     tree b;

2076     tree overrider;

2077     tree delta;

2078     tree virtual_base;

2079     tree first_defn;

2080     tree overrider_fn, overrider_target;

2081     tree target_fn = DECL_THUNK_P (fn) ? THUNK_TARGET (fn) : fn;

2082     tree over_return, base_return;

2083     bool lost = false;

2084  

2085     /* Find the nearest primary base (possibly binfo itself) which defines

2086       this function; this is the class the caller will convert to when

2087       calling FN through BINFO.  */

2088     for (b = binfo; ; b = get_primary_binfo (b))

2089     {

2090       my_friendly_assert (b, 20021227);

2091       if (look_for_overrides_here (BINFO_TYPE (b), target_fn))

2092         break ;

2093  

2094        /* The nearest definition is from a lost primary.  */

2095       if (BINFO_LOST_PRIMARY_P (b))

2096         lost = true;

2097     }

2098     first_defn = b;

2099  

2100     /* Find the final overrider.  */

2101     overrider = find_final_overrider (TYPE_BINFO (t), b, target_fn);

2102     if (overrider == error_mark_node)

2103     {

2104       error ("no unique final overrider for `%D' in `%T'", target_fn, t);

2105       return ;

2106     }

2107     overrider_target = overrider_fn = TREE_PURPOSE (overrider);

 

因为 dfs_modify_vtables dfs_walk_real 中被用作 postfn ,在派生树中它从底部开始处理基类,即首先是非派生类的基类。这个次序对于虚拟主要基类来说是重要的(但非虚拟主要基类不要求这个次序,因为每个派生类都有自己的基类 binfo 拷贝)。

因此对于类 C dfs_modify_vtables 首先处理 C 中的 A binfo 。在上面 2088 行的 FOR 循环中,对于指定的函数(即,带有 thunk B1::f ),它进入这个指定基类的主要基类链,并选出定义了这个函数的最靠近的主要基类。对于我们例子中的带有 thunk B1::f ,找出的 b B1 ,并且 lost false

当调用 find_final_overrider 时,注意到如果函数正在被处理的是一个 thunk ,需要提取真正的函数,并由下面的 fn 所指向。这里 fn 指向 C 中属于 A B1::f

 

1194   static tree

1195   find_final_overrider (tree derived, tree binfo, tree fn)                                          in class.c

1196   {

1197     find_final_overrider_data ffod;

1198     count_depth_data cd;

1199  

1200     /* Getting this right is a little tricky. This is valid:

1201  

1202        struct S { virtual void f (); };

1203        struct T { virtual void f (); };

1204        struct U : public S, public T { };

1205  

1206       even though calling `f' in `U' is ambiguous. But,

1207  

1208        struct R { virtual void f(); };

1209        struct S : virtual public R { virtual void f (); };

1210        struct T : virtual public R { virtual void f (); };

1211        struct U : public S, public T { };

1212  

1213       is not -- there's no way to decide whether to put `S::f' or

1214       `T::f' in the vtable for `R'. 

1215       

1216       The solution is to look at all paths to BINFO. If we find

1217       different overriders along any two, then there is a problem.  */

1218     if (DECL_THUNK_P (fn))

1219       fn = THUNK_TARGET (fn);

1220  

1221     /* Determine the depth of the hierarchy.  */

1222     cd.depth = 0;

1223     cd.max_depth = 0;

1224     dfs_walk (derived, dfs_depth_post , dfs_depth_q , &cd);

1225  

1226     ffod.fn = fn;

1227     ffod.declaring_base = binfo;

1228     ffod.most_derived_type = BINFO_TYPE (derived);

1229     ffod.candidates = NULL_TREE;

1230     ffod.vpath_list = (tree *) xcalloc (cd.max_depth, sizeof (tree));

1231     ffod.vpath = ffod.vpath_list;

1232  

1233     dfs_walk_real (derived,

1234                 dfs_find_final_overrider ,

1235                  dfs_find_final_overrider_post ,

1236                  dfs_find_final_overrider_q ,

1237                 &ffod);

1238  

1239     free (ffod.vpath_list);

1240  

1241     /* If there was no winner, issue an error message.  */

1242     if (!ffod.candidates || TREE_CHAIN (ffod.candidates))

1243       return error_mark_node;

1244  

1245     return ffod.candidates;

1246   }

 

具有类型 count_depth_data 的变量 cd 用在派生树的遍历过程。其类型定义如下。

 

1856   typedef struct count_depth_data {                                                             in class.c

1857     /* The depth of the current subobject, with "1" as the depth of the

1858       most derived object in the hierarchy.  */

1859     size_t depth;

1860     /* The maximum depth found so far.  */

1861     size_t max_depth;

1862   } count_depth_data ;

 

dfs_walk_real 中,函数 dfs_depth_q 被用作参数 qfn ,它自顶向下执行计算该类的派生层数( find_final_overrider 的参数 derived 在这里,是当前类,即 C )。

 

1886   static tree

1887   dfs_depth_q (tree derived, int i, void *data)                                                in class.c

1888   {

1889     count_depth_data *cd = (count_depth_data *) data;

1890     cd->depth++;

1891     return BINFO_BASETYPE (derived, i);

1892   }

 

dfs_depth_post dfs_walk_real 中作为参数 postfn ,它自底向上执行,趋向顶端派生程度最高的类。它在自顶向下访问树的过程中所作的记录里,找出最大派生层数。

 

1886   static tree

1887   dfs_depth_post (tree binfo ATTRIBUTE_UNUSED, void *data)                   in class.c

1888   {

1889     count_depth_data *cd = (count_depth_data *) data;

1890     if (cd->depth > cd->max_depth)

1891       cd->max_depth = cd->depth;

1892     cd->depth--;

1893     return NULL_TREE;

1894   }

 

看到在 1230 行, cd 的这个 max_depth 域被用作中 vpath_list 的维度, ffod 的类型是下面的 find_final_overrider_data

 

1893   typedef struct find_final_overrider_data_s {                                                in class.c

1894     /* The function for which we are trying to find a final overrider.  */

1895     tree fn;

1896     /* The base class in which the function was declared.  */

1897     tree declaring_base;

1898     /* The most derived class in the hierarchy.  */

1899     tree most_derived_type;

1900     /* The candidate overriders.  */

1901     tree candidates;

1902     /* Each entry in this array is the next-most-derived class for a

1903       virtual base class along the current path.  */

1904     tree *vpath_list;

1905     /* A pointer one past the top of the VPATH_LIST.  */

1906     tree *vpath;

1907   } find_final_overrider_data ;

 

在内层的遍历中, dfs_find_final_overrider 被用作 dfs_walk_real 中的 prefn ,它将以前序次序执行,并且如果它返回非 0 值,将中止遍历。注意到参数 binfo find_final_overrider 中的变量 derived ,并且作为 data 传入的 ffod declaring_base 域最初是被 dfs_modify_vtables 当前以后序访问的基类的 binfo ,而 most_derived_type 域则指向派生程度最高的类(当前类)。

 

1955   static tree

1956   dfs_find_final_overrider (tree binfo, void* data)                                         in class.c

1957   {

1958     find_final_overrider_data *ffod = (find_final_overrider_data *) data;

1959  

1960     if (binfo == ffod->declaring_base)

1961       dfs_find_final_overrider_1 (binfo, ffod->vpath, ffod);

1962  

1963     return NULL_TREE;

1964   }

 

注意到在内层遍历中, dfs_find_final_overrider 是以前序执行的,而 dfs_modify_vtables ,在外层遍历中,是以后序执行,并且 binfo 是正在被内层遍历访问的基类,而 data 记录了在运行内层遍历那一点上外层遍历的快照。因此当内层前序遍历运行到它被触发的那一点时,执行 dfs_find_final_overrider_1

不过在 1960 行的条件最终满足前, dfs_find_final_overrider_q 为每个遭遇的基类所执行。

 

1966   static tree

1967   dfs_find_final_overrider_q (tree derived, int ix, void *data)                          in class.c

1968   {

1969     tree binfo = BINFO_BASETYPE (derived, ix);

1970     find_final_overrider_data *ffod = (find_final_overrider_data *) data;

1971  

1972     if (TREE_VIA_VIRTUAL (binfo))

1973       *ffod->vpath++ = derived;

1974    

1975     return binfo;

1976   }

 

正如我们所期望的,被分析的虚拟基类被按照它们出现的次序来记录在 ffod vpath 中。因此当离开这个基类时,它应该被 dfs_find_final_overrider_post 移除。

 

1978   static tree

1979   dfs_find_final_overrider_post (tree binfo, void *data)                                  in class.c

1980   {

1981     find_final_overrider_data *ffod = (find_final_overrider_data *) data;

1982  

1983     if (TREE_VIA_VIRTUAL (binfo))

1984       ffod->vpath--;

1985    

1986     return NULL_TREE;

1987   }

 

dfs_find_final_overrider_1 中,参数 binfo 是在这次内层遍历中正在访问的基类,而 ffod declaring_base 是在外层遍历中正在访问的 binfo ,在这个 binfo 中我们正在确定由 ffod fn 所指定的虚函数的正确的重载版本。而现在 binfo declaring_base 是相同的。

 

1905   static bool

1906   dfs_find_final_overrider_1 (tree binfo,                                                       in class.c

1907                           tree *vpath,

1908                           find_final_overrider_data *ffod)

1909   {

1910     tree method;

1911         

1912     /* If BINFO is not the most derived type, try a more derived class.

1913       A definition there will overrider a definition here.  */

1914     if (!same_type_p (BINFO_TYPE (binfo), ffod->most_derived_type))

1915     {

1916       tree derived;

1917  

1918       if (TREE_VIA_VIRTUAL (binfo))

1919         derived = *--vpath;

1920       else

1921         derived = BINFO_INHERITANCE_CHAIN (binfo);

1922       if (dfs_find_final_overrider_1 (derived, vpath, ffod))

1923         return true;

1924     }

1925  

1926     method = look_for_overrides_here (BINFO_TYPE (binfo), ffod->fn);

1927     if (method)

1928     {

1929       tree *candidate = &ffod->candidates;

1930        

1931       /* Remove any candidates overridden by this new function.  */

1932       while (*candidate)

1933       {

1934          /* If *CANDIDATE overrides METHOD, then METHOD

1935            cannot override anything else on the list.  */

1936          if (base_derived_from (TREE_VALUE (*candidate), binfo))

1937            return true;

1938          /* If METHOD overrides *CANDIDATE, remove *CANDIDATE.  */

1939          if (base_derived_from (binfo, TREE_VALUE (*candidate)))

1940            *candidate = TREE_CHAIN (*candidate);

1941          else

1942            candidate = &TREE_CHAIN (*candidate);

1943       }

1944        

1945        /* Add the new function.  */

1946       ffod->candidates = tree_cons (method, binfo, ffod->candidates);

1947       return true;

1948     }

1949  

1950     return false;

1951   }

 

注意上面 1922 行的递归调用,该函数给了派生程度最高的类比基类更高的优先级。因此在 base_derived_from 的帮助下,它能找出重载了这个函数的派生程度最高的基类。 base_derived_from 确定了它从那里派生来的。

 

1836   static bool

1837   base_derived_from (tree derived, tree base)                                               in class.c

1838   {

1839     tree probe;

1840  

1841     for (probe = base; probe; probe = BINFO_INHERITANCE_CHAIN (probe))

1842     {

1843       if (probe == derived)

1844         return true;

1845       else if (TREE_VIA_VIRTUAL (probe))

1846         /* If we meet a virtual base, we can't follow the inheritance

1847            any more. See if the complete type of DERIVED contains

1848            such a virtual base.  */

1849         return purpose_member (BINFO_TYPE (probe),

1850                            CLASSTYPE_VBASECLASSES (BINFO_TYPE (derived)))

1851                              != NULL_TREE;

1852     }

1853     return false;

1854   }

 

这个来自派生程度最高的基类中的虚函数被赋予下面的 overrider_target 。对于我们的例子 A 中带有 thunk B::f overrider_target 获得的是 C::f 。现在对于这个例子,我们有, target_fn B* B::f() overrider_target C* C::f() 。记住这个 A 中的 B::f 具有一个结果调整的 thunk ,其中 virutal-offset 是: B1 中的 A fix-offset 是: 0 A -> B1 )。

看到如果该 thunk 包含了 virtual-offset ,它应该来自以 2140 行的 over_return 为根节点的派生树中。因此我们可以得到正确的虚拟基类偏移( virtual offset )。

 

update_vtable_entry_for_fn (continue)

 

2109     /* Check for adjusting covariant return types.  */

2110     over_return = TREE_TYPE (TREE_TYPE (overrider_target));

2111     base_return = TREE_TYPE (TREE_TYPE (target_fn));

2112    

2113     if (POINTER_TYPE_P (over_return)

2114        && TREE_CODE (over_return) == TREE_CODE (base_return)

2115        && CLASS_TYPE_P (TREE_TYPE (over_return))

2116        && CLASS_TYPE_P (TREE_TYPE (base_return)))

2117     {

2118       /* If FN is a covariant thunk, we must figure out the adjustment

2119          to the final base FN was converting to. As OVERRIDER_TARGET might

2120         also be converting to the return type of FN, we have to

2121         combine the two conversions here.  */

2122       tree fixed_offset, virtual_offset;

2123  

2124       over_return = TREE_TYPE (over_return);

2125       base_return = TREE_TYPE (base_return);

2126        

2127       if (DECL_THUNK_P (fn))

2128       {

2129          my_friendly_assert (DECL_RESULT_THUNK_P (fn), 20031211);

2130          fixed_offset = ssize_int (THUNK_FIXED_OFFSET (fn));

2131          virtual_offset = THUNK_VIRTUAL_OFFSET (fn);

2132       }

2133       else

2134         fixed_offset = virtual_offset = NULL_TREE;

2135  

2136       if (virtual_offset)

2137         /* Find the equivalent binfo within the return type of the

2138            overriding function. We will want the vbase offset from

2139            there.  */

2140         virtual_offset =

2141             TREE_VALUE (purpose_member

2142                            (BINFO_TYPE (virtual_offset),

2143                            CLASSTYPE_VBASECLASSES (over_return)));

2144       else if (!same_type_ignoring_top_level_qualifiers_p

2145                   (over_return, base_return))

2146       {

2147          /* There was no existing virtual thunk (which takes

2148            precedence). So find the binfo of the base function's

2149            return type within the overriding function's return type.

2150            We cannot call lookup base here, because we're inside a

2151            dfs_walk, and will therefore clobber the BINFO_MARKED

2152            flags. Fortunately we know the covariancy is valid (it

2153            has already been checked), so we can just iterate along

2154            the binfos, which have been chained in inheritance graph

2155            order. Of course it is lame that we have to repeat the

2156            search here anyway -- we should really be caching pieces

2157            of the vtable and avoiding this repeated work.  */

2158          tree thunk_binfo, base_binfo;

2159  

2160          /* Find the base binfo within the overriding function's

2161            return type. We will always find a thunk_binfo, except

2162            when the covariancy is invalid (which we will have

2163            already diagnosed).  */

2164          for (base_binfo = TYPE_BINFO (base_return),

2165              thunk_binfo = TYPE_BINFO (over_return);

2166              thunk_binfo;

2167              thunk_binfo = TREE_CHAIN (thunk_binfo))

2168            if (same_type_p (BINFO_TYPE (thunk_binfo),

2169                           BINFO_TYPE (base_binfo)))

2170              break ;

2171         

2172           /* See if virtual inheritance is involved.  */

2173          for (virtual_offset = thunk_binfo;

2174              virtual_offset;

2175              virtual_offset = BINFO_INHERITANCE_CHAIN (virtual_offset))

2176            if (TREE_VIA_VIRTUAL (virtual_offset))

2177              break ;

2178         

2179          if (virtual_offset

2180             || (thunk_binfo && !BINFO_OFFSET_ZEROP (thunk_binfo)))

2181          {

2182            tree offset = convert (ssizetype, BINFO_OFFSET (thunk_binfo));

2183  

2184            if (virtual_offset)

2185           {

2186               /* We convert via virtual base. Adjust the fixed

2187                offset to be from there.  */

2188              offset = size_diffop

2189                        (offset, convert

2190                                  (ssizetype, BINFO_OFFSET (virtual_offset)));

2191           }

2192             if (fixed_offset)

2193             /* There was an existing fixed offset, this must be

2194                  from the base just converted to, and the base the

2195                  FN was thunking to.  */

2196             fixed_offset = size_binop (PLUS_EXPR, fixed_offset, offset);

2197            else

2198             fixed_offset = offset;

2199            }

2200       }

2201        

2202       if (fixed_offset || virtual_offset)

2203         /* Replace the overriding function with a covariant thunk. We

2204             will emit the overriding function in its own slot as

2205            well.  */

2206         overrider_fn = make_thunk (overrider_target, /*this_adjusting=*/ 0,

2207                                 fixed_offset, virtual_offset);

2208     }

2209     else

2210       my_friendly_assert (!DECL_THUNK_P (fn), 20021231);

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值