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
的链头。
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
的链头。
相关文章推荐
- GCC-3.4.6源代码学习笔记(142)
- GCC-3.4.6源代码学习笔记(47)
- GCC-3.4.6源代码学习笔记(64)
- GCC-3.4.6源代码学习笔记(15)
- GCC-3.4.6源代码学习笔记(173)
- GCC-3.4.6源代码学习笔记(177)
- GCC-3.4.6源代码学习笔记(159)
- GCC-3.4.6源代码学习笔记(6)
- GCC-3.4.6源代码学习笔记(110)
- GCC-3.4.6源代码学习笔记(28)
- GCC-3.4.6源代码学习笔记 当前目录
- GCC-3.4.6源代码学习笔记(141-续1)
- GCC-3.4.6源代码学习笔记(95)
- GCC-3.4.6源代码学习笔记(62)
- GCC-3.4.6源代码学习笔记(96)
- GCC-3.4.6源代码学习笔记(34)
- GCC-3.4.6源代码学习笔记(170)
- GCC-3.4.6源代码学习笔记(149)
- GCC-3.4.6源代码学习笔记(20)
- GCC-3.4.6源代码学习笔记(73)