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

5.12.3.2.1.1.3.4.3.            缓存内联函数体

函数 start_method 为这个 method-declaration 的声明符构建了节点,随后如果方法有缺省参数,这些参数将被 parser unparsed_functions_queues 域所记录。而如果接下来的符号是“ { ”,表示适用 function-definition 规则,定义了内联函数。

 

cp_parser_save_member_function_body (continue)

 

14656   /* Remember it, if there default args to post process.  */

14657   cp_parser_save_default_args (parser, fn);

14658

14659   /* Create a token cache.  */

14660   cache = cp_token_cache_new ();

14661   /* Save away the tokens that make up the body of the

14662     function.  */

14663   cp_parser_cache_group (parser, cache, CPP_CLOSE_BRACE, /*depth=*/ 0);

14664   /* Handle function try blocks.  */

14665   while (cp_lexer_next_token_is_keyword (parser->lexer, RID_CATCH))

14666     cp_parser_cache_group (parser, cache, CPP_CLOSE_BRACE, /*depth=*/ 0);

14667

14668   /* Save away the inline definition; we will process it when the

14669     class is complete.  */

14670   DECL_PENDING_INLINE_INFO (fn) = cache;

14671   DECL_PENDING_INLINE_P (fn) = 1;

14672

14673   /* We need to know that this was defined in the class, so that

14674     friend templates are handled correctly.  */

14675   DECL_INITIALIZED_IN_CLASS_P (fn) = 1;

14676

14677   /* We're done with the inline definition.  */

14678   finish_method (fn);

14679

14680   /* Add FN to the queue of functions to be parsed later.  */

14681   TREE_VALUE (parser->unparsed_functions_queues)

14682     = tree_cons (NULL_TREE, fn,

14683                TREE_VALUE (parser->unparsed_functions_queues));

14684

14685   return fn;

14686 }

 

在调用处,内联函数要被展开,因此其定义需要被解析器记住。解析器使用类型为 cp_token_block 的块来缓存函数的定义。每个块的大小是 512 字节。

 

100    typedef struct cp_token_block GTY (())                                                     in parser.c

101    {

102      /* The tokens.  */

103      cp_token tokens[CP_TOKEN_BLOCK_NUM_TOKENS];

104      /* The number of tokens in this block.  */

105      size_t num_tokens;

106      /* The next token block in the chain.  */

107      struct cp_token_block *next;

108      /* The previous block in the chain.  */

109      struct cp_token_block *prev;

110     } cp_token_block;

 

112     typedef struct cp_token_cache GTY (())   

113     {

114       /* The first block in the cache. NULL if there are no tokens in the

115         cache.  */

116       cp_token_block *first;

117       /* The last block in the cache. NULL If there are no tokens in the

118         cache.  */

119       cp_token_block *last;

120    } cp_token_cache;

 

对于每个内联函数,都伴随一个 cp_token_cache ,它把保存定义的多个块串接起来。

 

131    static cp_token_cache *

132    cp_token_cache_new (void)                                                                      in parser.c

133    {

134      return ggc_alloc_cleared (sizeof (cp_token_cache));

135    }

 

函数 cp_parser_cache_group 是一个递归函数,因为一个函数可以包含任意对括号或大括号,这种情形由递归函数处理更为简单。注意到 end 或者是 CPP_CLOSE_PAREN ,或者是 CPP_CLOSE_BRACE ,而函数“消化”的第一个符号一定是“ { ”。

 

15349 static void

15350 cp_parser_cache_group (cp_parser *parser,                                                in parser.c

15351                     cp_token_cache *cache,

15352                     enum cpp_ttype end,

15353                     unsigned depth)

15354 {

15355   while (true)

15356   {

15357     cp_token *token;

15358

15359     /* Abort a parenthesized expression if we encounter a brace.  */

15360     if ((end == CPP_CLOSE_PAREN || depth == 0)

15361         && cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))

15362       return ;

15363     /* If we've reached the end of the file, stop.  */

15364     if (cp_lexer_next_token_is (parser->lexer, CPP_EOF))

15365       return ;

15366     /* Consume the next token.  */

15367     token = cp_lexer_consume_token (parser->lexer);

15368      /* Add this token to the tokens we are saving.  */

15369     cp_token_cache_push_token (cache, token);

15370      /* See if it starts a new group.  */

15371     if (token->type == CPP_OPEN_BRACE)

15372     {

15373       cp_parser_cache_group (parser, cache, CPP_CLOSE_BRACE, depth + 1);

15374       if (depth == 0)

15375         return ;

15376     }

15377     else if (token->type == CPP_OPEN_PAREN)

15378       cp_parser_cache_group (parser, cache, CPP_CLOSE_PAREN, depth + 1);

15379     else if (token->type == end)

15380       return ;

15381   }

15382 }

 

正常情况下,匹配的闭括号或闭大括号满足 15379 行的条件,使得函数体面退出。但是 15360 行的条件,并不像注释所说的那样,括号间的分号而不是大括号将使得条件成立。例如内联函数:

void m1() {

   for (int j = 0 ; j < 10; j++)

{

  …

}

}

开括号所触发的缓存仅是红色部分的符号,余下至闭括号的符号被保存在函数体起始的开大括号所开启的缓存里。

 

139    static void

140    cp_token_cache_push_token (cp_token_cache *cache,                                 in parser.c

141                            cp_token *token)

142    {

143      cp_token_block *b = cache->last;

144   

145      /* See if we need to allocate a new token block.  */

146      if (!b || b->num_tokens == CP_TOKEN_BLOCK_NUM_TOKENS)

147      {

148        b = ggc_alloc_cleared (sizeof (cp_token_block));

149        b->prev = cache->last;

150        if (cache->last)

151        {

152          cache->last->next = b;

153          cache->last = b;

154        }

155        else

156          cache->first = cache->last = b;

157      }

158      /* Add this token to the current token block.  */

159      b->tokens[b->num_tokens++] = *token;

160    }

5.12.3.2.1.1.3.4.4.            退出方法的作用域

在看到该方法的声明符的时候,前端加入方法的作用域对象,并使得其成为当前作用域。现在我们跨过该方法定义的闭大括号,应该退入上一级的作用域。

 

11111  tree

11112  finish_method (tree decl)                                                                                 in decl.c

11113  {

11114    tree fndecl = decl;

11115    tree old_initial;

11116 

11117    tree link;

11118 

11119    if (decl == void_type_node)

11120     return decl;

11121

11122   old_initial = DECL_INITIAL (fndecl);

11123

11124   /* Undo the level for the parms (from start_method).

11125     This is like poplevel, but it causes nothing to be

11126     saved. Saving information here confuses symbol-table

11127     output routines. Besides, this information will

11128     be correctly output when this method is actually

11129     compiled.  */

11130

11131   /* Clear out the meanings of the local variables of this level;

11132     also record in each decl which block it belongs to.  */

11133

11134   for (link = current_binding_level ->names; link; link = TREE_CHAIN (link))

11135   {

11136     if (DECL_NAME (link) != NULL_TREE)

11137       pop_binding (DECL_NAME (link), link);

11138     my_friendly_assert (TREE_CODE (link) != FUNCTION_DECL, 163);

11139     DECL_CONTEXT (link) = NULL_TREE;

11140   }

11141

11142   poplevel (0, 0, 0);

11143

11144   DECL_INITIAL (fndecl) = old_initial;

11145

11146   /* We used to check if the context of FNDECL was different from

11147     current_class_type as another way to get inside here. This didn't work

11148     for String.cc in libg++.  */

11149   if (DECL_FRIEND_P (fndecl))

11150   {

11151     CLASSTYPE_INLINE_FRIENDS (current_class_type )

11152        = tree_cons (NULL_TREE, fndecl, CLASSTYPE_INLINE_FRIENDS (current_class_type ));

11153     decl = void_type_node;

11154   }

11155

11156   return decl;

11157 }

 

我们的构造函数其函数体是空的,那么, finish_method 及其调用的函数仅是调用了 leave_scope 。看到作用域对象断开同作用域链的连接,被链入 free_binding_level

点此打开

72 :“ Lock ”构造函数的 FUNCTION_DECL —退出作用域

5.12.3.2.1.1.3.4.5.            把构造函数插入类

回到 cp_parser_member_declaration ,接下来的 finish_member_declaration 完成对方法的处理。下面因为构造函数是声明在 struct 里,在 pushclass 5482 行, current_access_specifier 被设置为 access_public_node

 

2089   void

2090   finish_member_declaration (tree decl)                                                in semantics.c

2091   {

2092     if (decl == error_mark_node || decl == NULL_TREE)

2093       return ;

2094  

2095     if (decl == void_type_node)

2096       /* The COMPONENT was a friend, not a member, and so there's

2097         nothing for us to do.  */

2098       return ;

2099  

2100     /* We should see only one DECL at a time.  */

2101     my_friendly_assert (TREE_CHAIN (decl) == NULL_TREE, 0);

2102  

2103     /* Set up access control for DECL.  */

2104     TREE_PRIVATE (decl)

2105         = (current_access_specifier == access_private_node);

2106     TREE_PROTECTED (decl)

2107         = (current_access_specifier == access_protected_node);

2108     if (TREE_CODE (decl) == TEMPLATE_DECL)

2109     {

2110       TREE_PRIVATE (DECL_TEMPLATE_RESULT (decl)) = TREE_PRIVATE (decl);

2111       TREE_PROTECTED (DECL_TEMPLATE_RESULT (decl)) = TREE_PROTECTED (decl);

2112     }

2113  

2114     /* Mark the DECL as a member of the current class.  */

2115     DECL_CONTEXT (decl) = current_class_type ;

2116  

2117     /* [dcl.link]

2118  

2119       A C language linkage is ignored for the names of class members

2120       and the member function type of class member functions.  */

2121     if (DECL_LANG_SPECIFIC (decl) && DECL_LANGUAGE (decl) == lang_c)

2122       SET_DECL_LANGUAGE (decl, lang_cplusplus);

2123  

2124     /* Put functions on the TYPE_METHODS list and everything else on the

2125       TYPE_FIELDS list. Note that these are built up in reverse order.

2126       We reverse them (to obtain declaration order) in finish_struct.  */

2127     if (TREE_CODE (decl) == FUNCTION_DECL

2128         || DECL_FUNCTION_TEMPLATE_P (decl))

2129     {

2130       /* We also need to add this function to the

2131          CLASSTYPE_METHOD_VEC.  */

2132       add_method (current_class_type , decl, /*error_p=*/ 0);

2133  

2134       TREE_CHAIN (decl) = TYPE_METHODS (current_class_type );

2135       TYPE_METHODS (current_class_type ) = decl;

2136  

2137       maybe_add_class_template_decl_list (current_class_type , decl,

2138                                      /*friend_p=*/ 0);

2139     }

2140     /* Enter the DECL into the scope of the class.  */

2141     else if ((TREE_CODE (decl) == USING_DECL && TREE_TYPE (decl))

2142            || pushdecl_class_level (decl))

2143     {

          …

2172     }

2173   }

 

现在可以向类的节点加入这个方法了。在前端中,类保持一个向量( vector )来保存在其中声明的所有方法。对于构造函数及析构函数,它们是常用的方法,因此它们放在固定的位置( 0 对应构造函数, 1 对应析构函数)。

 

721    void

722    add_method (tree type, tree method, int error_p)                                        in class.c

723    {

724      int using;

725      int len;

726      int slot;

727      tree method_vec;

728      int template_conv_p;

729   

730      if (method == error_mark_node)

731        return ;

732     

733      using = (DECL_CONTEXT (method) != type);

734      template_conv_p = (TREE_CODE (method) == TEMPLATE_DECL

735                         && DECL_TEMPLATE_CONV_FN_P (method));

736   

737      if (!CLASSTYPE_METHOD_VEC (type))

738        /* Make a new method vector. We start with 8 entries. We must

739          allocate at least two (for constructors and destructors), and

740          we're going to end up with an assignment operator at some point

741          as well.

742          

743          We could use a TREE_LIST for now, and convert it to a TREE_VEC

744          in finish_struct, but we would probably waste more memory

745          making the links in the list than we would by over-allocating

746          the size of the vector here. Furthermore, we would complicate

747          all the code that expects this to be a vector.  */

748        CLASSTYPE_METHOD_VEC (type) = make_tree_vec (8);

749   

750      method_vec = CLASSTYPE_METHOD_VEC (type);

751      len = TREE_VEC_LENGTH (method_vec);

752   

753      /* Constructors and destructors go in special slots.  */

754      if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (method))

755        slot = CLASSTYPE_CONSTRUCTOR_SLOT;

756      else if (DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (method))

757      {

758        slot = CLASSTYPE_DESTRUCTOR_SLOT;

759        TYPE_HAS_DESTRUCTOR (type) = 1;

760         

761        if (TYPE_FOR_JAVA (type))

762          error (DECL_ARTIFICIAL (method)

763               ? "Java class '%T' cannot have an implicit non-trivial destructor"

764               : "Java class '%T' cannot have a destructor",

765                 DECL_CONTEXT (method));

766      }

767      else

768      {

          …

866      }

867         

868      if (processing_template_decl )

869        /* TYPE is a template class. Don't issue any errors now; wait

870          until instantiation time to complain.  */

871        ;

872      else

873      {

          …

949      }

950   

951      /* Actually insert the new method.   */

952      TREE_VEC_ELT (method_vec, slot)

953         = build_overload (method, TREE_VEC_ELT (method_vec, slot));

954   

955      /* Add the new binding.  */

956      if (!DECL_CONSTRUCTOR_P (method)

957         && !DECL_DESTRUCTOR_P (method))

958        push_class_level_binding (DECL_NAME (method),

959                              TREE_VEC_ELT (method_vec, slot));

960    }

 

另外,对于类模板, maybe_add_class_template_decl_list 也要把该方法记录在该类模板的 decl_list 中。

点此打开

73 :加入默认构造函数

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值