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

    技术2022-06-27  56

    当完成 B1 的处理时, build_vcall_and_vbase_vtbl_entries 返回到处理类 C 的最顶层的调用中。这一次, build_vbase_offset_vtbl_entries 不做任何事,因为 A 的部分已经被处理,设置了 BINFO_VTABLE_PATH_MARKED 标记。而在 build_vcall_offset_vtbl_entries 中,对于类 C vid->generate_vcall_entries 被设置为 false ,而 vid->vbase 则设置为 C binfo 。涉及的调用栈如下。

    build_vcall_and_vbase_vtbl_entries:       对应 C

            build_vcall_offset_vtbl_entries:     对应 C

                   add_vcall_offset_vtbl_entries_r:    对应 C

                          add_vcall_offset_vtbl_entries_r:   对应 B1

                                 add_vcall_offset_vtbl_entries_r:    对应 A

                          add_vcall_offset_vtbl_entries_1:    对应 B1

                                 add_vcall_offset:    对应 B1

                          add_vcall_offset_vtbl_entries_1:    对应 C

                                 add_vcall_offset:    对应 C

                                 add_vcall_offset_vtbl_entries_r: 对应 B2

                                        add_vcall_offset_vtbl_entries_r: 对应 A

                                 add_vcall_offset_vtbl_entries_1: 对应 B2

                                        add_vcall_offset: 对应 B2

    在上面的调用栈中, add_vcall_offset_vtbl_entries_r 首先递归,直到 C A 。因为满足 7680 行条件,它不做任何事。在接下来的 add_vcall_offset 里, vid->fns 里现在缓存着前面处理过的虚函数,因此 7805 行的 same_signature_p 为所有 B1 的虚函数返回 true ,从 7810 行退出该函数。在从处理 B1 add_vcall_offset_vtbl_entries_r 返回后,为 C 调用 add_vcall_offset_vtbl_entries_1 。同样,在 add_vcall_offset 中, same_signature_p 为所有 C 的虚函数返回 true 。接着在 add_vcall_offset_vtbl_entries_r 7698 行,为 B2 (非主要基类)调用 add_vcall_offset_vtbl_entries_r ,它原来的主要基类 A 在递归时被 7680 行的条件滤除,同样的在 add_vcall_offset 中, same_signature_p 为所有 B2 的虚函数返回 true

    当从为 C 调用的 build_vcall_and_vbase_vtbl_entries 退出时,我们将得到下面的 vtable 初始值及 CLASSTYPE_VCALL_INDICES

    看到上图中 CLASSTYPE_VCALL_INDICES 的链表中, A::f 节点的 value 域是 -3 ,与 last_init 链所给出的 A::f 一致。

    回到还在处理 C build_vtbl_initializer 里。

     

    build_vtbl_initializer (continue)

     

    7378     /* If the target requires padding between data entries, add that now.  */

    7379     if (TARGET_VTABLE_DATA_ENTRY_DISTANCE > 1)

    7380     {

              …

    7395     }

    7396  

    7397     if (non_fn_entries_p)

    7398       *non_fn_entries_p = list_length (vid.inits);

    7399  

    7400     /* Go through all the ordinary virtual functions, building up

    7401       initializers.  */

    7402     vfun_inits = NULL_TREE;

    7403     for (v = BINFO_VIRTUALS (orig_binfo); v; v = TREE_CHAIN (v))

    7404     {

    7405       tree delta;

    7406       tree vcall_index;

    7407       tree fn, fn_original;

    7408       tree init = NULL_TREE;

    7409        

    7410       fn = BV_FN (v);

    7411       fn_original = fn;

    7412       if (DECL_THUNK_P (fn))

    7413       {

    7414         if (!DECL_NAME (fn))

    7415           finish_thunk (fn);

    7416         if (THUNK_ALIAS (fn))

    7417         {

    7418           fn = THUNK_ALIAS (fn);

    7419           BV_FN (v) = fn;

    7420         }

    7421          fn_original = THUNK_TARGET (fn);

    7422       }

    7423        

    7424       /* If the only definition of this function signature along our

    7425         primary base chain is from a lost primary, this vtable slot will

    7426         never be used, so just zero it out. This is important to avoid

    7427         requiring extra thunks which cannot be generated with the function.

    7428  

    7429         We first check this in update_vtable_entry_for_fn, so we handle

    7430         restored primary bases properly; we also need to do it here so we

    7431         zero out unused slots in ctor vtables, rather than filling themff

    7432         with erroneous values (though harmless, apart from relocation

    7433         costs).  */

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

    7435       {

    7436         /* We found a defn before a lost primary; go ahead as normal.  */

    7437         if (look_for_overrides_here (BINFO_TYPE (b), fn_original))

    7438           break ;

    7439  

    7440          /* The nearest definition is from a lost primary; clear the

    7441           slot.  */

    7442         if (BINFO_LOST_PRIMARY_P (b))

    7443         {

    7444           init = size_zero_node;

    7445           break ;

    7446         }

    7447       }

    7448  

    7449       if (! init)

    7450       {

    7451         /* Pull the offset for `this', and the function to call, out of

    7452           the list.  */

    7453         delta = BV_DELTA (v);

    7454          vcall_index = BV_VCALL_INDEX (v);

    7455  

    7456         my_friendly_assert (TREE_CODE (delta) == INTEGER_CST, 19990727);

    7457         my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 19990727);

    7458  

    7459         /* You can't call an abstract virtual function; it's abstract.

    7460           So, we replace these functions with __pure_virtual.  */

    7461         if (DECL_PURE_VIRTUAL_P (fn_original))

    7462           fn = abort_fndecl;

    7463         else if (!integer_zerop (delta) || vcall_index)

    7464         {

    7465           fn = make_thunk (fn, /*this_adjusting=*/ 1, delta, vcall_index);

    7466           if (!DECL_NAME (fn))

    7467             finish_thunk (fn);

    7468         }

    7469         /* Take the address of the function, considering it to be of an

    7470           appropriate generic type.  */

    7471          init = build1 (ADDR_EXPR, vfunc_ptr_type_node , fn);

    7472         /* The address of a function can't change.  */

    7473         TREE_CONSTANT (init) = 1;

    7474       }

    7475  

    7476       /* And add it to the chain of initializers.  */

    7477       if (TARGET_VTABLE_USES_DESCRIPTORS)

    7478       {

                …

    7493       }

    7494       else

    7495         vfun_inits = tree_cons (NULL_TREE, init, vfun_inits);

    7496     }

    7497  

    7498     /* The initializers for virtual functions were built up in reverse

    7499       order; straighten them out now.  */

    7450     vfun_inits = nreverse (vfun_inits);

    7451    

    7452     /* The negative offset initializers are also in reverse order.  */

    7453     vid.inits = nreverse (vid.inits);

    7454  

    7455     /* Chain the two together.  */

    7456     return chainon (vid.inits, vfun_inits);

    7457   }

     

    上面的 orig_binfo 来自当前类中,其 BINFO_VIRTUALS update_vtable_entry_for_fn 中得到处理(见前一节)。 BINFO_VIRTUALS 中的虚函数可以是 thunk ,这些 thunk 是由 update_vtable_entry_for_fn 构建的,它们只是结果指针调整 thunk 。而这里构建的是 this 指针调整 thunk ,同时该 thunk 所需要的 BV_DELTA BV_VCALL_INDEX (来自虚拟基类的 CLASSTYPE_VCALL_INDICES ,前面看到 C 也准备了这个,为未来做虚拟基类做打算)也是在 update_vtable_entry_for_fn 中准备的。

    现在所有的 thunk 还是匿名的。这在前端中表示该 thunk 还未完成。

     

    194    void

    195    finish_thunk (tree thunk)                                                                          in method.c

    196    {

    197      tree function, name;

    198      tree fixed_offset = ssize_int (THUNK_FIXED_OFFSET (thunk));

    199      tree virtual_offset = THUNK_VIRTUAL_OFFSET (thunk);

    200   

    201      my_friendly_assert (!DECL_NAME (thunk) && DECL_THUNK_P (thunk), 20021127);

    202      if (virtual_offset && DECL_RESULT_THUNK_P (thunk))

    203        virtual_offset = BINFO_VPTR_FIELD (virtual_offset);

    204      function = THUNK_TARGET (thunk);

    205      name = mangle_thunk (function, DECL_THIS_THUNK_P (thunk),

    206                          fixed_offset, virtual_offset);

    207   

    208      /* We can end up with declarations of (logically) different

    209        covariant thunks, that do identical adjustments. The two thunks

    210        will be adjusting between within different hierarchies, which

    211         happen to have the same layout. We must nullify one of them to

    212        refer to the other.  */

    213      if (DECL_RESULT_THUNK_P (thunk))

    214      {

    215        tree cov_probe;

    216   

    217        for (cov_probe = DECL_THUNKS (function);

    218             cov_probe; cov_probe = TREE_CHAIN (cov_probe))

    219          if (DECL_NAME (cov_probe) == name)

    220          {

    221             my_friendly_assert (!DECL_THUNKS (thunk), 20031023);

    222             THUNK_ALIAS (thunk) = (THUNK_ALIAS (cov_probe)

    223                                     ? THUNK_ALIAS (cov_probe) : cov_probe);

    224             break ;

    225           }

    226      }

    227     

    228      DECL_NAME (thunk) = name;

    229      SET_DECL_ASSEMBLER_NAME (thunk, name);

    230    }

     

    THUNK_VIRTUAL_OFFSET ,对于 this 指针调整 thunk ,保存了 vtable 的偏移,在 vtable 的该位置保存的是 vcall 偏移;而对于结果指针调整 thunk ,则是相关的虚拟基类的 binfo 。而 203 行的 BINFO_VPTR_FIELD 也是 vtable 的偏移,在那里可以找到这个虚拟基类的偏移量。因此对于结果指针调整 thunk ,需要 203 行的处理才能得到虚拟基类的偏移量。在 205 行, mangle_thunk 返回该 thunk 的修饰名(本节开头给出了 thunk 修饰名的例子)。在设置了 thunk 的名字后,它可以被视作已完成。因为 thunk 的名字是根据其作用来命名的,有可能会已经有了同名的 thunk ,这个时候把后面构建的 thunk 视为前一个的别名( alias ),它们共享同一个 thunk 函数。

     

    dfs_accumulate_vtbl_inits (continue)

     

    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   }

     

    回到 dfs_accumulate_vtbl_inits ,注意我们还在处理类 C 。上面的 l finish_vtbls 中的 list ,在其节点的 TREE_PURPOSE 域是 TYPE_BINFO_VTABLE (保存在类型的 binfo 中的 vtable ,它是由 build_primary_vtable 构建的 VAR_DECL )。而一开始, l 中节点的 TREE_VALUE 域是 NULL (但是在 accumulate_vtbl_inits 7185 行,它把 dfs_accumulate_vtbl_inits 返回的链表串接起来)。注意到 non_fn_entrie 记录了负索引的个数。这样就能知道该类型 vtable 的可见项从那里开始。

    当返回到 accumulate_vtbl_inits 时,在加长 finish_vtt 中的 list 之后,我们得到下图(记得在 create_vtable_ptr 中,每个虚函数都有一个 delta 0 的额外的节点)。

    接着,在 accumulate_vtbl_inits 7195 行的 FOR 循环中开始处理 C 中的非虚拟基类。 B1 没有处理,因为在其 binfo 中标记 BINFO_NEW_VTABLE_MARKED 没有设置(参见 7273 行的 dfs_accumulate_vtbl_inits )。而对于 C 中的 B2 ,它准备了次要 vtable ,因此顺利通过 7273 行的测试。此时, ctor_vtbl_p false binfo 是类 B2 binfo orig_binfo C B2 binfo rtti_binfo C binfo ,它经历了与上面 C 类似的处理。然后当回到 finish_vtbls 时,在 C 中的 A 6780 行的 accumulate_vtbl_inits 处理,其中 ctor_vtbl_p 仍然是 false 。但这个 A 没有设置标记 BINFO_NEW_VTABLE_MARKED ,直接从 dfs_accumulate_vtbl_inits 返回。

    那么在 6784 行调用 initialize_vtable 之前, list 就如下图所示。

    点此打开

    117 vtable 的初始值

    上图中没有出现 B1 A vtable 部分,因为它们与 C 公用同一部分的 vtable

    在下面的函数中,现在参数 inits 是由上图 list value 域所指向的链表。这个链表保存了用于类 C vtable 的初始值。注意到在 dfs_accumulate_vtbl_inits 7297 行的 vtbl 指向指定类 vtable 的开始点,它是 PLUS_EXPR ,对于 C vtbl+4 ,对于基类 B2 vtbl+8

     

    6789   static void

    6790   initialize_vtable (tree binfo, tree inits)                                                         in class.c

    6791   {

    6792     tree decl;

    6793  

    6794     layout_vtable_decl (binfo, list_length (inits));

    6795     decl = get_vtbl_decl_for_binfo (binfo);

    6796     initialize_array (decl, inits);

    6797     dump_vtable (BINFO_TYPE (binfo), binfo, decl);

    6798   }

     

    一开始在 build_vtable 中, vtable 被构建为具有类型 vtbl_type_node ,这个类型是 vtable_entry_type 类型的维度为 0 的数组。现在该数组的大小已经确定了,我们可以通过 layout_vtable_decl 来构建确切的类型。

     

    1778   static void

    1779   layout_vtable_decl (tree binfo, int n)                                                         in class.c

    1780   {

    1781     tree atype;

    1782     tree vtable;

    1783  

    1784     atype = build_cplus_array_type (vtable_entry_type ,

    1785                                build_index_type (size_int (n - 1)));

    1786     layout_type (atype);

    1787  

    1788     /* We may have to grow the vtable.  */

    1789     vtable = get_vtbl_decl_for_binfo (binfo);

    1790     if (!same_type_p (TREE_TYPE (vtable), atype))

    1791     {

    1792       TREE_TYPE (vtable) = atype;

    1793       DECL_SIZE (vtable) = DECL_SIZE_UNIT (vtable) = NULL_TREE;

    1794       layout_decl (vtable, 0);

    1795     }

    1796   }

     

    因此在 6795 行,所获得的 vtable VAR_DECL 已经有了正确定义的类型。并且它被传递作下面函数的参数 decl

     

    6803   static void

    6804   initialize_array (tree decl, tree inits)                                                            in class.c

    6805   {

    6806     tree context;

    6807  

    6808     context = DECL_CONTEXT (decl);

    6809     DECL_CONTEXT (decl) = NULL_TREE;

    6810     DECL_INITIAL (decl) = build_constructor (NULL_TREE, inits);

    6811     TREE_HAS_CONSTRUCTOR (DECL_INITIAL (decl)) = 1;

    6812     cp_finish_decl (decl, DECL_INITIAL (decl), NULL_TREE, 0);

    6813     DECL_CONTEXT (decl) = context;

    6814   }

     

    看到为这个 VAR_DECL 的初始化构建了 CONSTRUCTOR 节点。注意这个节点有空的 type 域(它作为“未知”来处理 ).

     

    444    tree

    445    build_constructor (tree type, tree vals)                                                             in tree.c

    446    {

    447      tree c = make_node (CONSTRUCTOR);

    448      TREE_TYPE (c) = type;

    449      CONSTRUCTOR_ELTS (c) = vals;

    450   

    451      /* ??? May not be necessary. Mirrors what build does.  */

    452      if (vals)

    453      {

    454        TREE_SIDE_EFFECTS (c) = TREE_SIDE_EFFECTS (vals);

    455        TREE_READONLY (c) = TREE_READONLY (vals);

    456        TREE_CONSTANT (c) = TREE_CONSTANT (vals);

    457      }

    458      else

    459        TREE_CONSTANT (c) = 0;  /* safe side */

    460   

    461      return c;

    462    }

     

    作为一个 VAR_DECL ,其处理的收尾工作由 cp_finish_decl 来完成。注意到我们现在仍然在处理“ SmallObject ”模板具现的另一个 cp_finish_decl 里。

     

    4768   void

    4769   cp_finish_decl (tree decl, tree init, tree asmspec_tree, int flags)                           in decl.c

    4770   {

    4771     tree type;

    4772     tree ttype = NULL_TREE;

    4773     tree cleanup;

    4774     const char *asmspec = NULL;

    4775     int was_readonly = 0;

    4776     bool var_definition_p = false;

    4777  

    4778     if (decl == error_mark_node)

    4779       return ;

    4780     else if (! decl)

    4781     {

    4782       if (init)

    4783         error ("assignment (not initialization) in declaration");

    4784       return ;

    4785     }

    4786  

    4787     my_friendly_assert (TREE_CODE (decl) != RESULT_DECL, 20030619);

    4788  

    4789     /* Assume no cleanup is required.  */

    4790     cleanup = NULL_TREE;

    4791  

    4792     /* If a name was specified, get the string.  */

    4793     if (global_scope_p (current_binding_level ))

    4794       asmspec_tree = maybe_apply_renaming_pragma (decl, asmspec_tree);

    4795     if (asmspec_tree)

    4796       asmspec = TREE_STRING_POINTER (asmspec_tree);

    4797  

    4798     if (init && TREE_CODE (init) == NAMESPACE_DECL)

    4799     {

    4800       error ("cannot initialize `%D' to namespace `%D'",

    4802             decl, init);

    4803       init = NULL_TREE;

    4804     }

    4805  

    4806     if (current_class_type

    4807        && CP_DECL_CONTEXT (decl) == current_class_type

    4808        && TYPE_BEING_DEFINED (current_class_type )

    4809        && (DECL_INITIAL (decl) || init))

    4810       DECL_INITIALIZED_IN_CLASS_P (decl) = 1;

    4811  

    4812     if (TREE_CODE (decl) == VAR_DECL

    4813        && DECL_CONTEXT (decl)

    4814        && TREE_CODE (DECL_CONTEXT (decl)) == NAMESPACE_DECL

    4815        && DECL_CONTEXT (decl) != current_namespace

    4816        && init)

    4817     {

    4818        /* Leave the namespace of the object.  */

    4819       pop_decl_namespace ();

    4820     }

    4821  

    4822     type = TREE_TYPE (decl);

    4823  

    4824     if (type == error_mark_node)

    4825       goto finish_end0;

    4826  

    4827     if (TYPE_HAS_MUTABLE_P (type))

    4828       TREE_READONLY (decl) = 0;

    4829  

    4830     if (processing_template_decl )

    4831     {

              …

    4842     }

    4843  

    4844     /* Parameters are handled by store_parm_decls, not cp_finish_decl.  */

    4845     my_friendly_assert (TREE_CODE (decl) != PARM_DECL, 19990828);

    4846  

    4847     /* Take care of TYPE_DECLs up front.  */

    4848     if (TREE_CODE (decl) == TYPE_DECL)

    4849     {

              …

    4868     }

    4869  

    4870     if (TREE_CODE (decl) != FUNCTION_DECL)

    4871       ttype = target_type (type);

    4872  

    4873    

    4874     /* Currently, GNU C++ puts constants in text space, making them

    4875       impossible to initialize. In the future, one would hope for

    4876       an operating system which understood the difference between

    4877       initialization and the running of a program.  */

    4878     if (! DECL_EXTERNAL (decl) && TREE_READONLY (decl))

    4879     {

    4880       was_readonly = 1;

    4881       if (TYPE_NEEDS_CONSTRUCTING (type)

    4882           || TREE_CODE (type) == REFERENCE_TYPE)

    4883         TREE_READONLY (decl) = 0;

    4884     }

    4885  

    4886     if (TREE_CODE (decl) == VAR_DECL)

    4887     {

    4888       /* Only PODs can have thread-local storage. Other types may require

    4889          various kinds of non-trivial initialization.  */

    4890       if (DECL_THREAD_LOCAL (decl) && !pod_type_p (TREE_TYPE (decl)))

    4891         error ("`%D' cannot be thread-local because it has non-POD type `%T'",

    4892               decl, TREE_TYPE (decl));

    4893       /* Convert the initializer to the type of DECL, if we have not

    4894          already initialized DECL.  */

    4895       if (!DECL_INITIALIZED_P (decl)

    4896           /* If !DECL_EXTERNAL then DECL is being defined. In the

    4897               case of a static data member initialized inside the

    4898               class-specifier, there can be an initializer even if DECL

    4899               is *not* defined.  */

    4900           && (!DECL_EXTERNAL (decl) || init))

    4901       {

    4902          init = check_initializer (decl, init, flags, &cleanup);

    4903           /* Thread-local storage cannot be dynamically initialized.  */

    4904          if (DECL_THREAD_LOCAL (decl) && init)

    4905          {

    4906            error ("`%D' is thread-local and so cannot be dynamically "

    4907                 "initialized", decl);

    4908            init = NULL_TREE;

    4909          }

    4910          if (DECL_EXTERNAL (decl) && init)

    4911          {

    4912            /* The static data member cannot be initialized by a

    4913              non-constant when being declared.  */

    4914            error ("`%D' cannot be initialized by a non-constant expression"

    4915                 " when being declared", decl);

    4916            DECL_INITIALIZED_IN_CLASS_P (decl) = 0;

    4917            init = NULL_TREE;

    4918          }

    4919         

    4920          /* Handle:

    4921            

    4922            [dcl.init]

    4923            

    4924            The memory occupied by any object of static storage

    4925            duration is zero-initialized at program startup before

    4926            any other initialization takes place.

    4927            

    4928            We cannot create an appropriate initializer until after

    4929            the type of DECL is finalized. If DECL_INITIAL is set,

    4930            then the DECL is statically initialized, and any

    4931            necessary zero-initialization has already been performed.  */

    4932           if (TREE_STATIC (decl) && !DECL_INITIAL (decl))

    4933            DECL_INITIAL (decl) = build_zero_init (TREE_TYPE (decl),

    4934                                              /*nelts=*/ NULL_TREE,

    4935                                              /*static_storage_p=*/ true);

    4936           /* Remember that the initialization for this variable has

    4937            taken place.  */

    4938          DECL_INITIALIZED_P (decl) = 1;

    4939          /* This declaration is the definition of this variable,

    4940            unless we are initializing a static data member within

    4941            the class specifier.  */

    4942          if (!DECL_EXTERNAL (decl))

    4943            var_definition_p = true;

    4944       }

              …

    4951     }

     

    在进入该函数之前 我们清除了 decl DELC_CONTEXT 4794 maybe_apply_renaming_pragma 出于兼容系统头文件的目的,仅用于 Solaris Tru64 上的 UNIX 系统。


    最新回复(0)