+ SCALE (G.bytes_mapped), STAT_LABEL (G.bytes_mapped),
+ SCALE (G.allocated), STAT_LABEL(G.allocated),
+ SCALE (total_overhead), STAT_LABEL (total_overhead));
+
+#ifdef GATHER_STATISTICS
+ {
+ fprintf (stderr, "\nTotal allocations and overheads during the compilation process\n");
+
+ fprintf (stderr, "Total Overhead: %10lld\n",
+ G.stats.total_overhead);
+ fprintf (stderr, "Total Allocated: %10lld\n",
+ G.stats.total_allocated);
+
+ fprintf (stderr, "Total Overhead under 32B: %10lld\n",
+ G.stats.total_overhead_under32);
+ fprintf (stderr, "Total Allocated under 32B: %10lld\n",
+ G.stats.total_allocated_under32);
+ fprintf (stderr, "Total Overhead under 64B: %10lld\n",
+ G.stats.total_overhead_under64);
+ fprintf (stderr, "Total Allocated under 64B: %10lld\n",
+ G.stats.total_allocated_under64);
+ fprintf (stderr, "Total Overhead under 128B: %10lld\n",
+ G.stats.total_overhead_under128);
+ fprintf (stderr, "Total Allocated under 128B: %10lld\n",
+ G.stats.total_allocated_under128);
+
+ for (i = 0; i < NUM_ORDERS; i++)
+ if (G.stats.total_allocated_per_order[i])
+ {
+ fprintf (stderr, "Total Overhead page size %7lu: %10lld\n",
+ (unsigned long) OBJECT_SIZE (i),
+ G.stats.total_overhead_per_order[i]);
+ fprintf (stderr, "Total Allocated page size %7lu: %10lld\n",
+ (unsigned long) OBJECT_SIZE (i),
+ G.stats.total_allocated_per_order[i]);
+ }
+ }
+#endif
+}
+\f
+struct ggc_pch_data
+{
+ struct ggc_pch_ondisk
+ {
+ unsigned totals[NUM_ORDERS];
+ } d;
+ size_t base[NUM_ORDERS];
+ size_t written[NUM_ORDERS];
+};
+
+struct ggc_pch_data *
+init_ggc_pch (void)
+{
+ return XCNEW (struct ggc_pch_data);
+}
+
+void
+ggc_pch_count_object (struct ggc_pch_data *d, void *x ATTRIBUTE_UNUSED,
+ size_t size, bool is_string ATTRIBUTE_UNUSED,
+ enum gt_types_enum type ATTRIBUTE_UNUSED)
+{
+ unsigned order;
+
+ if (size < NUM_SIZE_LOOKUP)
+ order = size_lookup[size];
+ else
+ {
+ order = 10;
+ while (size > OBJECT_SIZE (order))
+ order++;
+ }
+
+ d->d.totals[order]++;
+}
+
+size_t
+ggc_pch_total_size (struct ggc_pch_data *d)
+{
+ size_t a = 0;
+ unsigned i;
+
+ for (i = 0; i < NUM_ORDERS; i++)
+ a += ROUND_UP (d->d.totals[i] * OBJECT_SIZE (i), G.pagesize);
+ return a;
+}
+
+void
+ggc_pch_this_base (struct ggc_pch_data *d, void *base)
+{
+ size_t a = (size_t) base;
+ unsigned i;
+
+ for (i = 0; i < NUM_ORDERS; i++)
+ {
+ d->base[i] = a;
+ a += ROUND_UP (d->d.totals[i] * OBJECT_SIZE (i), G.pagesize);
+ }
+}
+
+
+char *
+ggc_pch_alloc_object (struct ggc_pch_data *d, void *x ATTRIBUTE_UNUSED,
+ size_t size, bool is_string ATTRIBUTE_UNUSED,
+ enum gt_types_enum type ATTRIBUTE_UNUSED)
+{
+ unsigned order;
+ char *result;
+
+ if (size < NUM_SIZE_LOOKUP)
+ order = size_lookup[size];
+ else
+ {
+ order = 10;
+ while (size > OBJECT_SIZE (order))
+ order++;
+ }
+
+ result = (char *) d->base[order];
+ d->base[order] += OBJECT_SIZE (order);
+ return result;
+}
+
+void
+ggc_pch_prepare_write (struct ggc_pch_data *d ATTRIBUTE_UNUSED,
+ FILE *f ATTRIBUTE_UNUSED)
+{
+ /* Nothing to do. */
+}
+
+void
+ggc_pch_write_object (struct ggc_pch_data *d ATTRIBUTE_UNUSED,
+ FILE *f, void *x, void *newx ATTRIBUTE_UNUSED,
+ size_t size, bool is_string ATTRIBUTE_UNUSED)
+{
+ unsigned order;
+ static const char emptyBytes[256];
+
+ if (size < NUM_SIZE_LOOKUP)
+ order = size_lookup[size];
+ else
+ {
+ order = 10;
+ while (size > OBJECT_SIZE (order))
+ order++;
+ }
+
+ if (fwrite (x, size, 1, f) != 1)
+ fatal_error ("can't write PCH file: %m");
+
+ /* If SIZE is not the same as OBJECT_SIZE(order), then we need to pad the
+ object out to OBJECT_SIZE(order). This happens for strings. */
+
+ if (size != OBJECT_SIZE (order))
+ {
+ unsigned padding = OBJECT_SIZE(order) - size;
+
+ /* To speed small writes, we use a nulled-out array that's larger
+ than most padding requests as the source for our null bytes. This
+ permits us to do the padding with fwrite() rather than fseek(), and
+ limits the chance the OS may try to flush any outstanding writes. */
+ if (padding <= sizeof(emptyBytes))
+ {
+ if (fwrite (emptyBytes, 1, padding, f) != padding)
+ fatal_error ("can't write PCH file");
+ }
+ else
+ {
+ /* Larger than our buffer? Just default to fseek. */
+ if (fseek (f, padding, SEEK_CUR) != 0)
+ fatal_error ("can't write PCH file");
+ }
+ }
+
+ d->written[order]++;
+ if (d->written[order] == d->d.totals[order]
+ && fseek (f, ROUND_UP_VALUE (d->d.totals[order] * OBJECT_SIZE (order),
+ G.pagesize),
+ SEEK_CUR) != 0)
+ fatal_error ("can't write PCH file: %m");
+}
+
+void
+ggc_pch_finish (struct ggc_pch_data *d, FILE *f)
+{
+ if (fwrite (&d->d, sizeof (d->d), 1, f) != 1)
+ fatal_error ("can't write PCH file: %m");
+ free (d);
+}
+
+/* Move the PCH PTE entries just added to the end of by_depth, to the
+ front. */
+
+static void
+move_ptes_to_front (int count_old_page_tables, int count_new_page_tables)
+{
+ unsigned i;
+
+ /* First, we swap the new entries to the front of the varrays. */
+ page_entry **new_by_depth;
+ unsigned long **new_save_in_use;
+
+ new_by_depth = XNEWVEC (page_entry *, G.by_depth_max);
+ new_save_in_use = XNEWVEC (unsigned long *, G.by_depth_max);
+
+ memcpy (&new_by_depth[0],
+ &G.by_depth[count_old_page_tables],
+ count_new_page_tables * sizeof (void *));
+ memcpy (&new_by_depth[count_new_page_tables],
+ &G.by_depth[0],
+ count_old_page_tables * sizeof (void *));
+ memcpy (&new_save_in_use[0],
+ &G.save_in_use[count_old_page_tables],
+ count_new_page_tables * sizeof (void *));
+ memcpy (&new_save_in_use[count_new_page_tables],
+ &G.save_in_use[0],
+ count_old_page_tables * sizeof (void *));
+
+ free (G.by_depth);
+ free (G.save_in_use);
+
+ G.by_depth = new_by_depth;
+ G.save_in_use = new_save_in_use;
+
+ /* Now update all the index_by_depth fields. */
+ for (i = G.by_depth_in_use; i > 0; --i)
+ {
+ page_entry *p = G.by_depth[i-1];
+ p->index_by_depth = i-1;
+ }
+
+ /* And last, we update the depth pointers in G.depth. The first
+ entry is already 0, and context 0 entries always start at index
+ 0, so there is nothing to update in the first slot. We need a
+ second slot, only if we have old ptes, and if we do, they start
+ at index count_new_page_tables. */
+ if (count_old_page_tables)
+ push_depth (count_new_page_tables);
+}
+
+void
+ggc_pch_read (FILE *f, void *addr)
+{
+ struct ggc_pch_ondisk d;
+ unsigned i;
+ char *offs = (char *) addr;
+ unsigned long count_old_page_tables;
+ unsigned long count_new_page_tables;
+
+ count_old_page_tables = G.by_depth_in_use;
+
+ /* We've just read in a PCH file. So, every object that used to be
+ allocated is now free. */
+ clear_marks ();
+#ifdef ENABLE_GC_CHECKING
+ poison_pages ();
+#endif
+ /* Since we free all the allocated objects, the free list becomes
+ useless. Validate it now, which will also clear it. */
+ validate_free_objects();
+
+ /* No object read from a PCH file should ever be freed. So, set the
+ context depth to 1, and set the depth of all the currently-allocated
+ pages to be 1 too. PCH pages will have depth 0. */
+ gcc_assert (!G.context_depth);
+ G.context_depth = 1;
+ for (i = 0; i < NUM_ORDERS; i++)
+ {
+ page_entry *p;
+ for (p = G.pages[i]; p != NULL; p = p->next)
+ p->context_depth = G.context_depth;
+ }
+
+ /* Allocate the appropriate page-table entries for the pages read from
+ the PCH file. */
+ if (fread (&d, sizeof (d), 1, f) != 1)
+ fatal_error ("can't read PCH file: %m");
+
+ for (i = 0; i < NUM_ORDERS; i++)
+ {
+ struct page_entry *entry;
+ char *pte;
+ size_t bytes;
+ size_t num_objs;
+ size_t j;
+
+ if (d.totals[i] == 0)
+ continue;
+
+ bytes = ROUND_UP (d.totals[i] * OBJECT_SIZE (i), G.pagesize);
+ num_objs = bytes / OBJECT_SIZE (i);
+ entry = XCNEWVAR (struct page_entry, (sizeof (struct page_entry)
+ - sizeof (long)
+ + BITMAP_SIZE (num_objs + 1)));
+ entry->bytes = bytes;
+ entry->page = offs;
+ entry->context_depth = 0;
+ offs += bytes;
+ entry->num_free_objects = 0;
+ entry->order = i;
+
+ for (j = 0;
+ j + HOST_BITS_PER_LONG <= num_objs + 1;
+ j += HOST_BITS_PER_LONG)
+ entry->in_use_p[j / HOST_BITS_PER_LONG] = -1;
+ for (; j < num_objs + 1; j++)
+ entry->in_use_p[j / HOST_BITS_PER_LONG]
+ |= 1L << (j % HOST_BITS_PER_LONG);
+
+ for (pte = entry->page;
+ pte < entry->page + entry->bytes;
+ pte += G.pagesize)
+ set_page_table_entry (pte, entry);
+
+ if (G.page_tails[i] != NULL)
+ G.page_tails[i]->next = entry;
+ else
+ G.pages[i] = entry;
+ G.page_tails[i] = entry;
+
+ /* We start off by just adding all the new information to the
+ end of the varrays, later, we will move the new information
+ to the front of the varrays, as the PCH page tables are at
+ context 0. */
+ push_by_depth (entry, 0);
+ }
+
+ /* Now, we update the various data structures that speed page table
+ handling. */
+ count_new_page_tables = G.by_depth_in_use - count_old_page_tables;
+
+ move_ptes_to_front (count_old_page_tables, count_new_page_tables);
+
+ /* Update the statistics. */
+ G.allocated = G.allocated_last_gc = offs - (char *)addr;