Studying note of GCC-3.4.6 source (141 - cont 1)

    技术2022-06-27  47

    When finishing handling of B1, build_vcall_and_vbase_vtbl_entries returns to the invocation of handling class C. This time build_vbase_offset_vtbl_entries does nothing, as base A has been processed with BINFO_VTABLE_PATH_MARKED set. And in build_vcall_offset_vtbl_entries , vid->generate_vcall_entries is set in false for class C, and vid->vbase is set to binfo of C. Below call stack would be involved.

    build_vcall_and_vbase_vtbl_entries:       for C

            build_vcall_offset_vtbl_entries:     for C

                   add_vcall_offset_vtbl_entries_r:    for C

                          add_vcall_offset_vtbl_entries_r:   for B1

                                 add_vcall_offset_vtbl_entries_r:    for A

                          add_vcall_offset_vtbl_entries_1:    for B1

                                 add_vcall_offset:    for B1

                          add_vcall_offset_vtbl_entries_1:    for C

                                 add_vcall_offset:    for C

                                 add_vcall_offset_vtbl_entries_r: for B2

                                        add_vcall_offset_vtbl_entries_r: for A

                                 add_vcall_offset_vtbl_entries_1: for B2

                                        add_vcall_offset: for B2

    In above call stack, add_vcall_offset_vtbl_entries_r first recurses for C’s A, but it does nothing as condition at line 7680 satisified. In following add_vcall_offset , vid->fns now holds virtual functions seen above, so same_signature_p at line 7805 returns true for B1’s virtual, and exits the function at line 7810. After returning from add_vcall_offset_vtbl_entries_r handling B1, invoking add_vcall_offset_vtbl_entries_1 for C. Similiarly, same_signature_p returns true for C’s virtual. Then add_vcall_offset_vtbl_entries_r at line 7698 is recursed for B2 (the non-primary base), it’s original primary base A is filtered out by conidtion at line 7680, also in add_vcall_offset , same_signature_p returns true for B2’s virtual.

    When exitting from build_vcall_and_vbase_vtbl_entries for C, we will get following vtable initializers and CLASSTYPE_VCALL_INDICES.

    In above figure, in the chain of CLASSTYPE_VCALL_INDICES, value field of node A::f is -3; it coordinate with A::f given in chain of last_init.

    Back build_vtbl_initializer , it is still handling C.

     

    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   }

     

    Above orig_binfo comes from current class, whose BINFO_VIRTUALS has been process by update_vtable_entry_for_fn (see previous section). Virtuals in BINFO_VIRTUALS can be a thunk, which is constructed in update_vtable_entry_for_fn , and only of result-adjustmnet. Here it is constructing this-adjustment thunk, and information BV_DELTA, BV_VCALL_INDEX (from CLASSTYPE_VCALL_INDICES of the virtual base. Above can see C also prepared it for future being virtual base) is also collected by update_vtable_entry_for_fn .

    Now all thunks are still anonymous. In the front-end, that indicates the thunk is incomplete.

     

    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, for this-adjusting thunk, it is the number of bytes to be added to the vtable to find the vcall offset; for a result adjusting thunk, it is the binfo of the relevant virtual base. BINFO_VPTR_FIELD at line 203 is an INTEGER_CST giving an offset into the vtable where the offset to the virtual base can be found. So for result adjusting thunk, needs treatment at line 203 to get the offset of the virtual base. At line 205, mangle_thunk returns the mangled name for the thunk (at section beginning, we have seen examples of thunk’s mangled name). After setting the name with the thunk, it can be regarded as finished. As thunk’s name is constructed by its action, it’s possible there exists thunk of same name, at which treats the thunk built later as the alias of the former one, they share the same thunk function.

     

    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   }

     

    Back to dfs_accumulate_vtbl_inits , note that we are still handling class C. above l is list in finish_vtbls , in its TREE_PURPOSE is the TYPE_BINFO_VTABLE (vtable saved in the binfo of the type, which is VAR_DECL generated by build_primary_vtable ). And originally, TREE_VALUE of l is NULL (but at line 7185 in accumulate_vtbl_inits , it chains l with the list returned by dfs_accumulate_vtbl_inits ). See that non_fn_entries records the number of entries of negative index. So it can know where to begin the entries visible to programmer.

    When returns back to accumulate_vtbl_inits , after chaining into list in finish_vtt , we get following figure (remember in create_vtable_ptr , every virtual function has an extra node generated with 0 delta).

    Next, in accumulate_vtbl_inits , at line 7195, in FOR block, binfo B1 within C is not handled as its BINFO_NEW_VTABLE_MARKED unset (see dfs_accumulate_vtbl_inits line 7273). While for B2 in C, it has secondary vtable generated, so passes the line successfully. At that time, ctor_vtbl_p is false, binfo from class B2, orig_binfo from B2 in C, and rtti_binfo is C’s binfo, it undergoes similar processing as that for C above. Then when back finish_vtbls , A in C is processed by accumulate_vtbl_inits at line 6780, in which ctor_vtbl_p is still false. But this A hasn’t flag BINFO_NEW_VTABLE_MARKED set, so exits dfs_accumulate_vtbl_inits immediately.

    So before invoking initialize_vtable at line 6784, list is given in below figure.

    (Click here for open )

    Figure 117 : initializer for vtable

    Above B1 and A don’t have their part of vtable as they share the same part with C.

    In below function, now argument inits is the chain referred by value slot of list in above figure. This chain holds all initializers for class C’s vtable. Note that at last vtbl at line 7297 in dfs_accumulate_vtbl_inits , points to the start point of vtable of specified class which is a PLUS_EXPR of vtbl+4 for C, vtbl+8 for base B2.

     

    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   }

     

    Originally in build_vtable , vtable is created as type of vtbl_type_node which is the array of type vtable_entry_type with empty dimension. Now the size of the array is settled down, we can create the exact type by 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   }

     

    So at line 6795, the vtable VAR_DECL fetched has correct type defined. And it is passed as argument decl in below function.

     

    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   }

     

    See node of CONSTRUCTOR is built for initializing this VAR_DECL. Note that this node has empty type field (it is treated as unknown).

     

    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    }

     

    Being a VAR_DECL, it is completed by cp_finish_decl . Note that we are still within another cp_finish_decl for the template instantiation of SmallObject.

     

    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     }

     

    Before entering the function, we clean DELC_CONTEXT of decl . At line 4794, maybe_apply_renaming_pragma is only useful for Solaris and Tru64 UNIX system for compatibility with the system headers.


    最新回复(0)