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

5.13.3.      为基本类型产生tinfo

操持完 PCH 文件,回到 finish_file 中继续为汇编代码的生成而奋斗。接下来编译器将为基本类型准备 tinfo

 

finish_file (continue)

 

2546     /* Otherwise, GDB can get confused, because in only knows

2547       about source for LINENO-1 lines.  */

2548     input_line -= 1;

2549  

2550     interface_unknown = 1;

2551     interface_only = 0;

2552  

2553     /* We now have to write out all the stuff we put off writing out.

2554       These include:

2555  

2556       o Template specializations that we have not yet instantiated,

2557         but which are needed.

2558       o Initialization and destruction for non-local objects with

2559         static storage duration. (Local objects with static storage

2560         duration are initialized when their scope is first entered,

2561         and are cleaned up via atexit.)

2562       o Virtual function tables. 

2563  

2564       All of these may cause others to be needed. For example,

2565       instantiating one function may cause another to be needed, and

2566       generating the initializer for an object may cause templates to be

2567       instantiated, etc., etc.  */

2568  

2569     timevar_push (TV_VARCONST);

2570  

2571     emit_support_tinfos ();

 

所有这样的 tinfo 将可以在名字空间 abi_node 中找到。在 get_tinfo_decl 中,这些 tinfo 将被串入 unemitted_tinfo_decls 。注意到数组 fundamentals 的内容是基本类型的节点,它们是在建立编译器环境时构建的。

 

1353   void

1354   emit_support_tinfos (void)                                                                                     in rtti.c

1355   {

1356     static tree *const fundamentals[] =

1357     {

1358        &void_type_node,

1359       &boolean_type_node,

1360       &wchar_type_node,

1361       &char_type_node, &signed_char_type_node, &unsigned_char_type_node,

1362       &short_integer_type_node, &short_unsigned_type_node,

1363       &integer_type_node, &unsigned_type_node,

1364       &long_integer_type_node, &long_unsigned_type_node,

1365       &long_long_integer_type_node, &long_long_unsigned_type_node,

1366       &float_type_node, &double_type_node, &long_double_type_node,

1367       0

1368     };

1369     int ix;

1370     tree bltn_type, dtor;

1371    

1372     push_nested_namespace (abi_node );

1373     bltn_type = xref_tag (class_type,

1374                       get_identifier ("__fundamental_type_info"),

1375                        true, false);

1376     pop_nested_namespace (abi_node );

1377     if (!COMPLETE_TYPE_P (bltn_type))

1378       return ;

1379     dtor = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (bltn_type), 1);

1380     if (DECL_EXTERNAL (dtor))

1381       return ;

1382     doing_runtime = 1;

1383     for (ix = 0; fundamentals[ix]; ix++)

1384     {

1385       tree bltn = *fundamentals[ix];

1386       tree bltn_ptr = build_pointer_type (bltn);

1387       tree bltn_const_ptr = build_pointer_type

1388                                (build_qualified_type (bltn, TYPE_QUAL_CONST));

1389       tree tinfo;

1390        

1391       tinfo = get_tinfo_decl (bltn);

1392       TREE_USED (tinfo) = 1;

1393       TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (tinfo)) = 1;

1394        

1395       tinfo = get_tinfo_decl (bltn_ptr);

1396       TREE_USED (tinfo) = 1;

1397       TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (tinfo)) = 1;

1398        

1399       tinfo = get_tinfo_decl (bltn_const_ptr);

1400       TREE_USED (tinfo) = 1;

1401       TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (tinfo)) = 1;

1402     }

1403   }

 

看到对于每个基本类型,需要产生 3 tinfo 一个对应朴素( plain )类型,一个对应指针,还有一个对应常量指针。

5.13.4.      稳定中间树

下面的庞大的 DO WHILE 循环不断重复,直到没有任何相关的东西发生改变。在 2582 行, instantiate_pending_templates 具现仍未了结的模板。在前端内部,一个全局的 tree_list 链表 pending_tempaltes 保存了所有具现被延迟的模板,它们要么定义还未知,要么我们推迟了这个具现。每个节点的 tree_purose 或者是一个 DECL (对于一个函数或者静态数据成员),或一个 TYPE (对于一个类),它代表我们所期望的具现形式。而 tree_value 不被使用。

 

finish_file (continue)

 

2573     do

2574     {

2575       tree t;

2576       size_t n_old, n_new;

2577  

2578       reconsider = false;

2579  

2580       /* If there are templates that we've put off instantiating, do

2581         them now.  */

2582       instantiate_pending_templates ();

2583       ggc_collect ();

2584  

2585       /* Write out virtual tables as required. Note that writing out

2586          the virtual table for a template class may cause the

2587         instantiation of members of that class. If we write out

2588          vtables then we remove the class from our list so we don't

2589          have to look at it again.  */

2590  

2591       while (keyed_classes != NULL_TREE

2592              && maybe_emit_vtables (TREE_VALUE (keyed_classes )))

2593       {

2594         reconsider = true;

2595         keyed_classes = TREE_CHAIN (keyed_classes );

2596       }

2597  

2598       t = keyed_classes ;

2599       if (t != NULL_TREE)

2600        {

2601         tree next = TREE_CHAIN (t);

2602  

2603         while (next)

2604           {

2605             if (maybe_emit_vtables (TREE_VALUE (next)))

2606            {

2607              reconsider = true;

2608              TREE_CHAIN (t) = TREE_CHAIN (next);

2609            }

2610            else

2611              t = next;

2612  

2613            next = TREE_CHAIN (t);

2614         }

2615       }

2616  

2617      /* Write out needed type info variables. We have to be careful

2618         looping through unemitted decls, because emit_tinfo_decl may

2619         cause other variables to be needed. We stick new elements

2620         (and old elements that we may need to reconsider) at the end

2621        of the array, then shift them back to the beginning once we're

2622         done.  */

2623    

2624       n_old = VARRAY_ACTIVE_SIZE (unemitted_tinfo_decls );

2625       for (i = 0; i < n_old; ++i)

2626       {

2627         tree tinfo_decl = VARRAY_TREE (unemitted_tinfo_decls , i);

2628         if (emit_tinfo_decl (tinfo_decl))

2629           reconsider = true;

2630         else

2631           VARRAY_PUSH_TREE (unemitted_tinfo_decls , tinfo_decl);

2632       }

2633    

2634        /* The only elements we want to keep are the new ones. Copy

2635         them to the beginning of the array, then get rid of the

2636         leftovers.  */

2637       n_new = VARRAY_ACTIVE_SIZE (unemitted_tinfo_decls ) - n_old;

2638       if (n_new)

2639         memmove (&VARRAY_TREE (unemitted_tinfo_decls , 0),

2640                   &VARRAY_TREE (unemitted_tinfo_decls , n_old),

2641                   n_new * sizeof (tree));

2642       memset (&VARRAY_TREE (unemitted_tinfo_decls , n_new),

2643               0, n_old * sizeof (tree));

2644       VARRAY_ACTIVE_SIZE (unemitted_tinfo_decls ) = n_new;

2645  

2646       /* The list of objects with static storage duration is built up

2647          i n reverse order. We clear STATIC_AGGREGATES so that any new

2648          aggregates added during the initialization of these will be

2649          initialized in the correct order when we next come around the

2650          loop.  */

2651       vars = prune_vars_needing_no_initialization (&static_aggregates );

2652  

2653       if (vars)

2654       {

2655         tree v;

2656  

2657          /* We need to start a new initialization function each time

2658           through the loop. That's because we need to know which

2659            vtables have been referenced, and TREE_SYMBOL_REFERENCED

2660            isn't computed until a function is finished, and written

2661            out. That's a deficiency in the back-end. When this is

2662            fixed, these initialization functions could all become

2663            inline, with resulting performance improvements.  */

2664         tree ssdf_body;

2665  

2666          /* Set the line and file, so that it is obviously not from

2667            the source file.  */

2668         input_location = locus;

2669         ssdf_body = start_static_storage_duration_function (ssdf_count);

2670  

2671         /* Make sure the back end knows about all the variables.  */

2672         write_out_vars (vars);

2673  

2674         /* First generate code to do all the initializations.  */

2675         for (v = vars; v; v = TREE_CHAIN (v))

2676           do_static_initialization (TREE_VALUE (v),

2677                               TREE_PURPOSE (v));

2678  

2679         /* Then, generate code to do all the destructions. Do these

2680            i n reverse order so that the most recently constructed

2681            variable is the first destroyed. If we're using

2682            __cxa_atexit, then we don't need to do this; functions

2683            were registered at initialization time to destroy the

2684            local statics.  */

2685         if (!flag_use_cxa_atexit )

2686         {

2687           vars = nreverse (vars);

2688           for (v = vars; v; v = TREE_CHAIN (v))

2689             do_static_destruction (TREE_VALUE (v));

2690         }

2691         else

2692           vars = NULL_TREE;

2693  

2694          /* Finish up the static storage duration function for this

2695            round.  */

2696         input_location = locus;

2697         finish_static_storage_duration_function (ssdf_body);

2698  

2699         /* All those initializations and finalizations might cause

2700            us to need more inline functions, more template

2701            instantiations, etc.  */

2702         reconsider = true;

2703         ssdf_count++;

2704         locus.line++;

2705       }

2706        

2707       for (i = 0; i < deferred_fns_used ; ++i)

2708       {

2709         tree decl = VARRAY_TREE (deferred_fns , i);

2710  

2711         /* Does it need synthesizing?  */

2712         if (DECL_ARTIFICIAL (decl) && ! DECL_INITIAL (decl)

2713            && TREE_USED (decl)

2714            && (! DECL_REALLY_EXTERN (decl) || DECL_INLINE (decl)))

2715         {

2716           /* Even though we're already at the top-level, we push

2717              there again. That way, when we pop back a few lines

2718              hence, all of our state is restored. Otherwise,

2719              finish_function doesn't clean things up, and we end

2720              up with CURRENT_FUNCTION_DECL set.  */

2721           push_to_top_level ();

2722           synthesize_method (decl);

2723           pop_from_top_level ();

2724           reconsider = true;

2725         }

2726  

2727         /* If the function has no body, avoid calling

2728            import_export_decl. On a system without weak symbols,

2729            calling import_export_decl will make an inline template

2730            instantiation "static", which will result in errors about

2731            the use of undefined functions if there is no body for

2732            the function.  */

2733         if (!DECL_SAVED_TREE (decl))

2734           continue ;

2735  

2736         import_export_decl (decl);

2737  

2738         /* We lie to the back-end, pretending that some functions

2739            are not defined when they really are. This keeps these

2740            functions from being put out unnecessarily. But, we must

2741            stop lying when the functions are referenced, or if they

2742            are not comdat since they need to be put out now. This

2743            is done in a separate for cycle, because if some deferred

2744            function is contained in another deferred function later

2745            i n deferred_fns varray, rest_of_compilation would skip

2746            this function and we really cannot expand the same

2747            function twice.  */

2748         if (DECL_NOT_REALLY_EXTERN (decl)

2749            && DECL_INITIAL (decl)

2750            && DECL_NEEDED_P (decl))

2751           DECL_EXTERNAL (decl) = 0;

2752  

2753         /* If we're going to need to write this function out, and

2754             there's already a body for it, create RTL for it now.

2755            (There might be no body if this is a method we haven't

2756            gotten around to synthesizing yet.)  */

2757         if (!DECL_EXTERNAL (decl)

2758            && DECL_NEEDED_P (decl)

2759            && DECL_SAVED_TREE (decl)

2760            && !TREE_ASM_WRITTEN (decl)

2761            && (!flag_unit_at_a_time

2762                || !cgraph_node (decl)->local.finalized))

2763         {

2764           /* We will output the function; no longer consider it in this

2765              loop.  */

2766           DECL_DEFER_OUTPUT (decl) = 0;

2767           /* Generate RTL for this function now that we know we

2768             need it.  */

2769           expand_or_defer_fn (decl);

2770           /* If we're compiling -fsyntax-only pretend that this

2771              function has been written out so that we don't try to

2772              expand it again.  */

2773           if (flag_syntax_only )

2774             TREE_ASM_WRITTEN (decl) = 1;

2775            reconsider = true;

2776         }

2777       }

2778  

2779       if (walk_namespaces (wrapup_globals_for_namespace , /*data=*/ 0))

2780         reconsider = true;

2781  

2782        /* Static data members are just like namespace-scope globals.  */

2783       for (i = 0; i < pending_statics_used ; ++i)

2784       {

2785         tree decl = VARRAY_TREE (pending_statics , i);

2786         if (var_finalized_p (decl))

2787           continue ;

2788         import_export_decl (decl);

2789         if (DECL_NOT_REALLY_EXTERN (decl) && ! DECL_IN_AGGR_P (decl))

2790           DECL_EXTERNAL (decl) = 0;

2791       }

2792       if (pending_statics

2793          && wrapup_global_declarations (&VARRAY_TREE (pending_statics , 0),

2794                                     pending_statics_used ))

2795       reconsider = true;

2796  

2797       if (cgraph_assemble_pending_functions ())

2798         reconsider = true;

2799     }

2800     while (reconsider);

5.13.4.1.              迭代 发布 vtable

首先,使用中的 vtable 应该被标记,以使编译器为之产生代码。在前面的章节中,我们已经看到对于一个类,其 CLASSTYPE_VTABLES 可能包含了一串 vtable 。这依赖于其基类及其定义。而如果一个类包含了 vtable ,它也同样被记录在 keyed_classes 链表中。在 1565 行, primary_vtbl 指向 ctype vtable 列表。

 

1556   static bool

1557   maybe_emit_vtables (tree ctype)                                                               in decl2.c

1558   {

1559     tree vtbl;

1560     tree primary_vtbl;

1561     bool needed = false;

1562  

1563     /* If the vtables for this class have already been emitted there is

1564       nothing more to do.  */

1565     primary_vtbl = CLASSTYPE_VTABLES (ctype);

1566     if (var_finalized_p (primary_vtbl))

1567       return false;

1568     /* Ignore dummy vtables made by get_vtable_decl.  */

1569     if (TREE_TYPE (primary_vtbl) == void_type_node)

1570       return false;

1571  

1572     import_export_class (ctype);

1573  

1574     /* See if any of the vtables are needed.  */

1575     for (vtbl = CLASSTYPE_VTABLES (ctype); vtbl; vtbl = TREE_CHAIN (vtbl))

1576     {

1577       import_export_vtable (vtbl, ctype, 1);

1578       if (!DECL_EXTERNAL (vtbl) && DECL_NEEDED_P (vtbl))

1579         break ;

1580     }

1581     if (!vtbl)

1582     {

1583       /* If the references to this class' vtables are optimized away,

1584         still emit the appropriate debugging information. See

1585         dfs_debug_mark.  */

1586       if (DECL_COMDAT (primary_vtbl)

1587          && CLASSTYPE_DEBUG_REQUESTED (ctype))

1588         note_debug_info_needed (ctype);

1589       return false;

1590     }

1591     else if (TREE_PUBLIC (vtbl) && !DECL_COMDAT (vtbl))

1592       needed = true;

 

所有的 vtable 都被编译器声明为公有的 VAR_DECL ,这样类型的节点通过 cgraph_varpool_node 关联起来,在其中如果标记 finalized 被设置,就意味着已经为该节点输出代码。

 

1544   static bool

1545   var_finalized_p (tree var)                                                                         in decl2.c

1546   {

1547     if (flag_unit_at_a_time )

1548       return cgraph_varpool_node (var)->finalized;

1549     else

1550       return TREE_ASM_WRITTEN (var);

1551   }

 

如果 flag_unit_at_a_time 不是 0 ,则为这个 VAR_DECL 构建一个 cgraph_varpool_node 在下面,哈希表 cgraph_varpool_hash cgraph_varpool_node 的一个队列,它由 GC 管理。

 

441    struct cgraph_varpool_node *

442    cgraph_varpool_node (tree decl)                                                                in cgraph.c

443    {

444      struct cgraph_varpool_node *node;

445      struct cgraph_varpool_node **slot;

446   

447      if (!DECL_P (decl) || TREE_CODE (decl) == FUNCTION_DECL)

448        abort ();

449   

450      if (!cgraph_varpool_hash)

451        cgraph_varpool_hash = htab_create_ggc (10, cgraph_varpool_hash_node,

452                                         eq_cgraph_varpool_node, NULL);

453      slot = (struct cgraph_varpool_node **)

454        htab_find_slot_with_hash (cgraph_varpool_hash , DECL_ASSEMBLER_NAME (decl),

455                             IDENTIFIER_HASH_VALUE (DECL_ASSEMBLER_NAME (decl)),

456                             INSERT);

457      if (*slot)

458        return *slot;

459      node = ggc_alloc_cleared (sizeof (*node));

460      node->decl = decl;

461      cgraph_varpool_n_nodes ++;

462      cgraph_varpool_nodes = node;

463      *slot = node;

464      return node;

465    }

 

而结构体 cgraph_varpool_node 具有以下的定义。

 

134    struct cgraph_varpool_node GTY(())                                                         in cgraph.h

135    {

136      tree decl;

137      /* Pointer to the next function in cgraph_varpool_nodes_queue.  */

138      struct cgraph_varpool_node *next_needed;

139   

140      /* Set when function must be output - it is externally visible

141        or it's address is taken.  */

142      bool needed;

143      /* Set once it has been finalized so we consider it to be output.  */

144      bool finalized;

145      /* Set when function is scheduled to be assembled.  */

146      bool output;

147    };

 

上面的 1572 行, import_export_class 确定是否需要在这个编译单元发布该类的整套内容;或者只是发布一个签名,而在链接时刻解析这些引用。

记得编译选项 -fno-implicit-templates 表示不要为隐式具现的非内联模板发布代码。对于这个情形,我们设置 import_export -1 要限制其代码发布。

接着需要确定指定的 vtable 是否是外部的(即便类本身是外部定义的,一旦其某一基类是定义在这个编译单元中,并在这里发布 vtable ,该类的 vtable 也需要在这里发布)。

 

1442   void

1443   import_export_vtable (tree decl, tree type, int final)                                     in decl2.c

1444   {

1445     if (DECL_INTERFACE_KNOWN (decl))

1446       return ;

1447  

1448     if (TYPE_FOR_JAVA (type))

1449     {

1450       TREE_PUBLIC (decl) = 1;

1451       DECL_EXTERNAL (decl) = 1;

1452       DECL_INTERFACE_KNOWN (decl) = 1;

1453     }

1454     else if (CLASSTYPE_INTERFACE_KNOWN (type))

1455     {

1456       TREE_PUBLIC (decl) = 1;

1457       DECL_EXTERNAL (decl) = CLASSTYPE_INTERFACE_ONLY (type);

1458       DECL_INTERFACE_KNOWN (decl) = 1;

1459     }

1460     else

1461     {

1462       /* We can only wait to decide if we have real non-inline virtual

1463          functions in our class, or if we come from a template.  */

1464  

1465       int found = (CLASSTYPE_TEMPLATE_INSTANTIATION (type)

1466                  || CLASSTYPE_KEY_METHOD (type) != NULL_TREE);

1467  

1468       if (final || ! found)

1469       {

1470         comdat_linkage (decl);

1471         DECL_EXTERNAL (decl) = 0;

1472       }

1473       else

1474       {

1475         TREE_PUBLIC (decl) = 1;

1476         DECL_EXTERNAL (decl) = 1;

1477       }

1478     }

1479   }

 

在函数 import_export_vtable 为代表 vtable VAR_DECL 设置了相应标记后, DECL_NEEDED_P 分辨这个 vtable 是否需要发布。断言 DECL_COMDAT 如果成立,表示就是具有 TREE_PUBLIC 属性,也不需要发布,除非这个编译单元需要。类似这样的实体在编译单元间共享(类似弱实体),但保证为任何需要它们的编译单元所产生, 因此不需要在不需要它们的地方发布。 DECL_COMDAT 只是给后端的一个暗示;由前端自由设置这个标记,它保证除了发布 DECL_COMDAT 的对象使得代码膨胀外,对代码没有别的坏处。

 

1730   #define DECL_NEEDED_P (DECL)                               /                           in cp-tree.h

1731     ((at_eof && TREE_PUBLIC (DECL) && !DECL_COMDAT (DECL))      /

1732      || (DECL_ASSEMBLER_NAME_SET_P (DECL)                            /

1733        && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (DECL)))/

1734      || (((flag_syntax_only || flag_unit_at_a_time ) && TREE_USED (DECL))))

 

如果 vtable 列表中有任一 vtable 需要发布代码,编译器将为所有的 vtable 发布代码。在这里标记它们。

 

maybe_emit_vtables (continue)

 

1595     /* The ABI requires that we emit all of the vtables if we emit any

1596       of them.  */

1597     for (vtbl = CLASSTYPE_VTABLES (ctype); vtbl; vtbl = TREE_CHAIN (vtbl))

1598     {

1599        /* Write it out.  */

1600       import_export_vtable (vtbl, ctype, 1);

1601       mark_vtable_entries (vtbl);

1602  

1603       /* If we know that DECL is needed, mark it as such for the varpool.  */

1604       if (needed)

1605         cgraph_varpool_mark_needed_node (cgraph_varpool_node (vtbl));

1606  

1607       if (TREE_TYPE (DECL_INITIAL (vtbl)) == 0)

1608       {

1609          /* It had better be all done at compile-time.  */

1610         if (store_init_value (vtbl, DECL_INITIAL (vtbl)))

1611           abort ();

1612       }

1613  

1614       if (write_symbols == DWARF_DEBUG || write_symbols == DWARF2_DEBUG)

1615       {

1616         /* Mark the VAR_DECL node representing the vtable itself as a

1617          "gratuitous" one, thereby forcing dwarfout.c to ignore it.

1618          It is rather important that such things be ignored because

1619          any effort to actually generate DWARF for them will run

1620          into trouble when/if we encounter code like:

1621  

1622           #pragma interface

1623          struct S { virtual void member (); };

1624  

1625          because the artificial declaration of the vtable itself (as

1626          manufactured by the g++ front end) will say that the vtable

1627          is a static member of `S' but only *after* the debug output

1628          for the definition of `S' has already been output. This causes

1629          grief because the DWARF entry for the definition of the vtable

1630          will try to refer back to an earlier *declaration* of the

1631          vtable as a static member of `S' and there won't be one.

1632          We might be able to arrange to have the "vtable static member"

1633          attached to the member list for `S' before the debug info for

1634          `S' get written (which would solve the problem) but that would

1635          require more intrusive changes to the g++ front end.  */

1636  

1637         DECL_IGNORED_P (vtbl) = 1;

1638       }

1639  

1640       /* Always make vtables weak.  */

1641       if (flag_weak )

1642         comdat_linkage (vtbl);

1643  

1644       rest_of_decl_compilation (vtbl, NULL, 1, 1);

1645  

1646       /* Because we're only doing syntax-checking, we'll never end up

1647         actually marking the variable as written.  */

1648       if (flag_syntax_only )

1649         TREE_ASM_WRITTEN (vtbl) = 1;

1650     }

1651  

1652     /* Since we're writing out the vtable here, also write the debug

1653       info.  */

1654     note_debug_info_needed (ctype);

1655  

1656     return true;

1657   }

 

下面的函数只是把虚函数标记为可寻址,并设置 in-used 标记来表示编译器需要在后面发布代码。记得总是为 vtable 的初始值构建 CONSTRUCTOR 节点,在调试模式中 CONSTRUCTOR_ELTS 可以执行额外的检查来保证这确实是 CONSTRUCTOR 实体,并获取 vtable 的初始值(参考 initialize_vtable build_vtt 中的 initialize_array 。至于初始值的例子,参考 5.12.5.2.2.2.1.3.11.完成派生类 RECORD_TYPE 完成 vtable 一节)。

 

1323   static void

1324   mark_vtable_entries (tree decl)                                                                 in decl2.c

1325   {

1326     tree entries = CONSTRUCTOR_ELTS (DECL_INITIAL (decl));

1327  

1328     for (; entries; entries = TREE_CHAIN (entries))

1329     {

1330       tree fnaddr = TREE_VALUE (entries);

1331       tree fn;

1332  

1333       STRIP_NOPS (fnaddr);

1334  

1335       if (TREE_CODE (fnaddr) != ADDR_EXPR

1336          && TREE_CODE (fnaddr) != FDESC_EXPR)

1337         /* This entry is an offset: a virtual base class offset, a

1338           virtual call offset, an RTTI offset, etc.  */

1339         continue ;

1340  

1341       fn = TREE_OPERAND (fnaddr, 0);

1342       TREE_ADDRESSABLE (fn) = 1;

1343       /* When we don't have vcall offsets, we output thunks whenever

1344         we output the vtables that contain them. With vcall offsets,

1345         we know all the thunks we'll need when we emit a virtual

1346         function, so we emit the thunks there instead.  */

1347       if (DECL_THUNK_P (fn))

1348         use_thunk (fn, /*emit_p=*/ 0);

1349       mark_used (fn);

1350     }

1351   }

 

decl 标记为在用可以帮助编译器在后面的优化中移除不使用的代码。这个标记在下面的 2982 行设置。而对于未发布的内联函数(一般而言,除了主管构造函数及析构函数外,内联函数此时都未发布。考虑内联函数定义在头文件中,而头文件可能在同一个编译单元不同的源文件中多处被引用,把它的处理推迟到前端最后完成编译单元的时刻,很有必要。虽然此处调用 mark_used 的地方其实已经前端所执行的最后阶段,但 mark_used 在前端中很多地方被调用),把它缓存入 deferred_fns 。在 2991 行,对于 x86 机器上的 Linux assemble_external 是无关重要的。在前面的章节中,我们已经看到编译器会“人工”产生方法(比如,类里的克隆构造函数及析构函数),这样的方法不会自己运行,而是通过用户定义的方法来触发(由 current_function_decl 指向)。在 2998 行,如果 DECL_INITIAL 是空的,这意味着函数还没有被调用序列: start_function begin_function_body begin_compound_stmt || finish_compound_stmt ] finish_function_body finish_function 所处理——即没有构建相应的 STMT 节点,并把它链入其触发者的 STMT 链表中。而在下面, synthesize_method 调用上面提及的调用序列来为这些函数产生必要的 STMT 节点,仿佛它来自用户的定义。接着,在 2983 行的 skip_evaluation 被解析器设置。在 C++ 中,存在不要求评估( evalutaion )的声明或表达式,例如,在操作符 sizeof typeof 中的表达式。

 

2967   void

2968   mark_used (tree decl)                                                                               in decl2.c

2969   {

2970     /* If DECL is a BASELINK for a single function, then treat it just

2971       like the DECL for the function. Otherwise, if the BASELINK is

2972       for an overloaded function, we don't know which function was

2973       actually used until after overload resolution.  */

2974     if (TREE_CODE (decl) == BASELINK)

2975     {

2976       decl = BASELINK_FUNCTIONS (decl);

2977       if (really_overloaded_fn (decl))

2978         return ;

2979       decl = OVL_CURRENT (decl);

2980     }

2981  

2982     TREE_USED (decl) = 1;

2983     if (processing_template_decl || skip_evaluation )

2984       return ;

2985  

2986     if (TREE_CODE (decl) == FUNCTION_DECL && DECL_DECLARED_INLINE_P (decl)

2987         && !TREE_ASM_WRITTEN (decl))

2988        /* Remember it, so we can check it was defined.  */

2989       defer_fn (decl);

2990  

2991     assemble_external (decl);

2992  

2993     /* Is it a synthesized method that needs to be synthesized?  */

2994     if (TREE_CODE (decl) == FUNCTION_DECL

2995         && DECL_NONSTATIC_MEMBER_FUNCTION_P (decl)

2996         && DECL_ARTIFICIAL (decl)

2997         && !DECL_THUNK_P (decl)

2998         && ! DECL_INITIAL (decl)

2999         /* Kludge: don't synthesize for default args.  */

3000         && current_function_decl )

3001     {

3002       synthesize_method (decl);

3003       /* If we've already synthesized the method we don't need to

3004          instantiate it, so we can return right away.  */

3005       return ;

3006     }

3007  

3008     /* If this is a function or variable that is an instance of some

3009       template, we now know that we will need to actually do the

3010       instantiation. We check that DECL is not an explicit

3011       instantiation because that is not checked in instantiate_decl.  */

3012     if ((DECL_NON_THUNK_FUNCTION_P (decl) || TREE_CODE (decl) == VAR_DECL)

3013         && DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl)

3014         && (!DECL_EXPLICIT_INSTANTIATION (decl)

3015             || (TREE_CODE (decl) == FUNCTION_DECL

3016                && DECL_INLINE (DECL_TEMPLATE_RESULT

3017                      (template_for_substitution (decl))))))

3018     {

3019       bool defer;

3020  

3021       /* Normally, we put off instantiating functions in order to

3022         improve compile times. Maintaining a stack of active

3023          functions is expensive, and the inliner knows to

3024          instantiate any functions it might need.

3025  

3026          However, if instantiating this function might help us mark

3027          the current function TREE_NOTHROW, we go ahead and

3028          instantiate it now. 

3029       

3030          This is not needed for unit-at-a-time since we reorder the functions

3031          i n topological order anyway.

3032        */

3033       defer = (!flag_exceptions

3034               || flag_unit_at_a_time

3035               || !optimize

3036               || TREE_CODE (decl) != FUNCTION_DECL

3037               /* If the called function can't throw, we don't need to

3038                  generate its body to find that out.  */

3039               || TREE_NOTHROW (decl)

3040               || !cfun

3041               || !current_function_decl

3042               /* If we already know the current function can't throw,

3043                  then we don't need to work hard to prove it.  */

3044               || TREE_NOTHROW (current_function_decl )

3045                /* If we already know that the current function *can*

3046                  throw, there's no point in gathering more

3047                  information.  */

3048               || cp_function_chain ->can_throw);

3049  

3050       instantiate_decl (decl, defer);

3051     }

3052   }

 

我们已经看过 thunk 是一个编译器产生的函数,也应该为它发布代码。不过,在这次调用中,参数 emit_p false ,结果仅是把 thunk 标记为在用,而没有真正为之发布代码。

 

336    void

337    use_thunk (tree thunk_fndecl, bool emit_p)                                                in method.c

338    {

339      tree function, alias;

340      tree virtual_offset;

341      HOST_WIDE_INT fixed_offset, virtual_value;

342      bool this_adjusting = DECL_THIS_THUNK_P (thunk_fndecl);

343   

344      /* We should have called finish_thunk to give it a name.  */

345      my_friendly_assert (DECL_NAME (thunk_fndecl), 20021127);

346   

347      /* We should never be using an alias, always refer to the

348        aliased thunk.  */

349      my_friendly_assert (!THUNK_ALIAS (thunk_fndecl), 20031023);

350   

351      if (TREE_ASM_WRITTEN (thunk_fndecl))

352        return ;

353     

354      function = THUNK_TARGET (thunk_fndecl);

355      if (DECL_RESULT (thunk_fndecl))

356        /* We already turned this thunk into an ordinary function.

357          There's no need to process this thunk again.  */

358        return ;

359   

360      if (DECL_THUNK_P (function))

361        /* The target is itself a thunk, process it now.  */

362        use_thunk (function, emit_p);

363     

364      /* Thunks are always addressable; they only appear in vtables.  */

365      TREE_ADDRESSABLE (thunk_fndecl) = 1;

366   

367      /* Figure out what function is being thunked to. It's referenced in

368        this translation unit.  */

369      TREE_ADDRESSABLE (function) = 1;

370      mark_used (function);

371      if (!emit_p)

372        return ;

       …

524    }

 

如果该 vtable 是公有的,而且不是编译单元间共享的,在 maybe_emit_vtables 1592 行设置 needed ,然后在 1605 行,调用下面的函数来设置相关联的 cgraph_varpool_node 节点的 needed 标记。

 

568    void

569    cgraph_varpool_mark_needed_node (struct cgraph_varpool_node *node)      in cgraph.c

570    {

571      if (!node->needed && node->finalized)

572      {

573        node->next_needed = cgraph_varpool_nodes_queue ;

574        cgraph_varpool_nodes_queue = node;

575        notice_global_symbol (node->decl);

576      }

577      node->needed = 1;

578    }

 

接着在 maybe_emit_vtables 1644 行,调用 rest_of_decl_compilation 根据中间节点来构建对应的 RTL 节点,并如果需要,发布汇编代码(标签定义,存储分配及初始化)。在这里,参数 top_level at_end 都是 1 ,而 asmspec NULL 。注意到在 1957 行,对于 x86/Linux ,没有定义 ASM_FINISH_DECLARE_OBJECT

 

1910   void

1911   rest_of_decl_compilation (tree decl,                                                         in toplev.c

1912                         const char *asmspec,

1913                         int top_level,

1914                         int at_end)

1915   {

1916     /* We deferred calling assemble_alias so that we could collect

1917       other attributes such as visibility. Emit the alias now.  */

1918     {

1919       tree alias;

1920       alias = lookup_attribute ("alias", DECL_ATTRIBUTES (decl));

1921       if (alias)

1922       {

1923         alias = TREE_VALUE (TREE_VALUE (alias));

1924         alias = get_identifier (TREE_STRING_POINTER (alias));

1925         assemble_alias (decl, alias);

1926       }

1927     }

1928  

1929     /* Forward declarations for nested functions are not "external",

1930       but we need to treat them as if they were.  */

1931     if (TREE_STATIC (decl) || DECL_EXTERNAL (decl)

1932         || TREE_CODE (decl) == FUNCTION_DECL)

1933     {

1934       timevar_push (TV_VARCONST);

1935  

1936       if (asmspec)

1937         make_decl_rtl (decl, asmspec);

1938  

1939       /* Don't output anything when a tentative file-scope definition

1940         is seen. But at end of compilation, do output code for them.

1941  

1942         We do output all variables when unit-at-a-time is active and rely on

1943         callgraph code to defer them except for forward declarations

1944         (see gcc.c-torture/compile/920624-1.c) */

1945       if ((at_end

1946            || !DECL_DEFER_OUTPUT (decl)

1947            || (flag_unit_at_a_time && DECL_INITIAL (decl)))

1948          && !DECL_EXTERNAL (decl))

1949       {

1950         if (flag_unit_at_a_time && !cgraph_global_info_ready

1951            && TREE_CODE (decl) != FUNCTION_DECL && top_level)

1952           cgraph_varpool_finalize_decl (decl);

1953         else

1954           assemble_variable (decl, top_level, at_end, 0);

1955       }

1956  

1957   #ifdef ASM_FINISH_DECLARE_OBJECT

       …

1963   #endif

1964  

1965       timevar_pop (TV_VARCONST);

1966     }

1967     else if (DECL_REGISTER (decl) && asmspec != 0)

1968     {

1969       if (decode_reg_name (asmspec) >= 0)

1970       {

1971         SET_DECL_RTL (decl, NULL_RTX);

1972         make_decl_rtl (decl, asmspec);

1973       }

1974       else

1975       {

1976         error ("invalid register name `%s' for register variable", asmspec);

1977         DECL_REGISTER (decl) = 0;

1978          if (!top_level)

1979           expand_decl (decl);

1980       }

1981     }

        …

2011   }

 

1950 行,当整个单元已经被分析过了, cgraph_global_info_ready 就不是 0 ,因此我们可以访问全局的信息(在当前情形下,它依旧是 false )。而 1946 行的断言 DECL_DEFER_OUTPUT 如果不是 0 ,表示这个 decl 的链接性状况还是未知的,因此它也不应该在现在发布。

因为 vtable 是一个 VAR_DECL ,调用下面的函数来设置相关联的 cgraph_varpool_node 节点的 finialized 标记,来表示将要为之输出代码。

 

580    void

581    cgraph_varpool_finalize_decl (tree decl)                                                     in cgraph.c

582    {

583      struct cgraph_varpool_node *node = cgraph_varpool_node (decl);

584   

585      /* The first declaration of a variable that comes through this function

586        decides whether it is global (in C, has external linkage)

587        or local (in C, has internal linkage). So do nothing more

588        if this function has already run.  */

589      if (node->finalized)

590        return ;

591      if (node->needed)

592      {

593        node->next_needed = cgraph_varpool_nodes_queue ;

594        cgraph_varpool_nodes_queue = node;

595        notice_global_symbol (decl);

596      }

597      node->finalized = true;

598   

599      if (/* Externally visible variables must be output. The exception are

600           COMDAT functions that must be output only when they are needed.  */

601         (TREE_PUBLIC (decl) && !DECL_COMDAT (decl))

602           /* Function whose name is output to the assembler file must be produced.

603            It is possible to assemble the name later after finalizing the function

604            and the fact is noticed in assemble_name then.  */

605          || (DECL_ASSEMBLER_NAME_SET_P (decl)

606            && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))))

607      {

608        cgraph_varpool_mark_needed_node (node);

609      }

610    }

 

因为上面在 maybe_emit_vtables 1605 行,已经为需要输出的 vtable 调用了 cgraph_varpool_mark_needed_node ;因此对于这样的 vtable ,其 cgraph 节点中的 needed 标记是 true ,在这里这个节点也会被链入 cgraph_varpool_nodes_queue (看到在 cgraph_varpool_mark_needed_node 571 行,链入的条件是“ (!node->needed && node->finalized) ”,如果那时没有链入,那么现在在这里链入);在 608 行,该 vtable 再次被 cgraph_varpool_mark_needed_node 处理,确保 cgraph 节点链入 cgraph_varpool_nodes_queue

注意到一旦 maybe_emit_vtables 成功处理了这个类,就把它从 keyed_classes 中移走,同时强制进行下一次的迭代。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值