GCC-3.4.6源代码学习笔记(161)

5.13.4.7.              发布代码根据优先级调用初始化函数

如果由代码 2573 2800 行执行的迭代稳定了下来——即不再产生新的东西,或者换句话说,所有显式或隐式涉及的对象都已经处理了,就可以继续完成机器代码分别这个目标。

 

finish_file (continue)

 

2801    /* All used inline functions must have a definition at this point.  */

2802    for (i = 0; i < deferred_fns_used; ++i)

2803    {

2804      tree decl = VARRAY_TREE (deferred_fns , i);

2805

2806      if (TREE_USED (decl) && DECL_DECLARED_INLINE_P (decl)

2807         && !(TREE_ASM_WRITTEN (decl) || DECL_SAVED_TREE (decl)

2808              /* An explicit instantiation can be used to specify

2809                that the body is in another unit. It will have

2810                already verified there was a definition.  */

2811              || DECL_EXPLICIT_INSTANTIATION (decl)))

2812      {

2813        cp_warning_at ("inline function `%D' used but never defined", decl);

2814        /* This symbol is effectively an "extern" declaration now.

2815          This is not strictly necessary, but removes a duplicate

2816          warning.   */

2817        TREE_PUBLIC (decl) = 1;

2818      }

2819       

2820    }

2821   

2822    /* We give C linkage to static constructors and destructors.  */

2823    push_lang_context (lang_name_c);

2824

2825    /* Generate initialization and destruction functions for all

2826      priorities for which they are required.  */

2827    if (priority_info_map )

2828      splay_tree_foreach (priority_info_map ,

2829                       generate_ctor_and_dtor_functions_for_priority ,

2830                       /*data=*/ &locus);

2831    else

2832    {

2833       

2834      if (static_ctors )

2835        generate_ctor_or_dtor_function (/*constructor_p=*/ true,

2836                                    DEFAULT_INIT_PRIORITY, &locus);

2837      if (static_dtors )

2838        generate_ctor_or_dtor_function (/*constructor_p=*/ false,

2839                                   DEFAULT_INIT_PRIORITY, &locus);

2840    }

2841

2842    /* We're done with the splay-tree now.  */

2843    if (priority_info_map)

2844      splay_tree_delete (priority_info_map);

2845

2846    /* We're done with static constructors, so we can go back to "C++"

2847      linkage now.  */

2848    pop_lang_context ();

 

首先,检查是否所有使用的内联函数都具有定义;否则就应该给出警告信息。

接着,我们已经看到具有初始值的全局聚集对象都已经构建了初始化函数。现在编译器已经定义了这样的初始化函数,编译器将要产生根据相关优先级调用这些函数的代码。注意到没有指定优先级的构造或析构函数将具有最低优先级,并且它们的初始化次序由编译器决定。

2824 行,因为所以初始化函数具有 C 链接性,首先使得 C 语言上下文成为当前的语言上下文。

除了属性“ init_priority ”,还有另一个属性具有类似的效果。

constructor [6]

destructor

constructor (priority)

destructor (priority)

constructor 属性使得该函数在执行进入 main () 之前被自动调用。相似地, destructor 属性使得这个函数,在 main () 完成或 exit () 被调用后,被自动调用。具有这些属性的函数,对于初始化在程序执行过程中被隐式使用的数据,是有用的。

你可以提供一个可选的整数优先级来控制构造函数及析构函数的运行次序。具有较小优先级数值的构造函数在具有较大优先级数值的构造函数之前运行;相反的关系对于析构函数成立。因此,如果你具有一个分配资源的构造函数,一个回收相同资源的析构函数,两者通常具有相同的优先级。构造函数及析构函数的优先级与那些为名字空间域中的 C++ 对象指定的相同。

[ 作者 ] gcc-3.4.6不支持后两者

如果看到这样的属性,它将被保存入 static_ctors static_dtors ;并且看到在下面的代码中,在 gcc-3.4.6 里,由上面属性引入的构造函数 / 析构函数仅具有默认的最低优先级。函数 splay_tree_foreach 依次访问伸展树 priority_info_map ,这棵树以优先级值排序,因此中序遍历使得下面的函数,以优先级值升序的次序,在节点上执行。

 

2471   static int

2472   generate_ctor_and_dtor_functions_for_priority (splay_tree_node n, void * data) in decl2.c

2473   {

2474     location_t *locus = data;

2475     int priority = (int) n->key;

2476     priority_info pi = (priority_info) n->value;

2477  

2478     /* Generate the functions themselves, but only if they are really

2479       needed.  */

2480     if (pi->initializations_p

2481         || (priority == DEFAULT_INIT_PRIORITY && static_ctors ))

2482       generate_ctor_or_dtor_function (/*constructor_p=*/ true, priority, locus);

2483     if (pi->destructions_p

2484         || (priority == DEFAULT_INIT_PRIORITY && static_dtors ))

2485       generate_ctor_or_dtor_function (/*constructor_p=*/ false, priority, locus);

2486  

2487     /* Keep iterating.  */

2488     return 0;

2489   }

 

那么对于所有具有相同优先级的对象,它们按声明次序初始化(它们以反序插入 static_aggregates pending_statics ,但编译器再反向地产生初始化函数)。

 

2398   static void

2399   generate_ctor_or_dtor_function (bool constructor_p, int priority,                  in decl2.c

2400                              location_t *locus)

2401   {

2402     char function_key;

2403     tree arguments;

2404     tree fndecl;

2405     tree body;

2406     size_t i;

2407  

2408     input_location = *locus;

2409     locus->line++;

2410    

2411     /* We use `I' to indicate initialization and `D' to indicate

2412       destruction.  */

2413     function_key = constructor_p ? 'I' : 'D';

2414  

2415     /* We emit the function lazily, to avoid generating empty

2416        global constructors and destructors.  */

2417     body = NULL_TREE;

2418  

2419     /* Call the static storage duration function with appropriate

2420       arguments.  */

2421     if (ssdf_decls )

2422       for (i = 0; i < ssdf_decls ->elements_used; ++i)

2423       {

2424         fndecl = VARRAY_TREE (ssdf_decls , i);

2425  

2426         /* Calls to pure or const functions will expand to nothing.  */

2427         if (! (flags_from_decl_or_type (fndecl) & (ECF_CONST | ECF_PURE)))

2428         {

2429           if (! body)

2430             body = start_objects (function_key, priority);

2431  

2432           arguments = tree_cons (NULL_TREE, build_int_2 (priority, 0),

2433                               NULL_TREE);

2434           arguments = tree_cons (NULL_TREE, build_int_2 (constructor_p, 0),

2435                               arguments);

2436           finish_expr_stmt (build_function_call (fndecl, arguments));

2437         }

2438       }

 

在前面的章节, void __static_initialization_and_destruction0 (int, int) 被定义在第一次迭代中,其中找到需要初始化的全局对象;然后 void __static_initialization_and_destruction1 (int, int) 被定义在第二次迭代中,其中具有需要初始化的全局对象;依此类推。在每个函数中,它把优先级接受为第二个参数,并仅初始化具有匹配优先级的对象。注意到所有初始化函数已经被记录在 ssdf_decls 中。在这些初始化函数里,任意纯的或常量函数将被滤除,因为将没有全局对象会被构建。下面的函数区分 exp 指定函数的特性。

 

698    int

699    flags_from_decl_or_type (tree exp)                                                           in call.c

700    {

701      int flags = 0;

702      tree type = exp;

703   

704      if (DECL_P (exp))

705      {

706        struct cgraph_rtl_info *i = cgraph_rtl_info (exp);

707        type = TREE_TYPE (exp);

708   

709        if (i)

710        {

711           if (i->pure_function)

712            flags |= ECF_PURE | ECF_LIBCALL_BLOCK;

713          if (i->const_function)

714            flags |= ECF_CONST | ECF_LIBCALL_BLOCK;

715        }

716   

717        /* The function exp may have the `malloc' attribute.  */

718        if (DECL_IS_MALLOC (exp))

719          flags |= ECF_MALLOC;

720   

721        /* The function exp may have the `pure' attribute.  */

722        if (DECL_IS_PURE (exp))

723          flags |= ECF_PURE | ECF_LIBCALL_BLOCK;

724   

725        if (TREE_NOTHROW (exp))

726          flags |= ECF_NOTHROW;

727   

728        if (TREE_READONLY (exp) && ! TREE_THIS_VOLATILE (exp))

729          flags |= ECF_LIBCALL_BLOCK;

730      }

731   

732      if (TREE_READONLY (exp) && ! TREE_THIS_VOLATILE (exp))

733        flags |= ECF_CONST;

734   

735      if (TREE_THIS_VOLATILE (exp))

736        flags |= ECF_NORETURN;

737   

738      /* Mark if the function returns with the stack pointer depressed. We

739        cannot consider it pure or constant in that case.  */

740      if (TREE_CODE (type) == FUNCTION_TYPE && TYPE_RETURNS_STACK_DEPRESSED (type))

741      {

742        flags |= ECF_SP_DEPRESSED;

743        flags &= ~(ECF_PURE | ECF_CONST | ECF_LIBCALL_BLOCK);

744      }

745   

746      return flags;

747    }

 

在这里,如果该函数具有关联的 cgraph_rtl_info 节点,就使用这个节点。否则,根据这个 *_DECL 节点执行调整。但是在 cgraph_rtl_info 节点中, pure 意味着仅读入非局部,非常量的实体;而 constant 意味着仅读入非局部及常量实体。那么对于留下的初始化函数,编译器需要产生一个函数来,为记录在 priority_info_map 中具有特定优先级的对象,调用这些函数。它们由 start_objects 来声明。

 

1883   static tree

1884   start_objects (int method_type, int initp)                                                    in decl2.c

1885   {

1886     tree fnname;

1887     tree body;

1888     char type[10];

1889  

1890     /* Make ctor or dtor function. METHOD_TYPE may be 'I' or 'D'.  */

1891  

1892     if (initp != DEFAULT_INIT_PRIORITY)

1893     {

1894       char joiner;

1895  

1896   #ifdef JOINER

1897       joiner = JOINER;

1898   #else

1899       joiner = '_';

1900   #endif

1901  

1902       sprintf (type, "%c%c%.5u", method_type, joiner, initp);

1903     }

1904     else

1905       sprintf (type, "%c", method_type);

1906  

1907     fnname = get_file_function_name_long (type);

1908  

1909     start_function (void_list_node,

1910                  make_call_declarator (fnname, void_list_node, NULL_TREE,

1911                                   NULL_TREE),

1912                 NULL_TREE, SF_DEFAULT);

1913  

1914     /* It can be a static function as long as collect2 does not have

1915       to scan the object file to find its ctor/dtor routine.  */

1916     TREE_PUBLIC (current_function_decl ) = ! targetm .have_ctors_dtors;

1917  

1918     /* Mark this declaration as used to avoid spurious warnings.  */

1919     TREE_USED (current_function_decl ) = 1;

1920  

1921     /* Mark this function as a global constructor or destructor.  */

1922     if (method_type == 'I')

1923       DECL_GLOBAL_CTOR_P (current_function_decl ) = 1;

1924     else

1925       DECL_GLOBAL_DTOR_P (current_function_decl ) = 1;

1926     DECL_LANG_SPECIFIC (current_function_decl )->decl_flags.u2sel = 1;

1927  

1928     body = begin_compound_stmt (/*has_no_scope=*/ false);

1929  

1940     /* We cannot allow these functions to be elided, even if they do not

1941       have external linkage. And, there's no point in deferring

1942       compilation of thes functions; they're all going to have to be

1943       out anyhow.  */

1944     current_function_cannot_inline

1945       = "static constructors and destructors cannot be inlined";

1946  

1947     return body;

1948   }

 

JOINER 在我们假定的平台下是“ $ ”,实参 method_type 对于构造函数是“ I ”,对于析构函数是“ D ”,因此 1905 行的 type ,对于构造函数将具有形式“ I$.1 ,“ I$.2 等,对于析构函数将具有形式“ D$.1 ,“ D$.2 等。

下面看到在 generate_ctor_or_dtor_function 2432 2436 行产生类似: __static_initialization_and_destruction0 (1, 1) 的语句来初始化具有优先级 1 的对象。注意到所有的初始化函数调用将使用优先级参数。

 

generate_ctor_or_dtor_function (continue)

 

2440     /* If we're generating code for the DEFAULT_INIT_PRIORITY, throw in

2441       calls to any functions marked with attributes indicating that

2442        they should be called at initialization- or destruction-time.  */

2443     if (priority == DEFAULT_INIT_PRIORITY)

2444     {

2445       tree fns;

2446  

2447       for (fns = constructor_p ? static_ctors : static_dtors ;

2448           fns;

2449           fns = TREE_CHAIN (fns))

2450       {

2451         fndecl = TREE_VALUE (fns);

2452  

2453         /* Calls to pure/const functions will expand to nothing.  */

2454         if (! (flags_from_decl_or_type (fndecl) & (ECF_CONST | ECF_PURE)))

2455         {

2456           if (! body)

2457             body = start_objects (function_key, priority);

2458           finish_expr_stmt (build_function_call (fndecl, NULL_TREE));

2459         }

2460       }

2461     }

2462  

2463     /* Close out the function.  */

2464     if (body)

2465       finish_objects (function_key, priority, body);

2466   }

 

对于具有默认优先级 DEFAULT_INIT_PRIORITY 0xffff )的对象,不需要产生初始化函数,这里仅需要依次调用注册的构造函数 / 析构函数。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值