Studying note of GCC-3.4.6 source (155)

5.13.2.      Output PCH file

Seeing something related to conversion, resumes our example in after-parsing stage. Return from expand_or_defer_fn we are back cp_parser_function_definition_after_declarator which returns the FUNCTION_DECL immediately, and which is returned in turn by cp_parser_function_definition_from_specifiers_and_declarator , then cp_parser_init_declarator , cp_parser_simple_declaration , cp_parser_block_declaration , cp_parser_declaration , then in cp_parser_declaration_seq_opt EOF breaks the WHILE loop at line 6224, and finally we return to the entry point of parser - cp_parser_translation_unit . In this function EOF is consumed at line 2336, and finish_translation_unit following restores the binding scope of global namespace.

Returning from cp_parser_translation_unit , now we are back in c_parser_file . Exitting it we go back to c_common_parse_file which is referred by parse_file of lang_hooks for C++. And see that c_parser_file is within a WHILE loop; if there is any other source file in the command line, the procedure we see in above will be repeated. That means if we use command line like: g++ -o all a.cc b.cc c.cc; the compiler will parse these three source files and put the result into a single tree of intermediate language. After all source files have been parsed, it comes to finish_file .

Arriving here, we must within the global namespace scope. Cheking at line 2540 promises it.

 

2527   void

2528   finish_file (void)                                                                                      in decl2.c

2529   {

2530     tree vars;

2531     bool reconsider;

2532     size_t i;

2533     location_t locus;

2534     unsigned ssdf_count = 0;

2535  

2536     locus = input_location ;

2537     at_eof = 1;

2538  

2539     /* Bad parse errors. Just forget about it.  */

2540     if (! global_bindings_p () || current_class_type || decl_namespace_list )

2541       return ;

2542  

2543     if (pch_file )

2544       c_common_write_pch ();

 

Below, cpp_write_pch_deps writes identifiers declared within files specified by this command line into PCH file designated by pch_outfile . And asm_file_startpos was set points to the end of asm_out_file in pch_init at time read in first source file; while in cpp_read_main_file at line 1242 in c_common_parse_file , asm_out_file is filled with content of included PCH files, and at line 177 asm_file_end points to the end of the file. So at line 178, h.asm_size will be the size of included PCH files. These content should be appended into the PCH file.

 

165    void

166    c_common_write_pch (void)                                                                    in c-pch.c

167    {

168      char *buf;

169      long asm_file_end;

170      long written;

171      struct c_pch_header h;

172   

173      (*debug_hooks ->handle_pch) (1);

174   

175      cpp_write_pch_deps (parse_in , pch_outfile );

176   

177      asm_file_end = ftell (asm_out_file );

178      h.asm_size = asm_file_end - asm_file_startpos ;

179     

180      if (fwrite (&h, sizeof (h), 1, pch_outfile ) != 1)

181        fatal_error ("can't write %s: %m", pch_file );

182     

183      buf = xmalloc (16384);

184      fflush (asm_out_file );

185   

186      if (fseek (asm_out_file , asm_file_startpos , SEEK_SET) != 0)

187        fatal_error ("can't seek in %s: %m", asm_file_name );

188   

189      for (written = asm_file_startpos ; written < asm_file_end; )

190      {

191        long size = asm_file_end - written;

192        if (size > 16384)

193          size = 16384;

194        if (fread (buf, size, 1, asm_out_file ) != 1)

195          fatal_error ("can't read %s: %m", asm_file_name );

196        if (fwrite (buf, size, 1, pch_outfile ) != 1)

197          fatal_error ("can't write %s: %m", pch_file );

198        written += size;

199      }

200      free (buf);

201      /* asm_out_file can be written afterwards, so must be flushed first.  */

202      fflush (asm_out_file );

203   

204      gt_pch_save (pch_outfile );

205      cpp_write_pch_state (parse_in , pch_outfile );

206   

207      if (fseek (pch_outfile , 0, SEEK_SET) != 0

208         || fwrite (get_ident (), IDENT_LENGTH, 1, pch_outfile ) != 1)

209        fatal_error ("can't write %s: %m", pch_file );

210   

211       fclose (pch_outfile );

212    }

 

Above at line 175, pch_outfile is the file handle opened for pch_file , which is also the same file handle written into in cpp_save_state . Now r->savedstate contains identifiers before us executing parsing for the files specified by command line.

 

299    int

300    cpp_write_pch_deps (cpp_reader *r, FILE *f)                                            in cpppch.c

301    {

302      struct macrodef_struct z;

303      struct cpp_savedstate *const ss = r->savedstate;

304      unsigned char *definedstrs;

305      size_t i;

306     

307      /* Collect the list of identifiers which have been seen and

308        weren't defined to anything previously.  */

309      ss->hashsize = 0;

310      ss->n_defs = 0;

311       cpp_forall_identifiers (r, count_defs , ss);

312   

313      ss->defs = xmalloc (ss->n_defs * sizeof (cpp_hashnode *));

314      ss->n_defs = 0;

315      cpp_forall_identifiers (r, write_defs , ss);

316   

317      /* Sort the list, copy it into a buffer, and write it out.  */

318      qsort (ss->defs, ss->n_defs, sizeof (cpp_hashnode *), &comp_hashnodes);

319      definedstrs = ss->definedstrs = xmalloc (ss->hashsize);

320      for (i = 0; i < ss->n_defs; ++i)

321      {

322        size_t len = NODE_LEN (ss->defs[i]);

323        memcpy (definedstrs, NODE_NAME (ss->defs[i]), len + 1);

324        definedstrs += len + 1;

325      }

326   

327      memset (&z, 0, sizeof (z));

328      z.definition_length = ss->hashsize;

329      if (fwrite (&z, sizeof (z), 1, f) != 1

330          || fwrite (ss->definedstrs, ss->hashsize, 1, f) != 1)

331      {

332        cpp_errno (r, CPP_DL_ERROR, "while writing precompiled header");

333        return -1;

334      }

335      free (ss->definedstrs);

336   

337      /* Free the saved state.  */

338      free (ss);

339      r->savedstate = NULL;

340      return 0;

341    }

 

Now the cpp_reader after parsing all files specified in command line, in its hash_table contains identifiers declared within those files. Then routine count_defs transverses the hash_table to count how many identifiers need be added, and calculate the size of buffer to hold names by hashsize field. Note that in save_idents invoked within cpp_save_state , node of type NT_VOID is ignored; but not here.

 

209    static int

210    count_defs (cpp_reader *pfile ATTRIBUTE_UNUSED, cpp_hashnode *hn, void *ss_p)

211     {

212      struct cpp_savedstate *const ss = (struct cpp_savedstate *)ss_p;

213     

214      switch (hn->type)

215      {

216        case NT_MACRO:

217          if (hn->flags & NODE_BUILTIN)

218            return 1;

219         

220          /* else fall through.  */

221   

222        case NT_VOID:

223        {

224          struct cpp_string news;

225          void **slot;

226        

227          news.len = NODE_LEN (hn);

228          news.text = NODE_NAME (hn);

229          slot = htab_find (ss->definedhash, &news);

230          if (slot == NULL)

231          {

232            ss->hashsize += NODE_LEN (hn) + 1;

233            ss->n_defs += 1;

234          }

235        }

236        return 1;

237   

238        case NT_ASSERTION:

239           /* Not currently implemented.  */

240          return 1;

241   

242        default :

243          abort ();

244      }

245    }

 

After allocating necessary resource, write_defs then iterates the hash_table of cpp_reader again to refer to identifiers not seen in cpp_save_state . Then after sorting at line 318 above, these names  are written into the PCH file.

 

248    static int

249    write_defs (cpp_reader *pfile ATTRIBUTE_UNUSED, cpp_hashnode *hn, void *ss_p)

250    {

251      struct cpp_savedstate *const ss = (struct cpp_savedstate *)ss_p;

252     

253      switch (hn->type)

254      {

255        case NT_MACRO:

256          if (hn->flags & NODE_BUILTIN)

257            return 1;

258         

259           /* else fall through.  */

260   

261        case NT_VOID:

262        {

263          struct cpp_string news;

264          void **slot;

265        

266          news.len = NODE_LEN (hn);

267          news.text = NODE_NAME (hn);

268          slot = htab_find (ss->definedhash, &news);

269          if (slot == NULL)

270          {

271            ss->defs[ss->n_defs] = hn;

272            ss->n_defs += 1;

273          }

274        }

275        return 1;

276   

277        case NT_ASSERTION:

278          /* Not currently implemented.  */

279          return 1;

280   

281        default :

282          abort ();

283      }

284    }

 

At the point of invoking gt_pch_save , the content of PCH file is shown in below figure. See that idn is the identifier that declared within source files by user.

t1

Further compiler generates many controlling data during compilation, and which we have seen is managed by GC. These data describe the characteristics of the program and effect the output of code emission, so must be saved in the PCH file.

 

423    void

424    gt_pch_save (FILE *f)                                                                             in ggc-common.c

425    {

426      const struct ggc_root_tab *const *rt;

427      const struct ggc_root_tab *rti;

428      size_t i;

429      struct traversal_state state;

430      char *this_object = NULL;

431      size_t this_object_size = 0;

432      struct mmap_info mmi;

433      size_t page_size = getpagesize();

434   

435      gt_pch_save_stringpool ();

 

Then gt_pch_save_stringpool saves the content of ident_hash , remember ident_hash is pointed by hash_table of the cpp_reader . First the content is copied into data structure of spd .

 

232    void

233    gt_pch_save_stringpool (void)                                                           in stringpool.c

234    {

235      unsigned int i;

236   

237      spd = ggc_alloc (sizeof (*spd ));

238      spd ->nslots = ident_hash ->nslots;

239      spd ->nelements = ident_hash ->nelements;

240      spd ->entries = ggc_alloc (sizeof (tree *) * spd ->nslots);

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

242        if (ident_hash ->entries[i] != NULL)

243          spd->entries[i] = HT_IDENT_TO_GCC_IDENT (ident_hash ->entries[i]);

244        else

245          spd->entries[i] = NULL;

246   

247      saved_ident_hash = ht_create (14);

248      saved_ident_hash ->alloc_node = alloc_node;

249      ht_forall (ident_hash , ht_copy_and_clear , saved_ident_hash );

250    }

 

To cache the content of ident_hash , spd has following structure. See that spd is within gt_ggc_r_gt_stringpool_h which is contained within gt_ggc_rtab . It will be written into the PCH file later and read out by files using the PCH file in gt_pch_restore_stringpool .

 

199    struct string_pool_data GTY(())                                                         in stringpool.c

200    {

201      tree * GTY((length ("%h.nslots"))) entries;

202      unsigned int nslots;

203      unsigned int nelements;

204    };

205

206     static GTY(()) struct string_pool_data * spd;

 

Second, it moves the content of ident_hash into saved_ident_hash with below function (it is cached to avoid affecting below procedure, it will be restored before exitting gt_pch_save ).

 

208    static int

209    ht_copy_and_clear (cpp_reader *r ATTRIBUTE_UNUSED, hashnode hp, const void *ht2_p)

210    {

211       cpp_hashnode *h = CPP_HASHNODE (hp);

212      struct ht *ht2 = (struct ht *) ht2_p;

213   

214      if (h->type != NT_VOID

215          && (h->flags & NODE_BUILTIN) == 0)

216      {

217        cpp_hashnode *h2 = CPP_HASHNODE (ht_lookup (ht2,

218                                          NODE_NAME (h),

219                                          NODE_LEN (h),

220                                          HT_ALLOC));

221        h2->type = h->type;

222        memcpy (&h2->value, &h->value, sizeof (h->value));

223   

224        h->type = NT_VOID;

225        memset (&h->value, 0, sizeof (h->value));

226      }

227      return 1;

228    }

 

Remember that in the compiler, all GC managing objects are processed by GC tool to generate gtype-* files. And in gtype-c.h, several global arrays are generated to hold the reference of these controlled objects. There are gt_ggc_rtab , gt_ggc_deletable_rtab (holds hash tables for deleted objects), gt_ggc_cache_rtab (used for garbage collection purpose), gt_pch_cache_rtab (same content as gt_ggc_cache_rtab but with different handling methods), gt_pch_scalar_rtab .

 

gt_pch_save (continue)

 

437      saving_htab = htab_create (50000, saving_htab_hash, saving_htab_eq, free);

438   

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

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

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

442            (*rti->pchw)(*(void **)((char *)rti->base + rti->stride * i));

443   

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

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

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

447            (*rti->pchw)(*(void **)((char *)rti->base + rti->stride * i));

448   

449      /* Prepare the objects for writing, determine addresses and such.  */

450      state.f = f;

451      state.d = init_ggc_pch();

452      state.count = 0;

453      htab_traverse (saving_htab , call_count , &state);

 

The content of PCH file is the intermediate code (i.e., in tree form), which we have already seen contains lots of pointers, how to maintain these pointers in PCH file, so as to they can be restored by the readin?

First of all, objects managed by GC are all global ones, and they form a close set (that is no reference to object outside of the set, and no object is referred from outside). Thus if copy the content and address of these objects faithfully into PCH file, then in reading restores them one by one, the PCH file’s content can be restored theoretically. However, it’s not practical as at reading the PCH file, some of the addresses are most likely occupied, it is hard to guarantee all addresses are usable; further restores objects one by one is inefficent.

As the global objects managed by GC form a close set, with memory management supported by the target, it would be able to: arranging all objects as compact as possible, and selecting a start address unlikely be occupied (for target using virtual memory, it is highly possible of unoccupancy), then updating all pointers in objects with these new addresses (assuming the start address usable); at last writing this mapping information, and updated objects into PCH file; by this way it can ensure this PCH file readin later. It is what GCC now does.

So the first step is to collect all pointers’ content in objects (including obejcts’ address), which is done by function referred by pchw , which saves this information into saving_htab . Takes cgraph_nodes_queue of gt_ggc_r_gtype_desc_c of gt_ggc_rtab as example, its pchw points to gt_pch_nx_cgraph_node which is generated by GC tool.

 

1306   void

1307   gt_pch_nx_cgraph_node (void *x_p)                                                 in gtype-desc.c

1308   {

1309     struct cgraph_node * x = (struct cgraph_node *)x_p;

1310     struct cgraph_node * xlimit = x;

1311     while (gt_pch_note_object (xlimit, xlimit, gt_pch_p_11cgraph_node ))

1312      xlimit = ((*xlimit).next);

1313     if (x != xlimit)

1314       for (;;)

1315       {

1316         struct cgraph_node * const xprev = ((*x).previous);

1317         if (xprev == NULL) break ;

1318         x = xprev;

1319         (void) gt_pch_note_object (xprev, xprev, gt_pch_p_11cgraph_node );

1320       }

1321     while (x != xlimit)

1322     {

1323       gt_pch_n_9tree_node ((*x).decl);

1324       gt_pch_n_11cgraph_edge ((*x).callees);

1325       gt_pch_n_11cgraph_edge ((*x).callers);

1326       gt_pch_n_11cgraph_node ((*x).next);

1327       gt_pch_n_11cgraph_node ((*x).previous);

1328       gt_pch_n_11cgraph_node ((*x).origin);

1329       gt_pch_n_11cgraph_node ((*x).nested);

1330       gt_pch_n_11cgraph_node ((*x).next_nested);

1331       gt_pch_n_11cgraph_node ((*x).next_needed);

1332       x = ((*x).next);

1333     }

1334   }

 

The key function here is gt_pch_note_object , routines gt_pch_n_* above also invoke gt_pch_note_object to cache nodes they handle.

 

251    int

252    gt_pch_note_object (void *obj, void *note_ptr_cookie,                        in ggc-common.c

253                     gt_note_pointers note_ptr_fn)

254    {

255      struct ptr_data **slot;

256   

257      if (obj == NULL || obj == (void *) 1)

258         return 0;

259   

260      slot = (struct ptr_data **)

261        htab_find_slot_with_hash (saving_htab , obj, POINTER_HASH (obj),

262                              INSERT);

263      if (*slot != NULL)

264      {

265        if ((*slot)->note_ptr_fn != note_ptr_fn

266           || (*slot)->note_ptr_cookie != note_ptr_cookie)

267          abort ();

268        return 0;

269      }

270   

271      *slot = xcalloc (sizeof (struct ptr_data), 1);

272      (*slot)->obj = obj;

273      (*slot)->note_ptr_fn = note_ptr_fn;

274      (*slot)->note_ptr_cookie = note_ptr_cookie;

275      if (note_ptr_fn == gt_pch_p_S)

276        (*slot)->size = strlen (obj) + 1;

277      else

278        (*slot)->size = ggc_get_size (obj);

279      return 1;

280    }

 

The content of saving_htab is of type ptr_data as below. Slot obj within the structure holds the address of the cached objects.

 

237    struct ptr_data                                                                                   in ggc-common.c

238    {

239      void *obj;

240      void *note_ptr_cookie;

241      gt_note_pointers note_ptr_fn;

242      gt_handle_reorder reorder_fn;

243      size_t size;

244      void *new_addr;

245    };

 

Then at line 453, htab_traverse iterates saving_htab and invokes call_count for every node within. See count field of state records the number of objects encountered.

 

328    static int

329    call_count (void **slot, void *state_p)                                                in ggc-common.c

330    {

331      struct ptr_data *d = (struct ptr_data *)*slot;

332      struct traversal_state *state = (struct traversal_state *)state_p;

333   

334      ggc_pch_count_object (state->d, d->obj, d->size, d->note_ptr_fn == gt_pch_p_S);

335      state->count++;

336      return 1;

337    }

 

Under Linux platform as target, ggc-page.c will be selected as the file offers memory management. Routine ggc_pch_count_object defined in the file helps to count the number of objects with specified size; order below indicates the size of 2 with power of order (it will be the size of memory allocated under page mechanism).

 

1941   void

1942   ggc_pch_count_object (struct ggc_pch_data *d, void *x ATTRIBUTE_UNUSED,

1943                        size_t size, bool is_string ATTRIBUTE_UNUSED)

1944   {

1945     unsigned order;

1946  

1947     if (size <= 256)

1948       order = size_lookup [size];

1949     else

1950     {

1951       order = 9;

1952       while (size > OBJECT_SIZE (order))

1953         order++;

1954     }

1955  

1956     d->d.totals[order]++;

1957   }

 

Below it will select the new start address which will be followed by the read-in procedure.

 

gt_pch_save (continue)

 

455      mmi.size = ggc_pch_total_size (state.d);

456   

457      /* Try to arrange things so that no relocation is necessary, but

458        don't try very hard. On most platforms, this will always work,

459        and on the rest it's a lot of work to do better. 

460        (The extra work goes in HOST_HOOKS_GT_PCH_GET_ADDRESS and

461        HOST_HOOKS_GT_PCH_USE_ADDRESS.)  */

462      mmi.preferred_base = host_hooks .gt_pch_get_address (mmi.size, fileno (f));

463         

464      ggc_pch_this_base (state.d, mmi.preferred_base);

465   

466      state.ptrs = xmalloc (state.count * sizeof (*state.ptrs));

467      state.ptrs_i = 0;

468      htab_traverse (saving_htab , call_alloc , &state);

469      qsort (state.ptrs, state.count, sizeof (*state.ptrs), compare_ptr_data);

470   

471      /* Write out all the scalar variables.  */

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

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

474          if (fwrite (rti->base, rti->stride, 1, f) != 1)

475             fatal_error ("can't write PCH file: %m");

 

First it needs know the total size of memory requested. The size is rounded up to the closest page boundary.

 

1959   size_t

1960   ggc_pch_total_size (struct ggc_pch_data *d)                                             in ggc-page.c

1961   {

1962     size_t a = 0;

1963     unsigned i;

1964  

1965     for (i = 0; i < NUM_ORDERS; i++)

1966       a += ROUND_UP (d->d.totals[i] * OBJECT_SIZE (i), G .pagesize);

1967     return a;

1968   }

 

Further the objects are handled with increasing size order, and all objects of the same size allocated will be placed tegother; base slot of below structure then gives the beginning address for these objects.

 

1925   struct ggc_pch_data                                                                                  in ggc-page.c

1926   {

1927     struct ggc_pch_ondisk

1928     {

1929       unsigned totals[NUM_ORDERS];

1930     } d;

1931     size_t base[NUM_ORDERS];

1932     size_t written[NUM_ORDERS];

1933   };

 

Under paging mechanism, all bases should also be rounded up to page boundary. See that every group of different size would have its own base.

 

1970   void

1971   ggc_pch_this_base (struct ggc_pch_data *d, void *base)                                   in ggc-page.c

1972   {

1973     size_t a = (size_t) base;

1974     unsigned i;

1975  

1976     for (i = 0; i < NUM_ORDERS; i++)

1977     {

1978       d->base[i] = a;

1979       a += ROUND_UP (d->d.totals[i] * OBJECT_SIZE (i), G .pagesize);

1980     }

1981   }

 

With above information, esepcially bases for objects, cached objects within saving_htab are relocated by call_alloc . Note that argument slot is the object comes from saving_htab .

 

339    static int

340    call_alloc (void **slot, void *state_p)                                                 in ggc-common.c

341    {

342      struct ptr_data *d = (struct ptr_data *)*slot;

343      struct traversal_state *state = (struct traversal_state *)state_p;

344   

345      d->new_addr = ggc_pch_alloc_object (state->d, d->obj, d->size, d->note_ptr_fn == gt_pch_p_S);

346      state->ptrs[state->ptrs_i++] = d;

347      return 1;

348    }

 

See at line 345, new_addr holds the address after relocating the object, and in function below, base slot of d always refers to the next available address for coming object, it is a rehearsal for memory allocation not real resource allocated yet.

 

1984   char *

1985   ggc_pch_alloc_object (struct ggc_pch_data *d, void *x ATTRIBUTE_UNUSED,  in ggc-page.c

1986                      size_t size, bool is_string ATTRIBUTE_UNUSED)

1987   {

1988     unsigned order;

1989     char *result;

1990  

1991     if (size <= 256)

1992       order = size_lookup [size];

1993     else

1994     {

1995       order = 9;

1996       while (size > OBJECT_SIZE (order))

1997         order++;

1998     }

1999  

2000     result = (char *) d->base[order];

2001     d->base[order] += OBJECT_SIZE (order);

2002     return result;

2003   }

 

Now in state below, its ptrs array refers to objects and with new_addr slot of every entity records the remapped address for the specified object.

 

gt_pch_save (continue)

 

477      /* Write out all the global pointers, after translation.  */

478      write_pch_globals (gt_ggc_rtab , &state);

479      write_pch_globals (gt_pch_cache_rtab , &state);

 

See write_pch_globals writes in the new address of the objects into PCH file.

 

381    static void

382    write_pch_globals (const struct ggc_root_tab * const *tab,                  in ggc-common.c

383                    struct traversal_state *state)

384    {

385      const struct ggc_root_tab *const *rt;

386      const struct ggc_root_tab *rti;

387      size_t i;

388   

389      for (rt = tab; *rt; rt++)

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

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

392           {

393            void *ptr = *(void **)((char *)rti->base + rti->stride * i);

394            struct ptr_data *new_ptr;

395            if (ptr == NULL || ptr == (void *)1)

396            {

397              if (fwrite (&ptr, sizeof (void *), 1, state->f)

398                   != 1)

399                fatal_error ("can't write PCH file: %m");

400            }

401            else

402            {

403              new_ptr = htab_find_with_hash (saving_htab , ptr,

404                                         POINTER_HASH (ptr));

405              if (fwrite (&new_ptr->new_addr, sizeof (void *), 1, state->f)

406                    != 1)

407                fatal_error ("can't write PCH file: %m");

408            }

409         }

410    }

 

After that is the part needs be mapped correctly during readning in. As long as this part is mapped correctly, the addresses recorded above are meaningful. In the rest part, except structure of mmi, the left part must be laid at page boundary (fill 0 it between and mmi), so on target OS offering system call mmap, it can be mapped directly by mmap.

 

gt_pch_save (continue)

 

481      ggc_pch_prepare_write (state.d, state.f);

482   

483      /* Pad the PCH file so that the mmapped area starts on a page boundary.  */

484      {

485        long o;

486        o = ftell (state.f) + sizeof (mmi);

487        if (o == -1)

488          fatal_error ("can't get position in PCH file: %m");

489        mmi.offset = page_size - o % page_size;

490        if (mmi.offset == page_size)

491          mmi.offset = 0;

492        mmi.offset += o;

493      }

494      if (fwrite (&mmi, sizeof (mmi), 1, state.f) != 1)

495        fatal_error ("can't write PCH file: %m");

496      if (mmi.offset != 0

497          && fseek (state.f, mmi.offset, SEEK_SET) != 0)

498        fatal_error ("can't write padding to PCH file: %m");

499   

500      /* Actually write out the objects.  */

501      for (i = 0; i < state.count; i++)

502      {

503        if (this_object_size < state.ptrs[i]->size)

504        {

505          this_object_size = state.ptrs[i]->size;

506          this_object = xrealloc (this_object, this_object_size);

507        }

508        memcpy (this_object, state.ptrs[i]->obj, state.ptrs[i]->size);

509        if (state.ptrs[i]->reorder_fn != NULL)

510          state.ptrs[i]->reorder_fn (state.ptrs[i]->obj,

511                                state.ptrs[i]->note_ptr_cookie,

512                               relocate_ptrs, &state);

513        state.ptrs[i]->note_ptr_fn (state.ptrs[i]->obj,

514                             state.ptrs[i]->note_ptr_cookie,

515                             relocate_ptrs , &state);

516        ggc_pch_write_object (state.d, state.f, state.ptrs[i]->obj,

517                           state.ptrs[i]->new_addr, state.ptrs[i]->size,

518                           state.ptrs[i]->note_ptr_fn == gt_pch_p_S);

519        if (state.ptrs[i]->note_ptr_fn != gt_pch_p_S)

520          memcpy (state.ptrs[i]->obj, this_object, state.ptrs[i]->size);

521      }

522      ggc_pch_finish (state.d, state.f);

523      gt_pch_fixup_stringpool ();

524   

525      free (state.ptrs);

526      htab_delete (saving_htab );

527    }

 

FOR loop at line 501 above, then writes the content of these GC managed objects into the file. Note that their content must be updated with the new addresses. Objects hold in array ptrs were allocated by gt_pch_note_object , which have empty reorder_fn but filled note_ptr_fn . Take cgraph_nodes_queue as example, its note_ptr_fn points to gt_pch_p_11cgraph_node .

 

2625   void

2626   gt_pch_p_11cgraph_node (void *this_obj ATTRIBUTE_UNUSED,               in ggc-desc.c

2627        void *x_p,

2628        gt_pointer_operator op ATTRIBUTE_UNUSED,

2629        void *cookie ATTRIBUTE_UNUSED)

2630   {

2631     struct cgraph_node * const x ATTRIBUTE_UNUSED = (struct cgraph_node *)x_p;

2632     if ((void *)(x) == this_obj)

2633       op (&((*x).decl), cookie);

2634     if ((void *)(x) == this_obj)

2635       op (&((*x).callees), cookie);

2636     if ((void *)(x) == this_obj)

2637       op (&((*x).callers), cookie);

2638     if ((void *)(x) == this_obj)

2639       op (&((*x).next), cookie);

2640     if ((void *)(x) == this_obj)

2641       op (&((*x).previous), cookie);

2642     if ((void *)(x) == this_obj)

2643       op (&((*x).origin), cookie);

2644     if ((void *)(x) == this_obj)

2645       op (&((*x).nested), cookie);

2646     if ((void *)(x) == this_obj)

2647       op (&((*x).next_nested), cookie);

2648     if ((void *)(x) == this_obj)

2649       op (&((*x).next_needed), cookie);

2650   }

 

The function invokes function referred by op to update slots holding addresses within the object accordingly. Op ususally refers to relocate_ptrs .

 

363    static void

364    relocate_ptrs (void *ptr_p, void *state_p)                                                  in ggc-common.c

365    {

366      void **ptr = (void **)ptr_p;

367      struct traversal_state *state ATTRIBUTE_UNUSED

368        = (struct traversal_state *)state_p;

369      struct ptr_data *result;

370   

371      if (*ptr == NULL || *ptr == (void *)1)

372        return ;

373   

374      result = htab_find_with_hash (saving_htab , *ptr, POINTER_HASH (*ptr));

375      if (result == NULL)

376        abort ();

377      *ptr = result->new_addr;

378    }

 

At line 516, ggc_pch_write_object writes the updated content of objects into the file. Then ggc_pch_finish release d in state . And ident_hash is restored by gt_pch_fixup_stringpool .

 

252    void

253    gt_pch_fixup_stringpool (void)                                                          in stringpool.c

254    {

255      ht_forall (saved_ident_hash , ht_copy_and_clear , ident_hash );

256      ht_destroy (saved_ident_hash );

257      saved_ident_hash = 0;

258    }

 

The last part of the PCH file then is the macro’s definitions within its source file and the dependence information carried by –MT or –MQ option.

 

364    int

365    cpp_write_pch_state (cpp_reader *r, FILE *f)                                                  in cpppch.c

366    {

367      struct macrodef_struct z;

368   

369      /* Write out the list of defined identifiers.  */

370      cpp_forall_identifiers (r, write_macdef , f);

371      memset (&z, 0, sizeof (z));

372      if (fwrite (&z, sizeof (z), 1, f) != 1)

373      {

374        cpp_errno (r, CPP_DL_ERROR, "while writing precompiled header");

375        return -1;

376      }

377   

378      if (!r->deps)

379        r->deps = deps_init ();

380   

381      if (deps_save (r->deps, f) != 0)

382      {

383        cpp_errno (r, CPP_DL_ERROR, "while writing precompiled header");

384        return -1;

385      }

386   

387      return 0;

388    }

 

Finally, the content of a PCH file is shown as below figure.

t2

Figure 118 : Content of PCH file

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值