Add a statistic for tracking how many cells are marked conservatively.
[bpt/guile.git] / libguile / gc-mark.c
CommitLineData
71c7cfa5 1/* Copyright (C) 1995,1996,1997,1998,1999,2000,2001, 2002, 2003, 2004, 2005, 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
19\f
3ba436c8
RB
20#if HAVE_CONFIG_H
21# include <config.h>
22#endif
23
c7743d02
HWN
24#include <stdio.h>
25#include <errno.h>
26#include <string.h>
27#include <assert.h>
28
29#ifdef __ia64__
30#include <ucontext.h>
31extern unsigned long * __libc_ia64_register_backing_store_base;
32#endif
33
34#include "libguile/_scm.h"
35#include "libguile/eval.h"
36#include "libguile/stime.h"
37#include "libguile/stackchk.h"
38#include "libguile/struct.h"
39#include "libguile/smob.h"
40#include "libguile/unif.h"
41#include "libguile/async.h"
42#include "libguile/ports.h"
43#include "libguile/root.h"
44#include "libguile/strings.h"
45#include "libguile/vectors.h"
46#include "libguile/weaks.h"
47#include "libguile/hashtab.h"
48#include "libguile/tags.h"
49#include "libguile/private-gc.h"
50#include "libguile/validate.h"
51#include "libguile/deprecation.h"
52#include "libguile/gc.h"
06c1d900 53#include "libguile/guardians.h"
c7743d02
HWN
54
55#ifdef GUILE_DEBUG_MALLOC
56#include "libguile/debug-malloc.h"
57#endif
58
59#ifdef HAVE_MALLOC_H
60#include <malloc.h>
61#endif
62
63#ifdef HAVE_UNISTD_H
64#include <unistd.h>
65#endif
66
c7743d02
HWN
67/*
68 Entry point for this file.
69 */
70void
71scm_mark_all (void)
72{
73 long j;
71c7cfa5 74 int loops;
06c1d900 75
d09752ff 76 scm_i_marking = 1;
06c1d900
MV
77 scm_i_init_weak_vectors_for_gc ();
78 scm_i_init_guardians_for_gc ();
c7743d02
HWN
79
80 scm_i_clear_mark_space ();
40945e5e 81 scm_i_find_heap_calls = 0;
c7743d02
HWN
82 /* Mark every thread's stack and registers */
83 scm_threads_mark_stacks ();
84
c7743d02
HWN
85 j = SCM_NUM_PROTECTS;
86 while (j--)
87 scm_gc_mark (scm_sys_protects[j]);
88
89 /* mark the registered roots */
90 {
91 size_t i;
c35738c1 92 for (i = 0; i < SCM_HASHTABLE_N_BUCKETS (scm_gc_registered_roots); ++i)
c7743d02 93 {
4057a3e0 94 SCM l = SCM_HASHTABLE_BUCKET (scm_gc_registered_roots, i);
d2e53ed6 95 for (; !scm_is_null (l); l = SCM_CDR (l))
c7743d02 96 {
b9bd8526 97 SCM *p = (SCM *) (scm_to_ulong (SCM_CAAR (l)));
c7743d02
HWN
98 scm_gc_mark (*p);
99 }
100 }
101 }
eab1b259 102
06c1d900
MV
103 scm_mark_subr_table ();
104
71c7cfa5 105 loops = 0;
06c1d900
MV
106 while (1)
107 {
06c1d900 108 int again;
71c7cfa5 109 loops++;
06c1d900
MV
110
111 /* Mark the non-weak references of weak vectors. For a weak key
112 alist vector, this would mark the values for keys that are
113 marked. We need to do this in a loop until everything
114 settles down since the newly marked values might be keys in
115 other weak key alist vectors, for example.
116 */
117 again = scm_i_mark_weak_vectors_non_weaks ();
118 if (again)
119 continue;
120
121 /* Now we scan all marked guardians and move all unmarked objects
122 from the accessible to the inaccessible list.
123 */
124 scm_i_identify_inaccessible_guardeds ();
125
126 /* When we have identified all inaccessible objects, we can mark
127 them.
128 */
129 again = scm_i_mark_inaccessible_guardeds ();
130
131 /* This marking might have changed the situation for weak vectors
132 and might have turned up new guardians that need to be processed,
133 so we do it all over again.
134 */
135 if (again)
136 continue;
137
138 /* Nothing new marked in this round, we are done.
139 */
140 break;
141 }
142
06c1d900 143 /* Remove all unmarked entries from the weak vectors.
c7743d02 144 */
06c1d900
MV
145 scm_i_remove_weaks_from_weak_vectors ();
146
147 /* Bring hashtables upto date.
148 */
149 scm_i_scan_weak_hashtables ();
d09752ff 150 scm_i_marking = 0;
c7743d02
HWN
151}
152
153/* {Mark/Sweep}
154 */
155
c7743d02
HWN
156/*
157 Mark an object precisely, then recurse.
158 */
159void
160scm_gc_mark (SCM ptr)
161{
162 if (SCM_IMP (ptr))
45a1c3e8 163 return;
c7743d02
HWN
164
165 if (SCM_GC_MARK_P (ptr))
45a1c3e8 166 return;
c7743d02
HWN
167
168 SCM_SET_GC_MARK (ptr);
169 scm_gc_mark_dependencies (ptr);
170}
171
d09752ff
HWN
172void
173ensure_marking (void)
174{
175 assert (scm_i_marking);
176}
177
c7743d02
HWN
178/*
179
180Mark the dependencies of an object.
181
33138b05 182Prefetching:
c7743d02
HWN
183
184Should prefetch objects before marking, i.e. if marking a cell, we
185should prefetch the car, and then mark the cdr. This will improve CPU
82ae1b8e 186cache misses, because the car is more likely to be in cache when we
c7743d02
HWN
187finish the cdr.
188
189See http://www.hpl.hp.com/techreports/2000/HPL-2000-99.pdf, reducing
190garbage collector cache misses.
191
192Prefetch is supported on GCC >= 3.1
193
33138b05
HWN
194(Some time later.)
195
196Tried this with GCC 3.1.1 -- the time differences are barely measurable.
197Perhaps this would work better with an explicit markstack?
198
199
200*/
06c1d900 201
c7743d02
HWN
202void
203scm_gc_mark_dependencies (SCM p)
204#define FUNC_NAME "scm_gc_mark_dependencies"
205{
206 register long i;
207 register SCM ptr;
702551e6 208 SCM cell_type;
c7743d02
HWN
209
210 ptr = p;
211 scm_mark_dependencies_again:
76da80e7 212
c7743d02
HWN
213 cell_type = SCM_GC_CELL_TYPE (ptr);
214 switch (SCM_ITAG7 (cell_type))
215 {
216 case scm_tcs_cons_nimcar:
217 if (SCM_IMP (SCM_CDR (ptr)))
218 {
219 ptr = SCM_CAR (ptr);
220 goto gc_mark_nimp;
221 }
33138b05
HWN
222
223
c7743d02
HWN
224 scm_gc_mark (SCM_CAR (ptr));
225 ptr = SCM_CDR (ptr);
226 goto gc_mark_nimp;
227 case scm_tcs_cons_imcar:
228 ptr = SCM_CDR (ptr);
229 goto gc_mark_loop;
230 case scm_tc7_pws:
33138b05 231
c7743d02
HWN
232 scm_gc_mark (SCM_SETTER (ptr));
233 ptr = SCM_PROCEDURE (ptr);
234 goto gc_mark_loop;
235 case scm_tcs_struct:
236 {
237 /* XXX - use less explicit code. */
238 scm_t_bits word0 = SCM_CELL_WORD_0 (ptr) - scm_tc3_struct;
239 scm_t_bits * vtable_data = (scm_t_bits *) word0;
240 SCM layout = SCM_PACK (vtable_data [scm_vtable_index_layout]);
eb01cb64
MV
241 long len = scm_i_symbol_length (layout);
242 const char *fields_desc = scm_i_symbol_chars (layout);
243 scm_t_bits *struct_data = (scm_t_bits *) SCM_STRUCT_DATA (ptr);
c7743d02
HWN
244
245 if (vtable_data[scm_struct_i_flags] & SCM_STRUCTF_ENTITY)
246 {
247 scm_gc_mark (SCM_PACK (struct_data[scm_struct_i_procedure]));
248 scm_gc_mark (SCM_PACK (struct_data[scm_struct_i_setter]));
249 }
250 if (len)
251 {
252 long x;
253
254 for (x = 0; x < len - 2; x += 2, ++struct_data)
255 if (fields_desc[x] == 'p')
256 scm_gc_mark (SCM_PACK (*struct_data));
257 if (fields_desc[x] == 'p')
258 {
259 if (SCM_LAYOUT_TAILP (fields_desc[x + 1]))
260 for (x = *struct_data++; x; --x, ++struct_data)
261 scm_gc_mark (SCM_PACK (*struct_data));
262 else
263 scm_gc_mark (SCM_PACK (*struct_data));
264 }
265 }
266 /* mark vtable */
267 ptr = SCM_PACK (vtable_data [scm_vtable_index_vtable]);
268 goto gc_mark_loop;
269 }
270 break;
271 case scm_tcs_closures:
272 if (SCM_IMP (SCM_ENV (ptr)))
273 {
274 ptr = SCM_CLOSCAR (ptr);
275 goto gc_mark_nimp;
276 }
277 scm_gc_mark (SCM_CLOSCAR (ptr));
278 ptr = SCM_ENV (ptr);
279 goto gc_mark_nimp;
280 case scm_tc7_vector:
4057a3e0 281 i = SCM_SIMPLE_VECTOR_LENGTH (ptr);
c7743d02
HWN
282 if (i == 0)
283 break;
284 while (--i > 0)
33138b05 285 {
4057a3e0
MV
286 SCM elt = SCM_SIMPLE_VECTOR_REF (ptr, i);
287 if (SCM_NIMP (elt))
288 scm_gc_mark (elt);
33138b05 289 }
4057a3e0 290 ptr = SCM_SIMPLE_VECTOR_REF (ptr, 0);
c7743d02
HWN
291 goto gc_mark_loop;
292#ifdef CCLO
293 case scm_tc7_cclo:
294 {
295 size_t i = SCM_CCLO_LENGTH (ptr);
296 size_t j;
297 for (j = 1; j != i; ++j)
298 {
299 SCM obj = SCM_CCLO_REF (ptr, j);
300 if (!SCM_IMP (obj))
301 scm_gc_mark (obj);
302 }
303 ptr = SCM_CCLO_REF (ptr, 0);
304 goto gc_mark_loop;
305 }
306#endif
eb01cb64 307
c7743d02 308 case scm_tc7_string:
eb01cb64
MV
309 ptr = scm_i_string_mark (ptr);
310 goto gc_mark_loop;
311 case scm_tc7_stringbuf:
312 ptr = scm_i_stringbuf_mark (ptr);
313 goto gc_mark_loop;
c7743d02 314
534c55a9 315 case scm_tc7_number:
f92e85f7
MV
316 if (SCM_TYP16 (ptr) == scm_tc16_fraction)
317 {
318 scm_gc_mark (SCM_CELL_OBJECT_1 (ptr));
319 ptr = SCM_CELL_OBJECT_2 (ptr);
320 goto gc_mark_loop;
321 }
534c55a9
DH
322 break;
323
c7743d02 324 case scm_tc7_wvect:
06c1d900 325 scm_i_mark_weak_vector (ptr);
c7743d02
HWN
326 break;
327
328 case scm_tc7_symbol:
eb01cb64 329 ptr = scm_i_symbol_mark (ptr);
c7743d02
HWN
330 goto gc_mark_loop;
331 case scm_tc7_variable:
332 ptr = SCM_CELL_OBJECT_1 (ptr);
333 goto gc_mark_loop;
334 case scm_tcs_subrs:
335 break;
336 case scm_tc7_port:
337 i = SCM_PTOBNUM (ptr);
338#if (SCM_DEBUG_CELL_ACCESSES == 1)
339 if (!(i < scm_numptob))
be3ff021
HWN
340 {
341 fprintf (stderr, "undefined port type");
342 abort();
343 }
c7743d02
HWN
344#endif
345 if (SCM_PTAB_ENTRY(ptr))
346 scm_gc_mark (SCM_FILENAME (ptr));
347 if (scm_ptobs[i].mark)
348 {
349 ptr = (scm_ptobs[i].mark) (ptr);
350 goto gc_mark_loop;
351 }
352 else
353 return;
354 break;
355 case scm_tc7_smob:
356 switch (SCM_TYP16 (ptr))
357 { /* should be faster than going through scm_smobs */
358 case scm_tc_free_cell:
359 /* We have detected a free cell. This can happen if non-object data
360 * on the C stack points into guile's heap and is scanned during
361 * conservative marking. */
362 break;
c7743d02
HWN
363 default:
364 i = SCM_SMOBNUM (ptr);
365#if (SCM_DEBUG_CELL_ACCESSES == 1)
366 if (!(i < scm_numsmob))
be3ff021
HWN
367 {
368 fprintf (stderr, "undefined smob type");
369 abort();
370 }
c7743d02
HWN
371#endif
372 if (scm_smobs[i].mark)
373 {
374 ptr = (scm_smobs[i].mark) (ptr);
375 goto gc_mark_loop;
376 }
377 else
378 return;
379 }
380 break;
381 default:
be3ff021
HWN
382 fprintf (stderr, "unknown type");
383 abort();
c7743d02
HWN
384 }
385
386 /*
387 If we got here, then exhausted recursion options for PTR. we
388 return (careful not to mark PTR, it might be the argument that we
389 were called with.)
390 */
391 return ;
06c1d900
MV
392
393 gc_mark_loop:
c7743d02
HWN
394 if (SCM_IMP (ptr))
395 return;
396
397 gc_mark_nimp:
398 {
399 int valid_cell = CELL_P (ptr);
400
401
402#if (SCM_DEBUG_CELL_ACCESSES == 1)
403 if (scm_debug_cell_accesses_p)
404 {
405 /* We are in debug mode. Check the ptr exhaustively. */
406
40945e5e 407 valid_cell = valid_cell && scm_in_heap_p (ptr);
c7743d02
HWN
408 }
409
410#endif
411 if (!valid_cell)
be3ff021
HWN
412 {
413 fprintf (stderr, "rogue pointer in heap");
414 abort();
415 }
c7743d02 416 }
eab1b259 417
82ae1b8e 418 if (SCM_GC_MARK_P (ptr))
76da80e7 419 return;
a54a94b3 420
76da80e7 421 SCM_SET_GC_MARK (ptr);
eab1b259 422
76da80e7 423 goto scm_mark_dependencies_again;
c7743d02
HWN
424
425}
426#undef FUNC_NAME
427
428
c7743d02
HWN
429/* Mark a region conservatively */
430void
431scm_mark_locations (SCM_STACKITEM x[], unsigned long n)
432{
433 unsigned long m;
434
435 for (m = 0; m < n; ++m)
436 {
437 SCM obj = * (SCM *) &x[m];
438 long int segment = scm_i_find_heap_segment_containing_object (obj);
439 if (segment >= 0)
440 scm_gc_mark (obj);
441 }
442}
443
444
445/* The function scm_in_heap_p determines whether an SCM value can be regarded as a
446 * pointer to a cell on the heap.
447 */
448int
449scm_in_heap_p (SCM value)
450{
451 long int segment = scm_i_find_heap_segment_containing_object (value);
452 return (segment >= 0);
453}
454
455
456#if SCM_ENABLE_DEPRECATED == 1
457
458/* If an allocated cell is detected during garbage collection, this
459 * means that some code has just obtained the object but was preempted
460 * before the initialization of the object was completed. This meanst
461 * that some entries of the allocated cell may already contain SCM
462 * objects. Therefore, allocated cells are scanned conservatively.
463 */
464
465scm_t_bits scm_tc16_allocated;
466
467static SCM
468allocated_mark (SCM cell)
469{
470 unsigned long int cell_segment = scm_i_find_heap_segment_containing_object (cell);
471 unsigned int span = scm_i_heap_segment_table[cell_segment]->span;
472 unsigned int i;
473
474 for (i = 1; i != span * 2; ++i)
475 {
476 SCM obj = SCM_CELL_OBJECT (cell, i);
477 long int obj_segment = scm_i_find_heap_segment_containing_object (obj);
478 if (obj_segment >= 0)
479 scm_gc_mark (obj);
480 }
481 return SCM_BOOL_F;
482}
483
484SCM
485scm_deprecated_newcell (void)
486{
487 scm_c_issue_deprecation_warning
488 ("SCM_NEWCELL is deprecated. Use `scm_cell' instead.\n");
489
490 return scm_cell (scm_tc16_allocated, 0);
491}
492
493SCM
494scm_deprecated_newcell2 (void)
495{
496 scm_c_issue_deprecation_warning
497 ("SCM_NEWCELL2 is deprecated. Use `scm_double_cell' instead.\n");
498
499 return scm_double_cell (scm_tc16_allocated, 0, 0, 0);
500}
501
502#endif /* SCM_ENABLE_DEPRECATED == 1 */
503
504
505void
506scm_gc_init_mark(void)
507{
508#if SCM_ENABLE_DEPRECATED == 1
509 scm_tc16_allocated = scm_make_smob_type ("allocated cell", 0);
510 scm_set_smob_mark (scm_tc16_allocated, allocated_mark);
511#endif
512}
513