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

来源:互联网 发布:淘宝新店如何找货源 编辑:程序博客网 时间:2024/05/23 11:28

5.13.3.      为基本类型产生tinfo

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

 

finish_file (continue)

 

2546     /* Otherwise, GDBcan get confused, because in only knows

2547       about source for LINENO-1lines.  */

2548     input_line -= 1;

2549  

2550     interface_unknown = 1;

2551     interface_only = 0;

2552  

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

2554       These include:

2555  

2556       o Template specializationsthat we have not yet instantiated,

2557         but which are needed.

2558       o Initialization anddestruction for non-local objects with

2559         static storage duration.(Local objects with static storage

2560         duration are initializedwhen their scope is first entered,

2561         and are cleaned up viaatexit.)

2562       o Virtual functiontables. 

2563  

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

2565       instantiating one function maycause another to be needed, and

2566       generating the initializer foran 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   }

 

看到对于每个基本类型,需要产生3tinfo一个对应朴素(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 aretemplates that we've put off instantiating, do

2581         them now.  */

2582       instantiate_pending_templates ();

2583       ggc_collect ();

2584  

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

2586         the virtual table for a template class maycause the

2587         instantiation of members ofthat class. If we write out

2588         vtables then we remove the class from our listso 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 outneeded type info variables. We have to be careful

2618        looping through unemitted decls, becauseemit_tinfo_decl may

2619        cause other variables to be needed. We sticknew elements

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

2621        of the array, then shift themback 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 thenew ones. Copy

2635         them to the beginning of thearray, 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 ofobjects with static storage duration is built up

2647         in reverse order. We clear STATIC_AGGREGATES so that any new

2648         aggregates added during the initialization ofthese will be

2649         initialized in the correct order when we nextcome 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 initializationfunction each time

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

2659           vtables have been referenced, andTREE_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 functionscould all become

2663           inline, with resulting performanceimprovements.  */

2664         tree ssdf_body;

2665  

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

2667           the source file.  */

2668         input_location = locus;

2669         ssdf_body = start_static_storage_duration_function(ssdf_count);

2670  

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

2672         write_out_vars(vars);

2673  

2674         /* Firstgenerate 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           in reverse order so that the most recently constructed

2681           variable is the first destroyed. If we'reusing

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

2683           were registered at initialization time todestroy 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 durationfunction for this

2695           round. */

2696         input_location = locus;

2697         finish_static_storage_duration_function(ssdf_body);

2698  

2699         /* All thoseinitializations and finalizations might cause

2700           us to need more inline functions, moretemplate

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 needsynthesizing?  */

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

2713            && TREE_USED (decl)

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

2715         {

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

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

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

2719             finish_function doesn't clean things up, andwe 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 thefunction has no body, avoid calling

2728           import_export_decl. On a system withoutweak symbols,

2729           calling import_export_decl will make aninline template

2730           instantiation "static", whichwill result in errors about

2731           the use of undefined functions if there isno body for

2732           the function.  */

2733         if (!DECL_SAVED_TREE (decl))

2734           continue;

2735  

2736         import_export_decl (decl);

2737  

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

2739           are not defined when they really are. Thiskeeps these

2740           functions from being put outunnecessarily. But, we must

2741           stop lying when the functions arereferenced, or if they

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

2743           is done in a separate for cycle, becauseif some deferred

2744           function is contained in another deferredfunction later

2745           in deferred_fns varray, rest_of_compilation would skip

2746           this function and we really cannot expandthe 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'regoing to need to write this function out, and

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

2755           (There might be no body if this is amethod 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 willoutput the function; no longer consider it in this

2765             loop. */

2766           DECL_DEFER_OUTPUT (decl) = 0;

2767           /* GenerateRTL for this function now that we know we

2768             need it.  */

2769           expand_or_defer_fn(decl);

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

2771             function has been written out so that we don'ttry 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 likenamespace-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指向ctypevtable列表。

 

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 vtablesfor 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       returnfalse;

1568    /* Ignore dummyvtables made by get_vtable_decl.  */

1569     if (TREE_TYPE (primary_vtbl) == void_type_node)

1570       returnfalse;

1571  

1572     import_export_class(ctype);

1573  

1574     /* See if any ofthe 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 thereferences to this class' vtables are optimized away,

1584         still emit the appropriatedebugging information. See

1585         dfs_debug_mark.  */

1586       if (DECL_COMDAT(primary_vtbl)

1587          && CLASSTYPE_DEBUG_REQUESTED(ctype))

1588         note_debug_info_needed (ctype);

1589       returnfalse;

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       returnTREE_ASM_WRITTEN (var);

1551   }

 

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

 

441    struct cgraph_varpool_node*

442    cgraph_varpool_node (tree decl)                                                                in cgraph.c

443    {

444      structcgraph_varpool_node *node;

445      structcgraph_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 = (structcgraph_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_nodeGTY(())                                                         in cgraph.h

135    {

136      tree decl;

137      /* Pointer to thenext function in cgraph_varpool_nodes_queue. */

138      structcgraph_varpool_node *next_needed;

139   

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

141        or it's addressis taken.  */

142      bool needed;

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

144      bool finalized;

145      /* Set whenfunction 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, treetype, 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 onlywait to decide if we have real non-inline virtual

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

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为代表vtableVAR_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 requiresthat 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 knowthat 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 atcompile-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 theVAR_DECL node representing the vtable itself as a

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

1618          It is rather important thatsuch things be ignored because

1619          any effort to actuallygenerate DWARF for them will run

1620          into trouble when/if weencounter code like:

1621  

1622          #pragma interface

1623          struct S { virtual voidmember (); };

1624  

1625          because the artificialdeclaration 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 DWARFentry for the definition of the vtable

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

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

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

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

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

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

1636  

1637         DECL_IGNORED_P (vtbl) = 1;

1638       }

1639  

1640       /* Always makevtables weak.  */

1641       if (flag_weak)

1642         comdat_linkage (vtbl);

1643  

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

1645  

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

1647         actually marking thevariable as written.  */

1648       if (flag_syntax_only)

1649         TREE_ASM_WRITTEN (vtbl) = 1;

1650     }

1651  

1652     /* Since we'rewriting 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_vtablebuild_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 entryis an offset: a virtual base class offset, a

1338           virtual call offset, anRTTI offset, etc.  */

1339         continue;

1340  

1341       fn = TREE_OPERAND (fnaddr, 0);

1342       TREE_ADDRESSABLE (fn) = 1;

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

1344         we output the vtables thatcontain them. With vcall offsets,

1345         we know all the thunks we'llneed when we emit a virtual

1346         function, so we emit thethunks 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机器上的Linuxassemble_external是无关重要的。在前面的章节中,我们已经看到编译器会“人工”产生方法(比如,类里的克隆构造函数及析构函数),这样的方法不会自己运行,而是通过用户定义的方法来触发(由current_function_decl指向)。在2998行,如果DECL_INITIAL是空的,这意味着函数还没有被调用序列:start_functionbegin_function_bodybegin_compound_stmt || finish_compound_stmt]finish_function_bodyfinish_function所处理——即没有构建相应的STMT节点,并把它链入其触发者的STMT链表中。而在下面,synthesize_method调用上面提及的调用序列来为这些函数产生必要的STMT节点,仿佛它来自用户的定义。接着,在2983行的skip_evaluation被解析器设置。在C++中,存在不要求评估(evalutaion)的声明或表达式,例如,在操作符sizeoftypeof中的表达式。

 

2967   void

2968   mark_used (tree decl)                                                                               in decl2.c

2969   {

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

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

2972       for an overloaded function, wedon't know which function was

2973       actually used until afteroverload 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 wasdefined.  */

2989       defer_fn (decl);

2990  

2991     assemble_external (decl);

2992  

2993    /* Is it asynthesized 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'vealready synthesized the method we don't need to

3004         instantiate it, so we can return rightaway.  */

3005       return;

3006     }

3007  

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

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

3010       instantiation. We check thatDECL is not an explicit

3011       instantiation because that isnot 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, weput off instantiating functions in order to

3022         improve compile times. Maintaininga stack of active

3023         functions is expensive, and the inliner knowsto

3024         instantiate any functions it might need.

3025  

3026         However, if instantiating this function mighthelp us mark

3027         the current function TREE_NOTHROW, we go aheadand

3028         instantiate it now. 

3029       

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

3031         in topological order anyway.

3032       */

3033       defer = (!flag_exceptions

3034               || flag_unit_at_a_time

3035               || !optimize

3036               || TREE_CODE (decl) !=FUNCTION_DECL

3037               /* If thecalled 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 wealready know the current function can't throw,

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

3044               || TREE_NOTHROW (current_function_decl)

3045               /* If we alreadyknow 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_pfalse,结果仅是把thunk标记为在用,而没有真正为之发布代码。

 

336    void

337    use_thunk (tree thunk_fndecl, boolemit_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 havecalled finish_thunk to give it a name. */

345      my_friendly_assert (DECL_NAME (thunk_fndecl),20021127);

346   

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

348        aliasedthunk.  */

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 alreadyturned this thunk into an ordinary function.

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

358        return;

359   

360      if (DECL_THUNK_P (function))

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

362        use_thunk(function, emit_p);

363     

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

365      TREE_ADDRESSABLE (thunk_fndecl) = 1;

366   

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

368        this translationunit.  */

369      TREE_ADDRESSABLE (function) = 1;

370      mark_used(function);

371      if (!emit_p)

372        return;

      

524    }

 

如果该vtable是公有的,而且不是编译单元间共享的,在maybe_emit_vtables1592行设置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_vtables1644行,调用rest_of_decl_compilation根据中间节点来构建对应的RTL节点,并如果需要,发布汇编代码(标签定义,存储分配及初始化)。在这里,参数top_levelat_end都是1,而asmspecNULL。注意到在1957行,对于x86/Linux,没有定义ASM_FINISH_DECLARE_OBJECT

 

1910   void

1911   rest_of_decl_compilation (tree decl,                                                        in toplev.c

1912                         constchar *asmspec,

1913                         int top_level,

1914                         int at_end)

1915   {

1916    /* We deferredcalling assemble_alias so that we could collect

1917       other attributes such asvisibility. 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     /* Forwarddeclarations for nested functions are not "external",

1930       but we need to treat them asif 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 outputanything when a tentative file-scope definition

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

1941  

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

1943         callgraph code to defer themexcept for forward declarations

1944         (seegcc.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      structcgraph_varpool_node *node = cgraph_varpool_node(decl);

584   

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

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

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

588        if this functionhas 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 (/* Externallyvisible variables must be output. The exception are

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

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

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

603            It ispossible to assemble the name later after finalizing the function

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

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

 

原创粉丝点击