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

    技术2025-06-25  10

    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)