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 }
看到对于每个基本类型,需要产生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 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指向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 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_hash是cgraph_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为代表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 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_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 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机器上的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 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_p是false,结果仅是把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_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 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_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中移走,同时强制进行下一次的迭代。
- GCC-3.4.6源代码学习笔记(156)
- GCC-3.4.6源代码学习笔记 (100)
- GCC-3.4.6源代码学习笔记 (101)
- GCC-3.4.6源代码学习笔记 (102)
- GCC-3.4.6源代码学习笔记 (103)
- GCC-3.4.6源代码学习笔记 (104)
- GCC-3.4.6源代码学习笔记 (105)
- GCC-3.4.6源代码学习笔记 (106)
- GCC-3.4.6源代码学习笔记(166)
- GCC-3.4.6源代码学习笔记
- GCC-3.4.6源代码学习笔记(6)
- GCC-3.4.6源代码学习笔记(1)
- GCC-3.4.6源代码学习笔记(2)
- GCC-3.4.6源代码学习笔记(3)
- GCC-3.4.6源代码学习笔记(4)
- GCC-3.4.6源代码学习笔记(5)
- GCC-3.4.6源代码学习笔记(7)
- GCC-3.4.6源代码学习笔记(8)
- 手把手教你制作手机离线地图
- 指针的指针--------二级指针(做一下总结,免得忘了)
- 【每天读一点英文】gnuhpc注释版:The True Nobility
- GCC-3.4.6源代码学习笔记(155)
- Studying note of GCC-3.4.6 source (155)
- GCC-3.4.6源代码学习笔记(156)
- Studying note of GCC-3.4.6 source (156)
- 【每天读一点英文】gnuhpc:The World As I See It(节选)
- 分形艺术网贺岁图集很有新意的新年礼物!
- 做事
- java的几种引用类型
- sql server image type
- 用Java语言编写一个绘图项目的完整过程
- 推荐书目 byr