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

4.1.3.1.2.1.2.              读入中间形式的PCH内容

之前,我们已经看到一些变量在声明中使用了GTY((…))GC程序(垃圾回收器)将解析指定的文件(在指定列表外的文件中的GTY((…))是不被解析的,它们将导致编译错误——未定义的识别符),并将结果输出到加上gt-前缀的同名文件中。而该文件才作为编译编译器时的真正输入。因此,以下所涉及的变量才是编译器真正使用的,它们来自由GC工具处理的,具有GTY((…))修饰的变量。

GC搜集GTY((…))所修饰变量的属性。那些被用作自由缓存(free buffer)的变量被搜集入gt_ggc_deletable_rtab,这里在543行,这些自由缓存被清空。

 

531    void

532    gt_pch_restore (FILE *f)                                                                  in ggc-common.c

533    {

534      const struct ggc_root_tab *const *rt;

535      const struct ggc_root_tab *rti;

536      size_t i;

537      struct mmap_info mmi;

538      int result;

539   

540      /* Delete any deletable objects. This makes ggc_pch_read much

541        faster, as it can be sure that no GCable objects remain other

542        than the ones just read in.  */

543      for (rt = gt_ggc_deletable_rtab; *rt; rt++)

544        for (rti = *rt; rti->base != NULL; rti++)

545          memset (rti->base, 0, rti->stride);

546   

547      /* Read in all the scalar variables.  */

548      for (rt = gt_pch_scalar_rtab; *rt; rt++)

549        for (rti = *rt; rti->base != NULL; rti++)

550          if (fread (rti->base, rti->stride, 1, f) != 1)

551            fatal_error ("can't read PCH file: %m");

552   

553      /* Read in all the global pointers, in 6 easy loops.  */

554      for (rt = gt_ggc_rtab; *rt; rt++)

555        for (rti = *rt; rti->base != NULL; rti++)

556          for (i = 0; i < rti->nelt; i++)

557            if (fread ((char *)rti->base + rti->stride * i,

558               sizeof (void *), 1, f) != 1)

559              fatal_error ("can't read PCH file: %m");

560   

561      for (rt = gt_pch_cache_rtab; *rt; rt++)

562        for (rti = *rt; rti->base != NULL; rti++)

563          for (i = 0; i < rti->nelt; i++)

564            if (fread ((char *)rti->base + rti->stride * i,

565               sizeof (void *), 1, f) != 1)

566              fatal_error ("can't read PCH file: %m");

567   

568      if (fread (&mmi, sizeof (mmi), 1, f) != 1)

569        fatal_error ("can't read PCH file: %m");

570   

571      result = host_hooks.gt_pch_use_address (mmi.preferred_base, mmi.size,

572                                       fileno (f), mmi.offset);

573      if (result < 0)

574        fatal_error ("had to relocate PCH");

575      if (result == 0)

576      {

577        if (fseek (f, mmi.offset, SEEK_SET) != 0

578           || fread (mmi.preferred_base, mmi.size, 1, f) != 1)

579        fatal_error ("can't read PCH file: %m");

580      }

581      else if (fseek (f, mmi.offset + mmi.size, SEEK_SET) != 0)

582        fatal_error ("can't read PCH file: %m");

583   

584      ggc_pch_read (f, mmi.preferred_base);

585   

586      gt_pch_restore_stringpool ();

587    }

 

以上代码按部就班地读入这个PCH文件的中间代码部分,其步骤如下。

4.1.3.1.2.1.2.1.        纯量变量的内容

GC把指定文件中由GTY((…))修饰的纯量变量(scalar variable),搜集入数组gt_pch_scalar_rtab,在上面548行,这些变量被首先读入。

 

137    const struct ggc_root_tab * const gt_pch_scalar_rtab[] = {                                  in gtype-c.h

138      gt_pch_rs_gtype_desc_c,

139      gt_pch_rs_gt_alias_h,

140      gt_pch_rs_gt_dbxout_h,

141      gt_pch_rs_gt_dwarf2out_h,

142      gt_pch_rs_gt_dwarf2asm_h,

143      gt_pch_rs_gt_emit_rtl_h,

144      gt_pch_rs_gt_except_h,

145      gt_pch_rs_gt_function_h,

146      gt_pch_rs_gt_langhooks_h,

147      gt_pch_rs_gt_sdbout_h,

148      gt_pch_rs_gt_tree_h,

149      gt_pch_rs_gt_varasm_h,

150      gt_pch_rs_gt_c_decl_h,

151      NULL

152    };

 

这个数组的元素具有如下类型ggc_root_tabgt_pointer_walker是一个函数指针。

 

67      struct ggc_root_tab {                                                                                in gtype-c.h

68        void *base;

69        size_t nelt;

70        size_t stride;

71        gt_pointer_walker cb;

72        gt_pointer_walker pchw;

73      };

 

如上所示,从相关的文件中抽取出来,这些元素构成了相应的数组。从它们的名字中,我们可以知道它们从何而来,例如,gt_pch_rs_gt_alias_halias.c文件产生。

纯量变量的内容包括为GC管理的全局数组的大小。例如gt_pch_rs_gtype_desc_c具有如下定义:

 

4532 const struct ggc_root_tab gt_pch_rs_gtype_desc_c[] = {                         in gtype-desc.c

4533   { &cgraph_varpool_n_nodes, 1, sizeof (cgraph_varpool_n_nodes), NULL, NULL },

4534   { &cgraph_max_uid, 1, sizeof (cgraph_max_uid), NULL, NULL },

4535   { &cgraph_n_nodes, 1, sizeof (cgraph_n_nodes), NULL, NULL },

4536   LAST_GGC_ROOT_TAB

4537 };

 

其中,cgraph_varpool_n_nodes保存了cgraph_varpool_nodes的长度,而cgraph_n_node则表示cgraph_nodes的长度。这2个数组则由下面的gt_ggc_rtab引用。.

4.1.3.1.2.1.2.2.        全局数组的内容

GC管理的全局数组由gt_ggc_rtab引用。这些对象同样按文件组织并由GC的工具产生。

 

55      const struct ggc_root_tab * const gt_ggc_rtab[] = {                                     in gtype-c.h

56        gt_ggc_r_gt_coverage_h,

57        gt_ggc_r_gtype_desc_c,

58        gt_ggc_r_gt_alias_h,

59        gt_ggc_r_gt_cselib_h,

60        gt_ggc_r_gt_cgraph_h,

61        gt_ggc_r_gt_dbxout_h,

62        gt_ggc_r_gt_dwarf2out_h,

63        gt_ggc_r_gt_dwarf2asm_h,

64        gt_ggc_r_gt_dojump_h,

65        gt_ggc_r_gt_emit_rtl_h,

66        gt_ggc_r_gt_except_h,

67        gt_ggc_r_gt_explow_h,

68        gt_ggc_r_gt_expr_h,

69        gt_ggc_r_gt_fold_const_h,

70        gt_ggc_r_gt_function_h,

71        gt_ggc_r_gt_gcse_h,

72        gt_ggc_r_gt_integrate_h,

73        gt_ggc_r_gt_optabs_h,

74        gt_ggc_r_gt_ra_build_h,

75        gt_ggc_r_gt_regclass_h,

76        gt_ggc_r_gt_reg_stack_h,

77        gt_ggc_r_gt_cfglayout_h,

78        gt_ggc_r_gt_langhooks_h,

79        gt_ggc_r_gt_sdbout_h,

80        gt_ggc_r_gt_stor_layout_h,

81        gt_ggc_r_gt_stringpool_h,

82        gt_ggc_r_gt_tree_h,

83        gt_ggc_r_gt_varasm_h,

84        gt_ggc_r_gt_i386_h,

85        gt_ggc_r_gt_c_parse_h,

86        gt_ggc_r_gt_c_decl_h,

87        gt_ggc_r_gt_c_common_h,

88        gt_ggc_r_gt_c_pragma_h,

89        NULL

90      };

 

这个数组元素的一个例子显示如下。在下面的结构体中,gt_ggc_mx_rtx_def引用了访问GC所管理的数组元素内容的方法,而gt_pch_nx_rtx_def引用了把整个结构存入GCsaving_htab的方法。saving_htab随后被写入PCH文件。

 

25      const struct ggc_root_tab gt_ggc_r_gt_coverage_h[] = {                       in gt-coverage.h

26        {

27          &ctr_labels[0],

28          1 * (GCOV_COUNTERS),

29          sizeof (ctr_labels[0]),

30          &gt_ggc_mx_rtx_def,

31          &gt_pch_nx_rtx_def

32        },

33        LAST_GGC_ROOT_TAB

34      };

4.1.3.1.2.1.2.3.        哈希表

同样在GCC中,某些哈希表也是由GC管理。以下被gt_pch_cache_rtab引用到的哈希表包括:const_double_htabreg_attrs_htabmem_attrs_htabconst_int_htab(出现在gt_pch_rc_gt_emit_rtl_h中,而这个对象保存,到目前为止在RTL生成阶段,所产生的常量对象);size_htab(出现在gt_pch_rc_gt_fold_const_h中,这个对象保存到目前为止编译器所要求的INTEGER_CST);type_hash_table(出现在gt_pch_rc_gt_tree_h中,这个对象是声明类型的哈希表)。

 

118     const struct ggc_root_tab * const gt_pch_cache_rtab[] = {                                   in gtype-c.h

119       gt_pch_rc_gt_emit_rtl_h,

120      gt_pch_rc_gt_fold_const_h,

121      gt_pch_rc_gt_tree_h,

122      NULL

123    };

4.1.3.1.2.1.2.4.        映射文件内容至虚存

除了上面这些在编译过程使用到的编译器内部变量,PCH文件本身的内容尚未读入。这个内容,在产生这个PCH文件时,是一棵中间形式的树。如何处理其中的指针是个大问题。在当前版本的GCC中,在写入PCH文件,是直接把这棵树映射入文件,并在如下mmap_info结构中记录有关映射的信息(关于映射文件,参考Linux有关内容,在此不详述)。

 

414    struct mmap_info                                                                              in ggc-common.c

415    {

416      size_t offset;

417      size_t size;

418      void *preferred_base;

419    };

 

那么在读入PCH文件这部分内容时,相应地要将其映射入同一地址。这样做的原因很显然,因为PCH文件中同时也保存了其中的识别符,要在恢复的树中正确地访问到这些识别符,必须要严格地匹配这2边的地址。在gt_pch_restore571行,gt_pch_use_address执行这个映射,在Linux平台上,这个钩子引用以下函数。

 

170    static int

171    linux_gt_pch_use_address (void *base, size_t size, int fd, size_t offset) in host-linux.c

172    {

173      void *addr;

174   

175      /* We're called with size == 0 if we're not planning to load a PCH

176        file at all. This allows the hook to free any static space that

177        we might have allocated at link time.  */

178      if (size == 0)

179        return -1;

180   

181      /* Try to map the file with MAP_PRIVATE.  */

182      addr = mmap (base, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, offset);

183   

184      if (addr == base)

185        return 1;

186   

187      if (addr != (void *) MAP_FAILED)

188        munmap (addr, size);

189   

190      /* Try to make an anonymous private mmap at the desired location.  */

191      addr = mmap (base, size, PROT_READ | PROT_WRITE,

192                MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);

193   

194      if (addr != base)

195      {

196        if (addr != (void *) MAP_FAILED)

197          munmap (addr, size);

198        return -1;

199      }

200   

201      if (lseek (fd, offset, SEEK_SET) == (off_t)-1)

202        return -1;

203   

204      while (size)

205      {

206        ssize_t nbytes;

207   

208        nbytes = read (fd, base, MIN (size, SSIZE_MAX));

209        if (nbytes <= 0)

210          return -1;

211         base = (char *) base + nbytes;

212        size -= nbytes;

213      }

214   

215      return 1;

216    }

 

上面的mmapLinux的系统调用,其细节参考Linux的手册。注意到如果文件不能映射至内存地址base,读入操作即失败。

回到gt_pch_restore,通过调用linux_gt_pch_use_address,在指定地址和大小的虚存已被保留,但物理内存尚未分配,现在584行,ggc_pch_read获取物理内存并读入文件内容。我们在以后看GC如何管理内存。

4.1.3.1.2.1.2.4.1.  恢复识别符

上面恢复了树形式的PCH文件内容,但树中的对象多为指针。其中所引用到的识别符虽然已经读入,但尚不能访问。它们必须出现在ident_hash中,编译器才能意识到其存在。

 

260    void

261    gt_pch_restore_stringpool (void)                                                       in stringpool.c

262    {

263      unsigned int i;

264   

265      ident_hash->nslots = spd->nslots;

266      ident_hash->nelements = spd->nelements;

267      ident_hash->entries = xrealloc (ident_hash->entries,

268                                sizeof (hashnode) * spd->nslots);

269      for (i = 0; i < spd->nslots; i++)

270        if (spd->entries[i] != NULL)

271          ident_hash->entries[i] = GCC_IDENT_TO_HT_IDENT (spd->entries[i]);

272        else

273          ident_hash->entries[i] = NULL;

274   

275      spd = NULL;

276    }

 

其中spdgt_ggc_r_gt_stringpool_h之中,gt_ggc_r_gt_stringpool_h则包含在gt_ggc_rtab内。

4.1.3.1.2.1.5.              恢复保存的宏及#pragma

预处理头文件对宏的使用有如下限制:在预处理头文件前定义的宏,要么与预处理头文件产生时的定义相同,要么不影响这个预处理头文件(这通常意味着这个宏不出现在该头文件中)。

这里首先恢复这些在预处理头文件前的宏,PCH文件中的宏定义在后面才读入,以符合其出现的次序。

 

605    int

606    cpp_read_state (cpp_reader *r, const char *name, FILE *f,                          in cpppch.c

607                struct save_macro_data *data)

608    {

609      struct macrodef_struct m;

610      size_t defnlen = 256;

611       unsigned char *defn = xmalloc (defnlen);

612      struct lexer_state old_state;

613      struct save_macro_item *d;

614      size_t i, mac_count;

615      int saved_line = r->line;

616   

617     /* Restore spec_nodes, which will be full of references to the old

618        hashtable entries and so will now be invalid.  */

619      {

620        struct spec_nodes *s = &r->spec_nodes;

621        s->n_defined       = cpp_lookup (r, DSC("defined"));

622        s->n_true     = cpp_lookup (r, DSC("true"));

623        s->n_false    = cpp_lookup (r, DSC("false"));

624        s->n__VA_ARGS__ = cpp_lookup (r, DSC("__VA_ARGS__"));

625      }

626   

627     /* Run through the carefully-saved macros, insert them.  */

628      d = data->macros;

629      mac_count = data->count;

630      while (d)

631      {

632        struct save_macro_item *nextd;

633        for (i = 0; i < mac_count; i++)

634        {

635          cpp_hashnode *h;

636          

637          h = cpp_lookup (r, HT_STR (HT_NODE (&d->macs[i])),

638                        HT_LEN (HT_NODE (&d->macs[i])));

639          h->type = d->macs[i].type;

640          h->flags = d->macs[i].flags;

641          h->value = d->macs[i].value;

642          free ((void *)HT_STR (HT_NODE (&d->macs[i])));

643        }

644        nextd = d->next;

645        free (d);

646        d = nextd;

647        mac_count = ARRAY_SIZE (d->macs);

648      }

649   

650      _cpp_restore_pragma_names (r, data->saved_pragmas);

651   

652      free (data);

 

类似的同样有#pragma指示。

 

1124 void

1125 _cpp_restore_pragma_names (cpp_reader *pfile, char **saved)                     in cpplib.c

1126 {

1127   (void) restore_registered_pragmas (pfile, pfile->pragmas, saved);

1128   free (saved);

1129 }

 

1107 static char **

1108 restore_registered_pragmas (cpp_reader *pfile, struct pragma_entry *pe,

1109                  char **sd)

1110 {

1111   for (; pe != NULL; pe = pe->next)

1112   {

1113     if (pe->is_nspace)

1114       sd = restore_registered_pragmas (pfile, pe->u.space, sd);

1115     pe->pragma = cpp_lookup (pfile, U *sd, strlen (*sd));

1116     free (*sd);

1117     sd++;

1118   }

1119   return sd;

1120 }

 

你可能感兴趣的:(linux,struct,File,null,编译器,fold)