00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "config.h"
00022 #include "system.h"
00023 #include "tree.h"
00024 #include "rtl.h"
00025 #include "tm_p.h"
00026 #include "toplev.h"
00027 #include "flags.h"
00028 #include "ggc.h"
00029 #include "timevar.h"
00030 #include "params.h"
00031 #ifdef ENABLE_VALGRIND_CHECKING
00032 #include <valgrind.h>
00033 #else
00034
00035 #define VALGRIND_DISCARD(x)
00036 #endif
00037
00038
00039
00040 #ifdef HAVE_MMAP_ANON
00041 # undef HAVE_MMAP_DEV_ZERO
00042
00043 # include <sys/mman.h>
00044 # ifndef MAP_FAILED
00045 # define MAP_FAILED -1
00046 # endif
00047 # if !defined (MAP_ANONYMOUS) && defined (MAP_ANON)
00048 # define MAP_ANONYMOUS MAP_ANON
00049 # endif
00050 # define USING_MMAP
00051
00052 #endif
00053
00054 #ifdef HAVE_MMAP_DEV_ZERO
00055
00056 # include <sys/mman.h>
00057 # ifndef MAP_FAILED
00058 # define MAP_FAILED -1
00059 # endif
00060 # define USING_MMAP
00061
00062 #endif
00063
00064 #ifndef USING_MMAP
00065 #define USING_MALLOC_PAGE_GROUPS
00066 #endif
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103 #define GGC_DEBUG_LEVEL (0)
00104
00105 #ifndef HOST_BITS_PER_PTR
00106 #define HOST_BITS_PER_PTR HOST_BITS_PER_LONG
00107 #endif
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132 #define PAGE_L1_BITS (8)
00133 #define PAGE_L2_BITS (32 - PAGE_L1_BITS - G.lg_pagesize)
00134 #define PAGE_L1_SIZE ((size_t) 1 << PAGE_L1_BITS)
00135 #define PAGE_L2_SIZE ((size_t) 1 << PAGE_L2_BITS)
00136
00137 #define LOOKUP_L1(p) \
00138 (((size_t) (p) >> (32 - PAGE_L1_BITS)) & ((1 << PAGE_L1_BITS) - 1))
00139
00140 #define LOOKUP_L2(p) \
00141 (((size_t) (p) >> G.lg_pagesize) & ((1 << PAGE_L2_BITS) - 1))
00142
00143
00144
00145 #define OBJECTS_PER_PAGE(ORDER) objects_per_page_table[ORDER]
00146
00147
00148 #define OBJECT_SIZE(ORDER) object_size_table[ORDER]
00149
00150
00151
00152
00153
00154 #define DIV_MULT(ORDER) inverse_table[ORDER].mult
00155 #define DIV_SHIFT(ORDER) inverse_table[ORDER].shift
00156 #define OFFSET_TO_BIT(OFFSET, ORDER) \
00157 (((OFFSET) * DIV_MULT (ORDER)) >> DIV_SHIFT (ORDER))
00158
00159
00160
00161
00162 #define NUM_EXTRA_ORDERS ARRAY_SIZE (extra_order_size_table)
00163
00164 #define RTL_SIZE(NSLOTS) \
00165 (sizeof (struct rtx_def) + ((NSLOTS) - 1) * sizeof (rtunion))
00166
00167
00168
00169
00170
00171 static const size_t extra_order_size_table[] = {
00172 sizeof (struct tree_decl),
00173 sizeof (struct tree_list),
00174 RTL_SIZE (2),
00175 RTL_SIZE (10),
00176 };
00177
00178
00179
00180 #define NUM_ORDERS (HOST_BITS_PER_PTR + NUM_EXTRA_ORDERS)
00181
00182
00183
00184
00185
00186 struct max_alignment {
00187 char c;
00188 union {
00189 HOST_WIDEST_INT i;
00190 #ifdef HAVE_LONG_DOUBLE
00191 long double d;
00192 #else
00193 double d;
00194 #endif
00195 } u;
00196 };
00197
00198
00199
00200 #define MAX_ALIGNMENT (offsetof (struct max_alignment, u))
00201
00202
00203
00204 static unsigned objects_per_page_table[NUM_ORDERS];
00205
00206
00207
00208 static size_t object_size_table[NUM_ORDERS];
00209
00210
00211
00212
00213
00214 static struct
00215 {
00216 unsigned int mult;
00217 unsigned int shift;
00218 }
00219 inverse_table[NUM_ORDERS];
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 char *page;
00235
00236 #ifdef USING_MALLOC_PAGE_GROUPS
00237
00238 struct page_group *group;
00239 #endif
00240
00241
00242
00243 unsigned long index_by_depth;
00244
00245
00246 unsigned short context_depth;
00247
00248
00249 unsigned short num_free_objects;
00250
00251
00252
00253 unsigned short next_bit_hint;
00254
00255
00256 unsigned char order;
00257
00258
00259
00260
00261 unsigned long in_use_p[1];
00262 } page_entry;
00263
00264 #ifdef USING_MALLOC_PAGE_GROUPS
00265
00266
00267 typedef struct page_group
00268 {
00269
00270 struct page_group *next;
00271
00272
00273 char *allocation;
00274
00275
00276 size_t alloc_size;
00277
00278
00279 unsigned int in_use;
00280 } page_group;
00281 #endif
00282
00283 #if HOST_BITS_PER_PTR <= 32
00284
00285
00286 typedef page_entry **page_table[PAGE_L1_SIZE];
00287
00288 #else
00289
00290
00291
00292
00293 typedef struct page_table_chain
00294 {
00295 struct page_table_chain *next;
00296 size_t high_bits;
00297 page_entry **table[PAGE_L1_SIZE];
00298 } *page_table;
00299
00300 #endif
00301
00302
00303 static struct globals
00304 {
00305
00306
00307
00308
00309 page_entry *pages[NUM_ORDERS];
00310
00311
00312
00313
00314 page_entry *page_tails[NUM_ORDERS];
00315
00316
00317 page_table lookup;
00318
00319
00320 size_t pagesize;
00321 size_t lg_pagesize;
00322
00323
00324 size_t allocated;
00325
00326
00327 size_t allocated_last_gc;
00328
00329
00330 size_t bytes_mapped;
00331
00332
00333 unsigned long context_depth_allocations;
00334
00335
00336 unsigned long context_depth_collections;
00337
00338
00339 unsigned short context_depth;
00340
00341
00342 #if defined (HAVE_MMAP_DEV_ZERO)
00343 int dev_zero_fd;
00344 #endif
00345
00346
00347 page_entry *free_pages;
00348
00349 #ifdef USING_MALLOC_PAGE_GROUPS
00350 page_group *page_groups;
00351 #endif
00352
00353
00354 FILE *debug_file;
00355
00356
00357 unsigned int depth_in_use;
00358
00359
00360 unsigned int depth_max;
00361
00362
00363
00364
00365 unsigned int *depth;
00366
00367
00368 unsigned int by_depth_in_use;
00369
00370
00371 unsigned int by_depth_max;
00372
00373
00374
00375
00376
00377
00378 page_entry **by_depth;
00379
00380
00381
00382
00383 unsigned long **save_in_use;
00384
00385 } G;
00386
00387
00388
00389 #define BITMAP_SIZE(Num_objects) \
00390 (CEIL ((Num_objects), HOST_BITS_PER_LONG) * sizeof(long))
00391
00392
00393
00394
00395
00396 #define GGC_QUIRE_SIZE 16
00397
00398
00399 #define INITIAL_PTE_COUNT 128
00400
00401 static int ggc_allocated_p PARAMS ((const void *));
00402 static page_entry *lookup_page_table_entry PARAMS ((const void *));
00403 static void set_page_table_entry PARAMS ((void *, page_entry *));
00404 #ifdef USING_MMAP
00405 static char *alloc_anon PARAMS ((char *, size_t));
00406 #endif
00407 #ifdef USING_MALLOC_PAGE_GROUPS
00408 static size_t page_group_index PARAMS ((char *, char *));
00409 static void set_page_group_in_use PARAMS ((page_group *, char *));
00410 static void clear_page_group_in_use PARAMS ((page_group *, char *));
00411 #endif
00412 static struct page_entry * alloc_page PARAMS ((unsigned));
00413 static void free_page PARAMS ((struct page_entry *));
00414 static void release_pages PARAMS ((void));
00415 static void clear_marks PARAMS ((void));
00416 static void sweep_pages PARAMS ((void));
00417 static void ggc_recalculate_in_use_p PARAMS ((page_entry *));
00418 static void compute_inverse PARAMS ((unsigned));
00419 static inline void adjust_depth PARAMS ((void));
00420
00421 #ifdef ENABLE_GC_CHECKING
00422 static void poison_pages PARAMS ((void));
00423 #endif
00424
00425 void debug_print_page_list PARAMS ((int));
00426 static void push_depth PARAMS ((unsigned int));
00427 static void push_by_depth PARAMS ((page_entry *, unsigned long *));
00428
00429
00430
00431 inline static void
00432 push_depth (i)
00433 unsigned int i;
00434 {
00435 if (G.depth_in_use >= G.depth_max)
00436 {
00437 G.depth_max *= 2;
00438 G.depth = (unsigned int *) xrealloc ((char *) G.depth,
00439 G.depth_max * sizeof (unsigned int));
00440 }
00441 G.depth[G.depth_in_use++] = i;
00442 }
00443
00444
00445
00446 inline static void
00447 push_by_depth (p, s)
00448 page_entry *p;
00449 unsigned long *s;
00450 {
00451 if (G.by_depth_in_use >= G.by_depth_max)
00452 {
00453 G.by_depth_max *= 2;
00454 G.by_depth = (page_entry **) xrealloc ((char *) G.by_depth,
00455 G.by_depth_max * sizeof (page_entry *));
00456 G.save_in_use = (unsigned long **) xrealloc ((char *) G.save_in_use,
00457 G.by_depth_max * sizeof (unsigned long *));
00458 }
00459 G.by_depth[G.by_depth_in_use] = p;
00460 G.save_in_use[G.by_depth_in_use++] = s;
00461 }
00462
00463
00464 #define prefetch(X) ((void) X)
00465
00466 #define save_in_use_p_i(__i) \
00467 (G.save_in_use[__i])
00468 #define save_in_use_p(__p) \
00469 (save_in_use_p_i (__p->index_by_depth))
00470
00471
00472
00473 static inline int
00474 ggc_allocated_p (p)
00475 const void *p;
00476 {
00477 page_entry ***base;
00478 size_t L1, L2;
00479
00480 #if HOST_BITS_PER_PTR <= 32
00481 base = &G.lookup[0];
00482 #else
00483 page_table table = G.lookup;
00484 size_t high_bits = (size_t) p & ~ (size_t) 0xffffffff;
00485 while (1)
00486 {
00487 if (table == NULL)
00488 return 0;
00489 if (table->high_bits == high_bits)
00490 break;
00491 table = table->next;
00492 }
00493 base = &table->table[0];
00494 #endif
00495
00496
00497 L1 = LOOKUP_L1 (p);
00498 L2 = LOOKUP_L2 (p);
00499
00500 return base[L1] && base[L1][L2];
00501 }
00502
00503
00504
00505
00506 static inline page_entry *
00507 lookup_page_table_entry(p)
00508 const void *p;
00509 {
00510 page_entry ***base;
00511 size_t L1, L2;
00512
00513 #if HOST_BITS_PER_PTR <= 32
00514 base = &G.lookup[0];
00515 #else
00516 page_table table = G.lookup;
00517 size_t high_bits = (size_t) p & ~ (size_t) 0xffffffff;
00518 while (table->high_bits != high_bits)
00519 table = table->next;
00520 base = &table->table[0];
00521 #endif
00522
00523
00524 L1 = LOOKUP_L1 (p);
00525 L2 = LOOKUP_L2 (p);
00526
00527 return base[L1][L2];
00528 }
00529
00530
00531
00532 static void
00533 set_page_table_entry(p, entry)
00534 void *p;
00535 page_entry *entry;
00536 {
00537 page_entry ***base;
00538 size_t L1, L2;
00539
00540 #if HOST_BITS_PER_PTR <= 32
00541 base = &G.lookup[0];
00542 #else
00543 page_table table;
00544 size_t high_bits = (size_t) p & ~ (size_t) 0xffffffff;
00545 for (table = G.lookup; table; table = table->next)
00546 if (table->high_bits == high_bits)
00547 goto found;
00548
00549
00550 table = (page_table) xcalloc (1, sizeof(*table));
00551 table->next = G.lookup;
00552 table->high_bits = high_bits;
00553 G.lookup = table;
00554 found:
00555 base = &table->table[0];
00556 #endif
00557
00558
00559 L1 = LOOKUP_L1 (p);
00560 L2 = LOOKUP_L2 (p);
00561
00562 if (base[L1] == NULL)
00563 base[L1] = (page_entry **) xcalloc (PAGE_L2_SIZE, sizeof (page_entry *));
00564
00565 base[L1][L2] = entry;
00566 }
00567
00568
00569
00570 void
00571 debug_print_page_list (order)
00572 int order;
00573 {
00574 page_entry *p;
00575 printf ("Head=%p, Tail=%p:\n", (PTR) G.pages[order],
00576 (PTR) G.page_tails[order]);
00577 p = G.pages[order];
00578 while (p != NULL)
00579 {
00580 printf ("%p(%1d|%3d) -> ", (PTR) p, p->context_depth,
00581 p->num_free_objects);
00582 p = p->next;
00583 }
00584 printf ("NULL\n");
00585 fflush (stdout);
00586 }
00587
00588 #ifdef USING_MMAP
00589
00590
00591
00592
00593 static inline char *
00594 alloc_anon (pref, size)
00595 char *pref ATTRIBUTE_UNUSED;
00596 size_t size;
00597 {
00598 #ifdef HAVE_MMAP_ANON
00599 char *page = (char *) mmap (pref, size, PROT_READ | PROT_WRITE,
00600 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
00601 #endif
00602 #ifdef HAVE_MMAP_DEV_ZERO
00603 char *page = (char *) mmap (pref, size, PROT_READ | PROT_WRITE,
00604 MAP_PRIVATE, G.dev_zero_fd, 0);
00605 #endif
00606
00607 if (page == (char *) MAP_FAILED)
00608 {
00609 perror ("virtual memory exhausted");
00610 exit (FATAL_EXIT_CODE);
00611 }
00612
00613
00614 G.bytes_mapped += size;
00615
00616
00617
00618
00619 VALGRIND_DISCARD (VALGRIND_MAKE_NOACCESS (page, size));
00620
00621 return page;
00622 }
00623 #endif
00624 #ifdef USING_MALLOC_PAGE_GROUPS
00625
00626
00627 static inline size_t
00628 page_group_index (allocation, page)
00629 char *allocation, *page;
00630 {
00631 return (size_t) (page - allocation) >> G.lg_pagesize;
00632 }
00633
00634
00635
00636 static inline void
00637 set_page_group_in_use (group, page)
00638 page_group *group;
00639 char *page;
00640 {
00641 group->in_use |= 1 << page_group_index (group->allocation, page);
00642 }
00643
00644 static inline void
00645 clear_page_group_in_use (group, page)
00646 page_group *group;
00647 char *page;
00648 {
00649 group->in_use &= ~(1 << page_group_index (group->allocation, page));
00650 }
00651 #endif
00652
00653
00654
00655
00656
00657 static inline struct page_entry *
00658 alloc_page (order)
00659 unsigned order;
00660 {
00661 struct page_entry *entry, *p, **pp;
00662 char *page;
00663 size_t num_objects;
00664 size_t bitmap_size;
00665 size_t page_entry_size;
00666 size_t entry_size;
00667 #ifdef USING_MALLOC_PAGE_GROUPS
00668 page_group *group;
00669 #endif
00670
00671 num_objects = OBJECTS_PER_PAGE (order);
00672 bitmap_size = BITMAP_SIZE (num_objects + 1);
00673 page_entry_size = sizeof (page_entry) - sizeof (long) + bitmap_size;
00674 entry_size = num_objects * OBJECT_SIZE (order);
00675 if (entry_size < G.pagesize)
00676 entry_size = G.pagesize;
00677
00678 entry = NULL;
00679 page = NULL;
00680
00681
00682 for (pp = &G.free_pages, p = *pp; p; pp = &p->next, p = *pp)
00683 if (p->bytes == entry_size)
00684 break;
00685
00686 if (p != NULL)
00687 {
00688
00689 *pp = p->next;
00690 page = p->page;
00691
00692 #ifdef USING_MALLOC_PAGE_GROUPS
00693 group = p->group;
00694 #endif
00695
00696
00697 if (p->order == order)
00698 {
00699 entry = p;
00700 memset (entry, 0, page_entry_size);
00701 }
00702 else
00703 free (p);
00704 }
00705 #ifdef USING_MMAP
00706 else if (entry_size == G.pagesize)
00707 {
00708
00709
00710
00711 struct page_entry *e, *f = G.free_pages;
00712 int i;
00713
00714 page = alloc_anon (NULL, G.pagesize * GGC_QUIRE_SIZE);
00715
00716
00717
00718 for (i = GGC_QUIRE_SIZE - 1; i >= 1; i--)
00719 {
00720 e = (struct page_entry *) xcalloc (1, page_entry_size);
00721 e->order = order;
00722 e->bytes = G.pagesize;
00723 e->page = page + (i << G.lg_pagesize);
00724 e->next = f;
00725 f = e;
00726 }
00727
00728 G.free_pages = f;
00729 }
00730 else
00731 page = alloc_anon (NULL, entry_size);
00732 #endif
00733 #ifdef USING_MALLOC_PAGE_GROUPS
00734 else
00735 {
00736
00737
00738
00739
00740 char *allocation, *a, *enda;
00741 size_t alloc_size, head_slop, tail_slop;
00742 int multiple_pages = (entry_size == G.pagesize);
00743
00744 if (multiple_pages)
00745 alloc_size = GGC_QUIRE_SIZE * G.pagesize;
00746 else
00747 alloc_size = entry_size + G.pagesize - 1;
00748 allocation = xmalloc (alloc_size);
00749
00750 page = (char *) (((size_t) allocation + G.pagesize - 1) & -G.pagesize);
00751 head_slop = page - allocation;
00752 if (multiple_pages)
00753 tail_slop = ((size_t) allocation + alloc_size) & (G.pagesize - 1);
00754 else
00755 tail_slop = alloc_size - entry_size - head_slop;
00756 enda = allocation + alloc_size - tail_slop;
00757
00758
00759
00760
00761 if (head_slop >= sizeof (page_group))
00762 group = (page_group *)page - 1;
00763 else
00764 {
00765
00766
00767 if (tail_slop == 0)
00768 {
00769 enda -= G.pagesize;
00770 tail_slop += G.pagesize;
00771 }
00772 if (tail_slop < sizeof (page_group))
00773 abort ();
00774 group = (page_group *)enda;
00775 tail_slop -= sizeof (page_group);
00776 }
00777
00778
00779 group->next = G.page_groups;
00780 group->allocation = allocation;
00781 group->alloc_size = alloc_size;
00782 group->in_use = 0;
00783 G.page_groups = group;
00784 G.bytes_mapped += alloc_size;
00785
00786
00787 if (multiple_pages)
00788 {
00789 struct page_entry *e, *f = G.free_pages;
00790 for (a = enda - G.pagesize; a != page; a -= G.pagesize)
00791 {
00792 e = (struct page_entry *) xcalloc (1, page_entry_size);
00793 e->order = order;
00794 e->bytes = G.pagesize;
00795 e->page = a;
00796 e->group = group;
00797 e->next = f;
00798 f = e;
00799 }
00800 G.free_pages = f;
00801 }
00802 }
00803 #endif
00804
00805 if (entry == NULL)
00806 entry = (struct page_entry *) xcalloc (1, page_entry_size);
00807
00808 entry->bytes = entry_size;
00809 entry->page = page;
00810 entry->context_depth = G.context_depth;
00811 entry->order = order;
00812 entry->num_free_objects = num_objects;
00813 entry->next_bit_hint = 1;
00814
00815 G.context_depth_allocations |= (unsigned long)1 << G.context_depth;
00816
00817 #ifdef USING_MALLOC_PAGE_GROUPS
00818 entry->group = group;
00819 set_page_group_in_use (group, page);
00820 #endif
00821
00822
00823
00824 entry->in_use_p[num_objects / HOST_BITS_PER_LONG]
00825 = (unsigned long) 1 << (num_objects % HOST_BITS_PER_LONG);
00826
00827 set_page_table_entry (page, entry);
00828
00829 if (GGC_DEBUG_LEVEL >= 2)
00830 fprintf (G.debug_file,
00831 "Allocating page at %p, object size=%lu, data %p-%p\n",
00832 (PTR) entry, (unsigned long) OBJECT_SIZE (order), page,
00833 page + entry_size - 1);
00834
00835 return entry;
00836 }
00837
00838
00839
00840
00841 static inline void
00842 adjust_depth ()
00843 {
00844 page_entry *top;
00845
00846 if (G.by_depth_in_use)
00847 {
00848 top = G.by_depth[G.by_depth_in_use-1];
00849
00850
00851
00852
00853 while (G.depth_in_use > (size_t)top->context_depth+1)
00854 --G.depth_in_use;
00855 }
00856 }
00857
00858
00859
00860 static inline void
00861 free_page (entry)
00862 page_entry *entry;
00863 {
00864 if (GGC_DEBUG_LEVEL >= 2)
00865 fprintf (G.debug_file,
00866 "Deallocating page at %p, data %p-%p\n", (PTR) entry,
00867 entry->page, entry->page + entry->bytes - 1);
00868
00869
00870
00871 VALGRIND_DISCARD (VALGRIND_MAKE_NOACCESS (entry->page, entry->bytes));
00872
00873 set_page_table_entry (entry->page, NULL);
00874
00875 #ifdef USING_MALLOC_PAGE_GROUPS
00876 clear_page_group_in_use (entry->group, entry->page);
00877 #endif
00878
00879 if (G.by_depth_in_use > 1)
00880 {
00881 page_entry *top = G.by_depth[G.by_depth_in_use-1];
00882
00883
00884
00885 if (entry->context_depth == top->context_depth)
00886 {
00887 int i = entry->index_by_depth;
00888 G.by_depth[i] = top;
00889 G.save_in_use[i] = G.save_in_use[G.by_depth_in_use-1];
00890 top->index_by_depth = i;
00891 }
00892 else
00893 {
00894
00895
00896 abort ();
00897 }
00898 }
00899 --G.by_depth_in_use;
00900
00901 adjust_depth ();
00902
00903 entry->next = G.free_pages;
00904 G.free_pages = entry;
00905 }
00906
00907
00908
00909 static void
00910 release_pages ()
00911 {
00912 #ifdef USING_MMAP
00913 page_entry *p, *next;
00914 char *start;
00915 size_t len;
00916
00917
00918 p = G.free_pages;
00919
00920 while (p)
00921 {
00922 start = p->page;
00923 next = p->next;
00924 len = p->bytes;
00925 free (p);
00926 p = next;
00927
00928 while (p && p->page == start + len)
00929 {
00930 next = p->next;
00931 len += p->bytes;
00932 free (p);
00933 p = next;
00934 }
00935
00936 munmap (start, len);
00937 G.bytes_mapped -= len;
00938 }
00939
00940 G.free_pages = NULL;
00941 #endif
00942 #ifdef USING_MALLOC_PAGE_GROUPS
00943 page_entry **pp, *p;
00944 page_group **gp, *g;
00945
00946
00947 pp = &G.free_pages;
00948 while ((p = *pp) != NULL)
00949 if (p->group->in_use == 0)
00950 {
00951 *pp = p->next;
00952 free (p);
00953 }
00954 else
00955 pp = &p->next;
00956
00957
00958 gp = &G.page_groups;
00959 while ((g = *gp) != NULL)
00960 if (g->in_use == 0)
00961 {
00962 *gp = g->next;
00963 G.bytes_mapped -= g->alloc_size;
00964 free (g->allocation);
00965 }
00966 else
00967 gp = &g->next;
00968 #endif
00969 }
00970
00971
00972
00973
00974
00975
00976
00977
00978
00979 static unsigned char size_lookup[289] =
00980 {
00981 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4,
00982 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
00983 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
00984 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
00985 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
00986 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
00987 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
00988 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
00989 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
00990 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
00991 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
00992 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
00993 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
00994 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
00995 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
00996 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
00997 8,
00998 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
00999 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8
01000 };
01001
01002
01003
01004
01005 void *
01006 ggc_alloc (size)
01007 size_t size;
01008 {
01009 unsigned order, word, bit, object_offset;
01010 struct page_entry *entry;
01011 void *result;
01012
01013 if (size <= 256)
01014 order = size_lookup[size];
01015 else
01016 {
01017 order = 9;
01018 while (size > OBJECT_SIZE (order))
01019 order++;
01020 }
01021
01022
01023
01024 entry = G.pages[order];
01025
01026
01027
01028 if (entry == NULL || entry->num_free_objects == 0)
01029 {
01030 struct page_entry *new_entry;
01031 new_entry = alloc_page (order);
01032
01033 new_entry->index_by_depth = G.by_depth_in_use;
01034 push_by_depth (new_entry, 0);
01035
01036
01037
01038 while (new_entry->context_depth >= G.depth_in_use)
01039 push_depth (G.by_depth_in_use-1);
01040
01041
01042 if (entry == NULL)
01043 G.page_tails[order] = new_entry;
01044
01045
01046 new_entry->next = entry;
01047 entry = new_entry;
01048 G.pages[order] = new_entry;
01049
01050
01051
01052 new_entry->next_bit_hint = 1;
01053 word = 0;
01054 bit = 0;
01055 object_offset = 0;
01056 }
01057 else
01058 {
01059
01060
01061
01062
01063 unsigned hint = entry->next_bit_hint;
01064 word = hint / HOST_BITS_PER_LONG;
01065 bit = hint % HOST_BITS_PER_LONG;
01066
01067
01068 if ((entry->in_use_p[word] >> bit) & 1)
01069 {
01070 word = bit = 0;
01071 while (~entry->in_use_p[word] == 0)
01072 ++word;
01073 while ((entry->in_use_p[word] >> bit) & 1)
01074 ++bit;
01075 hint = word * HOST_BITS_PER_LONG + bit;
01076 }
01077
01078
01079 entry->next_bit_hint = hint + 1;
01080
01081 object_offset = hint * OBJECT_SIZE (order);
01082 }
01083
01084
01085 entry->in_use_p[word] |= ((unsigned long) 1 << bit);
01086
01087
01088
01089
01090
01091 if (--entry->num_free_objects == 0
01092 && entry->next != NULL
01093 && entry->next->num_free_objects > 0)
01094 {
01095 G.pages[order] = entry->next;
01096 entry->next = NULL;
01097 G.page_tails[order]->next = entry;
01098 G.page_tails[order] = entry;
01099 }
01100
01101
01102 result = entry->page + object_offset;
01103
01104 #ifdef ENABLE_GC_CHECKING
01105
01106
01107
01108
01109 VALGRIND_DISCARD (VALGRIND_MAKE_WRITABLE (result, OBJECT_SIZE (order)));
01110
01111
01112
01113 memset (result, 0xaf, OBJECT_SIZE (order));
01114
01115
01116
01117 VALGRIND_DISCARD (VALGRIND_MAKE_NOACCESS ((char *) result + size,
01118 OBJECT_SIZE (order) - size));
01119 #endif
01120
01121
01122
01123
01124 VALGRIND_DISCARD (VALGRIND_MAKE_WRITABLE (result, size));
01125
01126
01127
01128 G.allocated += OBJECT_SIZE (order);
01129
01130 if (GGC_DEBUG_LEVEL >= 3)
01131 fprintf (G.debug_file,
01132 "Allocating object, requested size=%lu, actual=%lu at %p on %p\n",
01133 (unsigned long) size, (unsigned long) OBJECT_SIZE (order), result,
01134 (PTR) entry);
01135
01136 return result;
01137 }
01138
01139
01140
01141
01142
01143 int
01144 ggc_set_mark (p)
01145 const void *p;
01146 {
01147 page_entry *entry;
01148 unsigned bit, word;
01149 unsigned long mask;
01150
01151
01152
01153 entry = lookup_page_table_entry (p);
01154 #ifdef ENABLE_CHECKING
01155 if (entry == NULL)
01156 abort ();
01157 #endif
01158
01159
01160
01161 bit = OFFSET_TO_BIT (((const char *) p) - entry->page, entry->order);
01162 word = bit / HOST_BITS_PER_LONG;
01163 mask = (unsigned long) 1 << (bit % HOST_BITS_PER_LONG);
01164
01165
01166 if (entry->in_use_p[word] & mask)
01167 return 1;
01168
01169
01170 entry->in_use_p[word] |= mask;
01171 entry->num_free_objects -= 1;
01172
01173 if (GGC_DEBUG_LEVEL >= 4)
01174 fprintf (G.debug_file, "Marking %p\n", p);
01175
01176 return 0;
01177 }
01178
01179
01180
01181
01182
01183 int
01184 ggc_marked_p (p)
01185 const void *p;
01186 {
01187 page_entry *entry;
01188 unsigned bit, word;
01189 unsigned long mask;
01190
01191
01192
01193 entry = lookup_page_table_entry (p);
01194 #ifdef ENABLE_CHECKING
01195 if (entry == NULL)
01196 abort ();
01197 #endif
01198
01199
01200
01201 bit = OFFSET_TO_BIT (((const char *) p) - entry->page, entry->order);
01202 word = bit / HOST_BITS_PER_LONG;
01203 mask = (unsigned long) 1 << (bit % HOST_BITS_PER_LONG);
01204
01205 return (entry->in_use_p[word] & mask) != 0;
01206 }
01207
01208
01209
01210 size_t
01211 ggc_get_size (p)
01212 const void *p;
01213 {
01214 page_entry *pe = lookup_page_table_entry (p);
01215 return OBJECT_SIZE (pe->order);
01216 }
01217
01218
01219
01220
01221
01222
01223
01224
01225
01226 static void
01227 compute_inverse (order)
01228 unsigned order;
01229 {
01230 unsigned size, inv, e;
01231
01232
01233
01234 if (OBJECT_SIZE (order) > G.pagesize/2)
01235 {
01236 if (OBJECTS_PER_PAGE (order) != 1)
01237 abort ();
01238
01239 DIV_MULT (order) = 1;
01240 DIV_SHIFT (order) = 0;
01241 return;
01242 }
01243
01244 size = OBJECT_SIZE (order);
01245 e = 0;
01246 while (size % 2 == 0)
01247 {
01248 e++;
01249 size >>= 1;
01250 }
01251
01252 inv = size;
01253 while (inv * size != 1)
01254 inv = inv * (2 - inv*size);
01255
01256 DIV_MULT (order) = inv;
01257 DIV_SHIFT (order) = e;
01258 }
01259
01260
01261 void
01262 init_ggc ()
01263 {
01264 unsigned order;
01265
01266 G.pagesize = getpagesize();
01267 G.lg_pagesize = exact_log2 (G.pagesize);
01268
01269 #ifdef HAVE_MMAP_DEV_ZERO
01270 G.dev_zero_fd = open ("/dev/zero", O_RDONLY);
01271 if (G.dev_zero_fd == -1)
01272 fatal_io_error ("open /dev/zero");
01273 #endif
01274
01275 #if 0
01276 G.debug_file = fopen ("ggc-mmap.debug", "w");
01277 #else
01278 G.debug_file = stdout;
01279 #endif
01280
01281 #ifdef USING_MMAP
01282
01283
01284
01285
01286 {
01287 char *p = alloc_anon (NULL, G.pagesize);
01288 struct page_entry *e;
01289 if ((size_t)p & (G.pagesize - 1))
01290 {
01291
01292
01293
01294 p = alloc_anon (NULL, G.pagesize);
01295 if ((size_t)p & (G.pagesize - 1))
01296 abort ();
01297 }
01298
01299
01300 e = (struct page_entry *) xcalloc (1, sizeof (struct page_entry));
01301 e->bytes = G.pagesize;
01302 e->page = p;
01303 e->next = G.free_pages;
01304 G.free_pages = e;
01305 }
01306 #endif
01307
01308
01309 for (order = 0; order < HOST_BITS_PER_PTR; ++order)
01310 object_size_table[order] = (size_t) 1 << order;
01311 for (order = HOST_BITS_PER_PTR; order < NUM_ORDERS; ++order)
01312 {
01313 size_t s = extra_order_size_table[order - HOST_BITS_PER_PTR];
01314
01315
01316
01317 s = CEIL (s, MAX_ALIGNMENT) * MAX_ALIGNMENT;
01318 object_size_table[order] = s;
01319 }
01320
01321
01322 for (order = 0; order < NUM_ORDERS; ++order)
01323 {
01324 objects_per_page_table[order] = G.pagesize / OBJECT_SIZE (order);
01325 if (objects_per_page_table[order] == 0)
01326 objects_per_page_table[order] = 1;
01327 compute_inverse (order);
01328 }
01329
01330
01331
01332
01333
01334 for (order = HOST_BITS_PER_PTR; order < NUM_ORDERS; ++order)
01335 {
01336 int o;
01337 int i;
01338
01339 o = size_lookup[OBJECT_SIZE (order)];
01340 for (i = OBJECT_SIZE (order); size_lookup [i] == o; --i)
01341 size_lookup[i] = order;
01342 }
01343
01344 G.depth_in_use = 0;
01345 G.depth_max = 10;
01346 G.depth = (unsigned int *) xmalloc (G.depth_max * sizeof (unsigned int));
01347
01348 G.by_depth_in_use = 0;
01349 G.by_depth_max = INITIAL_PTE_COUNT;
01350 G.by_depth = (page_entry **) xmalloc (G.by_depth_max * sizeof (page_entry *));
01351 G.save_in_use = (unsigned long **) xmalloc (G.by_depth_max * sizeof (unsigned long *));
01352 }
01353
01354
01355
01356
01357 void
01358 ggc_push_context ()
01359 {
01360 ++G.context_depth;
01361
01362
01363 if (G.context_depth >= HOST_BITS_PER_LONG)
01364 abort ();
01365 }
01366
01367
01368
01369
01370 static void
01371 ggc_recalculate_in_use_p (p)
01372 page_entry *p;
01373 {
01374 unsigned int i;
01375 size_t num_objects;
01376
01377
01378
01379 num_objects = OBJECTS_PER_PAGE (p->order) + 1;
01380
01381
01382 p->num_free_objects = num_objects;
01383
01384
01385 for (i = 0;
01386 i < CEIL (BITMAP_SIZE (num_objects),
01387 sizeof (*p->in_use_p));
01388 ++i)
01389 {
01390 unsigned long j;
01391
01392
01393
01394 p->in_use_p[i] |= save_in_use_p (p)[i];
01395
01396
01397 for (j = p->in_use_p[i]; j; j >>= 1)
01398 p->num_free_objects -= (j & 1);
01399 }
01400
01401 if (p->num_free_objects >= num_objects)
01402 abort ();
01403 }
01404
01405
01406
01407
01408 void
01409 ggc_pop_context ()
01410 {
01411 unsigned long omask;
01412 unsigned int depth, i, e;
01413 #ifdef ENABLE_CHECKING
01414 unsigned int order;
01415 #endif
01416
01417 depth = --G.context_depth;
01418 omask = (unsigned long)1 << (depth + 1);
01419
01420 if (!((G.context_depth_allocations | G.context_depth_collections) & omask))
01421 return;
01422
01423 G.context_depth_allocations |= (G.context_depth_allocations & omask) >> 1;
01424 G.context_depth_allocations &= omask - 1;
01425 G.context_depth_collections &= omask - 1;
01426
01427
01428
01429 if (depth+1 < G.depth_in_use)
01430 e = G.depth[depth+1];
01431 else
01432 e = G.by_depth_in_use;
01433
01434
01435 if (depth < G.depth_in_use)
01436 {
01437
01438
01439
01440 for (i = G.depth[depth]; i < e; ++i)
01441 {
01442 page_entry *p;
01443
01444 #ifdef ENABLE_CHECKING
01445 p = G.by_depth[i];
01446
01447
01448
01449 if (p->context_depth != depth)
01450 abort ();
01451 if (p->index_by_depth != i)
01452 abort ();
01453 #endif
01454
01455 prefetch (&save_in_use_p_i (i+8));
01456 prefetch (&save_in_use_p_i (i+16));
01457 if (save_in_use_p_i (i))
01458 {
01459 p = G.by_depth[i];
01460 ggc_recalculate_in_use_p (p);
01461 free (save_in_use_p_i (i));
01462 save_in_use_p_i (i) = 0;
01463 }
01464 }
01465 }
01466
01467
01468
01469 for (i = e; i < G.by_depth_in_use; ++i)
01470 {
01471 page_entry *p = G.by_depth[i];
01472
01473
01474
01475 #ifdef ENABLE_CHECKING
01476 if (p->context_depth <= depth)
01477 abort ();
01478 if (p->index_by_depth != i)
01479 abort ();
01480 #endif
01481 p->context_depth = depth;
01482 }
01483
01484 adjust_depth ();
01485
01486 #ifdef ENABLE_CHECKING
01487 for (order = 2; order < NUM_ORDERS; order++)
01488 {
01489 page_entry *p;
01490
01491 for (p = G.pages[order]; p != NULL; p = p->next)
01492 {
01493 if (p->context_depth > depth)
01494 abort ();
01495 else if (p->context_depth == depth && save_in_use_p (p))
01496 abort ();
01497 }
01498 }
01499 #endif
01500 }
01501
01502
01503
01504 static inline void
01505 clear_marks ()
01506 {
01507 unsigned order;
01508
01509 for (order = 2; order < NUM_ORDERS; order++)
01510 {
01511 size_t num_objects = OBJECTS_PER_PAGE (order);
01512 size_t bitmap_size = BITMAP_SIZE (num_objects + 1);
01513 page_entry *p;
01514
01515 for (p = G.pages[order]; p != NULL; p = p->next)
01516 {
01517 #ifdef ENABLE_CHECKING
01518
01519 if ((size_t) p->page & (G.pagesize - 1))
01520 abort ();
01521 #endif
01522
01523
01524
01525
01526 if (p->context_depth < G.context_depth)
01527 {
01528 if (! save_in_use_p (p))
01529 save_in_use_p (p) = xmalloc (bitmap_size);
01530 memcpy (save_in_use_p (p), p->in_use_p, bitmap_size);
01531 }
01532
01533
01534
01535 p->num_free_objects = num_objects;
01536 memset (p->in_use_p, 0, bitmap_size);
01537
01538
01539 p->in_use_p[num_objects / HOST_BITS_PER_LONG]
01540 = ((unsigned long) 1 << (num_objects % HOST_BITS_PER_LONG));
01541 }
01542 }
01543 }
01544
01545
01546
01547
01548 static inline void
01549 sweep_pages ()
01550 {
01551 unsigned order;
01552
01553 for (order = 2; order < NUM_ORDERS; order++)
01554 {
01555
01556
01557 page_entry * const last = G.page_tails[order];
01558
01559 size_t num_objects = OBJECTS_PER_PAGE (order);
01560 size_t live_objects;
01561 page_entry *p, *previous;
01562 int done;
01563
01564 p = G.pages[order];
01565 if (p == NULL)
01566 continue;
01567
01568 previous = NULL;
01569 do
01570 {
01571 page_entry *next = p->next;
01572
01573
01574 done = (p == last);
01575
01576
01577
01578 live_objects = num_objects - p->num_free_objects;
01579
01580 G.allocated += OBJECT_SIZE (order) * live_objects;
01581
01582
01583
01584 if (p->context_depth < G.context_depth)
01585 ;
01586
01587
01588 else if (live_objects == 0)
01589 {
01590 if (! previous)
01591 G.pages[order] = next;
01592 else
01593 previous->next = next;
01594
01595
01596 if (p == G.page_tails[order])
01597 G.page_tails[order] = previous;
01598 free_page (p);
01599 p = previous;
01600 }
01601
01602
01603 else if (p->num_free_objects == 0)
01604 {
01605
01606 if (p != G.page_tails[order])
01607 {
01608
01609 p->next = NULL;
01610 G.page_tails[order]->next = p;
01611
01612
01613 G.page_tails[order] = p;
01614
01615
01616 if (! previous)
01617 G.pages[order] = next;
01618 else
01619 previous->next = next;
01620 p = previous;
01621 }
01622 }
01623
01624
01625
01626
01627
01628 else if (p != G.pages[order])
01629 {
01630 previous->next = p->next;
01631 p->next = G.pages[order];
01632 G.pages[order] = p;
01633
01634 if (G.page_tails[order] == p)
01635 G.page_tails[order] = previous;
01636 p = previous;
01637 }
01638
01639 previous = p;
01640 p = next;
01641 }
01642 while (! done);
01643
01644
01645
01646 for (p = G.pages[order]; p; p = p->next)
01647 if (p->context_depth != G.context_depth)
01648 ggc_recalculate_in_use_p (p);
01649 }
01650 }
01651
01652 #ifdef ENABLE_GC_CHECKING
01653
01654
01655 static inline void
01656 poison_pages ()
01657 {
01658 unsigned order;
01659
01660 for (order = 2; order < NUM_ORDERS; order++)
01661 {
01662 size_t num_objects = OBJECTS_PER_PAGE (order);
01663 size_t size = OBJECT_SIZE (order);
01664 page_entry *p;
01665
01666 for (p = G.pages[order]; p != NULL; p = p->next)
01667 {
01668 size_t i;
01669
01670 if (p->context_depth != G.context_depth)
01671
01672
01673
01674
01675 continue;
01676
01677 for (i = 0; i < num_objects; i++)
01678 {
01679 size_t word, bit;
01680 word = i / HOST_BITS_PER_LONG;
01681 bit = i % HOST_BITS_PER_LONG;
01682 if (((p->in_use_p[word] >> bit) & 1) == 0)
01683 {
01684 char *object = p->page + i * size;
01685
01686
01687
01688
01689
01690 VALGRIND_DISCARD (VALGRIND_MAKE_WRITABLE (object, size));
01691 memset (object, 0xa5, size);
01692
01693
01694 VALGRIND_DISCARD (VALGRIND_MAKE_NOACCESS (object, size));
01695 }
01696 }
01697 }
01698 }
01699 }
01700 #endif
01701
01702
01703
01704 void
01705 ggc_collect ()
01706 {
01707
01708
01709
01710 float allocated_last_gc =
01711 MAX (G.allocated_last_gc, (size_t)PARAM_VALUE (GGC_MIN_HEAPSIZE) * 1024);
01712
01713 float min_expand = allocated_last_gc * PARAM_VALUE (GGC_MIN_EXPAND) / 100;
01714
01715 if (G.allocated < allocated_last_gc + min_expand)
01716 return;
01717
01718 timevar_push (TV_GC);
01719 if (!quiet_flag)
01720 fprintf (stderr, " {GC %luk -> ", (unsigned long) G.allocated / 1024);
01721
01722
01723
01724 G.allocated = 0;
01725
01726
01727
01728 release_pages ();
01729
01730
01731 G.context_depth_collections = ((unsigned long)1 << (G.context_depth + 1)) - 1;
01732
01733 clear_marks ();
01734 ggc_mark_roots ();
01735
01736 #ifdef ENABLE_GC_CHECKING
01737 poison_pages ();
01738 #endif
01739
01740 sweep_pages ();
01741
01742 G.allocated_last_gc = G.allocated;
01743
01744 timevar_pop (TV_GC);
01745
01746 if (!quiet_flag)
01747 fprintf (stderr, "%luk}", (unsigned long) G.allocated / 1024);
01748 }
01749
01750
01751 #define SCALE(x) ((unsigned long) ((x) < 1024*10 \
01752 ? (x) \
01753 : ((x) < 1024*1024*10 \
01754 ? (x) / 1024 \
01755 : (x) / (1024*1024))))
01756 #define LABEL(x) ((x) < 1024*10 ? ' ' : ((x) < 1024*1024*10 ? 'k' : 'M'))
01757
01758 void
01759 ggc_print_statistics ()
01760 {
01761 struct ggc_statistics stats;
01762 unsigned int i;
01763 size_t total_overhead = 0;
01764
01765
01766 memset (&stats, 0, sizeof (stats));
01767
01768
01769 G.allocated_last_gc = 0;
01770
01771
01772 ggc_print_common_statistics (stderr, &stats);
01773
01774
01775
01776 release_pages ();
01777
01778
01779
01780 fprintf (stderr, "\n%-5s %10s %10s %10s\n",
01781 "Size", "Allocated", "Used", "Overhead");
01782 for (i = 0; i < NUM_ORDERS; ++i)
01783 {
01784 page_entry *p;
01785 size_t allocated;
01786 size_t in_use;
01787 size_t overhead;
01788
01789
01790 if (!G.pages[i])
01791 continue;
01792
01793 overhead = allocated = in_use = 0;
01794
01795
01796
01797
01798 for (p = G.pages[i]; p; p = p->next)
01799 {
01800 allocated += p->bytes;
01801 in_use +=
01802 (OBJECTS_PER_PAGE (i) - p->num_free_objects) * OBJECT_SIZE (i);
01803
01804 overhead += (sizeof (page_entry) - sizeof (long)
01805 + BITMAP_SIZE (OBJECTS_PER_PAGE (i) + 1));
01806 }
01807 fprintf (stderr, "%-5lu %10lu%c %10lu%c %10lu%c\n",
01808 (unsigned long) OBJECT_SIZE (i),
01809 SCALE (allocated), LABEL (allocated),
01810 SCALE (in_use), LABEL (in_use),
01811 SCALE (overhead), LABEL (overhead));
01812 total_overhead += overhead;
01813 }
01814 fprintf (stderr, "%-5s %10lu%c %10lu%c %10lu%c\n", "Total",
01815 SCALE (G.bytes_mapped), LABEL (G.bytes_mapped),
01816 SCALE (G.allocated), LABEL(G.allocated),
01817 SCALE (total_overhead), LABEL (total_overhead));
01818 }