diff options
Diffstat (limited to 'libguile/gc-segment-table.c')
-rw-r--r-- | libguile/gc-segment-table.c | 293 |
1 files changed, 293 insertions, 0 deletions
diff --git a/libguile/gc-segment-table.c b/libguile/gc-segment-table.c new file mode 100644 index 000000000..d627e9c1f --- /dev/null +++ b/libguile/gc-segment-table.c @@ -0,0 +1,293 @@ +/* Copyright (C) 1995,1996,1997,1998,1999,2000,2001, 2002, 2006 Free Software Foundation, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <assert.h> +#include <stdio.h> +#include <string.h> + +#include "libguile/_scm.h" +#include "libguile/pairs.h" +#include "libguile/gc.h" +#include "libguile/private-gc.h" + + +/* + Heap segment table. + + The table is sorted by the address of the data itself. This makes + for easy lookups. This is not portable: according to ANSI C, + pointers can only be compared within the same object (i.e. the same + block of malloced memory.). For machines with weird architectures, + this should be revised. + + (Apparently, for this reason 1.6 and earlier had macros for pointer + comparison. ) + + perhaps it is worthwhile to remove the 2nd level of indirection in + the table, but this certainly makes for cleaner code. +*/ +scm_t_heap_segment **scm_i_heap_segment_table; +size_t scm_i_heap_segment_table_size; +static scm_t_cell *lowest_cell; +static scm_t_cell *highest_cell; + + +/* + RETURN: index of inserted segment. + */ +int +scm_i_insert_segment (scm_t_heap_segment *seg) +{ + size_t size = (scm_i_heap_segment_table_size + 1) * sizeof (scm_t_heap_segment *); + SCM_SYSCALL(scm_i_heap_segment_table + = ((scm_t_heap_segment **) + realloc ((char *)scm_i_heap_segment_table, size))); + + /* + We can't alloc 4 more bytes. This is hopeless. + */ + if (!scm_i_heap_segment_table) + { + fprintf (stderr, "scm_i_get_new_heap_segment: Could not grow heap segment table.\n"); + abort (); + } + + if (!lowest_cell) + { + lowest_cell = seg->bounds[0]; + highest_cell = seg->bounds[1]; + } + else + { + lowest_cell = SCM_MIN (lowest_cell, seg->bounds[0]); + highest_cell = SCM_MAX (highest_cell, seg->bounds[1]); + } + + + { + int i = 0; + int j = 0; + + while (i < scm_i_heap_segment_table_size + && scm_i_heap_segment_table[i]->bounds[0] <= seg->bounds[0]) + i++; + + /* + We insert a new entry; if that happens to be before the + "current" segment of a freelist, we must move the freelist index + as well. + */ + if (scm_i_master_freelist.heap_segment_idx >= i) + scm_i_master_freelist.heap_segment_idx ++; + if (scm_i_master_freelist2.heap_segment_idx >= i) + scm_i_master_freelist2.heap_segment_idx ++; + + for (j = scm_i_heap_segment_table_size; j > i; --j) + scm_i_heap_segment_table[j] = scm_i_heap_segment_table[j - 1]; + + scm_i_heap_segment_table[i] = seg; + scm_i_heap_segment_table_size ++; + + return i; + } +} + + +/* + Determine whether the given value does actually represent a cell in + some heap segment. If this is the case, the number of the heap + segment is returned. Otherwise, -1 is returned. Binary search is + used to determine the heap segment that contains the cell. + + I think this function is too long to be inlined. --hwn +*/ +int +scm_i_find_heap_segment_containing_object (SCM obj) +{ + if (!CELL_P (obj)) + return -1; + + if ((scm_t_cell *) obj < lowest_cell || (scm_t_cell *) obj >= highest_cell) + return -1; + + { + scm_t_cell *ptr = SCM2PTR (obj); + unsigned int i = 0; + unsigned int j = scm_i_heap_segment_table_size - 1; + + if (ptr < scm_i_heap_segment_table[i]->bounds[0]) + return -1; + else if (scm_i_heap_segment_table[j]->bounds[1] <= ptr) + return -1; + else + { + while (i < j) + { + if (ptr < scm_i_heap_segment_table[i]->bounds[1]) + { + break; + } + else if (scm_i_heap_segment_table[j]->bounds[0] <= ptr) + { + i = j; + break; + } + else + { + unsigned long int k = (i + j) / 2; + + if (k == i) + return -1; + else if (ptr < scm_i_heap_segment_table[k]->bounds[1]) + { + j = k; + ++i; + if (ptr < scm_i_heap_segment_table[i]->bounds[0]) + return -1; + } + else if (scm_i_heap_segment_table[k]->bounds[0] <= ptr) + { + i = k; + --j; + if (scm_i_heap_segment_table[j]->bounds[1] <= ptr) + return -1; + } + } + } + + if (!SCM_DOUBLECELL_ALIGNED_P (obj) && scm_i_heap_segment_table[i]->span == 2) + return -1; + else if (SCM_GC_IN_CARD_HEADERP (ptr)) + return -1; + else + return i; + } + } +} + + +int +scm_i_marked_count (void) +{ + int i = 0; + int c = 0; + for (; i < scm_i_heap_segment_table_size; i++) + { + c += scm_i_heap_segment_marked_count (scm_i_heap_segment_table[i]); + } + return c; +} + + +SCM +scm_i_sweep_some_segments (scm_t_cell_type_statistics *freelist, + scm_t_sweep_statistics *sweep_stats) +{ + int i = freelist->heap_segment_idx; + SCM collected = SCM_EOL; + + if (i == -1) /* huh? --hwn */ + i++; + + for (; + i < scm_i_heap_segment_table_size; i++) + { + if (scm_i_heap_segment_table[i]->freelist != freelist) + continue; + + collected = scm_i_sweep_some_cards (scm_i_heap_segment_table[i], + sweep_stats, + DEFAULT_SWEEP_AMOUNT); + + if (collected != SCM_EOL) /* Don't increment i */ + break; + } + + freelist->heap_segment_idx = i; + + return collected; +} + +void +scm_i_reset_segments (void) +{ + int i = 0; + for (; i < scm_i_heap_segment_table_size; i++) + { + scm_t_heap_segment *seg = scm_i_heap_segment_table[i]; + seg->next_free_card = seg->bounds[0]; + } +} + + + + +/* + Return a hashtab with counts of live objects, with tags as keys. + */ +SCM +scm_i_all_segments_statistics (SCM tab) +{ + int i = 0; + for (; i < scm_i_heap_segment_table_size; i++) + { + scm_t_heap_segment *seg = scm_i_heap_segment_table[i]; + scm_i_heap_segment_statistics (seg, tab); + } + + return tab; +} + + +unsigned long* +scm_i_segment_table_info(int* size) +{ + *size = scm_i_heap_segment_table_size; + unsigned long *bounds = malloc (sizeof (unsigned long) * *size * 2); + int i; + if (!bounds) + abort(); + for (i = *size; i-- > 0; ) + { + bounds[2*i] = (unsigned long)scm_i_heap_segment_table[i]->bounds[0]; + bounds[2*i+1] = (unsigned long)scm_i_heap_segment_table[i]->bounds[1]; + } + return bounds; +} + + +void +scm_i_sweep_all_segments (char const *reason, + scm_t_sweep_statistics *sweep_stats) +{ + unsigned i= 0; + for (i = 0; i < scm_i_heap_segment_table_size; i++) + { + scm_i_sweep_segment (scm_i_heap_segment_table[i], sweep_stats); + } +} + + +void +scm_i_clear_mark_space (void) +{ + int i = 0; + for (; i < scm_i_heap_segment_table_size; i++) + { + scm_i_clear_segment_mark_space (scm_i_heap_segment_table[i]); + } +} |