Commit | Line | Data |
---|---|---|
2b829bbb | 1 | /* Copyright (C) 1995,1996,1997,1998,1999,2000,2001, 2002, 2006 Free Software Foundation, Inc. |
c7743d02 | 2 | * |
73be1d9e MV |
3 | * This library is free software; you can redistribute it and/or |
4 | * modify it under the terms of the GNU Lesser General Public | |
5 | * License as published by the Free Software Foundation; either | |
6 | * version 2.1 of the License, or (at your option) any later version. | |
c7743d02 | 7 | * |
73be1d9e | 8 | * This library is distributed in the hope that it will be useful, |
c7743d02 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
73be1d9e MV |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
11 | * Lesser General Public License for more details. | |
c7743d02 | 12 | * |
73be1d9e MV |
13 | * You should have received a copy of the GNU Lesser General Public |
14 | * License along with this library; if not, write to the Free Software | |
92205699 | 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
73be1d9e | 16 | */ |
c7743d02 HWN |
17 | |
18 | #include <assert.h> | |
19 | #include <stdio.h> | |
20 | #include <string.h> | |
21 | ||
22 | #include "libguile/_scm.h" | |
23 | #include "libguile/pairs.h" | |
24 | #include "libguile/gc.h" | |
25 | #include "libguile/private-gc.h" | |
26 | ||
c7743d02 HWN |
27 | size_t scm_max_segment_size; |
28 | ||
82ae1b8e HWN |
29 | /* Important entry point: try to grab some memory, and make it into a |
30 | segment; return the index of the segment. SWEEP_STATS should contain | |
31 | global GC sweep statistics collected since the last full GC. | |
32 | ||
33 | Returns the index of the segment. If error_policy != | |
34 | abort_on_error, we return -1 on failure. | |
35 | */ | |
36 | int | |
37 | scm_i_get_new_heap_segment (scm_t_cell_type_statistics *freelist, | |
38 | size_t len, | |
39 | policy_on_error error_policy) | |
40 | { | |
41 | if (len > scm_max_segment_size) | |
42 | len = scm_max_segment_size; | |
43 | ||
44 | if (len < SCM_MIN_HEAP_SEG_SIZE) | |
45 | len = SCM_MIN_HEAP_SEG_SIZE; | |
46 | ||
40945e5e | 47 | /* todo: consider having a more flexible lower bound. */ |
82ae1b8e HWN |
48 | { |
49 | scm_t_heap_segment *seg = scm_i_make_empty_heap_segment (freelist); | |
50 | ||
51 | /* Allocate with decaying ambition. */ | |
52 | while (len >= SCM_MIN_HEAP_SEG_SIZE) | |
53 | { | |
54 | if (scm_i_initialize_heap_segment_data (seg, len)) | |
55 | return scm_i_insert_segment (seg); | |
56 | ||
57 | len /= 2; | |
58 | } | |
59 | } | |
60 | ||
61 | if (error_policy == abort_on_error) | |
62 | { | |
63 | fprintf (stderr, "scm_i_get_new_heap_segment: Could not grow heap.\n"); | |
64 | abort (); | |
65 | } | |
66 | return -1; | |
67 | } | |
68 | ||
69 | ||
c7743d02 HWN |
70 | scm_t_heap_segment * |
71 | scm_i_make_empty_heap_segment (scm_t_cell_type_statistics *fl) | |
72 | { | |
82ae1b8e | 73 | scm_t_heap_segment *shs = calloc (1, sizeof (scm_t_heap_segment)); |
c7743d02 HWN |
74 | |
75 | if (!shs) | |
76 | { | |
77 | fprintf (stderr, "scm_i_get_new_heap_segment: out of memory.\n"); | |
78 | abort (); | |
79 | } | |
80 | ||
c7743d02 HWN |
81 | shs->span = fl->span; |
82 | shs->freelist = fl; | |
c7743d02 HWN |
83 | |
84 | return shs; | |
85 | } | |
86 | ||
1367aa5e HWN |
87 | void |
88 | scm_i_heap_segment_statistics (scm_t_heap_segment *seg, SCM tab) | |
89 | { | |
90 | scm_t_cell *p = seg->bounds[0]; | |
91 | while (p < seg->bounds[1]) | |
92 | { | |
93 | scm_i_card_statistics (p, tab, seg); | |
94 | p += SCM_GC_CARD_N_CELLS; | |
95 | } | |
96 | } | |
97 | ||
82ae1b8e HWN |
98 | /* |
99 | count number of marked bits, so we know how much cells are live. | |
100 | */ | |
101 | int | |
102 | scm_i_heap_segment_marked_count (scm_t_heap_segment *seg) | |
103 | { | |
104 | scm_t_c_bvec_long *bvec = (scm_t_c_bvec_long *) seg->bounds[1]; | |
105 | scm_t_c_bvec_long *bvec_end = | |
106 | (bvec + | |
107 | scm_i_segment_card_count (seg) * SCM_GC_CARD_BVEC_SIZE_IN_LONGS); | |
108 | ||
109 | int count = 0; | |
110 | while (bvec < bvec_end) { | |
111 | count += scm_i_uint_bit_count(*bvec); | |
112 | bvec ++; | |
113 | } | |
114 | return count * seg->span; | |
115 | } | |
116 | ||
117 | int | |
118 | scm_i_segment_card_number (scm_t_heap_segment *seg, | |
119 | scm_t_cell *card) | |
120 | { | |
121 | return (card - seg->bounds[0]) / SCM_GC_CARD_N_CELLS; | |
122 | } | |
123 | ||
c7743d02 HWN |
124 | /* |
125 | Fill SEGMENT with memory both for data and mark bits. | |
126 | ||
82ae1b8e | 127 | RETURN: 1 on success, 0 failure |
c7743d02 HWN |
128 | */ |
129 | int | |
82ae1b8e | 130 | scm_i_initialize_heap_segment_data (scm_t_heap_segment *segment, size_t requested) |
c7743d02 HWN |
131 | { |
132 | /* | |
133 | round upwards | |
134 | */ | |
135 | int card_data_cell_count = (SCM_GC_CARD_N_CELLS - SCM_GC_CARD_N_HEADER_CELLS); | |
82ae1b8e | 136 | int card_count = 1 + (requested / sizeof (scm_t_cell)) / card_data_cell_count; |
c7743d02 HWN |
137 | |
138 | /* | |
139 | one card extra due to alignment | |
140 | */ | |
82ae1b8e HWN |
141 | size_t mem_needed = (1 + card_count) * SCM_GC_SIZEOF_CARD |
142 | + SCM_GC_CARD_BVEC_SIZE_IN_LONGS * card_count * SCM_SIZEOF_LONG; | |
143 | scm_t_cell *memory = 0; | |
c7743d02 HWN |
144 | |
145 | /* | |
82ae1b8e | 146 | We use calloc to alloc the heap, so it is nicely initialized. |
c7743d02 | 147 | */ |
82ae1b8e | 148 | SCM_SYSCALL (memory = (scm_t_cell *) calloc (1, mem_needed)); |
c7743d02 HWN |
149 | |
150 | if (memory == NULL) | |
151 | return 0; | |
152 | ||
153 | segment->malloced = memory; | |
154 | segment->bounds[0] = SCM_GC_CARD_UP (memory); | |
155 | segment->bounds[1] = segment->bounds[0] + card_count * SCM_GC_CARD_N_CELLS; | |
82ae1b8e | 156 | segment->freelist->heap_total_cells += scm_i_segment_cell_count (segment); |
c7743d02 | 157 | |
1383773b HWN |
158 | /* |
159 | Don't init the mem or the bitvector. This is handled by lazy | |
160 | sweeping. | |
161 | */ | |
c7743d02 HWN |
162 | segment->next_free_card = segment->bounds[0]; |
163 | segment->first_time = 1; | |
164 | return 1; | |
165 | } | |
166 | ||
167 | int | |
82ae1b8e | 168 | scm_i_segment_card_count (scm_t_heap_segment *seg) |
c7743d02 HWN |
169 | { |
170 | return (seg->bounds[1] - seg->bounds[0]) / SCM_GC_CARD_N_CELLS; | |
171 | } | |
172 | ||
173 | /* | |
174 | Return the number of available single-cell data cells. | |
175 | */ | |
176 | int | |
82ae1b8e HWN |
177 | scm_i_segment_cell_count (scm_t_heap_segment *seg) |
178 | { | |
179 | return scm_i_segment_card_count (seg) | |
180 | * scm_i_segment_cells_per_card (seg); | |
181 | } | |
182 | ||
183 | int | |
184 | scm_i_segment_cells_per_card (scm_t_heap_segment *seg) | |
c7743d02 | 185 | { |
82ae1b8e HWN |
186 | return (SCM_GC_CARD_N_CELLS - SCM_GC_CARD_N_HEADER_CELLS |
187 | + ((seg->span == 2) ? -1 : 0)); | |
c7743d02 HWN |
188 | } |
189 | ||
190 | void | |
191 | scm_i_clear_segment_mark_space (scm_t_heap_segment *seg) | |
192 | { | |
82ae1b8e | 193 | scm_t_cell *markspace = seg->bounds[1]; |
c7743d02 HWN |
194 | |
195 | memset (markspace, 0x00, | |
82ae1b8e | 196 | scm_i_segment_card_count (seg) * SCM_GC_CARD_BVEC_SIZE_IN_LONGS * SCM_SIZEOF_LONG); |
c7743d02 HWN |
197 | } |
198 | ||
82ae1b8e HWN |
199 | |
200 | /* | |
201 | Force a sweep of this entire segment. | |
202 | */ | |
203 | void | |
204 | scm_i_sweep_segment (scm_t_heap_segment *seg, | |
205 | scm_t_sweep_statistics *sweep_stats) | |
206 | { | |
207 | int infinity = 1 << 30; | |
208 | scm_t_cell *remember = seg->next_free_card; | |
209 | while (scm_i_sweep_some_cards (seg, sweep_stats, infinity) != SCM_EOL) | |
210 | ; | |
211 | seg->next_free_card = remember; | |
212 | } | |
213 | ||
214 | ||
215 | /* Sweep cards from SEG until we've gathered THRESHOLD cells. On | |
216 | return, SWEEP_STATS, if non-NULL, contains the number of cells that | |
217 | have been visited and collected. A freelist is returned, | |
218 | potentially empty. */ | |
c7743d02 | 219 | SCM |
4c7016dc | 220 | scm_i_sweep_some_cards (scm_t_heap_segment *seg, |
82ae1b8e HWN |
221 | scm_t_sweep_statistics *sweep_stats, |
222 | int threshold) | |
c7743d02 HWN |
223 | { |
224 | SCM cells = SCM_EOL; | |
c7743d02 | 225 | int collected = 0; |
82ae1b8e | 226 | int (*sweeper) (scm_t_cell *, SCM *, scm_t_heap_segment *) |
1383773b | 227 | = (seg->first_time) ? &scm_i_init_card_freelist : &scm_i_sweep_card; |
c7743d02 | 228 | |
82ae1b8e | 229 | scm_t_cell *next_free = seg->next_free_card; |
c7743d02 | 230 | int cards_swept = 0; |
c7743d02 HWN |
231 | while (collected < threshold && next_free < seg->bounds[1]) |
232 | { | |
1383773b | 233 | collected += (*sweeper) (next_free, &cells, seg); |
c7743d02 HWN |
234 | next_free += SCM_GC_CARD_N_CELLS; |
235 | cards_swept ++; | |
236 | } | |
237 | ||
82ae1b8e | 238 | if (sweep_stats != NULL) |
4c7016dc | 239 | { |
82ae1b8e HWN |
240 | int swept = cards_swept |
241 | * ((SCM_GC_CARD_N_CELLS - SCM_GC_CARD_N_HEADER_CELLS) | |
242 | - seg->span + 1); | |
243 | int collected_cells = collected * seg->span; | |
244 | sweep_stats->swept += swept; | |
245 | sweep_stats->collected += collected_cells; | |
4c7016dc | 246 | } |
82ae1b8e HWN |
247 | |
248 | if (next_free == seg->bounds[1]) | |
c7743d02 HWN |
249 | { |
250 | seg->first_time = 0; | |
251 | } | |
252 | ||
253 | seg->next_free_card = next_free; | |
254 | return cells; | |
255 | } | |
256 | ||
257 | ||
1367aa5e HWN |
258 | |
259 | SCM | |
82ae1b8e | 260 | scm_i_sweep_for_freelist (scm_t_cell_type_statistics *freelist) |
c7743d02 | 261 | { |
82ae1b8e HWN |
262 | scm_t_sweep_statistics stats = { 0 }; |
263 | SCM result = scm_i_sweep_some_segments (freelist, &stats); | |
c7743d02 | 264 | |
82ae1b8e HWN |
265 | scm_i_gc_sweep_stats.collected += stats.collected; |
266 | scm_i_gc_sweep_stats.swept += stats.swept; | |
c7743d02 | 267 | |
82ae1b8e HWN |
268 | freelist->collected += stats.collected; |
269 | freelist->swept += stats.swept; | |
270 | return result; | |
c7743d02 HWN |
271 | } |
272 |