* gc-mark.c: #include <config.h> if HAVE_CONFIG_H. Rename usage
[bpt/guile.git] / libguile / gc-mark.c
1 /* Copyright (C) 1995,1996,1997,1998,1999,2000,2001, 2002, 2003 Free Software Foundation, Inc.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2, or (at your option)
6 * any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; see the file COPYING. If not, write to
15 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16 * Boston, MA 02111-1307 USA
17 *
18 * As a special exception, the Free Software Foundation gives permission
19 * for additional uses of the text contained in its release of GUILE.
20 *
21 * The exception is that, if you link the GUILE library with other files
22 * to produce an executable, this does not by itself cause the
23 * resulting executable to be covered by the GNU General Public License.
24 * Your use of that executable is in no way restricted on account of
25 * linking the GUILE library code into it.
26 *
27 * This exception does not however invalidate any other reasons why
28 * the executable file might be covered by the GNU General Public License.
29 *
30 * This exception applies only to the code released by the
31 * Free Software Foundation under the name GUILE. If you copy
32 * code from other Free Software Foundation releases into a copy of
33 * GUILE, as the General Public License permits, the exception does
34 * not apply to the code that you add in this way. To avoid misleading
35 * anyone as to the status of such modified files, you must delete
36 * this exception notice from them.
37 *
38 * If you write modifications of your own for GUILE, it is your choice
39 * whether to permit this exception to apply to your modifications.
40 * If you do not wish that, delete this exception notice. */
41
42
43 \f
44 #if HAVE_CONFIG_H
45 # include <config.h>
46 #endif
47
48 #include <stdio.h>
49 #include <errno.h>
50 #include <string.h>
51 #include <assert.h>
52
53 #ifdef __ia64__
54 #include <ucontext.h>
55 extern unsigned long * __libc_ia64_register_backing_store_base;
56 #endif
57
58 #include "libguile/_scm.h"
59 #include "libguile/eval.h"
60 #include "libguile/stime.h"
61 #include "libguile/stackchk.h"
62 #include "libguile/struct.h"
63 #include "libguile/smob.h"
64 #include "libguile/unif.h"
65 #include "libguile/async.h"
66 #include "libguile/ports.h"
67 #include "libguile/root.h"
68 #include "libguile/strings.h"
69 #include "libguile/vectors.h"
70 #include "libguile/weaks.h"
71 #include "libguile/hashtab.h"
72 #include "libguile/tags.h"
73 #include "libguile/private-gc.h"
74 #include "libguile/validate.h"
75 #include "libguile/deprecation.h"
76 #include "libguile/gc.h"
77
78 #ifdef GUILE_DEBUG_MALLOC
79 #include "libguile/debug-malloc.h"
80 #endif
81
82 #ifdef HAVE_MALLOC_H
83 #include <malloc.h>
84 #endif
85
86 #ifdef HAVE_UNISTD_H
87 #include <unistd.h>
88 #endif
89
90 #ifdef __ia64__
91 # define SCM_MARK_BACKING_STORE() do { \
92 ucontext_t ctx; \
93 SCM_STACKITEM * top, * bot; \
94 getcontext (&ctx); \
95 scm_mark_locations ((SCM_STACKITEM *) &ctx.uc_mcontext, \
96 ((size_t) (sizeof (SCM_STACKITEM) - 1 + sizeof ctx.uc_mcontext) \
97 / sizeof (SCM_STACKITEM))); \
98 bot = (SCM_STACKITEM *) __libc_ia64_register_backing_store_base; \
99 top = (SCM_STACKITEM *) ctx.uc_mcontext.sc_ar_bsp; \
100 scm_mark_locations (bot, top - bot); } while (0)
101 #else
102 # define SCM_MARK_BACKING_STORE()
103 #endif
104
105
106 /*
107 Entry point for this file.
108 */
109 void
110 scm_mark_all (void)
111 {
112 long j;
113
114
115 scm_i_clear_mark_space ();
116
117 /* Mark every thread's stack and registers */
118 scm_threads_mark_stacks ();
119
120 j = SCM_NUM_PROTECTS;
121 while (j--)
122 scm_gc_mark (scm_sys_protects[j]);
123
124 /* mark the registered roots */
125 {
126 size_t i;
127 for (i = 0; i < SCM_HASHTABLE_N_BUCKETS (scm_gc_registered_roots); ++i)
128 {
129 SCM l = SCM_HASHTABLE_BUCKETS (scm_gc_registered_roots)[i];
130 for (; !SCM_NULLP (l); l = SCM_CDR (l))
131 {
132 SCM *p = (SCM *) (scm_num2long (SCM_CAAR (l), 0, NULL));
133 scm_gc_mark (*p);
134 }
135 }
136 }
137
138
139 /* FIXME: we should have a means to register C functions to be run
140 * in different phases of GC
141 */
142 scm_mark_subr_table ();
143 }
144
145 /* {Mark/Sweep}
146 */
147
148 /*
149 Mark an object precisely, then recurse.
150 */
151 void
152 scm_gc_mark (SCM ptr)
153 {
154 if (SCM_IMP (ptr))
155 return ;
156
157 if (SCM_GC_MARK_P (ptr))
158 {
159 return;
160 }
161
162 SCM_SET_GC_MARK (ptr);
163 scm_gc_mark_dependencies (ptr);
164 }
165
166 /*
167
168 Mark the dependencies of an object.
169
170 Prefetching:
171
172 Should prefetch objects before marking, i.e. if marking a cell, we
173 should prefetch the car, and then mark the cdr. This will improve CPU
174 cache misses, because the car is more likely to be in core when we
175 finish the cdr.
176
177 See http://www.hpl.hp.com/techreports/2000/HPL-2000-99.pdf, reducing
178 garbage collector cache misses.
179
180 Prefetch is supported on GCC >= 3.1
181
182 (Some time later.)
183
184 Tried this with GCC 3.1.1 -- the time differences are barely measurable.
185 Perhaps this would work better with an explicit markstack?
186
187
188 */
189 void
190 scm_gc_mark_dependencies (SCM p)
191 #define FUNC_NAME "scm_gc_mark_dependencies"
192 {
193 register long i;
194 register SCM ptr;
195 scm_t_bits cell_type;
196
197 ptr = p;
198 scm_mark_dependencies_again:
199
200 cell_type = SCM_GC_CELL_TYPE (ptr);
201 switch (SCM_ITAG7 (cell_type))
202 {
203 case scm_tcs_cons_nimcar:
204 if (SCM_IMP (SCM_CDR (ptr)))
205 {
206 ptr = SCM_CAR (ptr);
207 goto gc_mark_nimp;
208 }
209
210
211 scm_gc_mark (SCM_CAR (ptr));
212 ptr = SCM_CDR (ptr);
213 goto gc_mark_nimp;
214 case scm_tcs_cons_imcar:
215 ptr = SCM_CDR (ptr);
216 goto gc_mark_loop;
217 case scm_tc7_pws:
218
219 scm_gc_mark (SCM_SETTER (ptr));
220 ptr = SCM_PROCEDURE (ptr);
221 goto gc_mark_loop;
222 case scm_tcs_struct:
223 {
224 /* XXX - use less explicit code. */
225 scm_t_bits word0 = SCM_CELL_WORD_0 (ptr) - scm_tc3_struct;
226 scm_t_bits * vtable_data = (scm_t_bits *) word0;
227 SCM layout = SCM_PACK (vtable_data [scm_vtable_index_layout]);
228 long len = SCM_SYMBOL_LENGTH (layout);
229 char * fields_desc = SCM_SYMBOL_CHARS (layout);
230 scm_t_bits * struct_data = (scm_t_bits *) SCM_STRUCT_DATA (ptr);
231
232 if (vtable_data[scm_struct_i_flags] & SCM_STRUCTF_ENTITY)
233 {
234 scm_gc_mark (SCM_PACK (struct_data[scm_struct_i_procedure]));
235 scm_gc_mark (SCM_PACK (struct_data[scm_struct_i_setter]));
236 }
237 if (len)
238 {
239 long x;
240
241 for (x = 0; x < len - 2; x += 2, ++struct_data)
242 if (fields_desc[x] == 'p')
243 scm_gc_mark (SCM_PACK (*struct_data));
244 if (fields_desc[x] == 'p')
245 {
246 if (SCM_LAYOUT_TAILP (fields_desc[x + 1]))
247 for (x = *struct_data++; x; --x, ++struct_data)
248 scm_gc_mark (SCM_PACK (*struct_data));
249 else
250 scm_gc_mark (SCM_PACK (*struct_data));
251 }
252 }
253 /* mark vtable */
254 ptr = SCM_PACK (vtable_data [scm_vtable_index_vtable]);
255 goto gc_mark_loop;
256 }
257 break;
258 case scm_tcs_closures:
259 if (SCM_IMP (SCM_ENV (ptr)))
260 {
261 ptr = SCM_CLOSCAR (ptr);
262 goto gc_mark_nimp;
263 }
264 scm_gc_mark (SCM_CLOSCAR (ptr));
265 ptr = SCM_ENV (ptr);
266 goto gc_mark_nimp;
267 case scm_tc7_vector:
268 i = SCM_VECTOR_LENGTH (ptr);
269 if (i == 0)
270 break;
271 while (--i > 0)
272 {
273 if (SCM_NIMP (SCM_VELTS (ptr)[i]))
274 scm_gc_mark (SCM_VELTS (ptr)[i]);
275 }
276 ptr = SCM_VELTS (ptr)[0];
277 goto gc_mark_loop;
278 #ifdef CCLO
279 case scm_tc7_cclo:
280 {
281 size_t i = SCM_CCLO_LENGTH (ptr);
282 size_t j;
283 for (j = 1; j != i; ++j)
284 {
285 SCM obj = SCM_CCLO_REF (ptr, j);
286 if (!SCM_IMP (obj))
287 scm_gc_mark (obj);
288 }
289 ptr = SCM_CCLO_REF (ptr, 0);
290 goto gc_mark_loop;
291 }
292 #endif
293 #ifdef SCM_HAVE_ARRAYS
294 case scm_tc7_bvect:
295 case scm_tc7_byvect:
296 case scm_tc7_ivect:
297 case scm_tc7_uvect:
298 case scm_tc7_fvect:
299 case scm_tc7_dvect:
300 case scm_tc7_cvect:
301 case scm_tc7_svect:
302 #if SCM_SIZEOF_LONG_LONG != 0
303 case scm_tc7_llvect:
304 #endif
305 #endif
306 case scm_tc7_string:
307 break;
308
309 case scm_tc7_wvect:
310 SCM_SET_WVECT_GC_CHAIN (ptr, scm_weak_vectors);
311 scm_weak_vectors = ptr;
312 if (SCM_IS_WHVEC_ANY (ptr))
313 {
314 long x;
315 long len;
316 int weak_keys;
317 int weak_values;
318
319 len = SCM_VECTOR_LENGTH (ptr);
320 weak_keys = SCM_WVECT_WEAK_KEY_P (ptr);
321 weak_values = SCM_WVECT_WEAK_VALUE_P (ptr);
322
323 for (x = 0; x < len; ++x)
324 {
325 SCM alist;
326 alist = SCM_VELTS (ptr)[x];
327
328 /* mark everything on the alist except the keys or
329 * values, according to weak_values and weak_keys. */
330 while ( SCM_CONSP (alist)
331 && !SCM_GC_MARK_P (alist)
332 && SCM_CONSP (SCM_CAR (alist)))
333 {
334 SCM kvpair;
335 SCM next_alist;
336
337 kvpair = SCM_CAR (alist);
338 next_alist = SCM_CDR (alist);
339 /*
340 * Do not do this:
341 * SCM_SET_GC_MARK (alist);
342 * SCM_SET_GC_MARK (kvpair);
343 *
344 * It may be that either the key or value is protected by
345 * an escaped reference to part of the spine of this alist.
346 * If we mark the spine here, and only mark one or neither of the
347 * key and value, they may never be properly marked.
348 * This leads to a horrible situation in which an alist containing
349 * freelist cells is exported.
350 *
351 * So only mark the spines of these arrays last of all marking.
352 * If somebody confuses us by constructing a weak vector
353 * with a circular alist then we are hosed, but at least we
354 * won't prematurely drop table entries.
355 */
356 if (!weak_keys)
357 scm_gc_mark (SCM_CAR (kvpair));
358 if (!weak_values)
359 scm_gc_mark (SCM_CDR (kvpair));
360 alist = next_alist;
361 }
362 if (SCM_NIMP (alist))
363 scm_gc_mark (alist);
364 }
365 }
366 break;
367
368 case scm_tc7_symbol:
369 ptr = SCM_PROP_SLOTS (ptr);
370 goto gc_mark_loop;
371 case scm_tc7_variable:
372 ptr = SCM_CELL_OBJECT_1 (ptr);
373 goto gc_mark_loop;
374 case scm_tcs_subrs:
375 break;
376 case scm_tc7_port:
377 i = SCM_PTOBNUM (ptr);
378 #if (SCM_DEBUG_CELL_ACCESSES == 1)
379 if (!(i < scm_numptob))
380 {
381 fprintf (stderr, "undefined port type");
382 abort();
383 }
384 #endif
385 if (SCM_PTAB_ENTRY(ptr))
386 scm_gc_mark (SCM_FILENAME (ptr));
387 if (scm_ptobs[i].mark)
388 {
389 ptr = (scm_ptobs[i].mark) (ptr);
390 goto gc_mark_loop;
391 }
392 else
393 return;
394 break;
395 case scm_tc7_smob:
396 switch (SCM_TYP16 (ptr))
397 { /* should be faster than going through scm_smobs */
398 case scm_tc_free_cell:
399 /* We have detected a free cell. This can happen if non-object data
400 * on the C stack points into guile's heap and is scanned during
401 * conservative marking. */
402 break;
403 case scm_tc16_big:
404 case scm_tc16_real:
405 case scm_tc16_complex:
406 break;
407 default:
408 i = SCM_SMOBNUM (ptr);
409 #if (SCM_DEBUG_CELL_ACCESSES == 1)
410 if (!(i < scm_numsmob))
411 {
412 fprintf (stderr, "undefined smob type");
413 abort();
414 }
415 #endif
416 if (scm_smobs[i].mark)
417 {
418 ptr = (scm_smobs[i].mark) (ptr);
419 goto gc_mark_loop;
420 }
421 else
422 return;
423 }
424 break;
425 default:
426 fprintf (stderr, "unknown type");
427 abort();
428 }
429
430 /*
431 If we got here, then exhausted recursion options for PTR. we
432 return (careful not to mark PTR, it might be the argument that we
433 were called with.)
434 */
435 return ;
436
437 gc_mark_loop:
438 if (SCM_IMP (ptr))
439 return;
440
441 gc_mark_nimp:
442 {
443 int valid_cell = CELL_P (ptr);
444
445
446 #if (SCM_DEBUG_CELL_ACCESSES == 1)
447 if (scm_debug_cell_accesses_p)
448 {
449 /* We are in debug mode. Check the ptr exhaustively. */
450
451 valid_cell = valid_cell && (scm_i_find_heap_segment_containing_object (ptr) >= 0);
452 }
453
454 #endif
455 if (!valid_cell)
456 {
457 fprintf (stderr, "rogue pointer in heap");
458 abort();
459 }
460 }
461
462 if (SCM_GC_MARK_P (ptr))
463 {
464 return;
465 }
466
467 SCM_SET_GC_MARK (ptr);
468
469 goto scm_mark_dependencies_again;
470
471 }
472 #undef FUNC_NAME
473
474
475
476
477 /* Mark a region conservatively */
478 void
479 scm_mark_locations (SCM_STACKITEM x[], unsigned long n)
480 {
481 unsigned long m;
482
483 for (m = 0; m < n; ++m)
484 {
485 SCM obj = * (SCM *) &x[m];
486 long int segment = scm_i_find_heap_segment_containing_object (obj);
487 if (segment >= 0)
488 scm_gc_mark (obj);
489 }
490 }
491
492
493 /* The function scm_in_heap_p determines whether an SCM value can be regarded as a
494 * pointer to a cell on the heap.
495 */
496 int
497 scm_in_heap_p (SCM value)
498 {
499 long int segment = scm_i_find_heap_segment_containing_object (value);
500 return (segment >= 0);
501 }
502
503
504 #if SCM_ENABLE_DEPRECATED == 1
505
506 /* If an allocated cell is detected during garbage collection, this
507 * means that some code has just obtained the object but was preempted
508 * before the initialization of the object was completed. This meanst
509 * that some entries of the allocated cell may already contain SCM
510 * objects. Therefore, allocated cells are scanned conservatively.
511 */
512
513 scm_t_bits scm_tc16_allocated;
514
515 static SCM
516 allocated_mark (SCM cell)
517 {
518 unsigned long int cell_segment = scm_i_find_heap_segment_containing_object (cell);
519 unsigned int span = scm_i_heap_segment_table[cell_segment]->span;
520 unsigned int i;
521
522 for (i = 1; i != span * 2; ++i)
523 {
524 SCM obj = SCM_CELL_OBJECT (cell, i);
525 long int obj_segment = scm_i_find_heap_segment_containing_object (obj);
526 if (obj_segment >= 0)
527 scm_gc_mark (obj);
528 }
529 return SCM_BOOL_F;
530 }
531
532 SCM
533 scm_deprecated_newcell (void)
534 {
535 scm_c_issue_deprecation_warning
536 ("SCM_NEWCELL is deprecated. Use `scm_cell' instead.\n");
537
538 return scm_cell (scm_tc16_allocated, 0);
539 }
540
541 SCM
542 scm_deprecated_newcell2 (void)
543 {
544 scm_c_issue_deprecation_warning
545 ("SCM_NEWCELL2 is deprecated. Use `scm_double_cell' instead.\n");
546
547 return scm_double_cell (scm_tc16_allocated, 0, 0, 0);
548 }
549
550 #endif /* SCM_ENABLE_DEPRECATED == 1 */
551
552
553 void
554 scm_gc_init_mark(void)
555 {
556 #if SCM_ENABLE_DEPRECATED == 1
557 scm_tc16_allocated = scm_make_smob_type ("allocated cell", 0);
558 scm_set_smob_mark (scm_tc16_allocated, allocated_mark);
559 #endif
560 }
561