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

    技术2025-03-17  16

    5.13.4.5.              迭代 处理名字空间中的全局对象

    前面我们已经为需要构造函数及析构函数的全局或静态对象准备、注册好了初始化函数及退出函数。这一次的迭代检查是否还有没有处理的全局对象,并处理之。函数 walk_namespaces 从上至下以前序访问名字空间树。

     

    848    int

    849    walk_namespaces (walk_namespaces_fn f, void* data)                                      in decl.c

    850    {

    851      return walk_namespaces_r (global_namespace , f, data);

    852    }

     

    namespaces 保存了在 namespace 中声明的名字空间列表。

     

    831    static int

    832    walk_namespaces_r (tree namespace, walk_namespaces_fn f, void* data)           in decl.c

    833    {

    834      int result = 0;

    835      tree current = NAMESPACE_LEVEL (namespace)->namespaces;    

    836   

    837      result |= (*f) (namespace, data);

    838   

    839      for (; current; current = TREE_CHAIN (current))

    840        result |= walk_namespaces_r (current, f, data);

    841   

    842      return result;

    843    }

     

    下面的函数是遍历过程中,在每个名字空间节点上执行的实参 f 。实参 data 由调用者传入,表示是否是该函数的最后一次调用。在这里是 0 ,而在 finish_file 2856 行,为 1

     

    905    int

    906    wrapup_globals_for_namespace (tree namespace, void* data)                                    in decl.c

    907    {

    908      struct cp_binding_level *level = NAMESPACE_LEVEL (namespace);

    909      varray_type statics = level->static_decls;

    910      tree *vec = &VARRAY_TREE (statics, 0);

    911       int len = VARRAY_ACTIVE_SIZE (statics);

    912      int last_time = (data != 0);

    913   

    914      if (last_time)

    915      {

    916        check_global_declarations (vec, len);

    917        return 0;

    918      }

    919   

    920      /* Write out any globals that need to be output.  */

    921      return wrapup_global_declarations (vec, len);

    922    }

     

    如果这不是最后的调用,那么调用下面的函数来处理名字空间中的全局或静态声明。下面 1572 行的钩子 finish_incomplete_decl ,对于 C++ 前端,指向 lhd_do_nothing_t ,它是一个空函数。

     

    1554   int

    1555   wrapup_global_declarations (tree *vec, int len)                                           in toplev.c

    1556   {

    1557     tree decl;

    1558     int i;

    1559     int reconsider;

    1560     int output_something = 0;

    1561  

    1562     for (i = 0; i < len; i++)

    1563     {

    1564       decl = vec[i];

    1565  

    1566        /* We're not deferring this any longer. Assignment is

    1567         conditional to avoid needlessly dirtying PCH pages.  */

    1568       if (DECL_DEFER_OUTPUT (decl) != 0)

    1569         DECL_DEFER_OUTPUT (decl) = 0;

    1570  

    1571       if (TREE_CODE (decl) == VAR_DECL && DECL_SIZE (decl) == 0)

    1572         (*lang_hooks .finish_incomplete_decl) (decl);

    1573     }

    1574  

    1575     /* Now emit any global variables or functions that we have been

    1576       putting off. We need to loop in case one of the things emitted

    1577       here references another one which comes earlier in the list.  */

    1578     do

    1579     {

    1580       reconsider = 0;

    1581       for (i = 0; i < len; i++)

    1582        {

    1583         decl = vec[i];

    1584  

    1585         if (TREE_ASM_WRITTEN (decl) || DECL_EXTERNAL (decl))

    1586           continue ;

    1587  

    1588         /* Don't write out static consts, unless we still need them.

    1589  

    1590           We also keep static consts if not optimizing (for debugging),

    1591           unless the user specified -fno-keep-static-consts.

    1592           ??? They might be better written into the debug information.

    1593           This is possible when using DWARF.

    1594  

    1595           A language processor that wants static constants to be always

    1596           written out (even if it is not used) is responsible for

    1597           calling rest_of_decl_compilation itself. E.g. the C front-end

    1598           calls rest_of_decl_compilation from finish_decl.

    1599           One motivation for this is that is conventional in some

    1600           environments to write things like:

    1601           static const char rcsid[] = "... version string ...";

    1602           intending to force the string to be in the executable.

    1603  

    1604            A language processor that would prefer to have unneeded

    1605           static constants "optimized away" would just defer writing

    1606           them out until here. E.g. C++ does this, because static

    1607           constants are often defined in header files.

    1608  

    1609           ??? A tempting alternative (for both C and C++) would be

    1610           to force a constant to be written if and only if it is

    1611           defined in a main file, as opposed to an include file.  */

    1612  

    1613         if (TREE_CODE (decl) == VAR_DECL && TREE_STATIC (decl))

    1614         {

    1615           bool needed = 1;

    1616  

    1617           if (flag_unit_at_a_time

    1618              && cgraph_varpool_node (decl)->finalized)

    1619             needed = 0;

    1620             else if ((flag_unit_at_a_time && !cgraph_global_info_ready )

    1621                  && (TREE_USED (decl)

    1622                       || TREE_USED (DECL_ASSEMBLER_NAME (decl))))

    1623             /* needed */ ;

    1624           else if (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))

    1625             /* needed */ ;

    1626           else if (DECL_COMDAT (decl))

    1627             needed = 0;

    1628           else if (TREE_READONLY (decl) && !TREE_PUBLIC (decl)

    1629                 && (optimize || !flag_keep_static_consts

    1630                       || DECL_ARTIFICIAL (decl)))

    1631             needed = 0;

    1632  

    1633           if (needed)

    1634           {

    1635             reconsider = 1;

    1636             rest_of_decl_compilation (decl, NULL, 1, 1);

    1637            }

    1638         }

    1639  

    1640         if (TREE_CODE (decl) == FUNCTION_DECL

    1641            && DECL_INITIAL (decl) != 0

    1642            && DECL_SAVED_INSNS (decl) != 0

    1643            && DECL_SAVED_INSNS (decl)->saved_for_inline

    1644            && (flag_keep_inline_functions

    1645                || (TREE_PUBLIC (decl) && !DECL_COMDAT (decl))

    1646                || TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))))

    1647         {

    1648           reconsider = 1;

    1649           output_inline_function (decl);

    1650         }

    1651       }

    1652  

    1653       if (reconsider)

    1654         output_something = 1;

    1655     }

    1656     while (reconsider);

    1657  

    1658     return output_something;

    1659   }

     

    注意在此时, 1620 行的 cgraph_global_info_ready 仍然是 false 。看到如果变量真正被使用,在 1636 行,调用 rest_of_decl_compilation ,在其中,对于非外部变量,调用 cgraph_varpool_finalize_decl 来确保生成相关的 cgrap_varpool_node ,并把这个节点标记为已完成( finialized )(对于 FUNCTION_DECL assemble_variable 不做任何事,仅清除 last_assemble_variable_decl )。

    另外对于已经被使用,或者在外部可见的内联函数,或者使用编译选项 –fkeep-inline-functions 来发布所有内联函数;其对应的调用表达式应该为函数体所替代,这由下面的函数来完成。

    下面的 write_symbols 表示所产生的调试信息的类型。看到真正的工作由 2995 行的 rest_of_compilation 完成,它包含了非常复杂的操作,因此我们暂时不看它。

     

    2965   void

    2966   output_inline_function (tree fndecl)                                                            in integrate.c

    2967   {

    2968     enum debug_info_type old_write_symbols = write_symbols ;

    2969     const struct gcc_debug_hooks *const old_debug_hooks = debug_hooks ;

    2970     struct function *f = DECL_SAVED_INSNS (fndecl);

    2971  

    2972     old_cfun = cfun ;

    2973     cfun = f;

    2974     current_function_decl = fndecl;

    2975  

    2976     set_new_last_label_num (f->inl_max_label_num);

    2977  

    2978     /* We're not deferring this any longer.  */

    2979     DECL_DEFER_OUTPUT (fndecl) = 0;

    2980  

    2981     /* If requested, suppress debugging information.  */

    2982     if (f->no_debugging_symbols)

    2983     {

    2984       write_symbols = NO_DEBUG;

    2985       debug_hooks = &do_nothing_debug_hooks ;

    2986     }

    2987  

    2988     /* Make sure warnings emitted by the optimizers (e.g. control reaches

    2989       end of non-void function) is not wildly incorrect.  */

    2990     input_location = DECL_SOURCE_LOCATION (fndecl);

    2991  

    2992     /* Compile this function all the way down to assembly code. As a

    2993       side effect this destroys the saved RTL representation, but

    2994       that's okay, because we don't need to inline this anymore.  */

    2995     rest_of_compilation (fndecl);

    2996     DECL_INLINE (fndecl) = 0;

    2997  

    2998     cfun = old_cfun;

    2999     current_function_decl = old_cfun ? old_cfun->decl : 0;

    3000     write_symbols = old_write_symbols;

    3001     debug_hooks = old_debug_hooks;

    3002   }

    5.13.4.6.              迭代 在类中没有初始值的静态成员

    接下来, pending_statics 保存了一个静态类变量列表。这是需要的,因为一个静态类变量可以被声明在该类中,并且不带初始值,然后在该类的外部静态地初始化这个变量。注意到 pending_statics 可能与 static_aggregates 重叠,不过那些变量已经在前面的章节中处理过了,不会在这里再处理。

    首先,需要调用 import_export_decl 来确定变量的可见性及链接属性;然后就是 wrapup_global_declarations 。注意没有初始值,不需要为这些对象构建初始化函数,就像章节 迭代 发布全局聚集类的构造函数 /析构函数 中所做的那样。

    然后在 DO…WHILE 循环的末尾的 2797 行,如果设置了 flag_unit_at_a_time cgraph_assemble_pending_functions 不做任何事。

     

    最新回复(0)