00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "config.h"
00027 #include "system.h"
00028 #include "coretypes.h"
00029 #include "tm.h"
00030 #include "tree.h"
00031 #include "rtl.h"
00032 #include "tm_p.h"
00033 #include "toplev.h"
00034 #include "varray.h"
00035 #include "flags.h"
00036 #include "ggc.h"
00037 #include "timevar.h"
00038 #include "params.h"
00039 #include "bitmap.h"
00040
00041 #ifdef ENABLE_VALGRIND_CHECKING
00042 # ifdef HAVE_VALGRIND_MEMCHECK_H
00043 # include <valgrind/memcheck.h>
00044 # elif defined HAVE_MEMCHECK_H
00045 # include <memcheck.h>
00046 # else
00047 # include <valgrind.h>
00048 # endif
00049 #else
00050
00051 #define VALGRIND_DISCARD(x)
00052 #define VALGRIND_MALLOCLIKE_BLOCK(w,x,y,z)
00053 #define VALGRIND_FREELIKE_BLOCK(x,y)
00054 #endif
00055
00056
00057
00058 #ifdef HAVE_MMAP_ANON
00059 # undef HAVE_MMAP_DEV_ZERO
00060
00061 # include <sys/mman.h>
00062 # ifndef MAP_FAILED
00063 # define MAP_FAILED -1
00064 # endif
00065 # if !defined (MAP_ANONYMOUS) && defined (MAP_ANON)
00066 # define MAP_ANONYMOUS MAP_ANON
00067 # endif
00068 # define USING_MMAP
00069 #endif
00070
00071 #ifdef HAVE_MMAP_DEV_ZERO
00072 # include <sys/mman.h>
00073 # ifndef MAP_FAILED
00074 # define MAP_FAILED -1
00075 # endif
00076 # define USING_MMAP
00077 #endif
00078
00079 #ifndef USING_MMAP
00080 #error Zone collector requires mmap
00081 #endif
00082
00083 #if (GCC_VERSION < 3001)
00084 #define prefetch(X) ((void) X)
00085 #define prefetchw(X) ((void) X)
00086 #else
00087 #define prefetch(X) __builtin_prefetch (X)
00088 #define prefetchw(X) __builtin_prefetch (X, 1, 3)
00089 #endif
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128 #define GGC_DEBUG_LEVEL (0)
00129
00130 #ifndef HOST_BITS_PER_PTR
00131 #define HOST_BITS_PER_PTR HOST_BITS_PER_LONG
00132 #endif
00133
00134
00135
00136
00137
00138
00139 struct alloc_chunk {
00140 struct alloc_chunk *next_free;
00141 unsigned int size;
00142 };
00143
00144
00145 #define PAGE_OVERHEAD (offsetof (struct small_page_entry, alloc_bits))
00146
00147
00148
00149
00150
00151
00152
00153
00154 #define GGC_PAGE_SIZE 4096
00155 #define GGC_PAGE_MASK (GGC_PAGE_SIZE - 1)
00156 #define GGC_PAGE_SHIFT 12
00157
00158 #if 0
00159
00160 #define GGC_PAGE_SIZE G.pagesize
00161 #define GGC_PAGE_MASK G.page_mask
00162 #define GGC_PAGE_SHIFT G.lg_pagesize
00163 #endif
00164
00165
00166
00167
00168 #define SMALL_PAGE_SIZE GGC_PAGE_SIZE
00169
00170
00171
00172
00173
00174
00175
00176
00177 #define NUM_FREE_BINS 64
00178 #define FREE_BIN_DELTA MAX_ALIGNMENT
00179 #define SIZE_BIN_DOWN(SIZE) ((SIZE) / FREE_BIN_DELTA)
00180
00181
00182
00183
00184 #define BYTES_PER_ALLOC_BIT MAX_ALIGNMENT
00185
00186
00187
00188
00189
00190 #define BYTES_PER_MARK_BIT BYTES_PER_ALLOC_BIT
00191
00192 #define BYTES_PER_MARK_WORD (8 * BYTES_PER_MARK_BIT * sizeof (mark_type))
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211 struct max_alignment {
00212 char c;
00213 union {
00214 HOST_WIDEST_INT i;
00215 double d;
00216 } u;
00217 };
00218
00219
00220
00221 #define MAX_ALIGNMENT (offsetof (struct max_alignment, u))
00222
00223
00224
00225 #define ROUND_UP(x, f) (CEIL (x, f) * (f))
00226
00227
00228
00229
00230
00231 typedef unsigned int alloc_type;
00232 typedef unsigned int mark_type;
00233 #define alloc_ffs(x) ffs(x)
00234
00235
00236
00237
00238 typedef struct page_entry
00239 {
00240
00241 char *page;
00242
00243
00244 struct alloc_zone *zone;
00245
00246 #ifdef GATHER_STATISTICS
00247
00248 size_t survived;
00249 #endif
00250
00251
00252 bool large_p;
00253
00254
00255 bool pch_p;
00256 } page_entry;
00257
00258
00259 struct small_page_entry
00260 {
00261 struct page_entry common;
00262
00263
00264 struct small_page_entry *next;
00265
00266
00267
00268
00269 mark_type *mark_bits;
00270
00271
00272
00273 alloc_type alloc_bits[1];
00274 };
00275
00276
00277 struct large_page_entry
00278 {
00279 struct page_entry common;
00280
00281
00282 struct large_page_entry *next;
00283
00284
00285 size_t bytes;
00286
00287
00288 struct large_page_entry *prev;
00289
00290
00291 bool mark_p;
00292 };
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316 #define PAGE_L1_BITS (8)
00317 #define PAGE_L2_BITS (32 - PAGE_L1_BITS - GGC_PAGE_SHIFT)
00318 #define PAGE_L1_SIZE ((size_t) 1 << PAGE_L1_BITS)
00319 #define PAGE_L2_SIZE ((size_t) 1 << PAGE_L2_BITS)
00320
00321 #define LOOKUP_L1(p) \
00322 (((size_t) (p) >> (32 - PAGE_L1_BITS)) & ((1 << PAGE_L1_BITS) - 1))
00323
00324 #define LOOKUP_L2(p) \
00325 (((size_t) (p) >> GGC_PAGE_SHIFT) & ((1 << PAGE_L2_BITS) - 1))
00326
00327 #if HOST_BITS_PER_PTR <= 32
00328
00329
00330 typedef page_entry **page_table[PAGE_L1_SIZE];
00331
00332 #else
00333
00334
00335
00336
00337 typedef struct page_table_chain
00338 {
00339 struct page_table_chain *next;
00340 size_t high_bits;
00341 page_entry **table[PAGE_L1_SIZE];
00342 } *page_table;
00343
00344 #endif
00345
00346
00347 static struct globals
00348 {
00349
00350 struct alloc_zone *zones;
00351
00352
00353 page_table lookup;
00354
00355
00356 size_t pagesize;
00357 size_t lg_pagesize;
00358 size_t page_mask;
00359
00360
00361
00362
00363 size_t small_page_overhead;
00364
00365 #if defined (HAVE_MMAP_DEV_ZERO)
00366
00367 int dev_zero_fd;
00368 #endif
00369
00370
00371
00372
00373 size_t quire_size;
00374
00375
00376 FILE *debug_file;
00377 } G;
00378
00379
00380
00381 struct alloc_zone
00382 {
00383
00384
00385
00386 char *cached_free;
00387 size_t cached_free_size;
00388
00389
00390
00391 struct alloc_chunk *free_chunks[NUM_FREE_BINS + 1];
00392
00393
00394
00395 size_t high_free_bin;
00396
00397
00398 size_t allocated;
00399
00400
00401 struct small_page_entry *pages;
00402
00403
00404 struct large_page_entry *large_pages;
00405
00406
00407 mark_type *mark_bits;
00408
00409
00410 const char *name;
00411
00412
00413 size_t n_small_pages;
00414
00415
00416 size_t allocated_last_gc;
00417
00418
00419 size_t bytes_mapped;
00420
00421
00422 struct small_page_entry *free_pages;
00423
00424
00425 struct alloc_zone *next_zone;
00426
00427
00428 bool was_collected;
00429
00430
00431 bool dead;
00432
00433 #ifdef GATHER_STATISTICS
00434 struct
00435 {
00436
00437 unsigned long long total_allocated;
00438
00439 unsigned long long total_overhead;
00440
00441
00442
00443
00444
00445 unsigned long long total_allocated_under32;
00446 unsigned long long total_overhead_under32;
00447
00448 unsigned long long total_allocated_under64;
00449 unsigned long long total_overhead_under64;
00450
00451 unsigned long long total_allocated_under128;
00452 unsigned long long total_overhead_under128;
00453 } stats;
00454 #endif
00455 } main_zone;
00456
00457
00458 struct alloc_zone rtl_zone;
00459 struct alloc_zone tree_zone;
00460 struct alloc_zone tree_id_zone;
00461
00462
00463
00464 struct pch_zone
00465 {
00466
00467 char *page;
00468
00469
00470 char *end;
00471
00472
00473 size_t bytes;
00474
00475
00476 alloc_type *alloc_bits;
00477
00478
00479
00480
00481
00482
00483 mark_type *mark_bits;
00484 } pch_zone;
00485
00486 #ifdef USING_MMAP
00487 static char *alloc_anon (char *, size_t, struct alloc_zone *);
00488 #endif
00489 static struct small_page_entry * alloc_small_page (struct alloc_zone *);
00490 static struct large_page_entry * alloc_large_page (size_t, struct alloc_zone *);
00491 static void free_chunk (char *, size_t, struct alloc_zone *);
00492 static void free_small_page (struct small_page_entry *);
00493 static void free_large_page (struct large_page_entry *);
00494 static void release_pages (struct alloc_zone *);
00495 static void sweep_pages (struct alloc_zone *);
00496 static bool ggc_collect_1 (struct alloc_zone *, bool);
00497 static void new_ggc_zone_1 (struct alloc_zone *, const char *);
00498
00499
00500
00501
00502 static inline page_entry *
00503 lookup_page_table_entry (const void *p)
00504 {
00505 page_entry ***base;
00506 size_t L1, L2;
00507
00508 #if HOST_BITS_PER_PTR <= 32
00509 base = &G.lookup[0];
00510 #else
00511 page_table table = G.lookup;
00512 size_t high_bits = (size_t) p & ~ (size_t) 0xffffffff;
00513 while (table->high_bits != high_bits)
00514 table = table->next;
00515 base = &table->table[0];
00516 #endif
00517
00518
00519 L1 = LOOKUP_L1 (p);
00520 L2 = LOOKUP_L2 (p);
00521
00522 return base[L1][L2];
00523 }
00524
00525
00526
00527
00528 static void
00529 set_page_table_entry (void *p, page_entry *entry)
00530 {
00531 page_entry ***base;
00532 size_t L1, L2;
00533
00534 #if HOST_BITS_PER_PTR <= 32
00535 base = &G.lookup[0];
00536 #else
00537 page_table table;
00538 size_t high_bits = (size_t) p & ~ (size_t) 0xffffffff;
00539 for (table = G.lookup; table; table = table->next)
00540 if (table->high_bits == high_bits)
00541 goto found;
00542
00543
00544 table = xcalloc (1, sizeof(*table));
00545 table->next = G.lookup;
00546 table->high_bits = high_bits;
00547 G.lookup = table;
00548 found:
00549 base = &table->table[0];
00550 #endif
00551
00552
00553 L1 = LOOKUP_L1 (p);
00554 L2 = LOOKUP_L2 (p);
00555
00556 if (base[L1] == NULL)
00557 base[L1] = xcalloc (PAGE_L2_SIZE, sizeof (page_entry *));
00558
00559 base[L1][L2] = entry;
00560 }
00561
00562
00563
00564 static inline struct page_entry *
00565 zone_get_object_page (const void *object)
00566 {
00567 return lookup_page_table_entry (object);
00568 }
00569
00570
00571
00572 static inline unsigned int
00573 zone_get_object_alloc_word (const void *object)
00574 {
00575 return (((size_t) object & (GGC_PAGE_SIZE - 1))
00576 / (8 * sizeof (alloc_type) * BYTES_PER_ALLOC_BIT));
00577 }
00578
00579
00580
00581 static inline unsigned int
00582 zone_get_object_alloc_bit (const void *object)
00583 {
00584 return (((size_t) object / BYTES_PER_ALLOC_BIT)
00585 % (8 * sizeof (alloc_type)));
00586 }
00587
00588
00589
00590 static inline unsigned int
00591 zone_get_object_mark_word (const void *object)
00592 {
00593 return (((size_t) object & (GGC_PAGE_SIZE - 1))
00594 / (8 * sizeof (mark_type) * BYTES_PER_MARK_BIT));
00595 }
00596
00597
00598
00599 static inline unsigned int
00600 zone_get_object_mark_bit (const void *object)
00601 {
00602 return (((size_t) object / BYTES_PER_MARK_BIT)
00603 % (8 * sizeof (mark_type)));
00604 }
00605
00606
00607
00608 static inline void
00609 zone_set_object_alloc_bit (const void *object)
00610 {
00611 struct small_page_entry *page
00612 = (struct small_page_entry *) zone_get_object_page (object);
00613 unsigned int start_word = zone_get_object_alloc_word (object);
00614 unsigned int start_bit = zone_get_object_alloc_bit (object);
00615
00616 page->alloc_bits[start_word] |= 1L << start_bit;
00617 }
00618
00619
00620
00621
00622 static inline void
00623 zone_clear_object_alloc_bit (struct small_page_entry *page,
00624 const void *object)
00625 {
00626 unsigned int start_word = zone_get_object_alloc_word (object);
00627 unsigned int start_bit = zone_get_object_alloc_bit (object);
00628
00629
00630 page->alloc_bits[start_word] &= ~(1L << start_bit);
00631 }
00632
00633
00634
00635
00636
00637 static inline size_t
00638 zone_object_size_1 (alloc_type *alloc_bits,
00639 size_t start_word, size_t start_bit,
00640 size_t max_size)
00641 {
00642 size_t size;
00643 alloc_type alloc_word;
00644 int indx;
00645
00646
00647 alloc_word = alloc_bits[start_word++];
00648
00649
00650
00651 if (start_bit)
00652 {
00653 indx = alloc_ffs (alloc_word >> start_bit);
00654 if (indx)
00655
00656
00657
00658 return indx * BYTES_PER_ALLOC_BIT;
00659
00660
00661 size = (sizeof (alloc_type) * 8 - start_bit + 1) * BYTES_PER_ALLOC_BIT;
00662
00663 if (size >= max_size)
00664 return max_size;
00665
00666 alloc_word = alloc_bits[start_word++];
00667 }
00668 else
00669 size = BYTES_PER_ALLOC_BIT;
00670
00671 while (alloc_word == 0)
00672 {
00673 size += sizeof (alloc_type) * 8 * BYTES_PER_ALLOC_BIT;
00674 if (size >= max_size)
00675 return max_size;
00676 alloc_word = alloc_bits[start_word++];
00677 }
00678
00679 indx = alloc_ffs (alloc_word);
00680 return size + (indx - 1) * BYTES_PER_ALLOC_BIT;
00681 }
00682
00683
00684
00685 static inline size_t
00686 zone_find_object_size (struct small_page_entry *page,
00687 const void *object)
00688 {
00689 const char *object_midptr = (const char *) object + BYTES_PER_ALLOC_BIT;
00690 unsigned int start_word = zone_get_object_alloc_word (object_midptr);
00691 unsigned int start_bit = zone_get_object_alloc_bit (object_midptr);
00692 size_t max_size = (page->common.page + SMALL_PAGE_SIZE
00693 - (char *) object);
00694
00695 return zone_object_size_1 (page->alloc_bits, start_word, start_bit,
00696 max_size);
00697 }
00698
00699
00700
00701 static void
00702 zone_allocate_marks (void)
00703 {
00704 struct alloc_zone *zone;
00705
00706 for (zone = G.zones; zone; zone = zone->next_zone)
00707 {
00708 struct small_page_entry *page;
00709 mark_type *cur_marks;
00710 size_t mark_words, mark_words_per_page;
00711 #ifdef ENABLE_CHECKING
00712 size_t n = 0;
00713 #endif
00714
00715 mark_words_per_page
00716 = (GGC_PAGE_SIZE + BYTES_PER_MARK_WORD - 1) / BYTES_PER_MARK_WORD;
00717 mark_words = zone->n_small_pages * mark_words_per_page;
00718 zone->mark_bits = (mark_type *) xcalloc (sizeof (mark_type),
00719 mark_words);
00720 cur_marks = zone->mark_bits;
00721 for (page = zone->pages; page; page = page->next)
00722 {
00723 page->mark_bits = cur_marks;
00724 cur_marks += mark_words_per_page;
00725 #ifdef ENABLE_CHECKING
00726 n++;
00727 #endif
00728 }
00729 #ifdef ENABLE_CHECKING
00730 gcc_assert (n == zone->n_small_pages);
00731 #endif
00732 }
00733
00734
00735
00736 if (pch_zone.bytes)
00737 pch_zone.mark_bits
00738 = (mark_type *) xcalloc (sizeof (mark_type),
00739 CEIL (pch_zone.bytes, BYTES_PER_MARK_WORD));
00740 }
00741
00742
00743 static void
00744 zone_free_marks (void)
00745 {
00746 struct alloc_zone *zone;
00747
00748 for (zone = G.zones; zone; zone = zone->next_zone)
00749 if (zone->mark_bits)
00750 {
00751 free (zone->mark_bits);
00752 zone->mark_bits = NULL;
00753 }
00754
00755 if (pch_zone.bytes)
00756 {
00757 free (pch_zone.mark_bits);
00758 pch_zone.mark_bits = NULL;
00759 }
00760 }
00761
00762 #ifdef USING_MMAP
00763
00764
00765
00766
00767 static inline char *
00768 alloc_anon (char *pref ATTRIBUTE_UNUSED, size_t size, struct alloc_zone *zone)
00769 {
00770 #ifdef HAVE_MMAP_ANON
00771 char *page = (char *) mmap (pref, size, PROT_READ | PROT_WRITE,
00772 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
00773 #endif
00774 #ifdef HAVE_MMAP_DEV_ZERO
00775 char *page = (char *) mmap (pref, size, PROT_READ | PROT_WRITE,
00776 MAP_PRIVATE, G.dev_zero_fd, 0);
00777 #endif
00778
00779 if (page == (char *) MAP_FAILED)
00780 {
00781 perror ("virtual memory exhausted");
00782 exit (FATAL_EXIT_CODE);
00783 }
00784
00785
00786 zone->bytes_mapped += size;
00787
00788
00789
00790
00791 VALGRIND_DISCARD (VALGRIND_MAKE_NOACCESS (page, size));
00792
00793 return page;
00794 }
00795 #endif
00796
00797
00798
00799
00800 static struct small_page_entry *
00801 alloc_small_page (struct alloc_zone *zone)
00802 {
00803 struct small_page_entry *entry;
00804
00805
00806 entry = zone->free_pages;
00807 if (entry != NULL)
00808 {
00809
00810 zone->free_pages = entry->next;
00811 }
00812 else
00813 {
00814
00815
00816
00817 struct small_page_entry *e, *f = zone->free_pages;
00818 int i;
00819 char *page;
00820
00821 page = alloc_anon (NULL, GGC_PAGE_SIZE * G.quire_size, zone);
00822
00823
00824
00825 for (i = G.quire_size - 1; i >= 1; i--)
00826 {
00827 e = xcalloc (1, G.small_page_overhead);
00828 e->common.page = page + (i << GGC_PAGE_SHIFT);
00829 e->common.zone = zone;
00830 e->next = f;
00831 f = e;
00832 set_page_table_entry (e->common.page, &e->common);
00833 }
00834
00835 zone->free_pages = f;
00836
00837 entry = xcalloc (1, G.small_page_overhead);
00838 entry->common.page = page;
00839 entry->common.zone = zone;
00840 set_page_table_entry (page, &entry->common);
00841 }
00842
00843 zone->n_small_pages++;
00844
00845 if (GGC_DEBUG_LEVEL >= 2)
00846 fprintf (G.debug_file,
00847 "Allocating %s page at %p, data %p-%p\n",
00848 entry->common.zone->name, (PTR) entry, entry->common.page,
00849 entry->common.page + SMALL_PAGE_SIZE - 1);
00850
00851 return entry;
00852 }
00853
00854
00855
00856 static struct large_page_entry *
00857 alloc_large_page (size_t size, struct alloc_zone *zone)
00858 {
00859 struct large_page_entry *entry;
00860 char *page;
00861 size_t needed_size;
00862
00863 needed_size = size + sizeof (struct large_page_entry);
00864 page = xmalloc (needed_size);
00865
00866 entry = (struct large_page_entry *) page;
00867
00868 entry->next = NULL;
00869 entry->common.page = page + sizeof (struct large_page_entry);
00870 entry->common.large_p = true;
00871 entry->common.pch_p = false;
00872 entry->common.zone = zone;
00873 #ifdef GATHER_STATISTICS
00874 entry->common.survived = 0;
00875 #endif
00876 entry->mark_p = false;
00877 entry->bytes = size;
00878 entry->prev = NULL;
00879
00880 set_page_table_entry (entry->common.page, &entry->common);
00881
00882 if (GGC_DEBUG_LEVEL >= 2)
00883 fprintf (G.debug_file,
00884 "Allocating %s large page at %p, data %p-%p\n",
00885 entry->common.zone->name, (PTR) entry, entry->common.page,
00886 entry->common.page + SMALL_PAGE_SIZE - 1);
00887
00888 return entry;
00889 }
00890
00891
00892
00893
00894 static inline void
00895 free_small_page (struct small_page_entry *entry)
00896 {
00897 if (GGC_DEBUG_LEVEL >= 2)
00898 fprintf (G.debug_file,
00899 "Deallocating %s page at %p, data %p-%p\n",
00900 entry->common.zone->name, (PTR) entry,
00901 entry->common.page, entry->common.page + SMALL_PAGE_SIZE - 1);
00902
00903 gcc_assert (!entry->common.large_p);
00904
00905
00906
00907 VALGRIND_DISCARD (VALGRIND_MAKE_NOACCESS (entry->common.page,
00908 SMALL_PAGE_SIZE));
00909
00910 entry->next = entry->common.zone->free_pages;
00911 entry->common.zone->free_pages = entry;
00912 entry->common.zone->n_small_pages--;
00913 }
00914
00915
00916
00917 static inline void
00918 free_large_page (struct large_page_entry *entry)
00919 {
00920 if (GGC_DEBUG_LEVEL >= 2)
00921 fprintf (G.debug_file,
00922 "Deallocating %s page at %p, data %p-%p\n",
00923 entry->common.zone->name, (PTR) entry,
00924 entry->common.page, entry->common.page + SMALL_PAGE_SIZE - 1);
00925
00926 gcc_assert (entry->common.large_p);
00927
00928 set_page_table_entry (entry->common.page, NULL);
00929 free (entry);
00930 }
00931
00932
00933
00934 static void
00935 release_pages (struct alloc_zone *zone)
00936 {
00937 #ifdef USING_MMAP
00938 struct small_page_entry *p, *next;
00939 char *start;
00940 size_t len;
00941
00942
00943 p = zone->free_pages;
00944
00945 while (p)
00946 {
00947 start = p->common.page;
00948 next = p->next;
00949 len = SMALL_PAGE_SIZE;
00950 set_page_table_entry (p->common.page, NULL);
00951 p = next;
00952
00953 while (p && p->common.page == start + len)
00954 {
00955 next = p->next;
00956 len += SMALL_PAGE_SIZE;
00957 set_page_table_entry (p->common.page, NULL);
00958 p = next;
00959 }
00960
00961 munmap (start, len);
00962 zone->bytes_mapped -= len;
00963 }
00964
00965 zone->free_pages = NULL;
00966 #endif
00967 }
00968
00969
00970
00971 static inline void
00972 free_chunk (char *ptr, size_t size, struct alloc_zone *zone)
00973 {
00974 struct alloc_chunk *chunk = (struct alloc_chunk *) ptr;
00975 size_t bin = 0;
00976
00977 bin = SIZE_BIN_DOWN (size);
00978 gcc_assert (bin != 0);
00979 if (bin > NUM_FREE_BINS)
00980 {
00981 bin = 0;
00982 VALGRIND_DISCARD (VALGRIND_MAKE_WRITABLE (chunk, sizeof (struct alloc_chunk)));
00983 chunk->size = size;
00984 chunk->next_free = zone->free_chunks[bin];
00985 VALGRIND_DISCARD (VALGRIND_MAKE_NOACCESS (ptr + sizeof (struct alloc_chunk),
00986 size - sizeof (struct alloc_chunk)));
00987 }
00988 else
00989 {
00990 VALGRIND_DISCARD (VALGRIND_MAKE_WRITABLE (chunk, sizeof (struct alloc_chunk *)));
00991 chunk->next_free = zone->free_chunks[bin];
00992 VALGRIND_DISCARD (VALGRIND_MAKE_NOACCESS (ptr + sizeof (struct alloc_chunk *),
00993 size - sizeof (struct alloc_chunk *)));
00994 }
00995
00996 zone->free_chunks[bin] = chunk;
00997 if (bin > zone->high_free_bin)
00998 zone->high_free_bin = bin;
00999 if (GGC_DEBUG_LEVEL >= 3)
01000 fprintf (G.debug_file, "Deallocating object, chunk=%p\n", (void *)chunk);
01001 }
01002
01003
01004
01005 void *
01006 ggc_alloc_zone_stat (size_t orig_size, struct alloc_zone *zone
01007 MEM_STAT_DECL)
01008 {
01009 size_t bin;
01010 size_t csize;
01011 struct small_page_entry *entry;
01012 struct alloc_chunk *chunk, **pp;
01013 void *result;
01014 size_t size = orig_size;
01015
01016
01017
01018 if (size == 0)
01019 size = MAX_ALIGNMENT;
01020 else
01021 size = (size + MAX_ALIGNMENT - 1) & -MAX_ALIGNMENT;
01022
01023
01024
01025
01026
01027
01028
01029
01030
01031
01032
01033
01034
01035
01036
01037
01038
01039
01040 if (size <= zone->cached_free_size)
01041 {
01042 result = zone->cached_free;
01043
01044 zone->cached_free_size -= size;
01045 if (zone->cached_free_size)
01046 {
01047 zone->cached_free += size;
01048 zone_set_object_alloc_bit (zone->cached_free);
01049 }
01050
01051 goto found;
01052 }
01053
01054
01055
01056
01057
01058
01059 bin = SIZE_BIN_DOWN (size);
01060
01061 if (bin <= NUM_FREE_BINS
01062 && (chunk = zone->free_chunks[bin]) != NULL)
01063 {
01064
01065
01066
01067 zone->free_chunks[bin] = chunk->next_free;
01068
01069
01070
01071 result = chunk;
01072
01073
01074
01075
01076
01077
01078 goto found;
01079 }
01080
01081
01082
01083
01084
01085
01086 if (zone->high_free_bin > bin)
01087 {
01088
01089
01090 while (zone->high_free_bin > bin
01091 && zone->free_chunks[zone->high_free_bin] == NULL)
01092 zone->high_free_bin--;
01093
01094 if (zone->high_free_bin > bin)
01095 {
01096 size_t tbin = zone->high_free_bin;
01097 chunk = zone->free_chunks[tbin];
01098
01099
01100 zone->free_chunks[tbin] = chunk->next_free;
01101
01102 result = (char *) chunk;
01103
01104
01105 if (zone->cached_free_size)
01106 free_chunk (zone->cached_free, zone->cached_free_size, zone);
01107
01108 chunk = (struct alloc_chunk *) ((char *) result + size);
01109 zone->cached_free = (char *) chunk;
01110 zone->cached_free_size = (tbin - bin) * FREE_BIN_DELTA;
01111
01112
01113
01114 zone_set_object_alloc_bit (chunk);
01115
01116
01117
01118
01119
01120 goto found;
01121 }
01122 }
01123
01124
01125
01126 pp = &(zone->free_chunks[0]);
01127 chunk = *pp;
01128 while (chunk && chunk->size < size)
01129 {
01130 pp = &chunk->next_free;
01131 chunk = *pp;
01132 }
01133
01134 if (chunk)
01135 {
01136
01137 *pp = chunk->next_free;
01138
01139 result = (char *) chunk;
01140
01141
01142
01143 csize = chunk->size;
01144 if (csize > size)
01145 {
01146 if (zone->cached_free_size)
01147 free_chunk (zone->cached_free, zone->cached_free_size, zone);
01148
01149 chunk = (struct alloc_chunk *) ((char *) result + size);
01150 zone->cached_free = (char *) chunk;
01151 zone->cached_free_size = csize - size;
01152
01153
01154 zone_set_object_alloc_bit (chunk);
01155 }
01156
01157 goto found;
01158 }
01159
01160
01161
01162
01163
01164
01165 if (size > GGC_PAGE_SIZE)
01166 {
01167 struct large_page_entry *entry = alloc_large_page (size, zone);
01168
01169 #ifdef GATHER_STATISTICS
01170 entry->common.survived = 0;
01171 #endif
01172
01173 entry->next = zone->large_pages;
01174 if (zone->large_pages)
01175 zone->large_pages->prev = entry;
01176 zone->large_pages = entry;
01177
01178 result = entry->common.page;
01179
01180 goto found;
01181 }
01182
01183
01184
01185 entry = alloc_small_page (zone);
01186 entry->next = zone->pages;
01187 zone->pages = entry;
01188
01189
01190 entry->alloc_bits[0] = 1;
01191
01192 result = entry->common.page;
01193 if (size < SMALL_PAGE_SIZE)
01194 {
01195 if (zone->cached_free_size)
01196 free_chunk (zone->cached_free, zone->cached_free_size, zone);
01197
01198 zone->cached_free = (char *) result + size;
01199 zone->cached_free_size = SMALL_PAGE_SIZE - size;
01200
01201
01202 zone_set_object_alloc_bit (zone->cached_free);
01203 }
01204
01205 found:
01206
01207
01208
01209
01210
01211
01212
01213 prefetchw (result);
01214
01215 #ifdef ENABLE_GC_CHECKING
01216
01217 VALGRIND_DISCARD (VALGRIND_MAKE_WRITABLE (result, size));
01218 memset (result, 0xaf, size);
01219 VALGRIND_DISCARD (VALGRIND_MAKE_NOACCESS (result + orig_size,
01220 size - orig_size));
01221 #endif
01222
01223
01224
01225
01226 VALGRIND_DISCARD (VALGRIND_MAKE_WRITABLE (result, orig_size));
01227
01228
01229
01230 zone->allocated += size;
01231
01232 timevar_ggc_mem_total += size;
01233
01234 #ifdef GATHER_STATISTICS
01235 ggc_record_overhead (orig_size, size - orig_size, result PASS_MEM_STAT);
01236
01237 {
01238 size_t object_size = size;
01239 size_t overhead = object_size - orig_size;
01240
01241 zone->stats.total_overhead += overhead;
01242 zone->stats.total_allocated += object_size;
01243
01244 if (orig_size <= 32)
01245 {
01246 zone->stats.total_overhead_under32 += overhead;
01247 zone->stats.total_allocated_under32 += object_size;
01248 }
01249 if (orig_size <= 64)
01250 {
01251 zone->stats.total_overhead_under64 += overhead;
01252 zone->stats.total_allocated_under64 += object_size;
01253 }
01254 if (orig_size <= 128)
01255 {
01256 zone->stats.total_overhead_under128 += overhead;
01257 zone->stats.total_allocated_under128 += object_size;
01258 }
01259 }
01260 #endif
01261
01262 if (GGC_DEBUG_LEVEL >= 3)
01263 fprintf (G.debug_file, "Allocating object, size=%lu at %p\n",
01264 (unsigned long) size, result);
01265
01266 return result;
01267 }
01268
01269
01270
01271
01272 void *
01273 ggc_alloc_typed_stat (enum gt_types_enum gte, size_t size
01274 MEM_STAT_DECL)
01275 {
01276 switch (gte)
01277 {
01278 case gt_ggc_e_14lang_tree_node:
01279 return ggc_alloc_zone_pass_stat (size, &tree_zone);
01280
01281 case gt_ggc_e_7rtx_def:
01282 return ggc_alloc_zone_pass_stat (size, &rtl_zone);
01283
01284 case gt_ggc_e_9rtvec_def:
01285 return ggc_alloc_zone_pass_stat (size, &rtl_zone);
01286
01287 default:
01288 return ggc_alloc_zone_pass_stat (size, &main_zone);
01289 }
01290 }
01291
01292
01293
01294 void *
01295 ggc_alloc_stat (size_t size MEM_STAT_DECL)
01296 {
01297 return ggc_alloc_zone_pass_stat (size, &main_zone);
01298 }
01299
01300
01301 #ifdef ENABLE_GC_CHECKING
01302 #define poison_region(PTR, SIZE) \
01303 memset ((PTR), 0xa5, (SIZE))
01304 #else
01305 #define poison_region(PTR, SIZE)
01306 #endif
01307
01308
01309
01310 void
01311 ggc_free (void *p)
01312 {
01313 struct page_entry *page;
01314
01315 #ifdef GATHER_STATISTICS
01316 ggc_free_overhead (p);
01317 #endif
01318
01319 poison_region (p, ggc_get_size (p));
01320
01321 page = zone_get_object_page (p);
01322
01323 if (page->large_p)
01324 {
01325 struct large_page_entry *large_page
01326 = (struct large_page_entry *) page;
01327
01328
01329 if (large_page->prev)
01330 large_page->prev->next = large_page->next;
01331 else
01332 {
01333 gcc_assert (large_page->common.zone->large_pages == large_page);
01334 large_page->common.zone->large_pages = large_page->next;
01335 }
01336 if (large_page->next)
01337 large_page->next->prev = large_page->prev;
01338
01339 large_page->common.zone->allocated -= large_page->bytes;
01340
01341
01342 free_large_page (large_page);
01343 }
01344 else if (page->pch_p)
01345
01346
01347 ;
01348 else
01349 {
01350 size_t size = ggc_get_size (p);
01351
01352 page->zone->allocated -= size;
01353
01354
01355
01356 free_chunk (p, size, page->zone);
01357 }
01358 }
01359
01360
01361
01362
01363
01364 int
01365 ggc_set_mark (const void *p)
01366 {
01367 struct page_entry *page;
01368 const char *ptr = (const char *) p;
01369
01370 page = zone_get_object_page (p);
01371
01372 if (page->pch_p)
01373 {
01374 size_t mark_word, mark_bit, offset;
01375 offset = (ptr - pch_zone.page) / BYTES_PER_MARK_BIT;
01376 mark_word = offset / (8 * sizeof (mark_type));
01377 mark_bit = offset % (8 * sizeof (mark_type));
01378
01379 if (pch_zone.mark_bits[mark_word] & (1 << mark_bit))
01380 return 1;
01381 pch_zone.mark_bits[mark_word] |= (1 << mark_bit);
01382 }
01383 else if (page->large_p)
01384 {
01385 struct large_page_entry *large_page
01386 = (struct large_page_entry *) page;
01387
01388 if (large_page->mark_p)
01389 return 1;
01390 large_page->mark_p = true;
01391 }
01392 else
01393 {
01394 struct small_page_entry *small_page
01395 = (struct small_page_entry *) page;
01396
01397 if (small_page->mark_bits[zone_get_object_mark_word (p)]
01398 & (1 << zone_get_object_mark_bit (p)))
01399 return 1;
01400 small_page->mark_bits[zone_get_object_mark_word (p)]
01401 |= (1 << zone_get_object_mark_bit (p));
01402 }
01403
01404 if (GGC_DEBUG_LEVEL >= 4)
01405 fprintf (G.debug_file, "Marking %p\n", p);
01406
01407 return 0;
01408 }
01409
01410
01411
01412
01413
01414 int
01415 ggc_marked_p (const void *p)
01416 {
01417 struct page_entry *page;
01418 const char *ptr = p;
01419
01420 page = zone_get_object_page (p);
01421
01422 if (page->pch_p)
01423 {
01424 size_t mark_word, mark_bit, offset;
01425 offset = (ptr - pch_zone.page) / BYTES_PER_MARK_BIT;
01426 mark_word = offset / (8 * sizeof (mark_type));
01427 mark_bit = offset % (8 * sizeof (mark_type));
01428
01429 return (pch_zone.mark_bits[mark_word] & (1 << mark_bit)) != 0;
01430 }
01431
01432 if (page->large_p)
01433 {
01434 struct large_page_entry *large_page
01435 = (struct large_page_entry *) page;
01436
01437 return large_page->mark_p;
01438 }
01439 else
01440 {
01441 struct small_page_entry *small_page
01442 = (struct small_page_entry *) page;
01443
01444 return 0 != (small_page->mark_bits[zone_get_object_mark_word (p)]
01445 & (1 << zone_get_object_mark_bit (p)));
01446 }
01447 }
01448
01449
01450
01451 size_t
01452 ggc_get_size (const void *p)
01453 {
01454 struct page_entry *page;
01455 const char *ptr = (const char *) p;
01456
01457 page = zone_get_object_page (p);
01458
01459 if (page->pch_p)
01460 {
01461 size_t alloc_word, alloc_bit, offset, max_size;
01462 offset = (ptr - pch_zone.page) / BYTES_PER_ALLOC_BIT + 1;
01463 alloc_word = offset / (8 * sizeof (alloc_type));
01464 alloc_bit = offset % (8 * sizeof (alloc_type));
01465 max_size = pch_zone.bytes - (ptr - pch_zone.page);
01466 return zone_object_size_1 (pch_zone.alloc_bits, alloc_word, alloc_bit,
01467 max_size);
01468 }
01469
01470 if (page->large_p)
01471 return ((struct large_page_entry *)page)->bytes;
01472 else
01473 return zone_find_object_size ((struct small_page_entry *) page, p);
01474 }
01475
01476
01477 void
01478 init_ggc (void)
01479 {
01480
01481
01482
01483
01484 gcc_assert (FREE_BIN_DELTA == MAX_ALIGNMENT);
01485
01486
01487 main_zone.name = "Main zone";
01488 G.zones = &main_zone;
01489
01490
01491 new_ggc_zone_1 (&rtl_zone, "RTL zone");
01492 new_ggc_zone_1 (&tree_zone, "Tree zone");
01493 new_ggc_zone_1 (&tree_id_zone, "Tree identifier zone");
01494
01495 G.pagesize = getpagesize();
01496 G.lg_pagesize = exact_log2 (G.pagesize);
01497 G.page_mask = ~(G.pagesize - 1);
01498
01499
01500 gcc_assert ((G.pagesize & (GGC_PAGE_SIZE - 1)) == 0);
01501
01502
01503 G.quire_size = 16 * G.pagesize / GGC_PAGE_SIZE;
01504
01505
01506
01507
01508 G.small_page_overhead
01509 = PAGE_OVERHEAD + (GGC_PAGE_SIZE / BYTES_PER_ALLOC_BIT / 8);
01510
01511
01512 #ifdef HAVE_MMAP_DEV_ZERO
01513 G.dev_zero_fd = open ("/dev/zero", O_RDONLY);
01514 gcc_assert (G.dev_zero_fd != -1);
01515 #endif
01516
01517 #if 0
01518 G.debug_file = fopen ("ggc-mmap.debug", "w");
01519 setlinebuf (G.debug_file);
01520 #else
01521 G.debug_file = stdout;
01522 #endif
01523
01524 #ifdef USING_MMAP
01525
01526
01527
01528
01529 {
01530 char *p = alloc_anon (NULL, G.pagesize, &main_zone);
01531 struct small_page_entry *e;
01532 if ((size_t)p & (G.pagesize - 1))
01533 {
01534
01535
01536
01537 p = alloc_anon (NULL, G.pagesize, &main_zone);
01538 gcc_assert (!((size_t)p & (G.pagesize - 1)));
01539 }
01540
01541 if (GGC_PAGE_SIZE == G.pagesize)
01542 {
01543
01544 e = xcalloc (1, G.small_page_overhead);
01545 e->common.page = p;
01546 e->common.zone = &main_zone;
01547 e->next = main_zone.free_pages;
01548 set_page_table_entry (e->common.page, &e->common);
01549 main_zone.free_pages = e;
01550 }
01551 else
01552 {
01553 munmap (p, G.pagesize);
01554 }
01555 }
01556 #endif
01557 }
01558
01559
01560
01561 static void
01562 new_ggc_zone_1 (struct alloc_zone *new_zone, const char * name)
01563 {
01564 new_zone->name = name;
01565 new_zone->next_zone = G.zones->next_zone;
01566 G.zones->next_zone = new_zone;
01567 }
01568
01569 struct alloc_zone *
01570 new_ggc_zone (const char * name)
01571 {
01572 struct alloc_zone *new_zone = xcalloc (1, sizeof (struct alloc_zone));
01573 new_ggc_zone_1 (new_zone, name);
01574 return new_zone;
01575 }
01576
01577
01578 void
01579 destroy_ggc_zone (struct alloc_zone * dead_zone)
01580 {
01581 struct alloc_zone *z;
01582
01583 for (z = G.zones; z && z->next_zone != dead_zone; z = z->next_zone)
01584
01585 continue;
01586
01587
01588 gcc_assert (z);
01589
01590
01591 z->dead = true;
01592 }
01593
01594
01595
01596 static void
01597 sweep_pages (struct alloc_zone *zone)
01598 {
01599 struct large_page_entry **lpp, *lp, *lnext;
01600 struct small_page_entry **spp, *sp, *snext;
01601 char *last_free;
01602 size_t allocated = 0;
01603 bool nomarksinpage;
01604
01605
01606
01607 memset (zone->free_chunks, 0, sizeof (zone->free_chunks));
01608 zone->high_free_bin = 0;
01609 zone->cached_free = NULL;
01610 zone->cached_free_size = 0;
01611
01612
01613
01614 lpp = &zone->large_pages;
01615 for (lp = zone->large_pages; lp != NULL; lp = lnext)
01616 {
01617 gcc_assert (lp->common.large_p);
01618
01619 lnext = lp->next;
01620
01621 #ifdef GATHER_STATISTICS
01622
01623 lp->common.survived++;
01624 #endif
01625
01626 if (lp->mark_p)
01627 {
01628 lp->mark_p = false;
01629 allocated += lp->bytes;
01630 lpp = &lp->next;
01631 }
01632 else
01633 {
01634 *lpp = lnext;
01635 #ifdef ENABLE_GC_CHECKING
01636
01637 memset (lp->common.page, 0xb5, SMALL_PAGE_SIZE);
01638 #endif
01639 if (lp->prev)
01640 lp->prev->next = lp->next;
01641 if (lp->next)
01642 lp->next->prev = lp->prev;
01643 free_large_page (lp);
01644 }
01645 }
01646
01647 spp = &zone->pages;
01648 for (sp = zone->pages; sp != NULL; sp = snext)
01649 {
01650 char *object, *last_object;
01651 char *end;
01652 alloc_type *alloc_word_p;
01653 mark_type *mark_word_p;
01654
01655 gcc_assert (!sp->common.large_p);
01656
01657 snext = sp->next;
01658
01659 #ifdef GATHER_STATISTICS
01660
01661 sp->common.survived++;
01662 #endif
01663
01664
01665
01666
01667
01668 last_object = object = sp->common.page;
01669 end = sp->common.page + SMALL_PAGE_SIZE;
01670 last_free = NULL;
01671 nomarksinpage = true;
01672 mark_word_p = sp->mark_bits;
01673 alloc_word_p = sp->alloc_bits;
01674
01675 gcc_assert (BYTES_PER_ALLOC_BIT == BYTES_PER_MARK_BIT);
01676
01677 object = sp->common.page;
01678 do
01679 {
01680 unsigned int i, n;
01681 alloc_type alloc_word;
01682 mark_type mark_word;
01683
01684 alloc_word = *alloc_word_p++;
01685 mark_word = *mark_word_p++;
01686
01687 if (mark_word)
01688 nomarksinpage = false;
01689
01690
01691 i = 0;
01692 while ((n = alloc_ffs (alloc_word)) != 0)
01693 {
01694
01695
01696
01697 alloc_word >>= n - 1;
01698 mark_word >>= n - 1;
01699 object += BYTES_PER_MARK_BIT * (n - 1);
01700
01701 if (mark_word & 1)
01702 {
01703 if (last_free)
01704 {
01705 VALGRIND_DISCARD (VALGRIND_MAKE_WRITABLE (last_free,
01706 object
01707 - last_free));
01708 poison_region (last_free, object - last_free);
01709 free_chunk (last_free, object - last_free, zone);
01710 last_free = NULL;
01711 }
01712 else
01713 allocated += object - last_object;
01714 last_object = object;
01715 }
01716 else
01717 {
01718 if (last_free == NULL)
01719 {
01720 last_free = object;
01721 allocated += object - last_object;
01722 }
01723 else
01724 zone_clear_object_alloc_bit (sp, object);
01725 }
01726
01727
01728 alloc_word >>= 1;
01729 mark_word >>= 1;
01730 object += BYTES_PER_MARK_BIT;
01731
01732 i += n;
01733 }
01734
01735 object += BYTES_PER_MARK_BIT * (8 * sizeof (alloc_type) - i);
01736 }
01737 while (object < end);
01738
01739 if (nomarksinpage)
01740 {
01741 *spp = snext;
01742 #ifdef ENABLE_GC_CHECKING
01743 VALGRIND_DISCARD (VALGRIND_MAKE_WRITABLE (sp->common.page, SMALL_PAGE_SIZE));
01744
01745 memset (sp->common.page, 0xb5, SMALL_PAGE_SIZE);
01746 #endif
01747 free_small_page (sp);
01748 continue;
01749 }
01750 else if (last_free)
01751 {
01752 VALGRIND_DISCARD (VALGRIND_MAKE_WRITABLE (last_free,
01753 object - last_free));
01754 poison_region (last_free, object - last_free);
01755 free_chunk (last_free, object - last_free, zone);
01756 }
01757 else
01758 allocated += object - last_object;
01759
01760 spp = &sp->next;
01761 }
01762
01763 zone->allocated = allocated;
01764 }
01765
01766
01767
01768
01769
01770
01771 static bool
01772 ggc_collect_1 (struct alloc_zone *zone, bool need_marking)
01773 {
01774 #if 0
01775
01776 {
01777 int i;
01778 for (i = 0; i < NUM_FREE_BINS + 1; i++)
01779 {
01780 struct alloc_chunk *chunk;
01781 int n, tot;
01782
01783 n = 0;
01784 tot = 0;
01785 chunk = zone->free_chunks[i];
01786 while (chunk)
01787 {
01788 n++;
01789 tot += chunk->size;
01790 chunk = chunk->next_free;
01791 }
01792 fprintf (stderr, "Bin %d: %d free chunks (%d bytes)\n",
01793 i, n, tot);
01794 }
01795 }
01796
01797 #endif
01798
01799 if (!quiet_flag)
01800 fprintf (stderr, " {%s GC %luk -> ",
01801 zone->name, (unsigned long) zone->allocated / 1024);
01802
01803
01804
01805 zone->allocated = 0;
01806
01807
01808
01809 release_pages (zone);
01810
01811 if (need_marking)
01812 {
01813 zone_allocate_marks ();
01814 ggc_mark_roots ();
01815 #ifdef GATHER_STATISTICS
01816 ggc_prune_overhead_list ();
01817 #endif
01818 }
01819
01820 sweep_pages (zone);
01821 zone->was_collected = true;
01822 zone->allocated_last_gc = zone->allocated;
01823
01824 if (!quiet_flag)
01825 fprintf (stderr, "%luk}", (unsigned long) zone->allocated / 1024);
01826 return true;
01827 }
01828
01829 #ifdef GATHER_STATISTICS
01830
01831
01832
01833 static float
01834 calculate_average_page_survival (struct alloc_zone *zone)
01835 {
01836 float count = 0.0;
01837 float survival = 0.0;
01838 struct small_page_entry *p;
01839 struct large_page_entry *lp;
01840 for (p = zone->pages; p; p = p->next)
01841 {
01842 count += 1.0;
01843 survival += p->common.survived;
01844 }
01845 for (lp = zone->large_pages; lp; lp = lp->next)
01846 {
01847 count += 1.0;
01848 survival += lp->common.survived;
01849 }
01850 return survival/count;
01851 }
01852 #endif
01853
01854
01855
01856 void
01857 ggc_collect (void)
01858 {
01859 struct alloc_zone *zone;
01860 bool marked = false;
01861
01862 timevar_push (TV_GC);
01863
01864 if (!ggc_force_collect)
01865 {
01866 float allocated_last_gc = 0, allocated = 0, min_expand;
01867
01868 for (zone = G.zones; zone; zone = zone->next_zone)
01869 {
01870 allocated_last_gc += zone->allocated_last_gc;
01871 allocated += zone->allocated;
01872 }
01873
01874 allocated_last_gc =
01875 MAX (allocated_last_gc,
01876 (size_t) PARAM_VALUE (GGC_MIN_HEAPSIZE) * 1024);
01877 min_expand = allocated_last_gc * PARAM_VALUE (GGC_MIN_EXPAND) / 100;
01878
01879 if (allocated < allocated_last_gc + min_expand)
01880 {
01881 timevar_pop (TV_GC);
01882 return;
01883 }
01884 }
01885
01886
01887 main_zone.was_collected = false;
01888 marked |= ggc_collect_1 (&main_zone, true);
01889
01890
01891
01892
01893
01894
01895
01896
01897
01898
01899
01900
01901 if (main_zone.was_collected)
01902 {
01903 struct alloc_zone *zone;
01904
01905 for (zone = main_zone.next_zone; zone; zone = zone->next_zone)
01906 {
01907 zone->was_collected = false;
01908 marked |= ggc_collect_1 (zone, !marked);
01909 }
01910 }
01911
01912 #ifdef GATHER_STATISTICS
01913
01914 if (GGC_DEBUG_LEVEL >= 2)
01915 {
01916 for (zone = G.zones; zone; zone = zone->next_zone)
01917 {
01918 if (zone->was_collected)
01919 {
01920 float f = calculate_average_page_survival (zone);
01921 printf ("Average page survival in zone `%s' is %f\n",
01922 zone->name, f);
01923 }
01924 }
01925 }
01926 #endif
01927
01928 if (marked)
01929 zone_free_marks ();
01930
01931
01932 for (zone = G.zones; zone && zone->next_zone; zone = zone->next_zone)
01933 {
01934 if (zone->next_zone->dead)
01935 {
01936 struct alloc_zone *dead_zone = zone->next_zone;
01937
01938 printf ("Zone `%s' is dead and will be freed.\n", dead_zone->name);
01939
01940
01941 gcc_assert (!dead_zone->allocated);
01942
01943
01944 zone->next_zone = zone->next_zone->next_zone;
01945 release_pages (dead_zone);
01946 free (dead_zone);
01947 }
01948 }
01949
01950 timevar_pop (TV_GC);
01951 }
01952
01953
01954 #define SCALE(x) ((unsigned long) ((x) < 1024*10 \
01955 ? (x) \
01956 : ((x) < 1024*1024*10 \
01957 ? (x) / 1024 \
01958 : (x) / (1024*1024))))
01959 #define LABEL(x) ((x) < 1024*10 ? ' ' : ((x) < 1024*1024*10 ? 'k' : 'M'))
01960
01961 void
01962 ggc_print_statistics (void)
01963 {
01964 struct alloc_zone *zone;
01965 struct ggc_statistics stats;
01966 size_t total_overhead = 0, total_allocated = 0, total_bytes_mapped = 0;
01967 size_t pte_overhead, i;
01968
01969
01970 memset (&stats, 0, sizeof (stats));
01971
01972
01973 ggc_force_collect = true;
01974
01975
01976 ggc_print_common_statistics (stderr, &stats);
01977
01978 ggc_force_collect = false;
01979
01980
01981
01982 for (zone = G.zones; zone; zone = zone->next_zone)
01983 release_pages (zone);
01984
01985
01986
01987 fprintf (stderr,
01988 "Memory still allocated at the end of the compilation process\n");
01989
01990 fprintf (stderr, "%20s %10s %10s %10s\n",
01991 "Zone", "Allocated", "Used", "Overhead");
01992 for (zone = G.zones; zone; zone = zone->next_zone)
01993 {
01994 struct large_page_entry *large_page;
01995 size_t overhead, allocated, in_use;
01996
01997
01998 if (!zone->pages && !zone->large_pages)
01999 continue;
02000
02001 allocated = in_use = 0;
02002
02003 overhead = sizeof (struct alloc_zone);
02004
02005 for (large_page = zone->large_pages; large_page != NULL;
02006 large_page = large_page->next)
02007 {
02008 allocated += large_page->bytes;
02009 in_use += large_page->bytes;
02010 overhead += sizeof (struct large_page_entry);
02011 }
02012
02013
02014
02015
02016
02017 allocated += GGC_PAGE_SIZE * zone->n_small_pages;
02018 in_use += GGC_PAGE_SIZE * zone->n_small_pages;
02019 overhead += G.small_page_overhead * zone->n_small_pages;
02020
02021 for (i = 0; i <= NUM_FREE_BINS; i++)
02022 {
02023 struct alloc_chunk *chunk = zone->free_chunks[i];
02024 while (chunk)
02025 {
02026 in_use -= ggc_get_size (chunk);
02027 chunk = chunk->next_free;
02028 }
02029 }
02030
02031 fprintf (stderr, "%20s %10lu%c %10lu%c %10lu%c\n",
02032 zone->name,
02033 SCALE (allocated), LABEL (allocated),
02034 SCALE (in_use), LABEL (in_use),
02035 SCALE (overhead), LABEL (overhead));
02036
02037 gcc_assert (in_use == zone->allocated);
02038
02039 total_overhead += overhead;
02040 total_allocated += zone->allocated;
02041 total_bytes_mapped += zone->bytes_mapped;
02042 }
02043
02044
02045 #if HOST_BITS_PER_PTR <= 32
02046 pte_overhead = sizeof (G.lookup);
02047 for (i = 0; i < PAGE_L1_SIZE; i++)
02048 if (G.lookup[i])
02049 pte_overhead += PAGE_L2_SIZE * sizeof (struct page_entry *);
02050 #else
02051 {
02052 page_table table = G.lookup;
02053 pte_overhead = 0;
02054 while (table)
02055 {
02056 pte_overhead += sizeof (*table);
02057 for (i = 0; i < PAGE_L1_SIZE; i++)
02058 if (table->table[i])
02059 pte_overhead += PAGE_L2_SIZE * sizeof (struct page_entry *);
02060 table = table->next;
02061 }
02062 }
02063 #endif
02064 fprintf (stderr, "%20s %11s %11s %10lu%c\n", "Page Table",
02065 "", "", SCALE (pte_overhead), LABEL (pte_overhead));
02066 total_overhead += pte_overhead;
02067
02068 fprintf (stderr, "%20s %10lu%c %10lu%c %10lu%c\n", "Total",
02069 SCALE (total_bytes_mapped), LABEL (total_bytes_mapped),
02070 SCALE (total_allocated), LABEL(total_allocated),
02071 SCALE (total_overhead), LABEL (total_overhead));
02072
02073 #ifdef GATHER_STATISTICS
02074 {
02075 unsigned long long all_overhead = 0, all_allocated = 0;
02076 unsigned long long all_overhead_under32 = 0, all_allocated_under32 = 0;
02077 unsigned long long all_overhead_under64 = 0, all_allocated_under64 = 0;
02078 unsigned long long all_overhead_under128 = 0, all_allocated_under128 = 0;
02079
02080 fprintf (stderr, "\nTotal allocations and overheads during the compilation process\n");
02081
02082 for (zone = G.zones; zone; zone = zone->next_zone)
02083 {
02084 all_overhead += zone->stats.total_overhead;
02085 all_allocated += zone->stats.total_allocated;
02086
02087 all_allocated_under32 += zone->stats.total_allocated_under32;
02088 all_overhead_under32 += zone->stats.total_overhead_under32;
02089
02090 all_allocated_under64 += zone->stats.total_allocated_under64;
02091 all_overhead_under64 += zone->stats.total_overhead_under64;
02092
02093 all_allocated_under128 += zone->stats.total_allocated_under128;
02094 all_overhead_under128 += zone->stats.total_overhead_under128;
02095
02096 fprintf (stderr, "%20s: %10lld\n",
02097 zone->name, zone->stats.total_allocated);
02098 }
02099
02100 fprintf (stderr, "\n");
02101
02102 fprintf (stderr, "Total Overhead: %10lld\n",
02103 all_overhead);
02104 fprintf (stderr, "Total Allocated: %10lld\n",
02105 all_allocated);
02106
02107 fprintf (stderr, "Total Overhead under 32B: %10lld\n",
02108 all_overhead_under32);
02109 fprintf (stderr, "Total Allocated under 32B: %10lld\n",
02110 all_allocated_under32);
02111 fprintf (stderr, "Total Overhead under 64B: %10lld\n",
02112 all_overhead_under64);
02113 fprintf (stderr, "Total Allocated under 64B: %10lld\n",
02114 all_allocated_under64);
02115 fprintf (stderr, "Total Overhead under 128B: %10lld\n",
02116 all_overhead_under128);
02117 fprintf (stderr, "Total Allocated under 128B: %10lld\n",
02118 all_allocated_under128);
02119 }
02120 #endif
02121 }
02122
02123
02124
02125
02126
02127
02128
02129
02130 #define NUM_PCH_BUCKETS (gt_types_enum_last + 3)
02131
02132 #define OTHER_BUCKET (gt_types_enum_last + 0)
02133 #define IDENTIFIER_BUCKET (gt_types_enum_last + 1)
02134 #define STRING_BUCKET (gt_types_enum_last + 2)
02135
02136 struct ggc_pch_ondisk
02137 {
02138 size_t total;
02139 size_t type_totals[NUM_PCH_BUCKETS];
02140 };
02141
02142 struct ggc_pch_data
02143 {
02144 struct ggc_pch_ondisk d;
02145 size_t base;
02146 size_t orig_base;
02147 size_t alloc_size;
02148 alloc_type *alloc_bits;
02149 size_t type_bases[NUM_PCH_BUCKETS];
02150 size_t start_offset;
02151 };
02152
02153
02154
02155 struct ggc_pch_data *
02156 init_ggc_pch (void)
02157 {
02158 return xcalloc (sizeof (struct ggc_pch_data), 1);
02159 }
02160
02161
02162
02163
02164
02165
02166 static int
02167 pch_bucket (void *x, enum gt_types_enum type,
02168 bool is_string)
02169 {
02170
02171
02172 if (type == gt_ggc_e_14lang_tree_node
02173 && TREE_CODE ((tree) x) == IDENTIFIER_NODE)
02174 return IDENTIFIER_BUCKET;
02175 else if (type == gt_types_enum_last)
02176 {
02177 if (is_string)
02178 return STRING_BUCKET;
02179 return OTHER_BUCKET;
02180 }
02181 return type;
02182 }
02183
02184
02185
02186 void
02187 ggc_pch_count_object (struct ggc_pch_data *d, void *x ATTRIBUTE_UNUSED,
02188 size_t size, bool is_string, enum gt_types_enum type)
02189 {
02190
02191
02192
02193
02194 d->d.type_totals[pch_bucket (x, type, is_string)] += size;
02195 }
02196
02197
02198
02199 size_t
02200 ggc_pch_total_size (struct ggc_pch_data *d)
02201 {
02202 enum gt_types_enum i;
02203 size_t alloc_size, total_size;
02204
02205 total_size = 0;
02206 for (i = 0; i < NUM_PCH_BUCKETS; i++)
02207 {
02208 d->d.type_totals[i] = ROUND_UP (d->d.type_totals[i], GGC_PAGE_SIZE);
02209 total_size += d->d.type_totals[i];
02210 }
02211 d->d.total = total_size;
02212
02213
02214 alloc_size = CEIL (d->d.total, BYTES_PER_ALLOC_BIT * 8);
02215 alloc_size = ROUND_UP (alloc_size, MAX_ALIGNMENT);
02216 d->alloc_size = alloc_size;
02217
02218 return d->d.total + alloc_size;
02219 }
02220
02221
02222
02223 void
02224 ggc_pch_this_base (struct ggc_pch_data *d, void *base_)
02225 {
02226 int i;
02227 size_t base = (size_t) base_;
02228
02229 d->base = d->orig_base = base;
02230 for (i = 0; i < NUM_PCH_BUCKETS; i++)
02231 {
02232 d->type_bases[i] = base;
02233 base += d->d.type_totals[i];
02234 }
02235
02236 if (d->alloc_bits == NULL)
02237 d->alloc_bits = xcalloc (1, d->alloc_size);
02238 }
02239
02240
02241
02242 char *
02243 ggc_pch_alloc_object (struct ggc_pch_data *d, void *x,
02244 size_t size, bool is_string,
02245 enum gt_types_enum type)
02246 {
02247 size_t alloc_word, alloc_bit;
02248 char *result;
02249 int bucket = pch_bucket (x, type, is_string);
02250
02251
02252
02253
02254
02255
02256 alloc_word = ((d->type_bases[bucket] - d->orig_base)
02257 / (8 * sizeof (alloc_type) * BYTES_PER_ALLOC_BIT));
02258 alloc_bit = ((d->type_bases[bucket] - d->orig_base)
02259 / BYTES_PER_ALLOC_BIT) % (8 * sizeof (alloc_type));
02260 d->alloc_bits[alloc_word] |= 1L << alloc_bit;
02261
02262
02263 result = (char *) d->type_bases[bucket];
02264 d->type_bases[bucket] += size;
02265 return result;
02266 }
02267
02268
02269
02270 void
02271 ggc_pch_prepare_write (struct ggc_pch_data *d,
02272 FILE *f)
02273 {
02274
02275
02276
02277 d->start_offset = ftell (f);
02278 }
02279
02280
02281
02282 void
02283 ggc_pch_write_object (struct ggc_pch_data *d,
02284 FILE *f, void *x, void *newx,
02285 size_t size, bool is_string ATTRIBUTE_UNUSED)
02286 {
02287 if (fseek (f, (size_t) newx - d->orig_base + d->start_offset, SEEK_SET) != 0)
02288 fatal_error ("can't seek PCH file: %m");
02289
02290 if (fwrite (x, size, 1, f) != 1)
02291 fatal_error ("can't write PCH file: %m");
02292 }
02293
02294 void
02295 ggc_pch_finish (struct ggc_pch_data *d, FILE *f)
02296 {
02297
02298 if (fseek (f, d->start_offset + d->d.total, SEEK_SET) != 0)
02299 fatal_error ("can't seek PCH file: %m");
02300
02301 if (fwrite (d->alloc_bits, d->alloc_size, 1, f) != 1)
02302 fatal_error ("can't write PCH fle: %m");
02303
02304
02305 if (fwrite (&d->d, sizeof (d->d), 1, f) != 1)
02306 fatal_error ("can't write PCH file: %m");
02307
02308 free (d->alloc_bits);
02309 free (d);
02310 }
02311
02312
02313
02314
02315 void
02316 ggc_pch_read (FILE *f, void *addr)
02317 {
02318 struct ggc_pch_ondisk d;
02319 size_t alloc_size;
02320 struct alloc_zone *zone;
02321 struct page_entry *pch_page;
02322 char *p;
02323
02324 if (fread (&d, sizeof (d), 1, f) != 1)
02325 fatal_error ("can't read PCH file: %m");
02326
02327 alloc_size = CEIL (d.total, BYTES_PER_ALLOC_BIT * 8);
02328 alloc_size = ROUND_UP (alloc_size, MAX_ALIGNMENT);
02329
02330 pch_zone.bytes = d.total;
02331 pch_zone.alloc_bits = (alloc_type *) ((char *) addr + pch_zone.bytes);
02332 pch_zone.page = (char *) addr;
02333 pch_zone.end = (char *) pch_zone.alloc_bits;
02334
02335
02336
02337 for (zone = G.zones; zone; zone = zone->next_zone)
02338 {
02339 struct small_page_entry *page, *next_page;
02340 struct large_page_entry *large_page, *next_large_page;
02341
02342 zone->allocated = 0;
02343
02344
02345 memset (zone->free_chunks, 0, sizeof (zone->free_chunks));
02346 zone->high_free_bin = 0;
02347 zone->cached_free = NULL;
02348 zone->cached_free_size = 0;
02349
02350
02351 for (page = zone->pages; page != NULL; page = next_page)
02352 {
02353 next_page = page->next;
02354 memset (page->alloc_bits, 0,
02355 G.small_page_overhead - PAGE_OVERHEAD);
02356 free_small_page (page);
02357 }
02358
02359
02360 for (large_page = zone->large_pages; large_page != NULL;
02361 large_page = next_large_page)
02362 {
02363 next_large_page = large_page->next;
02364 free_large_page (large_page);
02365 }
02366
02367 zone->pages = NULL;
02368 zone->large_pages = NULL;
02369 }
02370
02371
02372
02373 pch_page = xcalloc (1, sizeof (struct page_entry));
02374 pch_page->page = pch_zone.page;
02375 pch_page->pch_p = true;
02376
02377 for (p = pch_zone.page; p < pch_zone.end; p += GGC_PAGE_SIZE)
02378 set_page_table_entry (p, pch_page);
02379 }