您的位置:首页 > 其它

Studying note of GCC-3.4.6 source (67)

2010-07-28 11:33 369 查看
4.3.1.7.8.3. Exception handler
Next, if we don’t prohibit exception via switch -fno-exception, C++ runtime will setup the functions’ declaration excepted by exception handling. In C++, if throw an exception but not catch it, then in global namespace, the runtime would catch it and call std::terminate() to terminate the program. This funcationality is provided by the runtime function__cxa_call_unexpected defined in “gcc-3.4.6/libstdc++-v3/libstdsupc++/eh_personality.cc”.
In parsing throw and catch statement, the compiler would setup the context carried by the exception object, and invokes exception handling logic with the context, __cxa_call_unexpected, __gxx_personality_v0 or __gxx_personality_sj0 are all handlers refered by the context. The exception handling logic and the setup of the context is very complex, we don’t plan to go deep into it. After finishing the follow-up sections about parsing and hanlding complex types, code of this part isn’t very hard for understanding.

60 void
61 init_exception_processing (void) in expt.c
62 {
63 tree tmp;
64
65 /* void std::terminate (); */
66 push_namespace (std_identifier);
67 tmp = build_function_type (void_type_node, void_list_node);
68 terminate_node = build_cp_library_fn_ptr ("terminate", tmp);
69 TREE_THIS_VOLATILE (terminate_node) = 1;
70 TREE_NOTHROW (terminate_node) = 1;
71 pop_namespace ();
72
73 /* void __cxa_call_unexpected(void *); */
74 tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node);
75 tmp = build_function_type (void_type_node, tmp);
76 call_unexpected_node
77 = push_throw_library_fn (get_identifier ("__cxa_call_unexpected"), tmp);
78
79 eh_personality_libfunc = init_one_libfunc (USING_SJLJ_EXCEPTIONS
80 ? "__gxx_personality_sj0"
81 : "__gxx_personality_v0");
82
83 lang_eh_runtime_type = build_eh_type_type;
84 lang_protect_cleanup_actions = &cp_protect_cleanup_actions;
85 }

As std::terminate is a library routine, its declaration is built by build_cp_library_fn_ptr. Remember that build_cp_library_fn will find out (create if not find) the identifer node for mangled version for the declaration and set it as the assemble name for the declaration node. Then at linking stage, linker will find the function by this assemble name in the space of library.

3350 tree
3351 build_cp_library_fn_ptr (const char* name, tree type) in decl.c
3352 {
3353 return build_cp_library_fn (get_identifier (name), ERROR_MARK, type);
3354 }

Routine __cxa_call_unexpected is declared as extern “C”, which means a C version function declaration. Its name will not undergo mangling.

3393 tree
3394 push_throw_library_fn (tree name, tree type) in decl.c
3395 {
3396 tree fn = push_library_fn (name, type);
3397 TREE_THIS_VOLATILE (fn) = 1;
3398 TREE_NOTHROW (fn) = 0;
3399 return fn;
3400 }

Notice that in build_library_fn, the language for the declaration is set as C, and no assemble name is set as its name can’t be mangled under C.

3359 tree
3360 push_library_fn (tree name, tree type) in decl.c
3361 {
3362 tree fn = build_library_fn (name, type);
3363 pushdecl_top_level (fn);
3364 return fn;
3365 }

Now pushdecl_top_level will push this declaration into namespace of global.

3414 tree
3415 pushdecl_top_level (tree x) in name-lookup.c
3416 {
3417 return pushdecl_top_level_1 (x, NULL);
3418 }

Below push_to_top_level caches identifiers from current bindng scope to global namespace and it will leave us at global namespace. And pop_from_top_level would restore current scope.

3400 static tree
3401 pushdecl_top_level_1 (tree x, tree *init) in name-lookup.c
3402 {
3403 timevar_push (TV_NAME_LOOKUP);
3404 push_to_top_level ();
3405 x = pushdecl_namespace_level (x);
3406 if (init)
3407 cp_finish_decl (x, *init, NULL_TREE, 0);
3408 pop_from_top_level ();
3409 POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, x);
3410 }

Though it tries to push the entity into current namespace, it is possible that we are also within a binding scope within current namespace (of course, for our case here we just in global namespace, but from view of pushdecl_namespace_level, it is possible). Below at line 3232 current binding scope (current namespace or may not) is fetched.

3229 tree
3230 pushdecl_namespace_level (tree x) in name-lookup.c
3231 {
3232 struct cp_binding_level *b = current_binding_level;
3233 tree t;
3234
3235 timevar_push (TV_NAME_LOOKUP);
3236 t = pushdecl_with_scope (x, NAMESPACE_LEVEL (current_namespace));

For push entity within namespace, pushdecl_with_scope acts like pushdecl except it works for specified namespace instead of current ones, so caching current binding scope and restoring after that is required.

1941 tree
1942 pushdecl_with_scope (tree x, cxx_scope *level) in name-lookup.c
1943 {
1944 struct cp_binding_level *b;
1945 tree function_decl = current_function_decl;
1946
1947 timevar_push (TV_NAME_LOOKUP);
1948 current_function_decl = NULL_TREE;
1949 if (level->kind == sk_class)
1950 {
1951 b = class_binding_level;
1952 class_binding_level = level;
1953 pushdecl_class_level (x);
1954 class_binding_level = b;
1955 }
1956 else
1957 {
1958 b = current_binding_level;
1959 current_binding_level = level;
1960 x = pushdecl (x);
1961 current_binding_level = b;
1962 }
1963 current_function_decl = function_decl;
1964 POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, x);
1965 }

For each binding scope, if it is a class scope, field class_shadowed records types bound in. While field type_shadowed is not confined to class scope, but in all non-namespace scopes to record types being shadowed (if no shadowed type, it is itself). Why is non-namespace scope? Because via field level_chain, it is easily to determine whether specified identifier is visible at specified namespace due to they are always the outer-most scopes and effective.

pushdecl_namespace_level (continue)

3238 /* Now, the type_shadowed stack may screw us. Munge it so it does
3239 what we want. */
3240 if (TREE_CODE (x) == TYPE_DECL)
3241 {
3242 tree name = DECL_NAME (x);
3243 tree newval;
3244 tree *ptr = (tree *)0;
3245 for (; !global_scope_p (b); b = b->level_chain)
3246 {
3247 tree shadowed = b->type_shadowed;
3248 for (; shadowed; shadowed = TREE_CHAIN (shadowed))
3249 if (TREE_PURPOSE (shadowed) == name)
3250 {
3251 ptr = &TREE_VALUE (shadowed);
3252 /* Can't break out of the loop here because sometimes
3253 a binding level will have duplicate bindings for
3254 PT names. It's gross, but I haven't time to fix it. */
3255 }
3256 }
3257 newval = TREE_TYPE (x);
3258 if (ptr == (tree *)0)
3259 {
3260 /* @@ This shouldn't be needed. My test case "zstring.cc" trips
3261 up here if this is changed to an assertion. --KR */
3262 SET_IDENTIFIER_TYPE_VALUE (name, x);
3263 }
3264 else
3265 {
3266 *ptr = newval;
3267 }
3268 }
3269 POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, t);
3270 }

As we have mentioned above, current binding scope may be in current namespace. Now we have added new type into current namespace, then it needs to check if between current scope and current namespace, this type would be shadowed. At line 3245, b is the current scope, via level_chain, it can climb up to global namespace, but because type_shadowed is not used by namespace, so the entity found by FOR loop at line 3245, is the type shadowed by inner scope closest to current namespace, which is declared in outside namespace (the usage of the function promises this). No doubt, the type shadowed should be updated as currently adding type (line 3262). If these inner scopes haven’t type declaration of the name, ptr would be 0 (line 3258).
Both __gxx_personality_sj0 and __gxx_personality_v0 are declared with C signature (extern “C”). Their declaration is generated by init_one_libfunc, which likes: int __gxx_personality_sj0().

5126 rtx
5127 init_one_libfunc (const char *name) in optabs.c
5128 {
5129 rtx symbol;
5130
5131 /* Create a FUNCTION_DECL that can be passed to
5132 targetm.encode_section_info. */
5133 /* ??? We don't have any type information except for this is
5134 a function. Pretend this is "int foo()". */
5135 tree decl = build_decl (FUNCTION_DECL, get_identifier (name),
5136 build_function_type (integer_type_node, NULL_TREE));
5137 DECL_ARTIFICIAL (decl) = 1;
5138 DECL_EXTERNAL (decl) = 1;
5139 TREE_PUBLIC (decl) = 1;
5140
5141 symbol = XEXP (DECL_RTL (decl), 0);
5142
5143 /* Zap the nonsensical SYMBOL_REF_DECL for this. What we're left with
5144 are the flags assigned by targetm.encode_section_info. */
5145 SYMBOL_REF_DECL (symbol) = 0;
5146
5147 return symbol;
5148 }

At line 5141, DECL_RTL will invoke make_decl_rtl (to get detail, refer to Create RTX object for builtin). Notice that in that function at line 790, it will fetch the mangled name of the declaration, but we haven’t the correct function signature in hand now (compared with that in unwind-cxx.h)!
Fortunately, here we don’t need fully correct signature of the function to get the entry name in the library. Routines like __gxx_personality_v0 here generated by language-independent part has C linkage. That is the mangled names are the same of their declared name. As long as we provide correct arguments at run-time, everything is OK.
4.3.1.7.8.4. Detect behavor of linker and other
GCC supports concept of weak symbol.
Having two or more global symbols of the same name will not cause a conflict as long as all but one of them are declared as being weak symbols. The linker ignores the definitions of the weak symbols and uses the normal global symbol definition to resolve all references, but the weak symbols will be used if the normal global symbol is not available. A weak symbol can be used to name functions and data that can be overridden by user code. A weak symbol is also referred to as a weak alias, or simply weak.
Besides, GCC can also output following assembler directive.
linkonce[type]: Marks the current section so it is included by the linker only once, even if the same section appears in multiple modules. The directive must appear once in each instance of the section. The section is selected only by name, so the name must be unique.
The optional type argument can be discard to have duplicates silently discarded (the default). A type of one_only will issue a warning for each duplicate found. A type of same_size will issue a warning if any of the duplicates are not the same size. A type of same_contents will issue a warning if any of the duplicates do not contain exactly the same data.
These are all target dependent. For x86, elf format output, support_one_only returns 0 and sets flag_weak as 0.

4549 int
4550 supports_one_only (void) in varasm.c
4551 {
4552 if (SUPPORTS_ONE_ONLY)
4553 return 1;
4554 return SUPPORTS_WEAK;
4555 }

In coding, we can use __func__, __FUNCTION__, __PRETTY__FUNCTION__ to fetch current function name. Function pointer make_fname_decl saves the processing function, which at line 3129, is set by cp_make_fname_decl. Function start_fname_decls then prepares the stack for saving these functions’ name. Later we will see this funciton again.

4.3.1.8. Setup preprocessor

Returns from cxx_init_decl_processing, the front-end has C++ runtime setup, it comes to setup preprocessor. First it creates the familiar “null” object, which as we have seen in our program, in fact is an integer of 0. However, note that it has size of a pointer.

cxx_init (continue)

412 /* Create the built-in __null node. */
413 null_node = build_int_2 (0, 0);
414 TREE_TYPE (null_node) = c_common_type_for_size (POINTER_SIZE, 0);
415 ridpointers[RID_NULL] = null_node;
416
417 interface_unknown = 1;
418
419 if (c_common_init () == false)
420 {
421 pop_srcloc();
422 return false;
423 }

Below cpp_init_iconv initializes iconv descriptors for conversion from the source character set to the execution character sets. We ignore this part. And flag_preprocess_only if nonzero, means only to do preprocessing, which is ready here, and invokes preprocess_file at line 1207. And we will return here to finish the file’s compilation.

1186 bool
1187 c_common_init (void) in c-opts.c
1188 {
1189 input_line = saved_lineno;
1190
1191 /* Set up preprocessor arithmetic. Must be done after call to
1192 c_common_nodes_and_builtins for type nodes to be good. */
1193 cpp_opts->precision = TYPE_PRECISION (intmax_type_node);
1194 cpp_opts->char_precision = TYPE_PRECISION (char_type_node);
1195 cpp_opts->int_precision = TYPE_PRECISION (integer_type_node);
1196 cpp_opts->wchar_precision = TYPE_PRECISION (wchar_type_node);
1197 cpp_opts->unsigned_wchar = TREE_UNSIGNED (wchar_type_node);
1198 cpp_opts->bytes_big_endian = BYTES_BIG_ENDIAN;
1199
1200 /* This can't happen until after wchar_precision and bytes_big_endian
1201 are known. */
1202 cpp_init_iconv (parse_in);
1203
1204 if (flag_preprocess_only)
1205 {
1206 finish_options ();
1207 preprocess_file (parse_in);
1208 return false;
1209 }
1210
1211 /* Has to wait until now so that cpplib has its hash table. */
1212 init_pragma ();
1213
1214 return true;
1215 }

And if full compilation is expected, then for x86 linux, here only two directives “pack”, and “weak” are available for C (they will appear in __attribute__() block), as #pragma directive is architecture dependent.

494 void
495 init_pragma (void) in c-pragma.c
496 {
497 #ifdef HANDLE_PRAGMA_PACK
498 c_register_pragma (0, "pack", handle_pragma_pack);
499 #endif
500 #ifdef HANDLE_PRAGMA_WEAK
501 c_register_pragma (0, "weak", handle_pragma_weak);
502 #endif
503 #ifdef HANDLE_PRAGMA_REDEFINE_EXTNAME
504 c_register_pragma (0, "redefine_extname", handle_pragma_redefine_extname);
505 #endif
506 #ifdef HANDLE_PRAGMA_EXTERN_PREFIX
507 c_register_pragma (0, "extern_prefix", handle_pragma_extern_prefix);
508 #endif
509
510 #ifdef REGISTER_TARGET_PRAGMAS
511 REGISTER_TARGET_PRAGMAS ();
512 #endif
513 }

c_register_pragma inserts identifier of directives into hashtable of ident_hash and binds them with their handler.

486 void
487 c_register_pragma (const char *space, const char *name, in c-pragma.c
488 void (*handler) (struct cpp_reader *))
489 {
490 cpp_register_pragma (parse_in, space, name, handler);
491 }

4.3.1.9. Finish front-end initialization

C++ supports more #pragma directives, so initializes them in below.

cxx_init (continue)

425 init_cp_pragma ();
426
427 init_repo (main_input_filename);
428
429 pop_srcloc();
430 return true;
431 }

Below #pragma vtable is no longer supported, and #pragma unit, gcc doesn’t implement it yet.

368 static void
369 init_cp_pragma (void) in lex.c
370 {
371 c_register_pragma (0, "vtable", handle_pragma_vtable);
372 c_register_pragma (0, "unit", handle_pragma_unit);
373 c_register_pragma (0, "interface", handle_pragma_interface);
374 c_register_pragma (0, "implementation", handle_pragma_implementation);
375 c_register_pragma ("GCC", "interface", handle_pragma_interface);
376 c_register_pragma ("GCC", "implementation", handle_pragma_implementation);
377 c_register_pragma ("GCC", "java_exceptions", handle_pragma_java_exceptions);
378 }

When compiles the code using the -frepo option, it causes the creation of files with the suffix .rpo, each listing the template instantiations to be found in its corresponding object file. The link wrapper utility, named collect2, will then be invoked to update the .rpo files with instructions to the linker as to the placement of the template instances in the final program. The only difficulty with this approach has to do with libraries—unless the associated .rpo files are also present, linking template instantiations stored in a library will fail.
At line 427, init_repo creates .rpo version file for main input file.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: