GCC-3.4.6源代码学习笔记(156)
2011-02-02 09:45
381 查看
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
中移走,同时强制进行下一次的迭代。
相关文章推荐
- GCC-3.4.6源代码学习笔记(93)
- GCC-3.4.6源代码学习笔记(63)
- GCC-3.4.6源代码学习笔记(67)
- GCC-3.4.6源代码学习笔记 (100)
- GCC-3.4.6源代码学习笔记(146)
- GCC-3.4.6源代码学习笔记(71)
- GCC-3.4.6源代码学习笔记(19续)
- GCC-3.4.6源代码学习笔记(41)
- GCC-3.4.6源代码学习笔记(120)
- GCC-3.4.6源代码学习笔记(151)
- GCC-3.4.6源代码学习笔记(81)
- GCC-3.4.6源代码学习笔记(84)
- GCC-3.4.6源代码学习笔记(112)
- GCC-3.4.6源代码学习笔记(89)
- GCC-3.4.6源代码学习笔记(169)
- GCC-3.4.6源代码学习笔记(94)
- GCC-3.4.6源代码学习笔记(142)
- GCC-3.4.6源代码学习笔记(38)
- GCC-3.4.6源代码学习笔记(75)
- GCC-3.4.6源代码学习笔记(134)