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

来源:互联网 发布:norse attack map源码 编辑:程序博客网 时间:2024/06/08 09:23

 

layout_class_type (continue)

 

4664     /* Create a pointerto our virtual function table.  */

4665     vptr = create_vtable_ptr(t, virtuals_p);

4666  

4667    /* The vptr isalways the first thing in the class.  */

4668     if (vptr)

4669     {

4670       TREE_CHAIN (vptr) = TYPE_FIELDS (t);

4671       TYPE_FIELDS (t) = vptr;

4672       next_field = &TREE_CHAIN (vptr);

4673       place_field(rli, vptr);

4674     }

4675     else

4676       next_field = &TYPE_FIELDS (t);

 

回到layout_class_type,在对类进行了完整性检查并确定了主要基类后,编译器为vptr的生成做准备。这里在create_vtable_ptr中,参数virtuals_p来自finish_struct_1里的局部变量virtuals,参数t是类本身。注意到TYPE_VFIELD (t)不是空的,如果它的主要基类含有vptr(它在set_primary_base中设置)。因此只要该类能从其主要基类中得到TYPE_VFIELD,就不需要为其创建vptr

4328行的FOR循环对于vtable的构建是非常关键的,它把由该类声明的所有的虚函数拷贝到另一个链表virtual_p,并且注意4245行的赋值,被拷贝函数的BV_DELTA被设为0BV_DELTA代表当调用该虚函数时,需要从this指针减去的字节数【这时得到声明该虚函数的基类this指针】)。

DECL_VINDEXFUNCTION_DECL中有两个用途。在包含该FUNCTION_DECL的类被编排前,DECL_VINDEX可能指向一个基类中的一个FUNCTION_DECL,它是当前的FUNCTION_DECL作为虚函数所要替代的。当类编排后,这个指针就改为一个INTEGER_CST节点,用作虚函数表的索引。那么对于未编排类的FUNCTION_DECL,它们被记录在virtual_p所指向的tree_list中。

 

4232   static tree

4233   create_vtable_ptr (tree t, tree*virtuals_p)                                                         inclass.c

4234   {

4235     tree fn;

4236  

4237    /* Collect thevirtual functions declared in T.  */

4238     for (fn =TYPE_METHODS (t); fn; fn = TREE_CHAIN (fn))

4239       if (DECL_VINDEX (fn)&& !DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (fn)

4240          && TREE_CODE (DECL_VINDEX (fn))!= INTEGER_CST)

4241       {

4242         tree new_virtual = make_node(TREE_LIST);

4243       

4244         BV_FN (new_virtual) = fn;

4245        BV_DELTA (new_virtual) = integer_zero_node;

4246  

4247         TREE_CHAIN (new_virtual) = *virtuals_p;

4248         *virtuals_p = new_virtual;

4249       }

4250    

4251     /* If we couldn'tfind an appropriate base class, create a new field

4252       here. Even if there weren'tany new virtual functions, we might need a

4253       new virtual function table ifwe're supposed to include vptrs in

4254       all classes that needthem.  */

4255     if (!TYPE_VFIELD (t) && (*virtuals_p|| TYPE_CONTAINS_VPTR_P (t)))

4256     {

4257       /* We build thisdecl with vtbl_ptr_type_node, which is a

4258         `vtable_entry_type*'. Itmight seem more precise to use

4259         `vtable_entry_type (*)[N]'where N is the number of firtual

4260         functions. However, thatwould require the vtable pointer in

4261         base classes to have adifferent type than the vtable pointer

4262         in derived classes. We could make that happen,but that

4263         still wouldn't solve all theproblems. In particular, the

4264         type-based alias analysiscode would decide that assignments

4265         to the base class vtablepointer can't alias assignments to

4266         the derived class vtable pointer, sincethey have different

4267         types. Thus, in a derivedclass destructor, where the base

4268         class constructor wasinlined, we could generate bad code for

4269         setting up the vtablepointer. 

4270  

4271         Therefore, we use one typefor all vtable pointers. We still

4272         use a type-correct type;it's just doesn't indicate the array

4273         bounds. That's better thanusing `void*' or some such; it's

4274         cleaner, and it let's the aliasanalysis code know that these

4275         stores cannot alias storesto void*!  */

4276       tree field;

4277  

4278       field = build_decl(FIELD_DECL, get_vfield_name (t), vtbl_ptr_type_node);

4279       SET_DECL_ASSEMBLER_NAME (field,get_identifier (VFIELD_BASE));

4280       DECL_VIRTUAL_P (field) = 1;

4281       DECL_ARTIFICIAL (field) = 1;

4282       DECL_FIELD_CONTEXT (field) = t;

4283       DECL_FCONTEXT (field) = t;

4284        

4285       TYPE_VFIELD (t) = field;

4286        

4287       /* This class isnon-empty.  */

4288       CLASSTYPE_EMPTY_P (t) = 0;

4289  

4290       if (CLASSTYPE_N_BASECLASSES (t))

4291         /* If therewere any baseclasses, they can't possibly be at

4292           offset zero any more,because that's where the vtable

4293           pointer is. So, convertingto a base class is going to

4294           take work.  */

4295         TYPE_BASE_CONVS_MAY_REQUIRE_CODE_P (t) =1;

4296  

4297       returnfield;

4298     }

4299  

4300     returnNULL_TREE;

4301   }

 

如果主要基类没有vtable(或者压根没有主要基类),但派生类本身有虚函数,那么在这里编译器为其生成。在4279行的VFIELD_BASE是字符串“$vf”。而在4295行,如果类有基类,编译器还将需要产生转换操作符来执行派生类到基类间的转换。在4278行,在cxx_init_decl_processingvtbl_ptr_type_node被初始化为vtable_entry_type*,也即具有类型int(*)()

看到在layout_class_type4673行,如果要新建vtable,调用place_field首先在类里布局这个vtable

 

layout_class_type (continue)

 

4678     /* BuildFIELD_DECLs for all of the non-virtual base-types.  */

4679     empty_base_offsets = splay_tree_new(splay_tree_compare_integer_csts,

4680                                     NULL, NULL);

4681     build_base_fields(rli, empty_base_offsets, next_field);

 

而对于其他部分,一棵伸展树(splaying treeempty_base_offsets被创建在布局过程中保存空基类的偏移量。把这个伸展树作为offsets实参,build_base_fields开始布局类的基类。

 

3729   static void

3730   build_base_fields (record_layout_inforli,                                                    inclass.c

3731                   splay_tree offsets, tree*next_field)

3732   {

3733     /* Chain to holdall the new FIELD_DECLs which stand in for base class

3734       subobjects. */

3735    tree t = rli->t;

3736    int n_baseclasses = CLASSTYPE_N_BASECLASSES (t);

3737     int i;

3738  

3739     /* The primary baseclass is always allocated first.  */

3740     if (CLASSTYPE_HAS_PRIMARY_BASE_P (t))

3741       next_field = build_base_field(rli, CLASSTYPE_PRIMARY_BINFO (t),

3742                                offsets,next_field);

3743  

3744    /* Now allocate therest of the bases.  */

3745     for (i = 0; i < n_baseclasses; ++i)

3746     {

3747       tree base_binfo;

3748  

3749       base_binfo = BINFO_BASETYPE (TYPE_BINFO(t), i);

3750  

3751       /* The primarybase was already allocated above, so we don't

3752         need to allocate it againhere.  */

3753       if (base_binfo == CLASSTYPE_PRIMARY_BINFO(t))

3754         continue;

3755  

3756       /* Virtual basesare added at the end (a primary virtual base

3757         will have already beenadded).  */

3758       if (TREE_VIA_VIRTUAL (base_binfo))

3759         continue;

3760  

3761       next_field = build_base_field(rli, base_binfo,

3762                                offsets,next_field);

3763     }

3764   }

 

看到主要基类是首先被布局的(不管它是否是虚拟基类)——这就是为什么它被称为主要基类。然后其他基类按继承顺序处理。注意在3758行的条件,看到非主要虚拟基类不在这里编排,而是在后面的layout_virtual_bases里。

接着编译器要为这些基类构建对应的域,这样可以在派生类中采用统一的访问方式。

 

3628   static tree *

3629   build_base_field (record_layout_info rli,tree binfo,                                     inclass.c

3630                  splay_tree offsets, tree*next_field)

3631   {

3632     tree t = rli->t;

3633     tree basetype = BINFO_TYPE (binfo);

3634  

3635     if (!COMPLETE_TYPE_P (basetype))

3636       /* This error isnow reported in xref_tag, thus giving better

3637         location information.  */

3638       returnnext_field;

3639    

3640     /* Place the baseclass.  */

3641     if (!is_empty_class (basetype))

3642     {

3643       tree decl;

3644  

3645       /* The containingclass is non-empty because it has a non-empty

3646         base class.  */

3647       CLASSTYPE_EMPTY_P (t) = 0;

3648        

3649       /* Create theFIELD_DECL.  */

3650       decl = build_decl (FIELD_DECL, NULL_TREE, CLASSTYPE_AS_BASE(basetype));

3651       DECL_ARTIFICIAL (decl) = 1;

3652       DECL_FIELD_CONTEXT (decl) = t;

3653       DECL_SIZE (decl) = CLASSTYPE_SIZE(basetype);

3654       DECL_SIZE_UNIT (decl) = CLASSTYPE_SIZE_UNIT(basetype);

3655       DECL_ALIGN (decl) = CLASSTYPE_ALIGN(basetype);

3656       DECL_USER_ALIGN (decl) =CLASSTYPE_USER_ALIGN (basetype);

3657       DECL_IGNORED_P (decl) = 1;

3658  

3659       /* Try to place the field. It may take morethan one try if we

3660         have a hard time placing thefield without putting two

3661         objects of the same type atthe same address.  */

3662       layout_nonempty_base_or_field(rli, decl, binfo, offsets);

3663       /* Add the newFIELD_DECL to the list of fields for T. */

3664       TREE_CHAIN (decl) = *next_field;

3665       *next_field = decl;

3666       next_field = &TREE_CHAIN (decl);

3667     }

 

3650行的CLASSTYPE_AS_BASE给出了basetype作为基类的类型(后面在layout_class_type中,我们将看到这是个什么类型)。这些代表着基类的域,在派生类中如同其他普通域那样,需要布局,确定其位置。

 

3461   static void

3462   layout_nonempty_base_or_field (record_layout_info rli,                              in class.c

3463                              tree decl,

3464                              tree binfo,

3465                              splay_tree offsets)

3466   {

3467     tree offset = NULL_TREE;

3468     bool field_p;    

3469     tree type;

3470    

3471     if (binfo)

3472     {

3473       /* For thepurposes of determining layout conflicts, we want to

3474         use the class type of BINFO;TREE_TYPE (DECL) will be the

3475         CLASSTYPE_AS_BASE version,which does not contain entries for

3476         zero-sized bases.  */

3477       type = TREE_TYPE (binfo);

3478       field_p = false;

3479     }

3480     else

3481     {

3482       type = TREE_TYPE (decl);

3483       field_p = true;

3484     }

3485  

3486     /* Try to place thefield. It may take more than one try if we have

3487       a hard time placing the field without puttingtwo objects of the

3488       same type at the sameaddress.  */

3489     while (1)

3490     {

3491       structrecord_layout_info_s old_rli = *rli;

3492  

3493       /* Place thisfield.  */

3494       place_field(rli, decl);

3495       offset = byte_position(decl);

3496  

3497       /* We have tocheck to see whether or not there is already

3498         something of the same typeat the offset we're about to use.

3499         For example, consider:

3500       

3501          struct S {};

3502          struct T : public S { inti; };

3503          struct U : public S, publicT {};

3504       

3505         Here, we put S at offset zero in U. Then,we can't put T at

3506         offset zero -- its Scomponent would be at the same address

3507         as the S we alreadyallocated. So, we have to skip ahead.

3508         Since all data members,including those whose type is an

3509         empty class, have nonzerosize, any overlap can happen only

3510         with a direct or indirectbase-class -- it can't happen with

3511         a data member. */

3512       /* In a union,overlap is permitted; all members are placed at

3513         offset zero.  */

3514       if (TREE_CODE (rli->t) == UNION_TYPE)

3515         break;

3516       /* G++ 3.2 didnot check for overlaps when placing a non-empty

3517         virtual base.  */

3518       if (!abi_version_at_least (2) &&binfo && TREE_VIA_VIRTUAL (binfo))

3519         break;

3520       if (layout_conflict_p(field_p ? type : binfo, offset,

3521                         offsets, field_p))

3522       {

3523         /* Strip offthe size allocated to this field. That puts us

3524           at the first place wecould have put the field with

3525           proper alignment.  */

3526        *rli = old_rli;

3527  

3528         /* Bump up bythe alignment required for the type.  */

3529        rli->bitpos

3530           = size_binop (PLUS_EXPR, rli->bitpos,

3531                        bitsize_int (binfo

3532                                  ?CLASSTYPE_ALIGN (type)

3533                                  : TYPE_ALIGN(type)));

3534         normalize_rli(rli);

3535       }

3536       else

3537         /* There was noconflict. We're done laying out this field. */

3538         break;

3539     }

3540  

3541     /* Now that we knowwhere it will be placed, update its

3542       BINFO_OFFSET.  */

3543     if (binfo && CLASS_TYPE_P (BINFO_TYPE(binfo)))

3544       /* Indirectvirtual bases may have a nonzero BINFO_OFFSET at

3545         this point because theirBINFO_OFFSET is copied from another

3546         hierarchy. Therefore, we maynot need to add the entire

3547         OFFSET. */

3548       propagate_binfo_offsets (binfo,

3549                            size_diffop (convert(ssizetype, offset),

3550                            convert (ssizetype,

3551                                   BINFO_OFFSET(binfo))));

3552   }

 

RECORD_TYPE中的FIELD_DECL一节中已经给出了域布置的细节,它给处理的域填充DECL_FIELD_OFFSET(以字节为单位的偏移量)及DECL_FIELD_BIT_OFFSET(以比特为单位的偏移量),并在3530行更新rlibitpos域,以显示到类头部偏移的比特数(注意它不总是等于刚布置域的DECL_FIELD_BIT_OFFSET,因为可能有填充字节)。

 

1175   tree

1176   byte_position (tree field)                                                                                  intree.c

1177   {

1178     returnbyte_from_pos (DECL_FIELD_OFFSET (field),

1179                       DECL_FIELD_BIT_OFFSET (field));

1180   }

 

C++里,在布局过程中,空的基类可能不占空间。例如:

class A {}; sizeof (A)给出1,但在以下的语句中:

class B: publicA { public:int temp; };

class C { public:int temp; }; sizeof(B)sizeof(C)都给出了4

另外还有class D: public A, C {}; sizeof (D)亦给出了4。空类A不占空间,基类C可以与A共享同一个偏移位置。但是class D {A a; C c}; sizeof (D) 则给出了8。空类A与类C独自占有自己的空间。出现这种差异的根本原因在于,基类的布局首先考虑非空的基类,然后到空的基类,再到虚拟基类;但域的布局必须按照声明的次序。为了检验新布置的域是否与已有的域发生冲突,调用函数layout_conflict_p

 

3434   static int

3435   layout_conflict_p (tree type,                                                                      inclass.c

3436                  tree offset,

3437                  splay_tree offsets,

3438                  int vbases_p)

3439   {

3440     splay_tree_node max_node;

3441  

3442     /* Get the node inOFFSETS that indicates the maximum offset where

3443       an empty subobject islocated.  */

3444     max_node = splay_tree_max (offsets);

3445     /* If there aren'tany empty subobjects, then there's no point in

3446       performing this check.  */

3447     if (!max_node)

3448       return 0;

3449  

3450     return walk_subobject_offsets (type, check_subobject_offset, offset,

3451                              offsets, (tree)(max_node->key),

3452                              vbases_p);

3453   }

 

我们略过伸展树(splay tree)的细节。大致的,在这棵伸展树中,其节点以偏移量来排序(保存在key域中),具有同一偏移量的类域(field)或基类被链接在同一个树节点的value域中。在3444行,splay_tree_max返回当前已布置的最大偏移。这个偏移量划定了walk_subobject_offsets的查找范围。而函数check_subobject_offset给定一个偏移量,检查该位置是否已经放置了同样的一个类型。如果是,表明发生冲突,返回1

 

3193   static int

3194   check_subobject_offset (tree type, treeoffset, splay_tree offsets)                inclass.c

3195   {

3196     splay_tree_node n;

3197     tree t;

3198  

3199     if (!is_empty_class (type))

3200       return 0;

3201  

3202     /* Record thelocation of this empty object in OFFSETS. */

3203     n = splay_tree_lookup (offsets,(splay_tree_key) offset);

3204     if (!n)

3205       return 0;

3206  

3207     for (t =(tree) n->value; t; t = TREE_CHAIN (t))

3208       if (same_type_p (TREE_VALUE (t), type))

3209         return 1;

3210  

3211     return 0;

3212   }

 

在调用walk_subobject_offsets时的参数type可以是binfo(基类),或者是RECORD_TYPE(类类型的域(field)),或者内建类型。这3种情况并无本质的差别。注意这个时候,该type对象已经在前面由place_fields做了布局。

 

3225   static int

3226   walk_subobject_offsets (tree type,                                                            inclass.c

3227                       subobject_offset_fn f,

3228                       tree offset,

3229                       splay_tree offsets,

3230                       tree max_offset,

3231                       int vbases_p)

3232   {

3233    int r = 0;

3234     tree type_binfo = NULL_TREE;

3235  

3236    /* If this OFFSET isbigger than the MAX_OFFSET, then we should

3237       stop.  */

3238     if (max_offset && INT_CST_LT(max_offset, offset))

3239       return 0;

3240  

3241     if (!TYPE_P (type))

3242     {

3243       if (abi_version_at_least (2))

3244        type_binfo = type;

3245      type = BINFO_TYPE (type);

3246     }

3247  

3248     if (CLASS_TYPE_P (type))

3249     {

3250       tree field;

3251       tree binfo;

3252       int i;

3253  

3254       /* Avoidrecursing into objects that are not interesting.  */

3255       if (!CLASSTYPE_CONTAINS_EMPTY_CLASS_P(type))

3256         return 0;

3257  

3258       /* Record the location of TYPE.  */

3259       r = (*f) (type, offset, offsets);

3260       if (r)

3261         return r;

3262  

3263       /* Iteratethrough the direct base classes of TYPE. */

3264      if (!type_binfo)

3265        type_binfo = TYPE_BINFO (type);

3266       for (i = 0; i < BINFO_N_BASETYPES (type_binfo);++i)

3267      {

3268        tree binfo_offset;

3269  

3270        binfo = BINFO_BASETYPE (type_binfo, i);

3271  

3272         if (abi_version_at_least (2)

3273             && TREE_VIA_VIRTUAL (binfo))

3274           continue;

3275  

3276         if (!vbases_p

3277           && TREE_VIA_VIRTUAL (binfo)

3278           && !BINFO_PRIMARY_P (binfo))

3279           continue;

3280  

3281         if (!abi_version_at_least (2))

3282           binfo_offset = size_binop (PLUS_EXPR,

3283                                 offset,

3284                                 BINFO_OFFSET(binfo));

3285        else

3286        {

3287          tree orig_binfo;

3288           /* We cannotrely on BINFO_OFFSET being set for the base

3289             class yet, but theoffsets for direct non-virtual

3290             bases can be calculatedby going back to the TYPE.  */

3291          orig_binfo = BINFO_BASETYPE (TYPE_BINFO (type), i);

3292          binfo_offset = size_binop (PLUS_EXPR,        

3293                                 offset,

3294                                 BINFO_OFFSET(orig_binfo));

3295         }

3296  

3297         r = walk_subobject_offsets(binfo,

3298                                f,

3299                                binfo_offset,

3300                                offsets,

3301                                max_offset,

3302                                (abi_version_at_least (2)

3303                                ? /*vbases_p=*/0: vbases_p));

3304         if (r)

3305           returnr;

3306       }

3307  

3308       if (abi_version_at_least (2))

3309       {

3310         tree vbase;

3311  

3312         /* Iterate through the virtual base classes ofTYPE. In G++

3313           3.2, we included virtualbases in the direct base class

3314           loop above, which resultsin incorrect results; the

3315           correct offsets forvirtual bases are only known when

3316           working with the mostderived type.  */

3317         if (vbases_p)

3318           for(vbase = CLASSTYPE_VBASECLASSES (type);

3319               vbase;

3320               vbase = TREE_CHAIN (vbase))

3321           {

3322             binfo = TREE_VALUE (vbase);

3323             r = walk_subobject_offsets(binfo,

3324                                    f,

3325                                    size_binop(PLUS_EXPR,

3326                                             offset,

3327                                             BINFO_OFFSET (binfo)),

3328                                    offsets,

3329                                    max_offset,

3330                                    /*vbases_p=*/0);

3331             if (r)

3332               returnr;

3333           }

3334         else

3335         {

3336           /* We stillhave to walk the primary base, if it is

3337             virtual. (If it isnon-virtual, then it was walked

3338             above.)  */

3339           vbase = get_primary_binfo(type_binfo);

3340           if (vbase && TREE_VIA_VIRTUAL(vbase)

3341              && BINFO_PRIMARY_BASE_OF(vbase) == type_binfo)

3342           {

3343             r = (walk_subobject_offsets

3344                      (vbase, f, offset,

3345                       offsets, max_offset, /*vbases_p=*/0));

3346             if (r)

3347               returnr;

3348           }

3349         }

3350       }

3351  

3352       /* Iteratethrough the fields of TYPE.  */

3353       for (field= TYPE_FIELDS (type); field; field = TREE_CHAIN (field))

3354         if (TREE_CODE (field) == FIELD_DECL&& !DECL_ARTIFICIAL (field))

3355         {

3356           tree field_offset;

3357  

3358           if (abi_version_at_least (2))

3359             field_offset = byte_position (field);

3360           else

3361             /* In G++3.2, DECL_FIELD_OFFSET was used.  */

3362             field_offset = DECL_FIELD_OFFSET(field);

3363  

3364           r = walk_subobject_offsets(TREE_TYPE (field),

3365                                  f,

3366                                  size_binop(PLUS_EXPR,

3367                                           offset,

3368                                           field_offset),

3369                                  offsets,

3370                                  max_offset,

3371                                 /*vbases_p=*/1);

3372           if (r)

3373             returnr;

3374         }

3375     }

3376     else if (TREE_CODE (type) == ARRAY_TYPE)

3377     {

3378       tree element_type = strip_array_types(type);

3379       tree domain = TYPE_DOMAIN (type);

3380       tree index;

3381  

3382       /* Avoidrecursing into objects that are not interesting.  */

3383       if (!CLASS_TYPE_P (element_type)

3384           || !CLASSTYPE_CONTAINS_EMPTY_CLASS_P(element_type))

3385         return 0;

3386  

3387       /* Step througheach of the elements in the array.  */

3388       for (index= size_zero_node;

3389            /* G++ 3.2had an off-by-one error here.  */

3390            (abi_version_at_least (2)

3391               ? !INT_CST_LT (TYPE_MAX_VALUE(domain), index)

3392               : INT_CST_LT (index, TYPE_MAX_VALUE(domain)));

3393            index = size_binop (PLUS_EXPR, index,size_one_node))

3394       {

3395         r = walk_subobject_offsets(TREE_TYPE (type),

3396                                f,

3397                                offset,

3398                                offsets,

3399                                max_offset,

3400                                /*vbases_p=*/1);

3401         if (r)

3402           returnr;

3403         offset = size_binop (PLUS_EXPR, offset,

3404                          TYPE_SIZE_UNIT(TREE_TYPE (type)));

3405         /* If this newOFFSET is bigger than the MAX_OFFSET, then

3406           there's no point initerating through the remaining

3407           elements of thearray.  */

3408         if (max_offset && INT_CST_LT(max_offset, offset))

3409           break;

3410       }

3411     }

3412  

3413     return 0;

3414   }

 

上面的abi_version_at_least (2)返回非0值,如果G++是不早于3.4.0的版本。3312行的注释解释了G++3.4.0之后及之前版本间的差别。类的非直接基类的偏移量通过其在该基类的偏移量加上基类的偏移量得到。并且这个处理适用于非虚拟基类及类域(field)。

非空类型不在考虑之列,因为它们必定要独占一个空间。如果指定位置已经放置了同一类型的对象,layout_conflict_p返回1,这将使得偏移量上浮到基类的下一个对齐地址边界(对于类类型,对齐量通常是4字节)。

而在build_base_field中,空类具有特殊的处理。下面的rli_size_unit_so_far计算出已经布置的对象或域的字节大小(忽略多余的比特)因此eoc是最靠近已布局大小的对齐边界。

 

build_base_field (continue)

 

3668     else

3669     {

3670       tree eoc;

3671       bool atend;

3672  

3673       /* On someplatforms (ARM), even empty classes will not be

3674         byte-aligned.  */

3675       eoc = round_up (rli_size_unit_so_far (rli),

3676                     CLASSTYPE_ALIGN_UNIT(basetype));

3677       atend = layout_empty_base(binfo, eoc, offsets);

3678       /* A nearly-emptyclass "has no proper base class that is empty,

3679         not morally virtual, and atan offset other than zero."  */

3680       if (!TREE_VIA_VIRTUAL (binfo) &&CLASSTYPE_NEARLY_EMPTY_P (t))

3681       {

3682         if (atend)

3683           CLASSTYPE_NEARLY_EMPTY_P (t) = 0;

3684         /* The checkabove (used in G++ 3.2) is insufficient because

3685           an empty class placed atoffset zero might itself have an

3686           empty base at a nonzerooffset.  */

3687         else if (walk_subobject_offsets(basetype,

3688                                  empty_base_at_nonzero_offset_p,

3689                                   size_zero_node,

3690                                  /*offsets=*/NULL,

3691                                   /*max_offset=*/NULL_TREE,

3692                                   /*vbases_p=*/true))

3693         {

3694           if (abi_version_at_least (2))

3695             CLASSTYPE_NEARLY_EMPTY_P (t) = 0;

3696           else if (warn_abi)

3697             warning ("class `%T' will beconsidered nearly empty in a "

3698                     "future version ofGCC", t);

3699         }

3700       }

3701       

3702       /* We do notcreate a FIELD_DECL for empty base classes because

3703         it might overlap some otherfield. We want to be able to

3704         create CONSTRUCTORs for theclass by iterating over the

3705         FIELD_DECLs, and the backend does not handle overlapping

3706         FIELD_DECLs.  */

3707  

3708       /* An emptyvirtual base causes a class to be non-empty

3709         -- but in that case we donot need to clear CLASSTYPE_EMPTY_P

3710         here because that wasalready done when the virtual table

3711         pointer was created.  */

3712    }

3713  

3714     /* Record theoffsets of BINFO and its base subobjects. */

3715     record_subobject_offsets(binfo,

3716                          BINFO_OFFSET (binfo),

3717                          offsets,

3718                         /*vbases_p=*/0);

3719  

3720     returnnext_field;

3721   }

 

空的基类最好能放在偏移量为0(因为它们可以和主要基类共享空间)。在G++v.3.4,版本以后,空的基类总是被强制放在偏移量为0的地方。

 

3570   static bool

3571   layout_empty_base (tree binfo, tree eoc,splay_tree offsets)                         inclass.c

3572   {

3573     tree alignment;

3574     tree basetype = BINFO_TYPE (binfo);

3575     bool atend = false;

3576  

3577     /* This routineshould only be used for empty classes. */

3578     my_friendly_assert (is_empty_class(basetype), 20000321);

3579     alignment = ssize_int (CLASSTYPE_ALIGN_UNIT(basetype));

3580  

3581     if (!integer_zerop (BINFO_OFFSET (binfo)))

3582     {

3583       if (abi_version_at_least (2))

3584         propagate_binfo_offsets

3585               (binfo, size_diffop(size_zero_node, BINFO_OFFSET (binfo)));

3586       else if (warn_abi)

3587         warning ("offset of empty base `%T'may not be ABI-compliant and may"

3588                 "change in a future versionof GCC",

3589                 BINFO_TYPE (binfo));

3590     }

3591    

3592     /* This is an emptybase class. We first try to put it at offset

3593       zero.  */

3594     if (layout_conflict_p(binfo,

3595                       BINFO_OFFSET (binfo),

3596                       offsets,

3597                       /*vbases_p=*/0))

3598     {

3599       /* That didn'twork. Now, we move forward from the next

3600         available spot in theclass.  */

3601       atend = true;

3602       propagate_binfo_offsets(binfo, convert (ssizetype, eoc));

3603       while (1)

3604       {

3605         if (!layout_conflict_p(binfo,

3606                           BINFO_OFFSET (binfo),

3607                           offsets,

3608                           /*vbases_p=*/0))

3609           /* We finallyfound a spot where there's no overlap. */

3610           break;

3611  

3612         /* There'soverlap here, too. Bump along to the next spot. */

3613         propagate_binfo_offsets(binfo, alignment);

3614       }

3615     }

3616     return atend;

3617   }

 

如果偏移量为0的地方已经被同样的类型占据了,这个空的基类就要被放在上面计算出来的偏移量为eoc的地方。如果eoc也被占据了,把偏移量加上对齐量再尝试,直到这个空的基类可以被放置。注意到如果该空的基类不能放在偏移量为0的地方,该函数返回非0值。这时,即便该类包含的只是空基类,也被视为非空。不过即便该空基类被放在偏移量为0的位置,这也不保证该类是空的。考虑以下例子:

class A {};

class B: public A {};

class C: public A, B {};

基类B可以放在C中偏移量为0的地方,但是它的基类A不能放在偏移量为0的地方,因为C的基类A已经在那里了。C,按上面的规则,是非空类。empty_base_at_nonzero_offset_p检查是否有空基类具有非0的偏移量。

3702行的注释解释了为什么不能为空的基类构建FIELD_DECL节点。最后,在解决了冲突之后,需要以下函数把偏移量更新入伸展树。

 

3420   static void

3421   record_subobject_offsets (tree type,                                                                inclass.c

3422                        tree offset,

3423                        splay_tree offsets,

3424                        int vbases_p)

3425   {

3426     walk_subobject_offsets(type, record_subobject_offset, offset,

3427                         offsets, /*max_offset=*/NULL_TREE, vbases_p);

3428   }

 

注意我们仅记录空基类的偏移量。

 

3168   static int

3169   record_subobject_offset (tree type, treeoffset, splay_tree offsets)                      inclass.c

3170   {

3171     splay_tree_node n;

3172  

3173     if (!is_empty_class (type))

3174       return 0;

3175  

3176     /* Record thelocation of this empty object in OFFSETS. */

3177     n = splay_tree_lookup (offsets,(splay_tree_key) offset);

3178     if (!n)

3179       n = splay_tree_insert (offsets,

3180                         (splay_tree_key) offset,

3181                         (splay_tree_value) NULL_TREE);

3182     n->value = ((splay_tree_value)

3183                         tree_cons (NULL_TREE,

3184                                  type,

3185                                  (tree)n->value));

3186  

3187     return 0;

3188   }

 

在放置了所有的基类之后,接着是数据成员。记得对于非空基类,它们的FIELD_DECL被创建并位于non_static_data_members之前链入TYPE_FIELDS链,因此下面的FOR循环将不会再访问这些FIELD_DECL

 

原创粉丝点击