您的位置:首页 > 产品设计 > UI/UE

Studying note of GCC-3.4.6 source (162 - continue)

2011-02-19 11:44 337 查看
At line 5350 current_class_ptr

is the PARM_DECL for the `this'
pointer, when we're processing a member function. See that in below only the type
of instance

can be known for sure it returns non-null. Compared with condition at line
5281, which indicates a pointer, and in C++, it can be variant types in the
class hierarchy to support polymorphism. So it has to return NULL_TREE as
result.

5275

static
tree

5276

fixed_type_or_null

(tree instance, int*
nonnull, int* cdtorp)
in
class.c

5277

{

5278

switch
(TREE_CODE (instance))

5279

{

5280

case
INDIRECT_REF:

5281

if (POINTER_TYPE_P (TREE_TYPE (instance)))

5282

return
NULL_TREE;

5283

else

5284

return
fixed_type_or_null
(TREE_OPERAND
(instance, 0),

5285

nonnull, cdtorp);

5286

5287

case
CALL_EXPR:

5288

/* This is a
call to a constructor, hence it's never zero.

*/

5289

if (TREE_HAS_CONSTRUCTOR (instance))

5290

{

5291

if (nonnull)

5292

*nonnull = 1;

5293

return
TREE_TYPE (instance);

5294

}

5295

return
NULL_TREE;

5296

5297

case
SAVE_EXPR:

5298

/* This is a
call to a constructor, hence it's never zero.

*/

5299

if (TREE_HAS_CONSTRUCTOR (instance))

5300

{

5301

if (nonnull)

5302

*nonnull = 1;

5303

return
TREE_TYPE (instance);

5304

}

5305

return
fixed_type_or_null
(TREE_OPERAND (instance, 0),
nonnull, cdtorp);

5306

5307

case
RTL_EXPR:

5308

return
NULL_TREE;

5309

5310

case
PLUS_EXPR:

5311

case
MINUS_EXPR:

5312

if (TREE_CODE (TREE_OPERAND (instance,
0)) == ADDR_EXPR)

5313

return
fixed_type_or_null
(TREE_OPERAND
(instance, 0), nonnull, cdtorp);

5314

if (TREE_CODE (TREE_OPERAND (instance,
1)) == INTEGER_CST)

5315

/* Propagate
nonnull.
*/

5316

return
fixed_type_or_null
(TREE_OPERAND
(instance, 0), nonnull, cdtorp);

5317

return
NULL_TREE;

5318

5319

case
NOP_EXPR:

5320

case
CONVERT_EXPR:

5321

return
fixed_type_or_null
(TREE_OPERAND (instance, 0),
nonnull, cdtorp);

5322

5323

case
ADDR_EXPR:

5324

if (nonnull)

5325

*nonnull = 1;

5326

return
fixed_type_or_null
(TREE_OPERAND (instance, 0),
nonnull, cdtorp);

5327

5328

case
COMPONENT_REF:

5329

return
fixed_type_or_null
(TREE_OPERAND (instance, 1),
nonnull, cdtorp);

5330

5331

case
VAR_DECL:

5332

case
FIELD_DECL:

5333

if (TREE_CODE (TREE_TYPE (instance)) ==
ARRAY_TYPE

5334

&& IS_AGGR_TYPE (TREE_TYPE
(TREE_TYPE (instance))))

5335

{

5336

if (nonnull)

5337

*nonnull = 1;

5338

return
TREE_TYPE (TREE_TYPE (instance));

5339

}

5340

/* fall through...
*/

5341

case
TARGET_EXPR:

5342

case
PARM_DECL:

5343

case
RESULT_DECL:

5344

if (IS_AGGR_TYPE (TREE_TYPE (instance)))

5345

{

5346

if (nonnull)

5347

*nonnull = 1;

5348

return
TREE_TYPE (instance);

5349

}

5350

else if (instance == current_class_ptr

)

5351

{

5352

if (nonnull)

5353

*nonnull = 1;

5354

5355

/* if we're in a ctor or dtor, we know our
type.
*/

5356

if (DECL_LANG_SPECIFIC (current_function_decl

)

5357

&& (DECL_CONSTRUCTOR_P (current_function_decl

)

5358

|| DECL_DESTRUCTOR_P (current_function_decl

)))

5359

{

5360

if (cdtorp)

5361

*cdtorp = 1;

5362

return
TREE_TYPE (TREE_TYPE (instance));

5363

}

5364

}

5365

else if (TREE_CODE (TREE_TYPE (instance))
== REFERENCE_TYPE)

5366

{

5367

/* Reference
variables should be references to objects.

*/

5368

if (nonnull)

5369

*nonnull = 1;

5370

5371

/*
DECL_VAR_MARKED_P is used to prevent recursion; a

5372

variable's initializer
may refer to the variable

5373

itself.
*/

5374

if (TREE_CODE (instance) == VAR_DECL

5375

&& DECL_INITIAL (instance)

5376

&& !DECL_VAR_MARKED_P
(instance))

5377

{

5378

tree type;

5379

DECL_VAR_MARKED_P (instance) = 1;

5380

type = fixed_type_or_null
(DECL_INITIAL (instance),

5381

nonnull,
cdtorp);

5382

DECL_VAR_MARKED_P (instance) = 0;

5383

return
type;

5384

}

5385

}

5386

return
NULL_TREE;

5387

5388

default
:

5389

return
NULL_TREE;

5390

}

5391

}

Arriving here, fixed_type_p

is 0 if type of expr

is unknown for certainty
(polymorphism may be in used), or is -1 if expr

is constructor or destructor, otherwise is 1
as type is known for certainty. And v_binfo

is not NULL if there is virtual base involved.

build_base_path (continue)

293

if (want_pointer && !nonnull)

294

null_test = build (EQ_EXPR,
boolean_type_node, expr, integer_zero_node);

295

296

offset = BINFO_OFFSET (binfo);

If no vritual base found, offset

gotten at line 296 is all wanted. Code in
below then generates the expression (taking example 4 as instance in pseudo
code):

*(&b +
offset (A));

And if b

originally is a pointer, it will generate code to guard NULL
pointer too as below (taking example 5 as instance):

pa? (pa +
offset (A)) : 0;

build_base_path (continue)

350

target_type = code == PLUS_EXPR ?
BINFO_TYPE (binfo) : BINFO_TYPE (d_binfo);

351

352

target_type = cp_build_qualified_type

353

(target_type, cp_type_quals (TREE_TYPE
(TREE_TYPE (expr))));

354

ptr_target_type = build_pointer_type
(target_type);

355

if (want_pointer)

356

target_type = ptr_target_type;

357

358

expr = build1
(NOP_EXPR, ptr_target_type, expr);

359

360

if (!integer_zerop (offset))

361

expr = build
(code,
ptr_target_type, expr, offset);

362

else

363

null_test = NULL;

364

365

if (!want_pointer)

366

expr = build_indirect_ref
(expr, NULL);

367

368

if (null_test)

369

expr = build
(COND_EXPR, target_type, null_test,

370

build1
(NOP_EXPR, target_type, integer_zero_node),

371

expr);

372

373

return
expr;

374

}

However, if the conversion involves virtual base and expr

’s
dynamic type isn’t the same as static type, offset

gotten at line 296 is just the beginning.

build_base_path (continue)

298

if (v_binfo && fixed_type_p <= 0)

299

{

300

/* Going via
virtual base V_BINFO. We need the static offset

301

from V_BINFO to
BINFO, and the dynamic offset from D_BINFO to

302

V_BINFO. That
offset is an entry in D_BINFO's vtable.

*/

303

tree v_offset;

304

305

if (fixed_type_p < 0 && in_base_initializer

)

306

{

307

/* In a base
member initializer, we cannot rely on

308

the vtable
being set up. We have to use the vtt_parm.

*/

309

tree derived = BINFO_INHERITANCE_CHAIN
(v_binfo);

310

311

v_offset = build
(PLUS_EXPR, TREE_TYPE (current_vtt_parm

),

312

current_vtt_parm

, BINFO_VPTR_INDEX
(derived));

313

314

v_offset = build1
(INDIRECT_REF,

315

TREE_TYPE (TYPE_VFIELD
(BINFO_TYPE (derived))),

316

v_offset);

317

318

}

319

else

320

v_offset = build_vfield_ref
(build_indirect_ref (expr, NULL),

321

TREE_TYPE
(TREE_TYPE (expr)));

322

323

v_offset = build
(PLUS_EXPR, TREE_TYPE (v_offset),

324

v_offset,
BINFO_VPTR_FIELD (v_binfo));

325

v_offset = build1
(NOP_EXPR,

326

build_pointer_type (ptrdiff_type_node

),

327

v_offset);

328

v_offset = build_indirect_ref

(v_offset, NULL);

329

330

offset = convert_to_integer (ptrdiff_type_node

,

331

size_diffop (offset,

332

BINFO_OFFSET (v_binfo)));

333

334

if (!integer_zerop (offset))

335

v_offset = build
(code, ptrdiff_type_node

,
v_offset, offset);

336

337

if (fixed_type_p < 0)

338

/* Negative
fixed_type_p means this is a constructor or destructor;

339

virtual base layout is fixed in in-charge
[cd]tors, but not in

340

base
[cd]tors.
*/

341

offset = build

(COND_EXPR, ptrdiff_type_node

,

342

build

(EQ_EXPR, boolean_type_node,

343

current_in_charge_parm

, integer_zero_node),

344

v_offset,

345

BINFO_OFFSET (binfo));

346

else

347

offset = v_offset;

348

}

If there is virtual base between and it must use vtable to do the
conversion between the derived and the base, above at line 305 in

_base_initializer

is nonzero if it
is handling a base initializer, for which case vtable is not created. So it
needs use the placeholder current_vtt_parm

to indicate to involvement of
the vtable.

Function build_indirect_ref

builds INDIRECT_REF for
pointer type or reference type. For example, if p

is a pointer, then the
INDIRECT_REF node stands for the expression “*p”.

2028

tree

2029

build_indirect_ref
(tree ptr, const
char *errorstring)
in typeck.c

2030

{

2031

tree pointer, type;

2032

2033

if (ptr == error_mark_node)

2034

return
error_mark_node;

2035

2036

if (ptr == current_class_ptr

)

2037

return
current_class_ref

;

2038

2039

pointer = (TREE_CODE (TREE_TYPE (ptr)) ==
REFERENCE_TYPE

2040

? ptr : decay_conversion (ptr));

2041

type = TREE_TYPE (pointer);

2042

2043

if (TYPE_PTR_P (type) || TREE_CODE (type) ==
REFERENCE_TYPE)

2044

{

2045

/* [expr.unary.op]

2046

2047

If the type of the
expression is "pointer to T," the type

2048

of the result is
"T."

2049

2050

We must use the canonical
variant because certain parts of

2051

the back end, like fold, do
pointer comparisons between

2052

types.
*/

2053

tree t = canonical_type_variant (TREE_TYPE
(type));

2054

2055

if (VOID_TYPE_P (t))

2056

{

2057

/* A pointer to
incomplete type (other than cv void) can be

2058

dereferenced
[expr.unary.op]/1
*/

2059

error ("`%T' is not a
pointer-to-object type", type);

2060

return
error_mark_node;

2061

}

2062

else if (TREE_CODE (pointer) == ADDR_EXPR

2063

&& same_type_p (t, TREE_TYPE
(TREE_OPERAND (pointer, 0))))

2064

/* The POINTER
was something like `&x'.
We simplify
`*&x' to

2065

`x'.
*/

2066

return
TREE_OPERAND (pointer, 0);

2067

else

2068

{

2069

tree ref = build1
(INDIRECT_REF, t, pointer);

2070

2071

/* We *must*
set TREE_READONLY when dereferencing a pointer to const,

2072

so that we get the proper
error message if the result is used

2073

to assign to. Also, &*
is supposed to be a no-op.
*/

2074

TREE_READONLY (ref) = CP_TYPE_CONST_P
(t);

2075

TREE_THIS_VOLATILE (ref) =
CP_TYPE_VOLATILE_P (t);

2076

TREE_SIDE_EFFECTS (ref)

2077

= (TREE_THIS_VOLATILE (ref) ||
TREE_SIDE_EFFECTS (pointer));

2078

return
ref;

2079

}

2080

}

2081

/* `pointer' won't
be an error_mark_node if we were given a

2082

pointer to member, so it's
cool to check for this here.
*/

2083

else if (TYPE_PTR_TO_MEMBER_P (type))

2084

error ("invalid use of `%s' on pointer
to member", errorstring);

2085

else if (pointer != error_mark_node)

2086

{

2087

if (errorstring)

2088

error ("invalid type argument of
`%s'", errorstring);

2089

else

2090

error ("invalid type argument");

2091

}

2092

return
error_mark_node;

2093

}

As we have seen TYPE_VFIELD is the artificial field generated by the
compiler for class containing vtable. Now it also acts as a placeholder, it
will be replaced with the real address of vtable later.

115

tree

116

build_vfield_ref

(tree datum, tree type)

in
call.c

117

{

118

if (datum == error_mark_node)

119

return
error_mark_node;

120

121

if (TREE_CODE (TREE_TYPE (datum)) ==
REFERENCE_TYPE)

122

datum = convert_from_reference (datum);

123

124

if (TYPE_BASE_CONVS_MAY_REQUIRE_CODE_P (type)

125

&&
!same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (datum), type))

126

datum = convert_to_base (datum, type, /*check_access=*/
false);

127

128

return
build

(COMPONENT_REF, TREE_TYPE (TYPE_VFIELD (type)),

129

datum, TYPE_VFIELD (type));

130

}

Remember BINFO_VPTR_FIELD at line 324 is set for virtual base, in
which is an INTEGER_CST indicating the index of the entry in the vtable
recording the offset of the virtual base from the base of the derived (why not
BINFO_OFFSET (vbase)? because C++ standard requires accessing virtual base by
help of BINFO_VPTR_FIELD).

Note that if binfo

is
derived by v_binfo

,
then offset

at line 330 gets the relative offset between these two bases as indicated by
below figure (the red
arrow
is the offset

gotten at line 330).



Then line 334 introduces a minor optimizaton, note that code

of
MINUS_EXPR with v_binfo

not NULL is not allowed and error message is given at line 280. So at line 335, v_offset

at right hand side refers to the binfo of the virtual base via vtable, and plus
offset

gotten at line 330, v_offset

at left hand side then points to the
binfo in interesting. Following offset

is updated accordingly to record the
offset into the most derived class.

For our example 5, expr

generated finally would be:

(pa + offset
(A))? (pa + offset (A)): 0;

Back into get_member_function_from_ptrfunc

,
instance_ptr

is now the above statement returned by build_base_path

. Consider following example,
it gives output “C::f” (note that in class C, vtable entry of f of B1, B2, and
A are all overrided as C::f with appropriate thunk, which give us promise
here):

class
A { public
:

example
- 6

virtual
A*
f () { printf ("A::f/n"); return
0; }

virtual
A*
f1 () { printf ("A::f1/n"); return
0;
}

virtual
~A() {}

};

class
B1 : virtual
public
A { public
:
virtual
B1* f1 () { printf
("B1::f1/n"); return
0; } };

class
B2 : virtual
public
A {};

class
C: public
B1, public
B2 { public
:
virtual C* f () { printf ("C::f/n"); return
0; } };

int main() {

B2 *pc = new
C; // no matter declare
pc as A*, B1*, B2*, or C*, get same result, as // they all derive from A, and
pfn is declared as within A

A* (A::*pfn) () = &B2::f; // same result, use either B1, B2, A, or C at rhs

(pc->*pfn)();

delete
pc;

return
0;

}

For this example, instance_ptr

holds the statement to adjust pa

from B2* to A* (“B2 *pc = new C;” carries a
pointer converted from C* to B2* already); and delta

below gotten at line 2357
records the offset determined by statement “A* (A::*pfn) () = &B2::f;”
(it is 0 because the statement indicate a
meaningless adjustment from A to A). Then by expression: “instance_ptr +
delta”, it locates the base that defining the function specified by the pointer
to method; then idx is the index into the vtable for the virtual function (or
function address converting in type of vtable for non-virtual function).

get_member_function_from_ptrfunc
(continue)

2383

/* ...and then
the delta in the PMF.
*/

2384

instance_ptr =
build

(PLUS_EXPR, TREE_TYPE (instance_ptr),

2385

instance_ptr, delta);

2386

2387

/* Hand back the
adjusted 'this' argument to our caller.

*/

2388

*instance_ptrptr = instance_ptr;

2389

2390

/* Next extract
the vtable pointer from the object.
*/

2391

vtbl = build1
(NOP_EXPR, build_pointer_type
(vtbl_ptr_type_node),

2392

instance_ptr);

2393

vtbl = build_indirect_ref
(vtbl, NULL);

2394

2395

/* Finally,
extract the function pointer from the vtable.

*/

2396

e2 = fold (build

(PLUS_EXPR, TREE_TYPE (vtbl), vtbl, idx));

2397

e2 = build_indirect_ref
(e2, NULL);

2398

TREE_CONSTANT (e2) = 1;

2399

2400

/* When using
function descriptors, the address of the

2401

vtable entry is treated as a
function pointer.
*/

2402

if (TARGET_VTABLE_USES_DESCRIPTORS)

2403

e2 = build1
(NOP_EXPR, TREE_TYPE (e2),

2404

build_unary_op (ADDR_EXPR, e2, /*noconvert=*/
1));

2405

2406

TREE_TYPE (e2) = TREE_TYPE (e3);

2407

e1 = build_conditional_expr (e1, e2, e3);

2408

2409

/* Make sure this
doesn't get evaluated first inside one of the

2410

branches of the
COND_EXPR.
*/

2411

if (instance_save_expr)

2412

e1 = build

(COMPOUND_EXPR, TREE_TYPE (e1),

2413

instance_save_expr, e1);

2414

2415

function = e1;

2416

}

2417

return
function;

2418

}

In section of class
layout, we have seen that vptr is always placed at the beginning of the class.
So the code snippet generated would be like below for example 5:

idx =
(vtable_index_type) pfn;
// pfn returned by PFN_FROM_PTRMEMFUNC

instance_ptr
= instance_ptr? instance_ptr + offset (A): 0;

(idx
& 1)? *(((vtbl_ptr_type_node) instance_ptr) + (idx-1)): pfn;

At this point, for a
pointer-to-method, we have known which function is expected, and expression to
locate the location of the function is ready and returned to build_addr_func

,
then immediately to build_function_call

. Note that function

below now holds the expression for locating the function and its type is the
pointer of the function.

build_function_call (continue)

2464

if (function == error_mark_node)

2465

return
error_mark_node;

2466

2467

fntype = TREE_TYPE (function);

2468

2469

if (TYPE_PTRMEMFUNC_P (fntype))

2470

{

2471

error ("must use .* or ->* to call
pointer-to-member function in `%E (...)'",

2472

original);

2473

return
error_mark_node;

2474

}

2475

2476

is_method = (TREE_CODE (fntype) == POINTER_TYPE

2477

&& TREE_CODE (TREE_TYPE
(fntype)) == METHOD_TYPE);

2478

2479

if (!((TREE_CODE (fntype) == POINTER_TYPE

2480

&& TREE_CODE (TREE_TYPE
(fntype)) == FUNCTION_TYPE)

2481

|| is_method

2482

|| TREE_CODE (function) == TEMPLATE_ID_EXPR))

2483

{

2484

error ("`%E' cannot be used as a
function", original);

2485

return
error_mark_node;

2486

}

2487

2488

/* fntype now gets
the type of function pointed to.
*/

2489

fntype = TREE_TYPE (fntype);

2490

2491

/* Convert the
parameters to the types declared in the

2492

function prototype, or apply
default promotions.
*/

2493

2494

coerced_params = convert_arguments
(TYPE_ARG_TYPES (fntype),

2495

params,
fndecl, LOOKUP_NORMAL);

2496

if (coerced_params == error_mark_node)

2497

return
error_mark_node;

2498

2499

/* Check for errors
in format strings.
*/

2500

2501

if (warn_format

)

2502

check_function_format (NULL,
TYPE_ATTRIBUTES (fntype), coerced_params);

2503

2504

/* Recognize
certain built-in functions so we can make tree-codes

2505

other than CALL_EXPR. We do
this when it enables fold-const.c

2506

to do something useful.
*/

2507

2508

if (TREE_CODE (function) == ADDR_EXPR

2509

&& TREE_CODE (TREE_OPERAND
(function, 0)) == FUNCTION_DECL

2510

&& DECL_BUILT_IN (TREE_OPERAND
(function, 0)))

2511

{

2512

result = expand_tree_builtin (TREE_OPERAND
(function, 0),

2513

params,
coerced_params);

2514

if (result)

2515

return
result;

2516

}

2517

2518

return
build_cxx_call
(function, params, coerced_params);

2519

}

So fntype

at line 2489 refers to the type of the function in used. Then it needs do
conversion for the arguments according to the parameters declaration.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: