您的位置:首页 > 编程语言

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

中移走,同时强制进行下一次的迭代。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: