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 #include "config.h"
00026 #include "system.h"
00027 #include "coretypes.h"
00028 #include "tm.h"
00029 #include "tree.h"
00030 #include "rtl.h"
00031 #include "tm_p.h"
00032 #include "toplev.h"
00033 #include "varray.h"
00034 #include "flags.h"
00035 #include "ggc.h"
00036 #include "timevar.h"
00037 #include "params.h"
00038 #include "bitmap.h"
00039
00040 #ifdef ENABLE_VALGRIND_CHECKING
00041 # ifdef HAVE_VALGRIND_MEMCHECK_H
00042 # include <valgrind/memcheck.h>
00043 # elif defined HAVE_MEMCHECK_H
00044 # include <memcheck.h>
00045 # else
00046 # include <valgrind.h>
00047 # endif
00048 #else
00049
00050 #define VALGRIND_DISCARD(x)
00051 #define VALGRIND_MALLOCLIKE_BLOCK(w,x,y,z)
00052 #define VALGRIND_FREELIKE_BLOCK(x,y)
00053 #endif
00054
00055
00056 #ifdef HAVE_MMAP_ANON
00057 # undef HAVE_MMAP_DEV_ZERO
00058
00059 # include <sys/mman.h>
00060 # ifndef MAP_FAILED
00061 # define MAP_FAILED -1
00062 # endif
00063 # if !defined (MAP_ANONYMOUS) && defined (MAP_ANON)
00064 # define MAP_ANONYMOUS MAP_ANON
00065 # endif
00066 # define USING_MMAP
00067
00068 #endif
00069
00070 #ifdef HAVE_MMAP_DEV_ZERO
00071
00072 # include <sys/mman.h>
00073 # ifndef MAP_FAILED
00074 # define MAP_FAILED -1
00075 # endif
00076 # define USING_MMAP
00077
00078 #endif
00079
00080 #ifndef USING_MMAP
00081 #error "Zone collector requires mmap"
00082 #endif
00083
00084 #if (GCC_VERSION < 3001)
00085 #define prefetch(X) ((void) X)
00086 #else
00087 #define prefetch(X) __builtin_prefetch (X)
00088 #endif
00089
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 #define GGC_DEBUG_LEVEL (0)
00125
00126 #ifndef HOST_BITS_PER_PTR
00127 #define HOST_BITS_PER_PTR HOST_BITS_PER_LONG
00128 #endif
00129
00130 #ifdef COOKIE_CHECKING
00131 #define CHUNK_MAGIC 0x95321123
00132 #define DEADCHUNK_MAGIC 0x12817317
00133 #endif
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144 struct alloc_chunk {
00145 #ifdef COOKIE_CHECKING
00146 unsigned int magic;
00147 #endif
00148 unsigned int type:1;
00149 unsigned int mark:1;
00150 unsigned char large;
00151 unsigned short size;
00152
00153
00154
00155
00156 union {
00157 struct alloc_chunk *next_free;
00158 char data[1];
00159
00160
00161 HOST_WIDEST_INT align_i;
00162 #ifdef HAVE_LONG_DOUBLE
00163 long double align_d;
00164 #else
00165 double align_d;
00166 #endif
00167 } u;
00168 };
00169
00170 #define CHUNK_OVERHEAD (offsetof (struct alloc_chunk, u))
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182 #define NUM_FREE_BINS 64
00183 #define MAX_FREE_BIN_SIZE (64 * sizeof (void *))
00184 #define FREE_BIN_DELTA (MAX_FREE_BIN_SIZE / NUM_FREE_BINS)
00185 #define SIZE_BIN_UP(SIZE) (((SIZE) + FREE_BIN_DELTA - 1) / FREE_BIN_DELTA)
00186 #define SIZE_BIN_DOWN(SIZE) ((SIZE) / FREE_BIN_DELTA)
00187
00188
00189
00190 #define LARGE_OBJECT_SIZE 0x7fff
00191
00192
00193
00194
00195
00196 struct max_alignment {
00197 char c;
00198 union {
00199 HOST_WIDEST_INT i;
00200 #ifdef HAVE_LONG_DOUBLE
00201 long double d;
00202 #else
00203 double d;
00204 #endif
00205 } u;
00206 };
00207
00208
00209
00210 #define MAX_ALIGNMENT (offsetof (struct max_alignment, u))
00211
00212
00213
00214
00215 #define ROUND_UP_VALUE(x, f) ((f) - 1 - ((f) - 1 + (x)) % (f))
00216
00217
00218
00219 #define ROUND_UP(x, f) (CEIL (x, f) * (f))
00220
00221
00222
00223 typedef struct page_entry
00224 {
00225
00226
00227 struct page_entry *next;
00228
00229
00230
00231 size_t bytes;
00232
00233
00234 size_t survived;
00235
00236
00237 char *page;
00238
00239
00240 unsigned short context_depth;
00241
00242
00243 bool large_p;
00244
00245
00246 struct alloc_zone *zone;
00247 } page_entry;
00248
00249
00250
00251 static struct globals
00252 {
00253
00254 struct alloc_zone *zones;
00255
00256
00257 size_t pagesize;
00258 size_t lg_pagesize;
00259
00260
00261 #if defined (HAVE_MMAP_DEV_ZERO)
00262 int dev_zero_fd;
00263 #endif
00264
00265
00266 FILE *debug_file;
00267 } G;
00268
00269
00270 struct alloc_zone
00271 {
00272
00273 const char *name;
00274
00275
00276 page_entry *pages;
00277
00278
00279
00280 struct alloc_chunk *free_chunks[NUM_FREE_BINS + 1];
00281
00282
00283 size_t allocated;
00284
00285
00286 size_t allocated_last_gc;
00287
00288
00289 size_t bytes_mapped;
00290
00291
00292 unsigned long context_depth_allocations;
00293
00294
00295 unsigned long context_depth_collections;
00296
00297
00298 unsigned short context_depth;
00299
00300
00301 page_entry *free_pages;
00302
00303
00304 struct alloc_zone *next_zone;
00305
00306
00307 bool was_collected;
00308
00309
00310 bool dead;
00311
00312 #ifdef GATHER_STATISTICS
00313 struct
00314 {
00315
00316 unsigned long long total_allocated;
00317
00318 unsigned long long total_overhead;
00319
00320
00321
00322
00323
00324 unsigned long long total_allocated_under32;
00325 unsigned long long total_overhead_under32;
00326
00327 unsigned long long total_allocated_under64;
00328 unsigned long long total_overhead_under64;
00329
00330 unsigned long long total_allocated_under128;
00331 unsigned long long total_overhead_under128;
00332 } stats;
00333 #endif
00334 } main_zone;
00335
00336 struct alloc_zone *rtl_zone;
00337 struct alloc_zone *garbage_zone;
00338 struct alloc_zone *tree_zone;
00339
00340 static int always_collect;
00341
00342
00343
00344
00345
00346 #define GGC_QUIRE_SIZE 16
00347
00348 static int ggc_allocated_p (const void *);
00349 #ifdef USING_MMAP
00350 static char *alloc_anon (char *, size_t, struct alloc_zone *);
00351 #endif
00352 static struct page_entry * alloc_small_page ( struct alloc_zone *);
00353 static struct page_entry * alloc_large_page (size_t, struct alloc_zone *);
00354 static void free_chunk (struct alloc_chunk *, size_t, struct alloc_zone *);
00355 static void free_page (struct page_entry *);
00356 static void release_pages (struct alloc_zone *);
00357 static void sweep_pages (struct alloc_zone *);
00358 static void * ggc_alloc_zone_1 (size_t, struct alloc_zone *, short MEM_STAT_DECL);
00359 static bool ggc_collect_1 (struct alloc_zone *, bool);
00360 static void check_cookies (void);
00361
00362
00363
00364
00365 static inline int
00366 ggc_allocated_p (const void *p)
00367 {
00368 struct alloc_chunk *chunk;
00369 chunk = (struct alloc_chunk *) ((char *)p - CHUNK_OVERHEAD);
00370 #ifdef COOKIE_CHECKING
00371 gcc_assert (chunk->magic == CHUNK_MAGIC);
00372 #endif
00373 if (chunk->type == 1)
00374 return true;
00375 return false;
00376 }
00377
00378
00379 #ifdef USING_MMAP
00380
00381
00382
00383
00384 static inline char *
00385 alloc_anon (char *pref ATTRIBUTE_UNUSED, size_t size, struct alloc_zone *zone)
00386 {
00387 #ifdef HAVE_MMAP_ANON
00388 char *page = (char *) mmap (pref, size, PROT_READ | PROT_WRITE,
00389 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
00390 #endif
00391 #ifdef HAVE_MMAP_DEV_ZERO
00392 char *page = (char *) mmap (pref, size, PROT_READ | PROT_WRITE,
00393 MAP_PRIVATE, G.dev_zero_fd, 0);
00394 #endif
00395 VALGRIND_MALLOCLIKE_BLOCK(page, size, 0, 0);
00396
00397 if (page == (char *) MAP_FAILED)
00398 {
00399 perror ("virtual memory exhausted");
00400 exit (FATAL_EXIT_CODE);
00401 }
00402
00403
00404 zone->bytes_mapped += size;
00405
00406
00407
00408 VALGRIND_DISCARD (VALGRIND_MAKE_NOACCESS (page, size));
00409 return page;
00410 }
00411 #endif
00412
00413
00414
00415
00416 static inline struct page_entry *
00417 alloc_small_page (struct alloc_zone *zone)
00418 {
00419 struct page_entry *entry;
00420 char *page;
00421
00422 page = NULL;
00423
00424
00425 entry = zone->free_pages;
00426 if (entry != NULL)
00427 {
00428
00429 zone->free_pages = entry->next;
00430 page = entry->page;
00431
00432
00433 }
00434 #ifdef USING_MMAP
00435 else
00436 {
00437
00438
00439
00440 struct page_entry *e, *f = zone->free_pages;
00441 int i;
00442
00443 page = alloc_anon (NULL, G.pagesize * GGC_QUIRE_SIZE, zone);
00444
00445
00446
00447 for (i = GGC_QUIRE_SIZE - 1; i >= 1; i--)
00448 {
00449 e = (struct page_entry *) xmalloc (sizeof (struct page_entry));
00450 e->bytes = G.pagesize;
00451 e->page = page + (i << G.lg_pagesize);
00452 e->next = f;
00453 f = e;
00454 }
00455
00456 zone->free_pages = f;
00457 }
00458 #endif
00459 if (entry == NULL)
00460 entry = (struct page_entry *) xmalloc (sizeof (struct page_entry));
00461
00462 entry->next = 0;
00463 entry->bytes = G.pagesize;
00464 entry->page = page;
00465 entry->context_depth = zone->context_depth;
00466 entry->large_p = false;
00467 entry->zone = zone;
00468 zone->context_depth_allocations |= (unsigned long)1 << zone->context_depth;
00469
00470 if (GGC_DEBUG_LEVEL >= 2)
00471 fprintf (G.debug_file,
00472 "Allocating %s page at %p, data %p-%p\n", entry->zone->name,
00473 (PTR) entry, page, page + G.pagesize - 1);
00474
00475 return entry;
00476 }
00477
00478
00479 #define ROUND_UP(x, f) (CEIL (x, f) * (f))
00480
00481
00482
00483 static inline struct page_entry *
00484 alloc_large_page (size_t size, struct alloc_zone *zone)
00485 {
00486 struct page_entry *entry;
00487 char *page;
00488 size = ROUND_UP (size, 1024);
00489 page = (char *) xmalloc (size + CHUNK_OVERHEAD + sizeof (struct page_entry));
00490 entry = (struct page_entry *) (page + size + CHUNK_OVERHEAD);
00491
00492 entry->next = 0;
00493 entry->bytes = size;
00494 entry->page = page;
00495 entry->context_depth = zone->context_depth;
00496 entry->large_p = true;
00497 entry->zone = zone;
00498 zone->context_depth_allocations |= (unsigned long)1 << zone->context_depth;
00499
00500 if (GGC_DEBUG_LEVEL >= 2)
00501 fprintf (G.debug_file,
00502 "Allocating %s large page at %p, data %p-%p\n", entry->zone->name,
00503 (PTR) entry, page, page + size - 1);
00504
00505 return entry;
00506 }
00507
00508
00509
00510
00511 static inline void
00512 free_page (page_entry *entry)
00513 {
00514 if (GGC_DEBUG_LEVEL >= 2)
00515 fprintf (G.debug_file,
00516 "Deallocating %s page at %p, data %p-%p\n", entry->zone->name, (PTR) entry,
00517 entry->page, entry->page + entry->bytes - 1);
00518
00519 if (entry->large_p)
00520 {
00521 free (entry->page);
00522 VALGRIND_FREELIKE_BLOCK (entry->page, entry->bytes);
00523 }
00524 else
00525 {
00526
00527
00528 VALGRIND_DISCARD (VALGRIND_MAKE_NOACCESS (entry->page, entry->bytes));
00529
00530 entry->next = entry->zone->free_pages;
00531 entry->zone->free_pages = entry;
00532 }
00533 }
00534
00535
00536
00537 static void
00538 release_pages (struct alloc_zone *zone)
00539 {
00540 #ifdef USING_MMAP
00541 page_entry *p, *next;
00542 char *start;
00543 size_t len;
00544
00545
00546 p = zone->free_pages;
00547
00548 while (p)
00549 {
00550 start = p->page;
00551 next = p->next;
00552 len = p->bytes;
00553 free (p);
00554 p = next;
00555
00556 while (p && p->page == start + len)
00557 {
00558 next = p->next;
00559 len += p->bytes;
00560 free (p);
00561 p = next;
00562 }
00563
00564 munmap (start, len);
00565 zone->bytes_mapped -= len;
00566 }
00567
00568 zone->free_pages = NULL;
00569 #endif
00570 }
00571
00572
00573
00574 static inline void
00575 free_chunk (struct alloc_chunk *chunk, size_t size, struct alloc_zone *zone)
00576 {
00577 size_t bin = 0;
00578
00579 bin = SIZE_BIN_DOWN (size);
00580 gcc_assert (bin);
00581 if (bin > NUM_FREE_BINS)
00582 bin = 0;
00583 #ifdef COOKIE_CHECKING
00584 gcc_assert (chunk->magic == CHUNK_MAGIC || chunk->magic == DEADCHUNK_MAGIC);
00585 chunk->magic = DEADCHUNK_MAGIC;
00586 #endif
00587 chunk->u.next_free = zone->free_chunks[bin];
00588 zone->free_chunks[bin] = chunk;
00589 if (GGC_DEBUG_LEVEL >= 3)
00590 fprintf (G.debug_file, "Deallocating object, chunk=%p\n", (void *)chunk);
00591 VALGRIND_DISCARD (VALGRIND_MAKE_READABLE (chunk, sizeof (struct alloc_chunk)));
00592 }
00593
00594
00595
00596 static void *
00597 ggc_alloc_zone_1 (size_t orig_size, struct alloc_zone *zone,
00598 short type ATTRIBUTE_UNUSED
00599 MEM_STAT_DECL)
00600 {
00601 size_t bin = 0;
00602 size_t lsize = 0;
00603 struct page_entry *entry;
00604 struct alloc_chunk *chunk, *lchunk, **pp;
00605 void *result;
00606 size_t size = orig_size;
00607
00608
00609 if (size < FREE_BIN_DELTA)
00610 size = FREE_BIN_DELTA;
00611 size = (size + MAX_ALIGNMENT - 1) & -MAX_ALIGNMENT;
00612
00613
00614 if (size >= G.pagesize - 2*CHUNK_OVERHEAD - FREE_BIN_DELTA)
00615 {
00616 size = ROUND_UP (size, 1024);
00617 entry = alloc_large_page (size, zone);
00618 entry->survived = 0;
00619 entry->next = entry->zone->pages;
00620 entry->zone->pages = entry;
00621
00622 chunk = (struct alloc_chunk *) entry->page;
00623 VALGRIND_DISCARD (VALGRIND_MAKE_WRITABLE (chunk, sizeof (struct alloc_chunk)));
00624 chunk->large = 1;
00625 chunk->size = CEIL (size, 1024);
00626
00627 goto found;
00628 }
00629
00630
00631
00632 bin = SIZE_BIN_UP (size);
00633 if (bin <= NUM_FREE_BINS)
00634 {
00635 chunk = zone->free_chunks[bin];
00636 if (chunk)
00637 {
00638 zone->free_chunks[bin] = chunk->u.next_free;
00639 VALGRIND_DISCARD (VALGRIND_MAKE_WRITABLE (chunk, sizeof (struct alloc_chunk)));
00640 goto found;
00641 }
00642 }
00643
00644
00645
00646 pp = &(zone->free_chunks[0]);
00647 chunk = *pp;
00648 while (chunk && chunk->size < size)
00649 {
00650 pp = &chunk->u.next_free;
00651 chunk = *pp;
00652 }
00653
00654
00655 if (!chunk)
00656 {
00657 entry = alloc_small_page (zone);
00658 entry->next = entry->zone->pages;
00659 entry->zone->pages = entry;
00660
00661 chunk = (struct alloc_chunk *) entry->page;
00662 VALGRIND_DISCARD (VALGRIND_MAKE_WRITABLE (chunk, sizeof (struct alloc_chunk)));
00663 chunk->size = G.pagesize - CHUNK_OVERHEAD;
00664 chunk->large = 0;
00665 }
00666 else
00667 {
00668 *pp = chunk->u.next_free;
00669 VALGRIND_DISCARD (VALGRIND_MAKE_WRITABLE (chunk, sizeof (struct alloc_chunk)));
00670 chunk->large = 0;
00671 }
00672
00673 lsize = chunk->size - size;
00674 if (lsize >= CHUNK_OVERHEAD + FREE_BIN_DELTA)
00675 {
00676 VALGRIND_DISCARD (VALGRIND_MAKE_WRITABLE (chunk, sizeof (struct alloc_chunk)));
00677 chunk->size = size;
00678
00679 lsize -= CHUNK_OVERHEAD;
00680 lchunk = (struct alloc_chunk *)(chunk->u.data + size);
00681 VALGRIND_DISCARD (VALGRIND_MAKE_WRITABLE (lchunk, sizeof (struct alloc_chunk)));
00682 #ifdef COOKIE_CHECKING
00683 lchunk->magic = CHUNK_MAGIC;
00684 #endif
00685 lchunk->type = 0;
00686 lchunk->mark = 0;
00687 lchunk->size = lsize;
00688 lchunk->large = 0;
00689 free_chunk (lchunk, lsize, zone);
00690 lsize = 0;
00691 }
00692
00693
00694 found:
00695 #ifdef COOKIE_CHECKING
00696 chunk->magic = CHUNK_MAGIC;
00697 #endif
00698 chunk->type = 1;
00699 chunk->mark = 0;
00700
00701
00702 result = chunk->u.data;
00703
00704 #ifdef ENABLE_GC_CHECKING
00705
00706
00707
00708
00709 VALGRIND_DISCARD (VALGRIND_MAKE_WRITABLE (result, size));
00710
00711
00712 memset (result, 0xaf, size);
00713 #endif
00714
00715
00716
00717
00718 VALGRIND_DISCARD (VALGRIND_MAKE_WRITABLE (result, size));
00719
00720
00721
00722 zone->allocated += size;
00723
00724 #ifdef GATHER_STATISTICS
00725 ggc_record_overhead (orig_size, size + CHUNK_OVERHEAD - orig_size PASS_MEM_STAT);
00726
00727 {
00728 size_t object_size = size + CHUNK_OVERHEAD;
00729 size_t overhead = object_size - orig_size;
00730
00731 zone->stats.total_overhead += overhead;
00732 zone->stats.total_allocated += object_size;
00733
00734 if (orig_size <= 32)
00735 {
00736 zone->stats.total_overhead_under32 += overhead;
00737 zone->stats.total_allocated_under32 += object_size;
00738 }
00739 if (orig_size <= 64)
00740 {
00741 zone->stats.total_overhead_under64 += overhead;
00742 zone->stats.total_allocated_under64 += object_size;
00743 }
00744 if (orig_size <= 128)
00745 {
00746 zone->stats.total_overhead_under128 += overhead;
00747 zone->stats.total_allocated_under128 += object_size;
00748 }
00749 }
00750 #endif
00751
00752 if (GGC_DEBUG_LEVEL >= 3)
00753 fprintf (G.debug_file, "Allocating object, chunk=%p size=%lu at %p\n",
00754 (void *)chunk, (unsigned long) size, result);
00755
00756 return result;
00757 }
00758
00759
00760
00761
00762 void *
00763 ggc_alloc_typed_stat (enum gt_types_enum gte, size_t size
00764 MEM_STAT_DECL)
00765 {
00766 switch (gte)
00767 {
00768 case gt_ggc_e_14lang_tree_node:
00769 return ggc_alloc_zone_1 (size, tree_zone, gte PASS_MEM_STAT);
00770
00771 case gt_ggc_e_7rtx_def:
00772 return ggc_alloc_zone_1 (size, rtl_zone, gte PASS_MEM_STAT);
00773
00774 case gt_ggc_e_9rtvec_def:
00775 return ggc_alloc_zone_1 (size, rtl_zone, gte PASS_MEM_STAT);
00776
00777 default:
00778 return ggc_alloc_zone_1 (size, &main_zone, gte PASS_MEM_STAT);
00779 }
00780 }
00781
00782
00783
00784 void *
00785 ggc_alloc_stat (size_t size MEM_STAT_DECL)
00786 {
00787 return ggc_alloc_zone_1 (size, &main_zone, -1 PASS_MEM_STAT);
00788 }
00789
00790
00791
00792 void *
00793 ggc_alloc_zone_stat (size_t size, struct alloc_zone *zone MEM_STAT_DECL)
00794 {
00795 return ggc_alloc_zone_1 (size, zone, -1 PASS_MEM_STAT);
00796 }
00797
00798
00799 #ifdef ENABLE_GC_CHECKING
00800 #define poison_chunk(CHUNK, SIZE) \
00801 memset ((CHUNK)->u.data, 0xa5, (SIZE))
00802 #else
00803 #define poison_chunk(CHUNK, SIZE)
00804 #endif
00805
00806
00807
00808 void
00809 ggc_free (void *p)
00810 {
00811 struct alloc_chunk *chunk;
00812
00813 chunk = (struct alloc_chunk *) ((char *)p - CHUNK_OVERHEAD);
00814
00815
00816 poison_chunk (chunk, ggc_get_size (p));
00817 }
00818
00819
00820
00821
00822
00823 int
00824 ggc_set_mark (const void *p)
00825 {
00826 struct alloc_chunk *chunk;
00827
00828 chunk = (struct alloc_chunk *) ((char *)p - CHUNK_OVERHEAD);
00829 #ifdef COOKIE_CHECKING
00830 gcc_assert (chunk->magic == CHUNK_MAGIC);
00831 #endif
00832 if (chunk->mark)
00833 return 1;
00834 chunk->mark = 1;
00835
00836 if (GGC_DEBUG_LEVEL >= 4)
00837 fprintf (G.debug_file, "Marking %p\n", p);
00838
00839 return 0;
00840 }
00841
00842
00843
00844
00845
00846 int
00847 ggc_marked_p (const void *p)
00848 {
00849 struct alloc_chunk *chunk;
00850
00851 chunk = (struct alloc_chunk *) ((char *)p - CHUNK_OVERHEAD);
00852 #ifdef COOKIE_CHECKING
00853 gcc_assert (chunk->magic == CHUNK_MAGIC);
00854 #endif
00855 return chunk->mark;
00856 }
00857
00858
00859
00860 size_t
00861 ggc_get_size (const void *p)
00862 {
00863 struct alloc_chunk *chunk;
00864
00865 chunk = (struct alloc_chunk *) ((char *)p - CHUNK_OVERHEAD);
00866 #ifdef COOKIE_CHECKING
00867 gcc_assert (chunk->magic == CHUNK_MAGIC);
00868 #endif
00869 if (chunk->large)
00870 return chunk->size * 1024;
00871
00872 return chunk->size;
00873 }
00874
00875
00876 void
00877 init_ggc (void)
00878 {
00879
00880 main_zone.name = "Main zone";
00881 G.zones = &main_zone;
00882
00883
00884 rtl_zone = new_ggc_zone ("RTL zone");
00885 tree_zone = new_ggc_zone ("Tree zone");
00886 garbage_zone = new_ggc_zone ("Garbage zone");
00887
00888 G.pagesize = getpagesize();
00889 G.lg_pagesize = exact_log2 (G.pagesize);
00890 #ifdef HAVE_MMAP_DEV_ZERO
00891 G.dev_zero_fd = open ("/dev/zero", O_RDONLY);
00892 gcc_assert (G.dev_zero_fd != -1);
00893 #endif
00894
00895 #if 0
00896 G.debug_file = fopen ("ggc-mmap.debug", "w");
00897 setlinebuf (G.debug_file);
00898 #else
00899 G.debug_file = stdout;
00900 #endif
00901
00902 #ifdef USING_MMAP
00903
00904
00905
00906
00907 {
00908 char *p = alloc_anon (NULL, G.pagesize, &main_zone);
00909 struct page_entry *e;
00910 if ((size_t)p & (G.pagesize - 1))
00911 {
00912
00913
00914
00915 p = alloc_anon (NULL, G.pagesize, &main_zone);
00916 gcc_assert (!((size_t)p & (G.pagesize - 1)));
00917 }
00918
00919
00920 e = (struct page_entry *) xmalloc (sizeof (struct page_entry));
00921 e->bytes = G.pagesize;
00922 e->page = p;
00923 e->next = main_zone.free_pages;
00924 main_zone.free_pages = e;
00925 }
00926 #endif
00927 }
00928
00929
00930
00931 struct alloc_zone *
00932 new_ggc_zone (const char * name)
00933 {
00934 struct alloc_zone *new_zone = xcalloc (1, sizeof (struct alloc_zone));
00935 new_zone->name = name;
00936 new_zone->next_zone = G.zones->next_zone;
00937 G.zones->next_zone = new_zone;
00938 return new_zone;
00939 }
00940
00941
00942 void
00943 destroy_ggc_zone (struct alloc_zone * dead_zone)
00944 {
00945 struct alloc_zone *z;
00946
00947 for (z = G.zones; z && z->next_zone != dead_zone; z = z->next_zone)
00948
00949 continue;
00950
00951
00952 gcc_assert (z);
00953
00954
00955 z->dead= true;
00956 }
00957
00958
00959
00960
00961 void
00962 ggc_push_context (void)
00963 {
00964 struct alloc_zone *zone;
00965 for (zone = G.zones; zone; zone = zone->next_zone)
00966 ++(zone->context_depth);
00967
00968 gcc_assert (main_zone.context_depth < HOST_BITS_PER_LONG);
00969 }
00970
00971
00972
00973
00974 static void
00975 ggc_pop_context_1 (struct alloc_zone *zone)
00976 {
00977 unsigned long omask;
00978 unsigned depth;
00979 page_entry *p;
00980
00981 depth = --(zone->context_depth);
00982 omask = (unsigned long)1 << (depth + 1);
00983
00984 if (!((zone->context_depth_allocations | zone->context_depth_collections) & omask))
00985 return;
00986
00987 zone->context_depth_allocations |= (zone->context_depth_allocations & omask) >> 1;
00988 zone->context_depth_allocations &= omask - 1;
00989 zone->context_depth_collections &= omask - 1;
00990
00991
00992
00993
00994 for (p = zone->pages; p != NULL; p = p->next)
00995 if (p->context_depth > depth)
00996 p->context_depth = depth;
00997 }
00998
00999
01000
01001 void
01002 ggc_pop_context (void)
01003 {
01004 struct alloc_zone *zone;
01005 for (zone = G.zones; zone; zone = zone->next_zone)
01006 ggc_pop_context_1 (zone);
01007 }
01008
01009
01010
01011 static void
01012 sweep_pages (struct alloc_zone *zone)
01013 {
01014 page_entry **pp, *p, *next;
01015 struct alloc_chunk *chunk, *last_free, *end;
01016 size_t last_free_size, allocated = 0;
01017 bool nomarksinpage;
01018
01019
01020 memset (zone->free_chunks, 0, sizeof (zone->free_chunks));
01021 pp = &zone->pages;
01022 for (p = zone->pages; p ; p = next)
01023 {
01024 next = p->next;
01025
01026
01027
01028
01029 if (p->large_p)
01030 {
01031 if (((struct alloc_chunk *)p->page)->mark == 1)
01032 {
01033 ((struct alloc_chunk *)p->page)->mark = 0;
01034 allocated += p->bytes - CHUNK_OVERHEAD;
01035 pp = &p->next;
01036 }
01037 else
01038 {
01039 *pp = next;
01040 #ifdef ENABLE_GC_CHECKING
01041
01042 memset (p->page, 0xb5, p->bytes);
01043 #endif
01044 free_page (p);
01045 }
01046 continue;
01047 }
01048
01049
01050 p->survived++;
01051
01052
01053
01054
01055
01056
01057 chunk = (struct alloc_chunk *)p->page;
01058 end = (struct alloc_chunk *)(p->page + G.pagesize);
01059 last_free = NULL;
01060 last_free_size = 0;
01061 nomarksinpage = true;
01062 do
01063 {
01064 prefetch ((struct alloc_chunk *)(chunk->u.data + chunk->size));
01065 if (chunk->mark || p->context_depth < zone->context_depth)
01066 {
01067 nomarksinpage = false;
01068 if (last_free)
01069 {
01070 last_free->type = 0;
01071 last_free->size = last_free_size;
01072 last_free->mark = 0;
01073 poison_chunk (last_free, last_free_size);
01074 free_chunk (last_free, last_free_size, zone);
01075 last_free = NULL;
01076 }
01077 if (chunk->mark)
01078 {
01079 allocated += chunk->size;
01080 }
01081 chunk->mark = 0;
01082 }
01083 else
01084 {
01085 if (last_free)
01086 {
01087 last_free_size += CHUNK_OVERHEAD + chunk->size;
01088 }
01089 else
01090 {
01091 last_free = chunk;
01092 last_free_size = chunk->size;
01093 }
01094 }
01095
01096 chunk = (struct alloc_chunk *)(chunk->u.data + chunk->size);
01097 }
01098 while (chunk < end);
01099
01100 if (nomarksinpage)
01101 {
01102 *pp = next;
01103 #ifdef ENABLE_GC_CHECKING
01104
01105 memset (p->page, 0xb5, p->bytes);
01106 #endif
01107 free_page (p);
01108 continue;
01109 }
01110 else if (last_free)
01111 {
01112 last_free->type = 0;
01113 last_free->size = last_free_size;
01114 last_free->mark = 0;
01115 poison_chunk (last_free, last_free_size);
01116 free_chunk (last_free, last_free_size, zone);
01117 }
01118 pp = &p->next;
01119 }
01120
01121 zone->allocated = allocated;
01122 }
01123
01124
01125
01126
01127
01128
01129 static bool
01130 ggc_collect_1 (struct alloc_zone *zone, bool need_marking)
01131 {
01132 if (!quiet_flag)
01133 fprintf (stderr, " {%s GC %luk -> ",
01134 zone->name, (unsigned long) zone->allocated / 1024);
01135
01136
01137
01138 zone->allocated = 0;
01139
01140
01141
01142 release_pages (zone);
01143
01144
01145 zone->context_depth_collections
01146 = ((unsigned long)1 << (zone->context_depth + 1)) - 1;
01147 if (need_marking)
01148 ggc_mark_roots ();
01149 sweep_pages (zone);
01150 zone->was_collected = true;
01151 zone->allocated_last_gc = zone->allocated;
01152
01153 if (!quiet_flag)
01154 fprintf (stderr, "%luk}", (unsigned long) zone->allocated / 1024);
01155 return true;
01156 }
01157
01158
01159
01160
01161 static float
01162 calculate_average_page_survival (struct alloc_zone *zone)
01163 {
01164 float count = 0.0;
01165 float survival = 0.0;
01166 page_entry *p;
01167 for (p = zone->pages; p; p = p->next)
01168 {
01169 count += 1.0;
01170 survival += p->survived;
01171 }
01172 return survival/count;
01173 }
01174
01175
01176
01177
01178
01179 static inline void
01180 check_cookies (void)
01181 {
01182 #ifdef COOKIE_CHECKING
01183 page_entry *p;
01184 struct alloc_zone *zone;
01185
01186 for (zone = G.zones; zone; zone = zone->next_zone)
01187 {
01188 for (p = zone->pages; p; p = p->next)
01189 {
01190 if (!p->large_p)
01191 {
01192 struct alloc_chunk *chunk = (struct alloc_chunk *)p->page;
01193 struct alloc_chunk *end = (struct alloc_chunk *)(p->page + G.pagesize);
01194 do
01195 {
01196 gcc_assert (chunk->magic == CHUNK_MAGIC
01197 || chunk->magic == DEADCHUNK_MAGIC);
01198 chunk = (struct alloc_chunk *)(chunk->u.data + chunk->size);
01199 }
01200 while (chunk < end);
01201 }
01202 }
01203 }
01204 #endif
01205 }
01206
01207
01208 void
01209 ggc_collect (void)
01210 {
01211 struct alloc_zone *zone;
01212 bool marked = false;
01213 float f;
01214
01215 timevar_push (TV_GC);
01216 check_cookies ();
01217
01218 if (!always_collect)
01219 {
01220 float allocated_last_gc = 0, allocated = 0, min_expand;
01221
01222 for (zone = G.zones; zone; zone = zone->next_zone)
01223 {
01224 allocated_last_gc += zone->allocated_last_gc;
01225 allocated += zone->allocated;
01226 }
01227
01228 allocated_last_gc =
01229 MAX (allocated_last_gc,
01230 (size_t) PARAM_VALUE (GGC_MIN_HEAPSIZE) * 1024);
01231 min_expand = allocated_last_gc * PARAM_VALUE (GGC_MIN_EXPAND) / 100;
01232
01233 if (allocated < allocated_last_gc + min_expand)
01234 {
01235 timevar_pop (TV_GC);
01236 return;
01237 }
01238 }
01239
01240
01241 main_zone.was_collected = false;
01242 marked |= ggc_collect_1 (&main_zone, true);
01243
01244
01245
01246
01247
01248
01249
01250
01251
01252
01253
01254
01255 if (main_zone.was_collected)
01256 {
01257 struct alloc_zone *zone;
01258
01259 for (zone = main_zone.next_zone; zone; zone = zone->next_zone)
01260 {
01261 check_cookies ();
01262 zone->was_collected = false;
01263 marked |= ggc_collect_1 (zone, !marked);
01264 }
01265 }
01266
01267
01268 if (GGC_DEBUG_LEVEL >= 2)
01269 {
01270 for (zone = G.zones; zone; zone = zone->next_zone)
01271 {
01272 if (zone->was_collected)
01273 {
01274 f = calculate_average_page_survival (zone);
01275 printf ("Average page survival in zone `%s' is %f\n",
01276 zone->name, f);
01277 }
01278 }
01279 }
01280
01281
01282
01283
01284 if (marked)
01285 {
01286 page_entry *p;
01287 for (zone = G.zones; zone; zone = zone->next_zone)
01288 {
01289 if (zone->was_collected)
01290 continue;
01291 for (p = zone->pages; p; p = p->next)
01292 {
01293 if (!p->large_p)
01294 {
01295 struct alloc_chunk *chunk = (struct alloc_chunk *)p->page;
01296 struct alloc_chunk *end = (struct alloc_chunk *)(p->page + G.pagesize);
01297 do
01298 {
01299 prefetch ((struct alloc_chunk *)(chunk->u.data + chunk->size));
01300 if (chunk->mark || p->context_depth < zone->context_depth)
01301 {
01302 chunk->mark = 0;
01303 }
01304 chunk = (struct alloc_chunk *)(chunk->u.data + chunk->size);
01305 }
01306 while (chunk < end);
01307 }
01308 else
01309 {
01310 ((struct alloc_chunk *)p->page)->mark = 0;
01311 }
01312 }
01313 }
01314 }
01315
01316
01317 for (zone = G.zones; zone && zone->next_zone; zone = zone->next_zone)
01318 {
01319 if (zone->next_zone->dead)
01320 {
01321 struct alloc_zone *dead_zone = zone->next_zone;
01322
01323 printf ("Zone `%s' is dead and will be freed.\n", dead_zone->name);
01324
01325
01326 gcc_assert (!dead_zone->allocated);
01327
01328
01329 zone->next_zone = zone->next_zone->next_zone;
01330 release_pages (dead_zone);
01331 free (dead_zone);
01332 }
01333 }
01334
01335 timevar_pop (TV_GC);
01336 }
01337
01338
01339 #define SCALE(x) ((unsigned long) ((x) < 1024*10 \
01340 ? (x) \
01341 : ((x) < 1024*1024*10 \
01342 ? (x) / 1024 \
01343 : (x) / (1024*1024))))
01344 #define LABEL(x) ((x) < 1024*10 ? ' ' : ((x) < 1024*1024*10 ? 'k' : 'M'))
01345
01346 void
01347 ggc_print_statistics (void)
01348 {
01349 struct alloc_zone *zone;
01350 struct ggc_statistics stats;
01351 size_t total_overhead = 0, total_allocated = 0, total_bytes_mapped = 0;
01352
01353
01354 memset (&stats, 0, sizeof (stats));
01355
01356
01357 always_collect = 1;
01358
01359
01360 ggc_print_common_statistics (stderr, &stats);
01361
01362 always_collect = 0;
01363
01364
01365
01366 for (zone = G.zones; zone; zone = zone->next_zone)
01367 release_pages (zone);
01368
01369
01370
01371 fprintf (stderr,
01372 "Memory still allocated at the end of the compilation process\n");
01373
01374 fprintf (stderr, "%20s %10s %10s %10s\n",
01375 "Zone", "Allocated", "Used", "Overhead");
01376 for (zone = G.zones; zone; zone = zone->next_zone)
01377 {
01378 page_entry *p;
01379 size_t allocated;
01380 size_t in_use;
01381 size_t overhead;
01382
01383
01384 if (!zone->pages)
01385 continue;
01386
01387 overhead = allocated = in_use = 0;
01388
01389
01390
01391
01392 for (p = zone->pages; p; p = p->next)
01393 {
01394 struct alloc_chunk *chunk;
01395
01396
01397
01398 allocated += p->bytes;
01399 overhead += sizeof (page_entry);
01400
01401 if (p->large_p)
01402 {
01403 in_use += p->bytes - CHUNK_OVERHEAD;
01404 chunk = (struct alloc_chunk *) p->page;
01405 overhead += CHUNK_OVERHEAD;
01406 gcc_assert (chunk->type && !chunk->mark);
01407 continue;
01408 }
01409
01410 for (chunk = (struct alloc_chunk *) p->page;
01411 (char *) chunk < (char *) p->page + p->bytes;
01412 chunk = (struct alloc_chunk *)(chunk->u.data + chunk->size))
01413 {
01414 overhead += CHUNK_OVERHEAD;
01415 if (chunk->type)
01416 in_use += chunk->size;
01417 gcc_assert (!chunk->mark);
01418 }
01419 }
01420 fprintf (stderr, "%20s %10lu%c %10lu%c %10lu%c\n",
01421 zone->name,
01422 SCALE (allocated), LABEL (allocated),
01423 SCALE (in_use), LABEL (in_use),
01424 SCALE (overhead), LABEL (overhead));
01425
01426 gcc_assert (in_use == zone->allocated);
01427
01428 total_overhead += overhead;
01429 total_allocated += zone->allocated;
01430 total_bytes_mapped += zone->bytes_mapped;
01431 }
01432
01433 fprintf (stderr, "%20s %10lu%c %10lu%c %10lu%c\n", "Total",
01434 SCALE (total_bytes_mapped), LABEL (total_bytes_mapped),
01435 SCALE (total_allocated), LABEL(total_allocated),
01436 SCALE (total_overhead), LABEL (total_overhead));
01437
01438 #ifdef GATHER_STATISTICS
01439 {
01440 unsigned long long all_overhead = 0, all_allocated = 0;
01441 unsigned long long all_overhead_under32 = 0, all_allocated_under32 = 0;
01442 unsigned long long all_overhead_under64 = 0, all_allocated_under64 = 0;
01443 unsigned long long all_overhead_under128 = 0, all_allocated_under128 = 0;
01444
01445 fprintf (stderr, "\nTotal allocations and overheads during the compilation process\n");
01446
01447 for (zone = G.zones; zone; zone = zone->next_zone)
01448 {
01449 all_overhead += zone->stats.total_overhead;
01450 all_allocated += zone->stats.total_allocated;
01451
01452 all_allocated_under32 += zone->stats.total_allocated_under32;
01453 all_overhead_under32 += zone->stats.total_overhead_under32;
01454
01455 all_allocated_under64 += zone->stats.total_allocated_under64;
01456 all_overhead_under64 += zone->stats.total_overhead_under64;
01457
01458 all_allocated_under128 += zone->stats.total_allocated_under128;
01459 all_overhead_under128 += zone->stats.total_overhead_under128;
01460
01461 fprintf (stderr, "%20s: %10lld\n",
01462 zone->name, zone->stats.total_allocated);
01463 }
01464
01465 fprintf (stderr, "\n");
01466
01467 fprintf (stderr, "Total Overhead: %10lld\n",
01468 all_overhead);
01469 fprintf (stderr, "Total Allocated: %10lld\n",
01470 all_allocated);
01471
01472 fprintf (stderr, "Total Overhead under 32B: %10lld\n",
01473 all_overhead_under32);
01474 fprintf (stderr, "Total Allocated under 32B: %10lld\n",
01475 all_allocated_under32);
01476 fprintf (stderr, "Total Overhead under 64B: %10lld\n",
01477 all_overhead_under64);
01478 fprintf (stderr, "Total Allocated under 64B: %10lld\n",
01479 all_allocated_under64);
01480 fprintf (stderr, "Total Overhead under 128B: %10lld\n",
01481 all_overhead_under128);
01482 fprintf (stderr, "Total Allocated under 128B: %10lld\n",
01483 all_allocated_under128);
01484 }
01485 #endif
01486 }
01487
01488 struct ggc_pch_data
01489 {
01490 struct ggc_pch_ondisk
01491 {
01492 unsigned total;
01493 } d;
01494 size_t base;
01495 size_t written;
01496 };
01497
01498
01499
01500 struct ggc_pch_data *
01501 init_ggc_pch (void)
01502 {
01503 return xcalloc (sizeof (struct ggc_pch_data), 1);
01504 }
01505
01506
01507
01508 void
01509 ggc_pch_count_object (struct ggc_pch_data *d, void *x ATTRIBUTE_UNUSED,
01510 size_t size, bool is_string)
01511 {
01512 if (!is_string)
01513 {
01514 d->d.total += size + CHUNK_OVERHEAD;
01515 }
01516 else
01517 d->d.total += size;
01518 }
01519
01520
01521
01522 size_t
01523 ggc_pch_total_size (struct ggc_pch_data *d)
01524 {
01525 return d->d.total;
01526 }
01527
01528
01529
01530 void
01531 ggc_pch_this_base (struct ggc_pch_data *d, void *base)
01532 {
01533 d->base = (size_t) base;
01534 }
01535
01536
01537
01538 char *
01539 ggc_pch_alloc_object (struct ggc_pch_data *d, void *x,
01540 size_t size, bool is_string)
01541 {
01542 char *result;
01543 result = (char *)d->base;
01544 if (!is_string)
01545 {
01546 struct alloc_chunk *chunk = (struct alloc_chunk *) ((char *)x - CHUNK_OVERHEAD);
01547 if (chunk->large)
01548 d->base += ggc_get_size (x) + CHUNK_OVERHEAD;
01549 else
01550 d->base += chunk->size + CHUNK_OVERHEAD;
01551 return result + CHUNK_OVERHEAD;
01552 }
01553 else
01554 {
01555 d->base += size;
01556 return result;
01557 }
01558
01559 }
01560
01561
01562
01563 void
01564 ggc_pch_prepare_write (struct ggc_pch_data *d ATTRIBUTE_UNUSED,
01565 FILE *f ATTRIBUTE_UNUSED)
01566 {
01567
01568 }
01569
01570
01571
01572 void
01573 ggc_pch_write_object (struct ggc_pch_data *d ATTRIBUTE_UNUSED,
01574 FILE *f, void *x, void *newx ATTRIBUTE_UNUSED,
01575 size_t size, bool is_string)
01576 {
01577 if (!is_string)
01578 {
01579 struct alloc_chunk *chunk = (struct alloc_chunk *) ((char *)x - CHUNK_OVERHEAD);
01580 size = ggc_get_size (x);
01581 if (fwrite (chunk, size + CHUNK_OVERHEAD, 1, f) != 1)
01582 fatal_error ("can't write PCH file: %m");
01583 d->written += size + CHUNK_OVERHEAD;
01584 }
01585 else
01586 {
01587 if (fwrite (x, size, 1, f) != 1)
01588 fatal_error ("can't write PCH file: %m");
01589 d->written += size;
01590 }
01591 }
01592
01593 void
01594 ggc_pch_finish (struct ggc_pch_data *d, FILE *f)
01595 {
01596 if (fwrite (&d->d, sizeof (d->d), 1, f) != 1)
01597 fatal_error ("can't write PCH file: %m");
01598 free (d);
01599 }
01600 void
01601 ggc_pch_read (FILE *f, void *addr)
01602 {
01603 struct ggc_pch_ondisk d;
01604 struct page_entry *entry;
01605 struct alloc_zone *pch_zone;
01606 if (fread (&d, sizeof (d), 1, f) != 1)
01607 fatal_error ("can't read PCH file: %m");
01608 entry = xcalloc (1, sizeof (struct page_entry));
01609 entry->bytes = d.total;
01610 entry->page = addr;
01611 entry->context_depth = 0;
01612 pch_zone = new_ggc_zone ("PCH zone");
01613 entry->zone = pch_zone;
01614 entry->next = entry->zone->pages;
01615 entry->zone->pages = entry;
01616 }