Revert "(scm_shell_usage): Note need for subscription to bug-guile@gnu.org."
[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
dbb605f5 20#ifdef HAVE_CONFIG_H
3ba436c8
RB
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 167
7ddb9baf
HWN
168 if (!scm_i_marking)
169 {
170 static const char msg[]
171 = "Should only call scm_gc_mark() during GC.";
172 scm_c_issue_deprecation_warning (msg);
173 }
174
c7743d02
HWN
175 SCM_SET_GC_MARK (ptr);
176 scm_gc_mark_dependencies (ptr);
177}
178
d09752ff 179void
7ddb9baf 180scm_i_ensure_marking (void)
d09752ff
HWN
181{
182 assert (scm_i_marking);
183}
184
c7743d02
HWN
185/*
186
187Mark the dependencies of an object.
188
33138b05 189Prefetching:
c7743d02
HWN
190
191Should prefetch objects before marking, i.e. if marking a cell, we
192should prefetch the car, and then mark the cdr. This will improve CPU
82ae1b8e 193cache misses, because the car is more likely to be in cache when we
c7743d02
HWN
194finish the cdr.
195
196See http://www.hpl.hp.com/techreports/2000/HPL-2000-99.pdf, reducing
197garbage collector cache misses.
198
199Prefetch is supported on GCC >= 3.1
200
33138b05
HWN
201(Some time later.)
202
203Tried this with GCC 3.1.1 -- the time differences are barely measurable.
204Perhaps this would work better with an explicit markstack?
205
206
207*/
06c1d900 208
c7743d02
HWN
209void
210scm_gc_mark_dependencies (SCM p)
211#define FUNC_NAME "scm_gc_mark_dependencies"
212{
213 register long i;
214 register SCM ptr;
702551e6 215 SCM cell_type;
c7743d02
HWN
216
217 ptr = p;
218 scm_mark_dependencies_again:
76da80e7 219
c7743d02
HWN
220 cell_type = SCM_GC_CELL_TYPE (ptr);
221 switch (SCM_ITAG7 (cell_type))
222 {
223 case scm_tcs_cons_nimcar:
224 if (SCM_IMP (SCM_CDR (ptr)))
225 {
226 ptr = SCM_CAR (ptr);
227 goto gc_mark_nimp;
228 }
33138b05
HWN
229
230
c7743d02
HWN
231 scm_gc_mark (SCM_CAR (ptr));
232 ptr = SCM_CDR (ptr);
233 goto gc_mark_nimp;
234 case scm_tcs_cons_imcar:
235 ptr = SCM_CDR (ptr);
236 goto gc_mark_loop;
237 case scm_tc7_pws:
33138b05 238
c7743d02
HWN
239 scm_gc_mark (SCM_SETTER (ptr));
240 ptr = SCM_PROCEDURE (ptr);
241 goto gc_mark_loop;
242 case scm_tcs_struct:
243 {
244 /* XXX - use less explicit code. */
245 scm_t_bits word0 = SCM_CELL_WORD_0 (ptr) - scm_tc3_struct;
246 scm_t_bits * vtable_data = (scm_t_bits *) word0;
247 SCM layout = SCM_PACK (vtable_data [scm_vtable_index_layout]);
eb01cb64
MV
248 long len = scm_i_symbol_length (layout);
249 const char *fields_desc = scm_i_symbol_chars (layout);
250 scm_t_bits *struct_data = (scm_t_bits *) SCM_STRUCT_DATA (ptr);
c7743d02
HWN
251
252 if (vtable_data[scm_struct_i_flags] & SCM_STRUCTF_ENTITY)
253 {
254 scm_gc_mark (SCM_PACK (struct_data[scm_struct_i_procedure]));
255 scm_gc_mark (SCM_PACK (struct_data[scm_struct_i_setter]));
256 }
257 if (len)
258 {
259 long x;
260
261 for (x = 0; x < len - 2; x += 2, ++struct_data)
262 if (fields_desc[x] == 'p')
263 scm_gc_mark (SCM_PACK (*struct_data));
264 if (fields_desc[x] == 'p')
265 {
266 if (SCM_LAYOUT_TAILP (fields_desc[x + 1]))
267 for (x = *struct_data++; x; --x, ++struct_data)
268 scm_gc_mark (SCM_PACK (*struct_data));
269 else
270 scm_gc_mark (SCM_PACK (*struct_data));
271 }
272 }
273 /* mark vtable */
274 ptr = SCM_PACK (vtable_data [scm_vtable_index_vtable]);
275 goto gc_mark_loop;
276 }
277 break;
278 case scm_tcs_closures:
279 if (SCM_IMP (SCM_ENV (ptr)))
280 {
281 ptr = SCM_CLOSCAR (ptr);
282 goto gc_mark_nimp;
283 }
284 scm_gc_mark (SCM_CLOSCAR (ptr));
285 ptr = SCM_ENV (ptr);
286 goto gc_mark_nimp;
287 case scm_tc7_vector:
4057a3e0 288 i = SCM_SIMPLE_VECTOR_LENGTH (ptr);
c7743d02
HWN
289 if (i == 0)
290 break;
291 while (--i > 0)
33138b05 292 {
4057a3e0
MV
293 SCM elt = SCM_SIMPLE_VECTOR_REF (ptr, i);
294 if (SCM_NIMP (elt))
295 scm_gc_mark (elt);
33138b05 296 }
4057a3e0 297 ptr = SCM_SIMPLE_VECTOR_REF (ptr, 0);
c7743d02
HWN
298 goto gc_mark_loop;
299#ifdef CCLO
300 case scm_tc7_cclo:
301 {
302 size_t i = SCM_CCLO_LENGTH (ptr);
303 size_t j;
304 for (j = 1; j != i; ++j)
305 {
306 SCM obj = SCM_CCLO_REF (ptr, j);
307 if (!SCM_IMP (obj))
308 scm_gc_mark (obj);
309 }
310 ptr = SCM_CCLO_REF (ptr, 0);
311 goto gc_mark_loop;
312 }
313#endif
eb01cb64 314
c7743d02 315 case scm_tc7_string:
eb01cb64
MV
316 ptr = scm_i_string_mark (ptr);
317 goto gc_mark_loop;
318 case scm_tc7_stringbuf:
319 ptr = scm_i_stringbuf_mark (ptr);
320 goto gc_mark_loop;
c7743d02 321
534c55a9 322 case scm_tc7_number:
f92e85f7
MV
323 if (SCM_TYP16 (ptr) == scm_tc16_fraction)
324 {
325 scm_gc_mark (SCM_CELL_OBJECT_1 (ptr));
326 ptr = SCM_CELL_OBJECT_2 (ptr);
327 goto gc_mark_loop;
328 }
534c55a9
DH
329 break;
330
c7743d02 331 case scm_tc7_wvect:
06c1d900 332 scm_i_mark_weak_vector (ptr);
c7743d02
HWN
333 break;
334
335 case scm_tc7_symbol:
eb01cb64 336 ptr = scm_i_symbol_mark (ptr);
c7743d02
HWN
337 goto gc_mark_loop;
338 case scm_tc7_variable:
339 ptr = SCM_CELL_OBJECT_1 (ptr);
340 goto gc_mark_loop;
341 case scm_tcs_subrs:
342 break;
343 case scm_tc7_port:
344 i = SCM_PTOBNUM (ptr);
345#if (SCM_DEBUG_CELL_ACCESSES == 1)
346 if (!(i < scm_numptob))
be3ff021
HWN
347 {
348 fprintf (stderr, "undefined port type");
1f584400 349 abort ();
be3ff021 350 }
c7743d02 351#endif
1f584400 352 if (SCM_PTAB_ENTRY (ptr))
c7743d02
HWN
353 scm_gc_mark (SCM_FILENAME (ptr));
354 if (scm_ptobs[i].mark)
355 {
356 ptr = (scm_ptobs[i].mark) (ptr);
357 goto gc_mark_loop;
358 }
359 else
360 return;
361 break;
362 case scm_tc7_smob:
363 switch (SCM_TYP16 (ptr))
364 { /* should be faster than going through scm_smobs */
365 case scm_tc_free_cell:
366 /* We have detected a free cell. This can happen if non-object data
367 * on the C stack points into guile's heap and is scanned during
368 * conservative marking. */
369 break;
c7743d02
HWN
370 default:
371 i = SCM_SMOBNUM (ptr);
372#if (SCM_DEBUG_CELL_ACCESSES == 1)
373 if (!(i < scm_numsmob))
be3ff021
HWN
374 {
375 fprintf (stderr, "undefined smob type");
1f584400 376 abort ();
be3ff021 377 }
c7743d02
HWN
378#endif
379 if (scm_smobs[i].mark)
380 {
381 ptr = (scm_smobs[i].mark) (ptr);
382 goto gc_mark_loop;
383 }
384 else
385 return;
386 }
387 break;
388 default:
be3ff021 389 fprintf (stderr, "unknown type");
1f584400 390 abort ();
c7743d02
HWN
391 }
392
393 /*
394 If we got here, then exhausted recursion options for PTR. we
395 return (careful not to mark PTR, it might be the argument that we
396 were called with.)
397 */
398 return ;
06c1d900
MV
399
400 gc_mark_loop:
c7743d02
HWN
401 if (SCM_IMP (ptr))
402 return;
403
404 gc_mark_nimp:
405 {
406 int valid_cell = CELL_P (ptr);
407
408
409#if (SCM_DEBUG_CELL_ACCESSES == 1)
410 if (scm_debug_cell_accesses_p)
411 {
412 /* We are in debug mode. Check the ptr exhaustively. */
413
40945e5e 414 valid_cell = valid_cell && scm_in_heap_p (ptr);
c7743d02
HWN
415 }
416
417#endif
418 if (!valid_cell)
be3ff021
HWN
419 {
420 fprintf (stderr, "rogue pointer in heap");
1f584400 421 abort ();
be3ff021 422 }
c7743d02 423 }
eab1b259 424
82ae1b8e 425 if (SCM_GC_MARK_P (ptr))
76da80e7 426 return;
a54a94b3 427
76da80e7 428 SCM_SET_GC_MARK (ptr);
eab1b259 429
76da80e7 430 goto scm_mark_dependencies_again;
c7743d02
HWN
431
432}
433#undef FUNC_NAME
434
435
c7743d02
HWN
436/* Mark a region conservatively */
437void
438scm_mark_locations (SCM_STACKITEM x[], unsigned long n)
439{
440 unsigned long m;
441
442 for (m = 0; m < n; ++m)
443 {
444 SCM obj = * (SCM *) &x[m];
445 long int segment = scm_i_find_heap_segment_containing_object (obj);
446 if (segment >= 0)
447 scm_gc_mark (obj);
448 }
449}
450
451
452/* The function scm_in_heap_p determines whether an SCM value can be regarded as a
453 * pointer to a cell on the heap.
454 */
455int
456scm_in_heap_p (SCM value)
457{
458 long int segment = scm_i_find_heap_segment_containing_object (value);
459 return (segment >= 0);
460}
461
462
463#if SCM_ENABLE_DEPRECATED == 1
464
465/* If an allocated cell is detected during garbage collection, this
466 * means that some code has just obtained the object but was preempted
467 * before the initialization of the object was completed. This meanst
468 * that some entries of the allocated cell may already contain SCM
469 * objects. Therefore, allocated cells are scanned conservatively.
470 */
471
472scm_t_bits scm_tc16_allocated;
473
474static SCM
475allocated_mark (SCM cell)
476{
477 unsigned long int cell_segment = scm_i_find_heap_segment_containing_object (cell);
478 unsigned int span = scm_i_heap_segment_table[cell_segment]->span;
479 unsigned int i;
480
481 for (i = 1; i != span * 2; ++i)
482 {
483 SCM obj = SCM_CELL_OBJECT (cell, i);
484 long int obj_segment = scm_i_find_heap_segment_containing_object (obj);
485 if (obj_segment >= 0)
486 scm_gc_mark (obj);
487 }
488 return SCM_BOOL_F;
489}
490
491SCM
492scm_deprecated_newcell (void)
493{
494 scm_c_issue_deprecation_warning
495 ("SCM_NEWCELL is deprecated. Use `scm_cell' instead.\n");
496
497 return scm_cell (scm_tc16_allocated, 0);
498}
499
500SCM
501scm_deprecated_newcell2 (void)
502{
503 scm_c_issue_deprecation_warning
504 ("SCM_NEWCELL2 is deprecated. Use `scm_double_cell' instead.\n");
505
506 return scm_double_cell (scm_tc16_allocated, 0, 0, 0);
507}
508
509#endif /* SCM_ENABLE_DEPRECATED == 1 */
510
511
512void
1f584400 513scm_gc_init_mark (void)
c7743d02
HWN
514{
515#if SCM_ENABLE_DEPRECATED == 1
516 scm_tc16_allocated = scm_make_smob_type ("allocated cell", 0);
517 scm_set_smob_mark (scm_tc16_allocated, allocated_mark);
518#endif
519}
520