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

GCC-3.4.6源代码学习笔记(142-续1)

2011-01-15 11:03 381 查看
好了,现在让我们看一下
GCC
对我们例
1
的输出。


1


Vtable for C

C::_ZTV1C: 12u entries

0
0u
// vbase offset

4
0u
// vcall offset

8
(int (*)(...))0

12
(int (*)(...))(& _ZTI1C)

16
C
::_ZTcv0_n12_v0_n16_N1C1fEv
// slot for C::B1::A::f

20
C
::f
// slot for C::f

24
-4u

28
-4u

32
(int (*)(...))-0x000000004

36
(int (*)(...))(& _ZTI1C)

40
C
::_ZTcvn4_n12_v0_n16_N1C1fEv
// slot for C::B2::A::f

44
C
::_ZTchn4_h4_N1C1fEv
// slot for C::B2::f

… // no VTT for A

VTT for B1

B1::_ZTT2B1:
2u entries

0
((& B1::_ZTV2B1) + 16u)

4
((& B1::_ZTV2B1) + 16u)



VTT for B2

B2::_ZTT2B2:
2u entries

0
((& B2::_ZTV2B2) + 16u)

4
((& B2::_ZTV2B2) + 16u)



Construction
vtable for B1 (0xb7f2d980 instance)
in C

C::_ZTC1C0_2B1: 6u
entries

0
0u

4
0u

8
(int (*)(...))0

12
(int (*)(...))(& _ZTI2B1)

16
B1::_ZTcv0_n12_v0_n16_N2B11fEv
// C::B1::f

20
B1::f

Construction
vtable for B2 (0xb7f2da00
instance) in C

C::_ZTC1C4_2B2: 10u
entries

0
-4u

4
0u

8
(int (*)(...))0

12
(int (*)(...))(& _ZTI2B2)

16
B2::_ZTcv0_n12_v0_n16_N2B21fEv
// C::B2::f

20
B2::f

24
4u

28
(int (*)(...))4

32
(int (*)(...))(& _ZTI2B2)

36
B2::_ZTcv0_n12_v0_n16_N2B21fEv
// C::B2::f

VTT for C

C::_ZTT1C: 7u entries

0
((& C::_ZTV1C) + 16u)
// vptr for C

4
((& C::_ZTC1C0_2B1) + 16u)
// construction vtable used for B1

8
((& C::_ZTC1C0_2B1) + 16u)
// construction vtable used for B1::A

12
((& C::_ZTC1C4_2B2) + 16u)
// construction vtable used for B2

16
((& C::_ZTC1C4_2B2) + 36u)
// construction vtable used for B2::A

20
((& C::_ZTV1C) + 16u)

// vptr for
secondary vtable of B2

24
((& C::_ZTV1C) + 40u)
// vptr for secondary vtable of A

VTT
的构造由下面的函数完成。

6829

static
void

6830

build_vtt

(tree t)

in
class.c

6831

{

6832

tree inits;

6833

tree type;

6834

tree vtt;

6835

tree index;

6836

6837

/* Build up the
initializers for the VTT.
*/

6838

inits = NULL_TREE;

6839

index = size_zero_node;

6840

build_vtt_inits
(TYPE_BINFO (t), t, &inits, &index);

6841

6842

/* If we didn't
need a VTT, we're done.
*/

6843

if (!inits)

6844

return
;

6845

6846

/* Figure out the
type of the VTT.
*/

6847

type = build_index_type
(size_int (list_length (inits) - 1));

6848

type = build_cplus_array_type
(const_ptr_type_node, type);

6849

6850

/* Now, build the
VTT object itself.
*/

6851

vtt = build_vtable
(t, get_vtt_name (t), type);

6852

initialize_array
(vtt, inits);

6853

/* Add the VTT to
the vtables list.

*/

6854

TREE_CHAIN (vtt) = TREE_CHAIN (CLASSTYPE_VTABLES (t));

6855

TREE_CHAIN (CLASSTYPE_VTABLES (t)) = vtt;

6856

6857

dump_vtt (t, vtt);

6858

}

在我们的例子中

对于类
B1

B2

C

VTT
是期望的

其主体由下面的
build_vtt_init

构建。其中参数
binfo

是最后派生类的
binfo

t

是最后派生类


index

是在
VTT
中最后占用的索引。

6892

static
tree *

6893

build_vtt_inits

(tree binfo, tree t,
tree* inits, tree* index)
in

class.c

6894

{

6895

int i;

6896

tree b;

6897

tree init;

6898

tree secondary_vptrs;

6899

int top_level_p = same_type_p (TREE_TYPE
(binfo), t);

6900

6901

/* We only need VTTs
for subobjects with virtual bases.
*/

6902

if (!TYPE_USES_VIRTUAL_BASECLASSES
(BINFO_TYPE (binfo)))

6903

return
inits;

6904

6905

/* We need to use a
construction vtable if this is not the primary

6906

VTT.
*/

6907

if (!top_level_p)

6908

{

6909

build_ctor_vtbl_group
(binfo, t);

6910

6911

/* Record the
offset in the VTT where this sub-VTT can be found.
*/

6912

BINFO_SUBVTT_INDEX (binfo) = *index;

6913

}

6914

6915

/* Add the address
of the primary vtable for the complete object.

*/

6916

init = binfo_ctor_vtable
(binfo);

6917

*inits = build_tree_list (NULL_TREE, init);

6918

inits = &TREE_CHAIN (*inits);

6919

if (top_level_p)

6920

{

6921

my_friendly_assert (!BINFO_VPTR_INDEX
(binfo), 20010129);

6922

BINFO_VPTR_INDEX
(binfo) = *index;

6923

}

6924

*index = size_binop (PLUS_EXPR, *index,
TYPE_SIZE_UNIT (ptr_type_node));

6925

6926

/* Recursively add
the secondary VTTs for non-virtual bases.

*/

6927

for
(i = 0; i < BINFO_N_BASETYPES (binfo); ++i)

6928

{

6929

b = BINFO_BASETYPE (binfo, i);

6930

if (!TREE_VIA_VIRTUAL (b))

6931

inits = build_vtt_inits
(BINFO_BASETYPE (binfo, i), t,

6932

inits, index);

6933

}

在前一节中,类的
BINFO_VTABLE

dfs_accumulate_vtbl_inits

中设置了
vtable
初始值。它是一个
PLUS_EXPR
,指定了作为
vtable
开头的初始值的位置。在上面的
6916
行,
binfo_ctor_vtable

从类得到这个表达式。

6865

static
tree

6866

binfo_ctor_vtable

(tree binfo)
in

class.c

6867

{

6868

tree vt;

6869

6870

while
(1)

6871

{

6872

vt = BINFO_VTABLE (binfo);

6873

if (TREE_CODE (vt) == TREE_LIST)

6874

vt = TREE_VALUE (vt);

6875

if (TREE_CODE (vt) == TREE_VEC)

6876

binfo = vt;

6877

else

6878

break
;

6879

}

6880

6881

return
vt;

6882

}

在上面的
6917
行,由
binfo_ctor_vtable

返回的
init

被构建入一个
tree_list
;而在
6918
行,
inits

又指向了这个
tree_list

chain

域的地址,那么在
6931
行递归进入这个函数时,将继续往这个链表上添加节点。上面的参数
index


VTT
中下一个成员的索引(它也是字节数),一开始它为
size_zero_node




6922
行的
BINFO_VPTR_INDEX
保存了
VTT
的索引,在那里可以找到该子对象的虚指针。对于最后派生类
C
,其虚指针在
VTT
索引为
0
的地方。首先,对非虚拟基类,
build_ctor_vtbl_group

执行以下的处理。

7098

static
void

7099

build_ctor_vtbl_group

(tree binfo, tree
t)
in

class.c

7100

{

7101

tree list;

7102

tree type;

7103

tree vtbl;

7104

tree inits;

7105

tree id;

7106

tree vbase;

7107

7108

/* See if we've
already created this construction vtable group.

*/

7109

id = mangle_ctor_vtbl_for_type (t, binfo);

7110

if (IDENTIFIER_GLOBAL_VALUE (id))

7111

return
;

7112

7113

my_friendly_assert (!same_type_p (BINFO_TYPE
(binfo), t), 20010124);

7114

/* Build a version
of VTBL (with the wrong type) for use in

7115

constructing the addresses of
secondary vtables in the

7116

construction vtable
group.
*/

7117

vtbl = build_vtable
(t, id, ptr_type_node);

7118

list = build_tree_list (vtbl, NULL_TREE);

7119

accumulate_vtbl_inits
(binfo, TYPE_BINFO (TREE_TYPE (binfo)),

7120

binfo, t, list);

7121

7122

/* Add the vtables
for each of our virtual bases using the vbase in T

7123

binfo.

*/

7124

for
(vbase = TYPE_BINFO (BINFO_TYPE (binfo));

7125

vbase;

7126

vbase = TREE_CHAIN (vbase))

7127

{

7128

tree b;

7129

7130

if (!TREE_VIA_VIRTUAL (vbase))

7131

continue
;

7132

b = copied_binfo
(vbase, binfo);

7133

7134

accumulate_vtbl_inits
(b, vbase, binfo, t, list);

7135

}

7136

inits = TREE_VALUE (list);

7137

7138

/* Figure out the
type of the construction vtable.
*/

7139

type = build_index_type
(size_int (list_length (inits) - 1));

7140

type = build_cplus_array_type
(vtable_entry_type, type);

7141

TREE_TYPE (vtbl) = type;

7142

7143

/* Initialize the
construction vtable.

*/

7144

CLASSTYPE_VTABLES (t) = chainon (CLASSTYPE_VTABLES (t), vtbl);

7145

initialize_array

(vtbl, inits);

7146

dump_vtable (t, binfo, vtbl);

7147

}

在上面的
7109


mangle_ctor_vtbl_for_type

返回用于链接目的的
vtable
修饰名。接着的断言确保只有基类才会进入这个函数。然后一个新构建的
vtable
对象被封装入一个
tree_list
节点,并在
7119
行作为最后的参数传给下面的函数。注意
rtti_binfo

是合资格直接基类的
binfo
,该函数将为这个基类准备初始值。

这里,
accumulate_vtbl_inits

按前序的次序处理感兴趣的基类及它的非虚拟基类,然后在
build_ctor_vblt_group

中,以在派生树中出现的次序,调用该函数处理基类的虚拟基类。出于方便,我们在下面重新显示相关的函数。

7159

static
void

7160

accumulate_vtbl_inits
(tree binfo,
in

class.c

7161

tree orig_binfo,

7162

tree rtti_binfo,

7163

tree t,

7164

tree inits)

7165

{

7166

int i;

7167

int ctor_vtbl_p = !same_type_p (BINFO_TYPE
(rtti_binfo), t);

7168

7169

my_friendly_assert (same_type_p (BINFO_TYPE
(binfo),

7170

BINFO_TYPE (orig_binfo)),

7171

20000517);

7172

7173

/* If it doesn't
have a vptr, we don't do anything.
*/

7174

if (!TYPE_CONTAINS_VPTR_P (BINFO_TYPE
(binfo)))

7175

return
;

7176

7177

/* If we're
building a construction vtable, we're not interested in

7178

subobjects that don't require
construction vtables.
*/

7179

if (ctor_vtbl_p

7180

&& !TYPE_USES_VIRTUAL_BASECLASSES
(BINFO_TYPE (binfo))

7181

&& !binfo_via_virtual (orig_binfo, BINFO_TYPE (rtti_binfo)))

7182

return
;

7183

7184

/* Build the
initializers for the BINFO-in-T vtable.
*/

7185

TREE_VALUE (inits)

7186

= chainon (TREE_VALUE (inits),

7187

dfs_accumulate_vtbl_inits

(binfo, orig_binfo,

7188

rtti_binfo, t, inits));

7189

7190

/* Walk the BINFO
and its bases. We walk in preorder so that as we

7191

initialize each vtable we can
figure out at what offset the

7192

secondary vtable lies from the
primary vtable. We can't use

7193

dfs_walk here because we need
to iterate through bases of BINFO

7194

and RTTI_BINFO
simultaneously.
*/

7195

for
(i = 0; i
< BINFO_N_BASETYPES (binfo); ++i)

7196

{

7197

tree base_binfo = BINFO_BASETYPE (binfo,
i);

7198

7199

/* Skip virtual
bases.
*/

7200

if (TREE_VIA_VIRTUAL (base_binfo))

7201

continue
;

7202

accumulate_vtbl_inits

(base_binfo,

7203

BINFO_BASETYPE (orig_binfo, i),

7204

rtti_binfo, t,

7205

inits);

7206

}

7207

}

这一次

上面
7167
行的
ctor_vtbl_p


true

因为参数
t

总是指向最后派生类


rtti_binfo

总是其基类。
7179
行的条件滤除不从虚拟基类派生的非虚拟基类。

7212

static
tree

7213

dfs_accumulate_vtbl_inits
(tree binfo,
in

class.c

7214

tree orig_binfo,

7215

tree rtti_binfo,

7216

tree t,

7217

tree l)

7218

{

7219

tree inits = NULL_TREE;

7220

tree vtbl = NULL_TREE;

7221

int ctor_vtbl_p = !same_type_p (BINFO_TYPE
(rtti_binfo), t);

7222

7223

if (ctor_vtbl_p

7224

&& TREE_VIA_VIRTUAL (orig_binfo)
&& BINFO_PRIMARY_P (orig_binfo))

7225

{

7226

/* In the
hierarchy of BINFO_TYPE (RTTI_BINFO), this is a

7227

primary virtual base. If it is not the same
primary in

7228

the hierarchy of T, we'll need to generate a
ctor vtable

7229

for it, to place at its location in T. If it
is the same

7230

primary, we still need a VTT entry for the
vtable, but it

7231

should point to the ctor vtable for the base
it is a

7232

primary for within the sub-hierarchy of
RTTI_BINFO.

7233

7234

There are three possible cases:

7235

7236

1) We are in the same place.

7237

2) We are a primary base within a lost primary
virtual base of

7238

RTTI_BINFO.

7239

3) We are primary to something not a base of
RTTI_BINFO.
*/

7240

7241

tree b = BINFO_PRIMARY_BASE_OF (binfo);

7242

tree last = NULL_TREE;

7243

7244

/* First, look
through the bases we are primary to for RTTI_BINFO

7245

or a virtual base.
*/

7246

for
(; b; b
= BINFO_PRIMARY_BASE_OF (b))

7247

{

7248

last = b;

7249

if
(TREE_VIA_VIRTUAL (b) || b == rtti_binfo)

7250

break
;

7251

}

7252

/* If we run out
of primary links, keep looking down our

7253

inheritance chain; we might be an indirect
primary.
*/

7254

if (b == NULL_TREE)

7255

for
(b =
last; b; b = BINFO_INHERITANCE_CHAIN (b))

7256

if (TREE_VIA_VIRTUAL (b) || b == rtti_binfo)

7257

break
;

7258

7259

/* If we found RTTI_BINFO, this is case 1. If
we found a virtual

7260

base B and it is a base of
RTTI_BINFO, this is case 2. In

7261

either case, we share our vtable with LAST,
i.e. the

7262

derived-most base within B of which we are a
primary.
*/

7263

if (b == rtti_binfo

7264

||
(b && purpose_member (BINFO_TYPE (b),

7265

CLASSTYPE_VBASECLASSES (BINFO_TYPE
(rtti_binfo)))))

7266

/* Just set our
BINFO_VTABLE to point to LAST, as we may not have

7267

set LAST's BINFO_VTABLE yet. We'll extract
the actual vptr in

7268

binfo_ctor_vtable after everything's been
set up.
*/

7269

vtbl = last;

7270

7271

/* Otherwise, this is case 3 and we get our
own.
*/

7272

}

7273

else if (!BINFO_NEW_VTABLE_MARKED
(orig_binfo))

7274

return
inits;

7275

7276

if (!vtbl)

7277

{

7278

tree index;

7279

int non_fn_entries;

7280

7281

/* Compute the initializer for this
vtable.
*/

7282

inits = build_vtbl_initializer
(binfo, orig_binfo, t, rtti_binfo,

7283

&non_fn_entries);

7284

7285

/* Figure out the
position to which the VPTR should point.

*/

7286

vtbl = TREE_PURPOSE (l);

7287

vtbl = build1
(ADDR_EXPR,

7288

vtbl_ptr_type_node,

7289

vtbl);

7290

TREE_CONSTANT (vtbl) = 1;

7291

index = size_binop (PLUS_EXPR,

7292

size_int (non_fn_entries),

7293

size_int (list_length (TREE_VALUE (l))));

7294

index = size_binop (MULT_EXPR,

7295

TYPE_SIZE_UNIT (vtable_entry_type),

7296

index);

7297

vtbl = build
(PLUS_EXPR, TREE_TYPE (vtbl), vtbl, index);

7298

TREE_CONSTANT (vtbl) = 1;

7299

}

7300

7301

if (ctor_vtbl_p)

7302

/* For a
construction vtable, we can't overwrite BINFO_VTABLE.

7303

So, we make a TREE_LIST.
Later, dfs_fixup_binfo_vtbls will

7304

straighten this out.
*/

7305

BINFO_VTABLE (binfo) = tree_cons
(rtti_binfo, vtbl, BINFO_VTABLE (binfo));

7306

else if (BINFO_PRIMARY_P (binfo) &&
TREE_VIA_VIRTUAL (binfo))

7307

inits = NULL_TREE;

7308

else

7309

/* For an
ordinary vtable, set BINFO_VTABLE.
*/

7310

BINFO_VTABLE (binfo) = vtbl;

7311

7312

return
inits;

7313

}

参数
orig_binfo

应该总是指向感兴趣基类类型的
binfo
。而在
7273
行的断言
BINFO_NEW_VTABLE_MARKED
返回
true
,如果类型有属于自己的
vtable
。现在
rtti_binfo

是感兴趣直接基类的
binfo
。在我们的例子里,当处理
C
时,
B1

B2
就是这样的基类。而
t

指向最后派生类的
binfo
,在我们的例子中,它是类
C
。另外
binfo

是正在处理的基类的
binfo


这里当
accumulate_vtbl_inits

处理
B1
时,在
dfs_accumulate_vtbl_inits


7224
行条件,
TREE_VIA_VIRTUAL

BINFO_PRIMARY_P
对于
orig_binfo

都是不成立的(这里是
B1

binfo
);而在
7273
行的条件,
orig_binfo

显然具有自己的
vtable
,该条件亦不成立。因此将进入
7276
行的
IF
块,这里面的处理在前一节已经看过,大同小异。因为
ctor_vtbl_p


true
,因而
7305
行得到执行,注意
binfo


B1-in-C

binfo
,它的
BINFO_VTABLE

NULL
。因为这里得到的
vtable
是构造(
construction

vtable
,它只能暂时借用
BINFO_VTABLE
,所以把它构建入一个
tree_list
。为之配合的函数有:
binfo_ctor_vtable


dfs_fixup_binfo_vtbls




7119
行,当从
accumulate_vtbl_inits

退出时,例
1

B1-in-C
应该在其构造(
construction

vtable
里,具有如下的项(保存在
build_ctor_vtbl_group


7118
行的
list


TREE_PURPOSE
域,及
BINFO_VTABLE (B1-in-C

binfo)
)。

Construction
vtable for B1 (0xb7f2d980
instance) in C

C::_ZTC1C0_2B1: 6u
entries

0
0u

4
0u

8
(int (*)(...))0

12
(int (*)(...))(& _ZTI2B1)

16
B1::_ZTcv0_n12_v0_n16_N2B11fEv
// slot of
B1::A::f

20
B1::f
// slot of B1::f

接着在
7134
行对
accumulate_vtbl_inits

的调用中,
binfo


C::B1

binfo
,而
7124
行获得了类型
B1

binfo
,因此
vbase


B1::A

binfo
,而
b


C::B1::A

binfo
,而
t

仍然是类型
C
。它们被传递给
dfs_accumulate_vtbl_inits

,按如下的映射关系:
binfo


b

),
orig_binfo


vbase

),
rtti_binfo


binfo

)及
t


t

)。

那么
7223
行条件满足。在
7241
行,
b


C::B1

binfo
;而
last


7248
行得到
C::B1

binfo
。结果
vtbl


7269
行被设置为
C::B1

binfo
。最后,在
7305
行,
BINFO_VTABLE (C::B1::A

binfo)
被加入一个包含
C::B1

binfo

tree_list
节点。并且为
NULL

inits

被返回。

不过对于
B2-in-C
,事情稍有不同。同样在
7119
行退出
accumulate_vtbl_inits

时,例
1
中的
B2-in-C
应该在其构造(
construction

vtable
里,具有如下的项(保存在
build_ctor_vtbl_group


7118
行的
list


TREE_PURPOSE
域)。

Construction
vtable for B2 (0xb7f2da00 instance)
in C

C::_ZTC1C4_2B2: 10u
entries

0
-4u

4
0u

8
(int (*)(...))0

12
(int (*)(...))(& _ZTI2B2)

16
B2::_ZTcv0_n12_v0_n16_N2B21fEv

20
B2::f
// slot of B2::f

但在为
B2::A
调用的
dfs_accumulate_vtbl_inits

中,
binfo


C::B2

binfo
(参数:
rtti_binfo

),
vbase


B2::A

binfo
(参数:
orig_binfo

),
b


C::B2::A

binfo
(参数:
binfo

),
t


C
(参数:
t

)。

那么在
7241
行,
b

这次是
C::B2

binfo
;而在
7248
行的
last

得到
NULL
,因为它沿着路径
A
à

B1
à

C
攀升。因此在
7276
行的条件中,
vtbl

保持为
NULL
。因而为
B2::A
产生的构造(
construction

vtable
具有如下的项:

24
4u
// part of A in B2 - begin

28
(int (*)(...))4

32
(int (*)(...))(& _ZTI2B2)

36
B2::_ZTcv0_n12_v0_n16_N2B21fEv
// part of A
in B2 - end


build_ctor_vtbl_group


7140
行为这些构造(
construction

vtable
重新构建了数组类型。接着在
7144
行,这个用于基类构造的
vtable
串接入最后派生类的
CLASSTYPE_VTABLES
。而在
7145
行的
initialize_array


vtable
项确切的类型准备初始值。


build_ctor_vtbl_group

回到
build_vtt_inits

时,
6916
行的
binfo_ctor_vtable


C::B1
得到
C::B1
的构造(
construction

vtable

index

1
)。

6927
行的
FOR

循环对于
B1

B2
不做任何事,那么我们来到下面的代码。

build_vtt_inits (continue)

6935

/* Add secondary
virtual pointers for all subobjects of BINFO with

6936

either virtual bases or
reachable along a virtual path, except

6937

subobjects that are
non-virtual primary bases.
*/

6938

secondary_vptrs = tree_cons (t, NULL_TREE,
BINFO_TYPE (binfo));

6939

TREE_TYPE (secondary_vptrs) = *index;

6940

VTT_TOP_LEVEL_P (secondary_vptrs) =
top_level_p;

6941

VTT_MARKED_BINFO_P (secondary_vptrs) = 0;

6942

6943

dfs_walk_real
(binfo,

6944

dfs_build_secondary_vptr_vtt_inits
,

6945

NULL,

6946

dfs_ctor_vtable_bases_queue_p,

6947

secondary_vptrs);

6948

VTT_MARKED_BINFO_P (secondary_vptrs) = 1;

6949

dfs_walk (binfo, dfs_unmark,
dfs_ctor_vtable_bases_queue_p,

6950

secondary_vptrs);

6951

6952

*index = TREE_TYPE (secondary_vptrs);

6953

6954

/* The secondary
vptrs come back in reverse order. After we reverse

6955

them, and add the INITS, the
last init will be the first element

6956

of the chain.
*/

6957

secondary_vptrs = TREE_VALUE
(secondary_vptrs);

6958

if (secondary_vptrs)

6959

{

6960

*inits = nreverse (secondary_vptrs);

6961

inits = &TREE_CHAIN (secondary_vptrs);

6962

my_friendly_assert (*inits == NULL_TREE,
20000517);

6963

}

6964

6965

/* Add the
secondary VTTs for virtual bases.
*/

6966

if (top_level_p)

6967

for
(b =
TYPE_BINFO (BINFO_TYPE (binfo)); b; b = TREE_CHAIN (b))

6968

{

6969

if (!TREE_VIA_VIRTUAL (b))

6970

continue
;

6971

6972

inits = build_vtt_inits
(b, t, inits, index);

6973

}

6974

6975

if (!top_level_p)

6976

{

6977

tree data = tree_cons (t, binfo,
NULL_TREE);

6978

VTT_TOP_LEVEL_P (data) = 0;

6979

VTT_MARKED_BINFO_P (data) = 0;

6980

6981

dfs_walk (binfo, dfs_fixup_binfo_vtbls
,

6982

dfs_ctor_vtable_bases_queue_p,

6983

data);

6984

}

6985

6986

return
inits;

6987

}

上面的
secondary_vptrs

正如其名字所表示的,是在最后派生类的
VTT
中指向次要
vtable
的指针;而
index

指出这个指针所在的
VTT
的项。在
6943
行的遍历从
binfo

所指定的基类
binfo
开始(这里,即是
C::B1

binfo

C::B2

binfo
),并步入这个节点。下面的函数则以前序的次序处理访问的节点,看到参数
data


secondary_vptrs



6996

static
tree

6997

dfs_build_secondary_vptr_vtt_inits

(tree
binfo, void* data)
in

class.c

6998

{

6999

tree l;

7000

tree t;

7001

tree init;

7002

tree index;

7003

int top_level_p;

7004

7005

l = (tree) data;

7006

t = TREE_CHAIN (l);

7007

top_level_p = VTT_TOP_LEVEL_P (l);

7008

7009

BINFO_MARKED (binfo) = 1;

7010

7011

/* We don't care
about bases that don't have vtables.
*/

7012

if (!TYPE_VFIELD (BINFO_TYPE (binfo)))

7013

return
NULL_TREE;

7014

7015

/* We're only
interested in proper subobjects of T.
*/

7016

if (same_type_p (BINFO_TYPE (binfo), t))

7017

return
NULL_TREE;

7018

7019

/* We're not
interested in non-virtual primary bases.

*/

7020

if (!TREE_VIA_VIRTUAL (binfo) &&
BINFO_PRIMARY_P (binfo))

7021

return
NULL_TREE;

7022

7023

/* If BINFO has virtual
bases or is reachable via a virtual path

7024

from T, it'll have a
secondary vptr.
*/

7025

if (!TYPE_USES_VIRTUAL_BASECLASSES
(BINFO_TYPE (binfo))

7026

&& !binfo_via_virtual (binfo, t))

7027

return
NULL_TREE;

7028

7029

/* Record the index
where this secondary vptr can be found.

*/

7030

index = TREE_TYPE (l);

7031

if (top_level_p)

7032

{

7033

my_friendly_assert (!BINFO_VPTR_INDEX
(binfo), 20010129);

7034

BINFO_VPTR_INDEX
(binfo) = index;

7035

}

7036

TREE_TYPE (l) = size_binop (PLUS_EXPR, index,

7037

TYPE_SIZE_UNIT (ptr_type_node));

7038

7039

/* Add the
initializer for the secondary vptr itself.

*/

7040

if (top_level_p && TREE_VIA_VIRTUAL
(binfo))

7041

{

7042

/* It's a primary virtual base, and this is
not the construction

7043

vtable. Find the base this
is primary of in the inheritance graph,

7044

and use that base's vtable
now.
*/

7045

while
(BINFO_PRIMARY_BASE_OF (binfo))

7046

binfo = BINFO_PRIMARY_BASE_OF (binfo);

7047

}

7048

init =
binfo_ctor_vtable

(binfo);

7049

TREE_VALUE (l) = tree_cons (NULL_TREE, init,
TREE_VALUE (l));

7050

7051

return
NULL_TREE;

7052

}

当遍历以
C::B1

binfo
为根的子树时,上面的
top_level_p


false

7006
行的
t

是类型
B1
。这个节点被跳过,因为满足
7016
行的条件;在访问
C::B1::A

binfo
时,在
7048
行,因为
C::B1::A

binfo

BINFO_VTABLE
中保存的是
C::B1

binfo

binfo_ctor_vtable

辗转地再一次获得了
C::B1
的构造(
construction

vtable
(保存在
index

2
的位置)。注意到这个函数总是返回
NULL
,它将强制进行整棵子树的遍历。

记得在
dfs_accumulate_vtbl_inits


7305
行,构造(
construction

vtable
暂时栖身在
BINFO_VTABLE
中。现在构造(
construction

vtable
已经记录在
VTT
中,不再需要在
BINFO_VTABLE
里混了。现在要通过尝试把
BINFO_VTABLE
恢复过来。注意其参数
data
的构成,在我们这里,上面由
C::B1::A
暂存的节点被移走了(对
C::B2
则是
C::B2::A
)。

7075

static
tree

7076

dfs_fixup_binfo_vtbls

(tree binfo, void*
data)
in

class.c

7077

{

7078

BINFO_MARKED (binfo) = 0;

7079

7080

/* We don't care
about bases that don't have vtables.
*/

7081

if (!TYPE_VFIELD (BINFO_TYPE (binfo)))

7082

return
NULL_TREE;

7083

7084

/* If we scribbled
the construction vtable vptr into BINFO, clear it

7085

out now.
*/

7086

if (BINFO_VTABLE (binfo)

7087

&& TREE_CODE (BINFO_VTABLE
(binfo)) == TREE_LIST

7088

&& (TREE_PURPOSE (BINFO_VTABLE
(binfo))

7089

== TREE_VALUE ((tree) data)))

7090

BINFO_VTABLE (binfo) = TREE_CHAIN
(BINFO_VTABLE (binfo));

7091

7092

return
NULL_TREE;

7093

}

回过去看上面提到的
C::B2
的处理,在其
build_ctor_vtbl_group

返回到
build_vtt_inits

时,其构造(
construction

vtable
被保存在
VTT

index

3
的地方。而在其后对
C::B2

dfs_build_secondary_vptr_vtt_inits

的调用中,在
7048
行,
binfo_ctor_vtable

得到了
B2::A
的构造(
construction

vtable

index

4
)。

当完成了
B1

B2
的处理后,在
build_vtt_inits


6938
行,继续处理
C
。在
6943
行,开始遍历以
C
为根节点的派生树。那么在
dfs_build_secondary_vptr_vtt_inits

中,
top_level_p


true

t

是最后派生类
C
。在这个前序遍历中,
C
满足
7016
行条件,
C::B1
满足
7020
行条件,退出该函数。对于
C::B2

VTT
的索引
5
被置为
C::B2

vptr
,而其
vtable
(这是个次要
vtable
)的初始值则是上一节中得到的
BINFO_VTABLE(C::B2)
;同样对于
C::B1::A
,它的
vptr

VTT
索引为
6
的地方,其
vtable
(也是次要
vtable
)的初始值也是前一节中保存在
BINFO_VTABLE(A-in-C)
的内容。
C::B2::A
跳过,因为
A
已经在
C::B1::A
中访问了。


build_vtt_inits


6972
行,最后处理
A
,不过因为
A
不包含虚拟基类,
build_vtt_inits

对它不做处理。

回到
build_vtt

,如果处理成功,
inits

不为
NULL
。接下来就是为
VTT
构建正确的类型,及
VTT
类型的静态成员对象,并且把这个
VTT
对象置入最后派生类
CLASSTYPE_VTABLES
的链头。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: