*** empty log message ***
[bpt/guile.git] / libguile / gc.c
CommitLineData
acb0a19c 1/* Copyright (C) 1995, 96, 97, 98, 99, 2000 Free Software Foundation, Inc.
0f2d19dd
JB
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
82892bed
JB
15 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16 * Boston, MA 02111-1307 USA
0f2d19dd
JB
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.
82892bed 40 * If you do not wish that, delete this exception notice. */
1bbd0b84
GB
41
42/* Software engineering face-lift by Greg J. Badros, 11-Dec-1999,
43 gjb@cs.washington.edu, http://www.cs.washington.edu/homes/gjb */
44
0f2d19dd
JB
45\f
46#include <stdio.h>
47#include "_scm.h"
20e6290e
JB
48#include "stime.h"
49#include "stackchk.h"
50#include "struct.h"
51#include "genio.h"
52#include "weaks.h"
0493cd89 53#include "guardians.h"
20e6290e
JB
54#include "smob.h"
55#include "unif.h"
56#include "async.h"
0f2d19dd 57
b6791b2e 58#include "validate.h"
fce59c93
JB
59#include "gc.h"
60
0f2d19dd 61#ifdef HAVE_MALLOC_H
95b88819 62#include <malloc.h>
0f2d19dd
JB
63#endif
64
65#ifdef HAVE_UNISTD_H
95b88819 66#include <unistd.h>
0f2d19dd
JB
67#endif
68
1cc91f1b
JB
69#ifdef __STDC__
70#include <stdarg.h>
71#define var_start(x, y) va_start(x, y)
72#else
73#include <varargs.h>
74#define var_start(x, y) va_start(x)
75#endif
76
0f2d19dd
JB
77\f
78/* {heap tuning parameters}
79 *
80 * These are parameters for controlling memory allocation. The heap
81 * is the area out of which scm_cons, and object headers are allocated.
82 *
83 * Each heap cell is 8 bytes on a 32 bit machine and 16 bytes on a
84 * 64 bit machine. The units of the _SIZE parameters are bytes.
85 * Cons pairs and object headers occupy one heap cell.
86 *
87 * SCM_INIT_HEAP_SIZE is the initial size of heap. If this much heap is
88 * allocated initially the heap will grow by half its current size
89 * each subsequent time more heap is needed.
90 *
91 * If SCM_INIT_HEAP_SIZE heap cannot be allocated initially, SCM_HEAP_SEG_SIZE
92 * will be used, and the heap will grow by SCM_HEAP_SEG_SIZE when more
93 * heap is needed. SCM_HEAP_SEG_SIZE must fit into type scm_sizet. This code
94 * is in scm_init_storage() and alloc_some_heap() in sys.c
95 *
96 * If SCM_INIT_HEAP_SIZE can be allocated initially, the heap will grow by
97 * SCM_EXPHEAP(scm_heap_size) when more heap is needed.
98 *
99 * SCM_MIN_HEAP_SEG_SIZE is minimum size of heap to accept when more heap
100 * is needed.
101 *
102 * INIT_MALLOC_LIMIT is the initial amount of malloc usage which will
103 * trigger a GC.
6064dcc6
MV
104 *
105 * SCM_MTRIGGER_HYSTERESIS is the amount of malloc storage that must be
106 * reclaimed by a GC triggered by must_malloc. If less than this is
107 * reclaimed, the trigger threshold is raised. [I don't know what a
108 * good value is. I arbitrarily chose 1/10 of the INIT_MALLOC_LIMIT to
109 * work around a oscillation that caused almost constant GC.]
0f2d19dd
JB
110 */
111
945fec60
MD
112#define SCM_INIT_HEAP_SIZE (40000L * sizeof (scm_cell))
113#define SCM_MIN_HEAP_SEG_SIZE (2048L * sizeof (scm_cell))
0f2d19dd
JB
114#ifdef _QC
115# define SCM_HEAP_SEG_SIZE 32768L
116#else
117# ifdef sequent
118# define SCM_HEAP_SEG_SIZE (7000L*sizeof(scm_cell))
119# else
120# define SCM_HEAP_SEG_SIZE (16384L*sizeof(scm_cell))
121# endif
122#endif
4a4c9785 123#define SCM_EXPHEAP(scm_heap_size) (scm_heap_size / 2)
0f2d19dd 124#define SCM_INIT_MALLOC_LIMIT 100000
6064dcc6 125#define SCM_MTRIGGER_HYSTERESIS (SCM_INIT_MALLOC_LIMIT/10)
0f2d19dd 126
4a4c9785
MD
127#define SCM_GC_TRIGGER 10000
128#define SCM_GC_TRIGGER2 10000
129
0f2d19dd
JB
130/* CELL_UP and CELL_DN are used by scm_init_heap_seg to find scm_cell aligned inner
131 bounds for allocated storage */
132
133#ifdef PROT386
134/*in 386 protected mode we must only adjust the offset */
135# define CELL_UP(p) MK_FP(FP_SEG(p), ~7&(FP_OFF(p)+7))
136# define CELL_DN(p) MK_FP(FP_SEG(p), ~7&FP_OFF(p))
137#else
138# ifdef _UNICOS
139# define CELL_UP(p) (SCM_CELLPTR)(~1L & ((long)(p)+1L))
140# define CELL_DN(p) (SCM_CELLPTR)(~1L & (long)(p))
141# else
142# define CELL_UP(p) (SCM_CELLPTR)(~(sizeof(scm_cell)-1L) & ((long)(p)+sizeof(scm_cell)-1L))
143# define CELL_DN(p) (SCM_CELLPTR)(~(sizeof(scm_cell)-1L) & (long)(p))
144# endif /* UNICOS */
145#endif /* PROT386 */
146
147
148\f
945fec60 149/* scm_freelists
0f2d19dd 150 */
945fec60 151
4a4c9785
MD
152#ifdef GUILE_NEW_GC_SCHEME
153SCM scm_freelist = SCM_EOL;
154scm_freelist_t scm_master_freelist = {
dd45c0df 155 SCM_EOL, 0, SCM_EOL, SCM_EOL, 0, 0, 1, 0, 0
4a4c9785
MD
156};
157SCM scm_freelist2 = SCM_EOL;
158scm_freelist_t scm_master_freelist2 = {
dd45c0df 159 SCM_EOL, 0, SCM_EOL, SCM_EOL, 0, 0, 2, 0, 0
4a4c9785
MD
160};
161#else
945fec60
MD
162scm_freelist_t scm_freelist = { SCM_EOL, 1, 0, 0 };
163scm_freelist_t scm_freelist2 = { SCM_EOL, 2, 0, 0 };
4a4c9785 164#endif
0f2d19dd
JB
165
166/* scm_mtrigger
167 * is the number of bytes of must_malloc allocation needed to trigger gc.
168 */
15e9d186 169unsigned long scm_mtrigger;
0f2d19dd
JB
170
171
172/* scm_gc_heap_lock
173 * If set, don't expand the heap. Set only during gc, during which no allocation
174 * is supposed to take place anyway.
175 */
176int scm_gc_heap_lock = 0;
177
178/* GC Blocking
179 * Don't pause for collection if this is set -- just
180 * expand the heap.
181 */
182
183int scm_block_gc = 1;
184
185/* If fewer than MIN_GC_YIELD cells are recovered during a garbage
186 * collection (GC) more space is allocated for the heap.
187 */
945fec60 188#define MIN_GC_YIELD(freelist) (freelist->heap_size / 4)
0f2d19dd
JB
189
190/* During collection, this accumulates objects holding
191 * weak references.
192 */
ab4bef85 193SCM scm_weak_vectors;
0f2d19dd
JB
194
195/* GC Statistics Keeping
196 */
197unsigned long scm_cells_allocated = 0;
a5c314c8 198long scm_mallocated = 0;
945fec60 199/* unsigned long scm_gc_cells_collected; */
0f2d19dd
JB
200unsigned long scm_gc_malloc_collected;
201unsigned long scm_gc_ports_collected;
202unsigned long scm_gc_rt;
203unsigned long scm_gc_time_taken = 0;
204
205SCM_SYMBOL (sym_cells_allocated, "cells-allocated");
206SCM_SYMBOL (sym_heap_size, "cell-heap-size");
207SCM_SYMBOL (sym_mallocated, "bytes-malloced");
208SCM_SYMBOL (sym_mtrigger, "gc-malloc-threshold");
209SCM_SYMBOL (sym_heap_segments, "cell-heap-segments");
210SCM_SYMBOL (sym_gc_time_taken, "gc-time-taken");
211
212
213struct scm_heap_seg_data
214{
cf2d30f6
JB
215 /* lower and upper bounds of the segment */
216 SCM_CELLPTR bounds[2];
217
218 /* address of the head-of-freelist pointer for this segment's cells.
219 All segments usually point to the same one, scm_freelist. */
945fec60 220 scm_freelist_t *freelistp;
cf2d30f6
JB
221
222 /* number of SCM words per object in this segment */
945fec60 223 int span;
cf2d30f6
JB
224
225 /* If SEG_DATA->valid is non-zero, the conservative marking
226 functions will apply SEG_DATA->valid to the purported pointer and
227 SEG_DATA, and mark the object iff the function returns non-zero.
228 At the moment, I don't think anyone uses this. */
0f2d19dd
JB
229 int (*valid) ();
230};
231
232
233
234
945fec60
MD
235static void scm_mark_weak_vector_spines (void);
236static scm_sizet init_heap_seg (SCM_CELLPTR, scm_sizet, scm_freelist_t *);
237static void alloc_some_heap (scm_freelist_t *);
0f2d19dd
JB
238
239
240\f
cf2d30f6
JB
241/* Debugging functions. */
242
fca7547b 243#ifdef GUILE_DEBUG_FREELIST
cf2d30f6
JB
244
245/* Return the number of the heap segment containing CELL. */
246static int
247which_seg (SCM cell)
248{
249 int i;
250
251 for (i = 0; i < scm_n_heap_segs; i++)
252 if (SCM_PTR_LE (scm_heap_table[i].bounds[0], (SCM_CELLPTR) cell)
253 && SCM_PTR_GT (scm_heap_table[i].bounds[1], (SCM_CELLPTR) cell))
254 return i;
255 fprintf (stderr, "which_seg: can't find segment containing cell %lx\n",
945fec60 256 SCM_UNPACK (cell));
cf2d30f6
JB
257 abort ();
258}
259
260
8ded62a3
MD
261#ifdef GUILE_NEW_GC_SCHEME
262static void
263map_free_list (scm_freelist_t *master, SCM freelist)
264{
265 int last_seg = -1, count = 0;
266 SCM f;
267
268 for (f = freelist; SCM_NIMP (f); f = SCM_CDR (f))
269 {
270 int this_seg = which_seg (f);
271
272 if (this_seg != last_seg)
273 {
274 if (last_seg != -1)
275 fprintf (stderr, " %5d %d-cells in segment %d\n",
276 count, master->span, last_seg);
277 last_seg = this_seg;
278 count = 0;
279 }
280 count++;
281 }
282 if (last_seg != -1)
283 fprintf (stderr, " %5d %d-cells in segment %d\n",
284 count, master->span, last_seg);
285}
286#else
acb0a19c 287static void
945fec60 288map_free_list (scm_freelist_t *freelistp)
cf2d30f6
JB
289{
290 int last_seg = -1, count = 0;
291 SCM f;
292
945fec60 293 for (f = freelistp->cells; SCM_NIMP (f); f = SCM_CDR (f))
cf2d30f6
JB
294 {
295 int this_seg = which_seg (f);
296
297 if (this_seg != last_seg)
298 {
299 if (last_seg != -1)
acb0a19c 300 fprintf (stderr, " %5d %d-cells in segment %d\n",
945fec60 301 count, freelistp->span, last_seg);
cf2d30f6
JB
302 last_seg = this_seg;
303 count = 0;
304 }
305 count++;
306 }
307 if (last_seg != -1)
acb0a19c 308 fprintf (stderr, " %5d %d-cells in segment %d\n",
945fec60 309 count, freelistp->span, last_seg);
acb0a19c 310}
8ded62a3 311#endif
cf2d30f6 312
acb0a19c
MD
313SCM_DEFINE (scm_map_free_list, "map-free-list", 0, 0, 0,
314 (),
315 "Print debugging information about the free-list.\n"
316 "`map-free-list' is only included in GUILE_DEBUG_FREELIST builds of Guile.")
317#define FUNC_NAME s_scm_map_free_list
318{
319 fprintf (stderr, "%d segments total\n", scm_n_heap_segs);
4a4c9785 320#ifdef GUILE_NEW_GC_SCHEME
8ded62a3
MD
321 map_free_list (&scm_master_freelist, scm_freelist);
322 map_free_list (&scm_master_freelist2, scm_freelist2);
4a4c9785 323#else
945fec60
MD
324 map_free_list (&scm_freelist);
325 map_free_list (&scm_freelist2);
4a4c9785 326#endif
cf2d30f6
JB
327 fflush (stderr);
328
329 return SCM_UNSPECIFIED;
330}
1bbd0b84 331#undef FUNC_NAME
cf2d30f6
JB
332
333
334/* Number of calls to SCM_NEWCELL since startup. */
335static unsigned long scm_newcell_count;
acb0a19c 336static unsigned long scm_newcell2_count;
cf2d30f6
JB
337
338/* Search freelist for anything that isn't marked as a free cell.
339 Abort if we find something. */
8ded62a3
MD
340#ifdef GUILE_NEW_GC_SCHEME
341static void
342scm_check_freelist (SCM freelist)
343{
344 SCM f;
345 int i = 0;
346
347 for (f = freelist; SCM_NIMP (f); f = SCM_CDR (f), i++)
348 if (SCM_CAR (f) != (SCM) scm_tc_free_cell)
349 {
350 fprintf (stderr, "Bad cell in freelist on newcell %lu: %d'th elt\n",
351 scm_newcell_count, i);
352 fflush (stderr);
353 abort ();
354 }
355}
356#else
cf2d30f6 357static void
945fec60 358scm_check_freelist (scm_freelist_t *freelistp)
cf2d30f6
JB
359{
360 SCM f;
361 int i = 0;
362
945fec60 363 for (f = freelistp->cells; SCM_NIMP (f); f = SCM_CDR (f), i++)
cf2d30f6
JB
364 if (SCM_CAR (f) != (SCM) scm_tc_free_cell)
365 {
366 fprintf (stderr, "Bad cell in freelist on newcell %lu: %d'th elt\n",
367 scm_newcell_count, i);
368 fflush (stderr);
369 abort ();
370 }
371}
8ded62a3 372#endif
cf2d30f6
JB
373
374static int scm_debug_check_freelist = 0;
25748c78 375
a1ec6916 376SCM_DEFINE (scm_gc_set_debug_check_freelist_x, "gc-set-debug-check-freelist!", 1, 0, 0,
1bbd0b84 377 (SCM flag),
da4a1dba
GB
378 "If FLAG is #t, check the freelist for consistency on each cell allocation.\n"
379 "This procedure only exists because the GUILE_DEBUG_FREELIST \n"
380 "compile-time flag was selected.\n")
1bbd0b84 381#define FUNC_NAME s_scm_gc_set_debug_check_freelist_x
25748c78 382{
945fec60 383 SCM_VALIDATE_BOOL_COPY (1, flag, scm_debug_check_freelist);
25748c78
GB
384 return SCM_UNSPECIFIED;
385}
1bbd0b84 386#undef FUNC_NAME
25748c78
GB
387
388
4a4c9785
MD
389#ifdef GUILE_NEW_GC_SCHEME
390
391SCM
392scm_debug_newcell (void)
393{
394 SCM new;
395
396 scm_newcell_count++;
397 if (scm_debug_check_freelist)
398 {
8ded62a3 399 scm_check_freelist (scm_freelist);
4a4c9785
MD
400 scm_gc();
401 }
402
403 /* The rest of this is supposed to be identical to the SCM_NEWCELL
404 macro. */
405 if (SCM_IMP (scm_freelist))
406 new = scm_gc_for_newcell (&scm_master_freelist, &scm_freelist);
407 else
408 {
409 new = scm_freelist;
410 scm_freelist = SCM_CDR (scm_freelist);
411 SCM_SETCAR (new, scm_tc16_allocated);
412 }
413
414 return new;
415}
416
417SCM
418scm_debug_newcell2 (void)
419{
420 SCM new;
421
422 scm_newcell2_count++;
423 if (scm_debug_check_freelist)
424 {
8ded62a3 425 scm_check_freelist (scm_freelist2);
4a4c9785
MD
426 scm_gc ();
427 }
428
429 /* The rest of this is supposed to be identical to the SCM_NEWCELL
430 macro. */
431 if (SCM_IMP (scm_freelist2))
432 new = scm_gc_for_newcell (&scm_master_freelist2, &scm_freelist2);
433 else
434 {
435 new = scm_freelist2;
436 scm_freelist2 = SCM_CDR (scm_freelist2);
437 SCM_SETCAR (new, scm_tc16_allocated);
438 }
439
440 return new;
441}
442
443#else /* GUILE_NEW_GC_SCHEME */
444
f2333166
JB
445SCM
446scm_debug_newcell (void)
cf2d30f6 447{
f2333166
JB
448 SCM new;
449
cf2d30f6 450 scm_newcell_count++;
945fec60
MD
451 if (scm_debug_check_freelist)
452 {
453 scm_check_freelist (&scm_freelist);
454 scm_gc();
455 }
cf2d30f6
JB
456
457 /* The rest of this is supposed to be identical to the SCM_NEWCELL
458 macro. */
945fec60
MD
459 if (SCM_IMP (scm_freelist.cells))
460 new = scm_gc_for_newcell (&scm_freelist);
cf2d30f6
JB
461 else
462 {
945fec60
MD
463 new = scm_freelist.cells;
464 scm_freelist.cells = SCM_CDR (scm_freelist.cells);
d9de3881 465 SCM_SETCAR (new, scm_tc16_allocated);
cf2d30f6
JB
466 ++scm_cells_allocated;
467 }
f2333166
JB
468
469 return new;
cf2d30f6
JB
470}
471
acb0a19c
MD
472SCM
473scm_debug_newcell2 (void)
474{
475 SCM new;
476
477 scm_newcell2_count++;
478 if (scm_debug_check_freelist) {
945fec60 479 scm_check_freelist (&scm_freelist2);
acb0a19c
MD
480 scm_gc();
481 }
482
483 /* The rest of this is supposed to be identical to the SCM_NEWCELL2
484 macro. */
945fec60
MD
485 if (SCM_IMP (scm_freelist2.cells))
486 new = scm_gc_for_newcell (&scm_freelist2);
acb0a19c
MD
487 else
488 {
945fec60
MD
489 new = scm_freelist2.cells;
490 scm_freelist2.cells = SCM_CDR (scm_freelist2.cells);
acb0a19c
MD
491 SCM_SETCAR (new, scm_tc16_allocated);
492 scm_cells_allocated += 2;
493 }
494
495 return new;
496}
497
4a4c9785 498#endif /* GUILE_NEW_GC_SCHEME */
fca7547b 499#endif /* GUILE_DEBUG_FREELIST */
cf2d30f6
JB
500
501\f
0f2d19dd
JB
502
503/* {Scheme Interface to GC}
504 */
505
a1ec6916 506SCM_DEFINE (scm_gc_stats, "gc-stats", 0, 0, 0,
1bbd0b84 507 (),
b380b885 508 "Returns an association list of statistics about Guile's current use of storage. ")
1bbd0b84 509#define FUNC_NAME s_scm_gc_stats
0f2d19dd
JB
510{
511 int i;
512 int n;
513 SCM heap_segs;
c209c88e
GB
514 long int local_scm_mtrigger;
515 long int local_scm_mallocated;
516 long int local_scm_heap_size;
517 long int local_scm_cells_allocated;
518 long int local_scm_gc_time_taken;
0f2d19dd
JB
519 SCM answer;
520
521 SCM_DEFER_INTS;
522 scm_block_gc = 1;
523 retry:
524 heap_segs = SCM_EOL;
525 n = scm_n_heap_segs;
526 for (i = scm_n_heap_segs; i--; )
527 heap_segs = scm_cons (scm_cons (scm_ulong2num ((unsigned long)scm_heap_table[i].bounds[1]),
528 scm_ulong2num ((unsigned long)scm_heap_table[i].bounds[0])),
529 heap_segs);
530 if (scm_n_heap_segs != n)
531 goto retry;
532 scm_block_gc = 0;
533
c209c88e 534 /// ? ?? ?
0f2d19dd
JB
535 local_scm_mtrigger = scm_mtrigger;
536 local_scm_mallocated = scm_mallocated;
4a4c9785
MD
537#ifdef GUILE_NEW_GC_SCHEME
538 local_scm_heap_size = scm_master_freelist.heap_size; /*fixme*/
539#else
945fec60 540 local_scm_heap_size = scm_freelist.heap_size; /*fixme*/
4a4c9785 541#endif
0f2d19dd
JB
542 local_scm_cells_allocated = scm_cells_allocated;
543 local_scm_gc_time_taken = scm_gc_time_taken;
544
545 answer = scm_listify (scm_cons (sym_gc_time_taken, scm_ulong2num (local_scm_gc_time_taken)),
546 scm_cons (sym_cells_allocated, scm_ulong2num (local_scm_cells_allocated)),
547 scm_cons (sym_heap_size, scm_ulong2num (local_scm_heap_size)),
548 scm_cons (sym_mallocated, scm_ulong2num (local_scm_mallocated)),
549 scm_cons (sym_mtrigger, scm_ulong2num (local_scm_mtrigger)),
550 scm_cons (sym_heap_segments, heap_segs),
551 SCM_UNDEFINED);
552 SCM_ALLOW_INTS;
553 return answer;
554}
1bbd0b84 555#undef FUNC_NAME
0f2d19dd
JB
556
557
0f2d19dd 558void
6e8d25a6 559scm_gc_start (const char *what)
0f2d19dd
JB
560{
561 scm_gc_rt = SCM_INUM (scm_get_internal_run_time ());
945fec60 562 /* scm_gc_cells_collected = 0; */
0f2d19dd
JB
563 scm_gc_malloc_collected = 0;
564 scm_gc_ports_collected = 0;
565}
566
0f2d19dd
JB
567void
568scm_gc_end ()
0f2d19dd
JB
569{
570 scm_gc_rt = SCM_INUM (scm_get_internal_run_time ()) - scm_gc_rt;
c209c88e 571 scm_gc_time_taken += scm_gc_rt;
9ea54cc6 572 scm_system_async_mark (scm_gc_async);
0f2d19dd
JB
573}
574
575
a1ec6916 576SCM_DEFINE (scm_object_address, "object-address", 1, 0, 0,
1bbd0b84 577 (SCM obj),
b380b885
MD
578 "Return an integer that for the lifetime of @var{obj} is uniquely\n"
579 "returned by this function for @var{obj}")
1bbd0b84 580#define FUNC_NAME s_scm_object_address
0f2d19dd 581{
acb0a19c 582 return scm_ulong2num ((unsigned long) obj);
0f2d19dd 583}
1bbd0b84 584#undef FUNC_NAME
0f2d19dd
JB
585
586
3b3b36dd 587SCM_DEFINE (scm_gc, "gc", 0, 0, 0,
1bbd0b84 588 (),
b380b885
MD
589 "Scans all of SCM objects and reclaims for further use those that are\n"
590 "no longer accessible.")
1bbd0b84 591#define FUNC_NAME s_scm_gc
0f2d19dd
JB
592{
593 SCM_DEFER_INTS;
594 scm_igc ("call");
595 SCM_ALLOW_INTS;
596 return SCM_UNSPECIFIED;
597}
1bbd0b84 598#undef FUNC_NAME
0f2d19dd
JB
599
600
601\f
602/* {C Interface For When GC is Triggered}
603 */
604
4a4c9785
MD
605#ifdef GUILE_NEW_GC_SCHEME
606
607/* When we get POSIX threads support, the master will be global and
608 common while the freelist will be individual for each thread. */
609
610SCM
611scm_gc_for_newcell (scm_freelist_t *master, SCM *freelist)
612{
613 SCM cell;
614 ++scm_ints_disabled;
615 if (master->triggeredp)
616 scm_igc ("cells");
617 else if (SCM_NULLP (master->clusters))
618 alloc_some_heap (master);
dd45c0df 619 else if (SCM_NULLP (SCM_CDR (master->clusters)))
4a4c9785
MD
620 /* we are satisfied; GC instead of alloc next time around */
621 master->triggeredp = 1;
622 --scm_ints_disabled;
623 cell = SCM_CAR (master->clusters);
624 master->clusters = SCM_CDR (master->clusters);
625 *freelist = SCM_CDR (cell);
626 SCM_SETCAR (cell, scm_tc16_allocated);
627 return cell;
628}
629
630#else /* GUILE_NEW_GC_SCHEME */
631
0f2d19dd 632void
945fec60 633scm_gc_for_alloc (scm_freelist_t *freelistp)
0f2d19dd
JB
634{
635 SCM_REDEFER_INTS;
636 scm_igc ("cells");
945fec60 637#ifdef GUILE_DEBUG_FREELIST
acb0a19c 638 fprintf (stderr, "Collected: %d, min_yield: %d\n",
945fec60 639 freelistp->collected, MIN_GC_YIELD (freelistp));
acb0a19c 640#endif
945fec60
MD
641 if ((freelistp->collected < MIN_GC_YIELD (freelistp))
642 || SCM_IMP (freelistp->cells))
643 alloc_some_heap (freelistp);
0f2d19dd
JB
644 SCM_REALLOW_INTS;
645}
646
647
0f2d19dd 648SCM
945fec60 649scm_gc_for_newcell (scm_freelist_t *freelistp)
0f2d19dd
JB
650{
651 SCM fl;
945fec60
MD
652 scm_gc_for_alloc (freelistp);
653 fl = freelistp->cells;
654 freelistp->cells = SCM_CDR (fl);
acb0a19c 655 SCM_SETCAR (fl, scm_tc16_allocated);
0f2d19dd
JB
656 return fl;
657}
658
4a4c9785
MD
659#endif /* GUILE_NEW_GC_SCHEME */
660
0f2d19dd 661void
1bbd0b84 662scm_igc (const char *what)
0f2d19dd
JB
663{
664 int j;
665
42db06f0
MD
666#ifdef USE_THREADS
667 /* During the critical section, only the current thread may run. */
668 SCM_THREAD_CRITICAL_SECTION_START;
669#endif
670
e242dfd2 671 /* fprintf (stderr, "gc: %s\n", what); */
c68296f8 672
ab4bef85
JB
673 scm_gc_start (what);
674
675 if (!scm_stack_base || scm_block_gc)
676 {
677 scm_gc_end ();
678 return;
679 }
680
a5c314c8
JB
681 if (scm_mallocated < 0)
682 /* The byte count of allocated objects has underflowed. This is
683 probably because you forgot to report the sizes of objects you
684 have allocated, by calling scm_done_malloc or some such. When
685 the GC freed them, it subtracted their size from
686 scm_mallocated, which underflowed. */
687 abort ();
c45acc34 688
ab4bef85
JB
689 if (scm_gc_heap_lock)
690 /* We've invoked the collector while a GC is already in progress.
691 That should never happen. */
692 abort ();
0f2d19dd
JB
693
694 ++scm_gc_heap_lock;
ab4bef85
JB
695
696 scm_weak_vectors = SCM_EOL;
0f2d19dd 697
0493cd89
MD
698 scm_guardian_gc_init ();
699
0f2d19dd
JB
700 /* unprotect any struct types with no instances */
701#if 0
702 {
703 SCM type_list;
704 SCM * pos;
705
706 pos = &scm_type_obj_list;
707 type_list = scm_type_obj_list;
708 while (type_list != SCM_EOL)
709 if (SCM_VELTS (SCM_CAR (type_list))[scm_struct_i_refcnt])
710 {
24e68a57 711 pos = SCM_CDRLOC (type_list);
0f2d19dd
JB
712 type_list = SCM_CDR (type_list);
713 }
714 else
715 {
716 *pos = SCM_CDR (type_list);
717 type_list = SCM_CDR (type_list);
718 }
719 }
720#endif
721
722 /* flush dead entries from the continuation stack */
723 {
724 int x;
725 int bound;
726 SCM * elts;
727 elts = SCM_VELTS (scm_continuation_stack);
728 bound = SCM_LENGTH (scm_continuation_stack);
729 x = SCM_INUM (scm_continuation_stack_ptr);
730 while (x < bound)
731 {
732 elts[x] = SCM_BOOL_F;
733 ++x;
734 }
735 }
736
42db06f0
MD
737#ifndef USE_THREADS
738
0f2d19dd
JB
739 /* Protect from the C stack. This must be the first marking
740 * done because it provides information about what objects
741 * are "in-use" by the C code. "in-use" objects are those
742 * for which the values from SCM_LENGTH and SCM_CHARS must remain
743 * usable. This requirement is stricter than a liveness
744 * requirement -- in particular, it constrains the implementation
745 * of scm_vector_set_length_x.
746 */
747 SCM_FLUSH_REGISTER_WINDOWS;
748 /* This assumes that all registers are saved into the jmp_buf */
749 setjmp (scm_save_regs_gc_mark);
750 scm_mark_locations ((SCM_STACKITEM *) scm_save_regs_gc_mark,
ce4a361d
JB
751 ( (scm_sizet) (sizeof (SCM_STACKITEM) - 1 +
752 sizeof scm_save_regs_gc_mark)
753 / sizeof (SCM_STACKITEM)));
0f2d19dd
JB
754
755 {
756 /* stack_len is long rather than scm_sizet in order to guarantee that
757 &stack_len is long aligned */
758#ifdef SCM_STACK_GROWS_UP
759#ifdef nosve
760 long stack_len = (SCM_STACKITEM *) (&stack_len) - scm_stack_base;
761#else
762 long stack_len = scm_stack_size (scm_stack_base);
763#endif
764 scm_mark_locations (scm_stack_base, (scm_sizet) stack_len);
765#else
766#ifdef nosve
767 long stack_len = scm_stack_base - (SCM_STACKITEM *) (&stack_len);
768#else
769 long stack_len = scm_stack_size (scm_stack_base);
770#endif
771 scm_mark_locations ((scm_stack_base - stack_len), (scm_sizet) stack_len);
772#endif
773 }
774
42db06f0
MD
775#else /* USE_THREADS */
776
777 /* Mark every thread's stack and registers */
945fec60 778 scm_threads_mark_stacks ();
42db06f0
MD
779
780#endif /* USE_THREADS */
0f2d19dd
JB
781
782 /* FIXME: insert a phase to un-protect string-data preserved
783 * in scm_vector_set_length_x.
784 */
785
786 j = SCM_NUM_PROTECTS;
787 while (j--)
788 scm_gc_mark (scm_sys_protects[j]);
789
9de33deb
MD
790 /* FIXME: we should have a means to register C functions to be run
791 * in different phases of GC
792 */
793 scm_mark_subr_table ();
794
42db06f0
MD
795#ifndef USE_THREADS
796 scm_gc_mark (scm_root->handle);
797#endif
0f2d19dd
JB
798
799 scm_mark_weak_vector_spines ();
800
0493cd89
MD
801 scm_guardian_zombify ();
802
0f2d19dd
JB
803 scm_gc_sweep ();
804
805 --scm_gc_heap_lock;
806 scm_gc_end ();
42db06f0
MD
807
808#ifdef USE_THREADS
809 SCM_THREAD_CRITICAL_SECTION_END;
810#endif
0f2d19dd
JB
811}
812
813\f
814/* {Mark/Sweep}
815 */
816
817
818
819/* Mark an object precisely.
820 */
0f2d19dd 821void
1bbd0b84 822scm_gc_mark (SCM p)
0f2d19dd
JB
823{
824 register long i;
825 register SCM ptr;
826
827 ptr = p;
828
829gc_mark_loop:
830 if (SCM_IMP (ptr))
831 return;
832
833gc_mark_nimp:
834 if (SCM_NCELLP (ptr))
f8392303 835 scm_wta (ptr, "rogue pointer in heap", NULL);
0f2d19dd
JB
836
837 switch (SCM_TYP7 (ptr))
838 {
839 case scm_tcs_cons_nimcar:
840 if (SCM_GCMARKP (ptr))
841 break;
842 SCM_SETGCMARK (ptr);
843 if (SCM_IMP (SCM_CDR (ptr))) /* SCM_IMP works even with a GC mark */
844 {
845 ptr = SCM_CAR (ptr);
846 goto gc_mark_nimp;
847 }
848 scm_gc_mark (SCM_CAR (ptr));
849 ptr = SCM_GCCDR (ptr);
850 goto gc_mark_nimp;
851 case scm_tcs_cons_imcar:
acb0a19c
MD
852 if (SCM_GCMARKP (ptr))
853 break;
854 SCM_SETGCMARK (ptr);
855 ptr = SCM_GCCDR (ptr);
856 goto gc_mark_loop;
e641afaf 857 case scm_tc7_pws:
0f2d19dd
JB
858 if (SCM_GCMARKP (ptr))
859 break;
860 SCM_SETGCMARK (ptr);
acb0a19c 861 scm_gc_mark (SCM_CELL_WORD (ptr, 2));
0f2d19dd
JB
862 ptr = SCM_GCCDR (ptr);
863 goto gc_mark_loop;
864 case scm_tcs_cons_gloc:
865 if (SCM_GCMARKP (ptr))
866 break;
867 SCM_SETGCMARK (ptr);
868 {
869 SCM vcell;
870 vcell = SCM_CAR (ptr) - 1L;
f1267706 871 switch (SCM_UNPACK (SCM_CDR (vcell)))
0f2d19dd
JB
872 {
873 default:
874 scm_gc_mark (vcell);
875 ptr = SCM_GCCDR (ptr);
876 goto gc_mark_loop;
877 case 1: /* ! */
878 case 0: /* ! */
879 {
880 SCM layout;
881 SCM * vtable_data;
882 int len;
883 char * fields_desc;
ad75306c
MD
884 register SCM * mem;
885 register int x;
0f2d19dd
JB
886
887 vtable_data = (SCM *)vcell;
4bfdf158 888 layout = vtable_data[scm_vtable_index_layout];
0f2d19dd
JB
889 len = SCM_LENGTH (layout);
890 fields_desc = SCM_CHARS (layout);
14d1400f
JB
891 /* We're using SCM_GCCDR here like STRUCT_DATA, except
892 that it removes the mark */
893 mem = (SCM *)SCM_GCCDR (ptr);
0f2d19dd 894
f1267706 895 if (SCM_UNPACK (vtable_data[scm_struct_i_flags]) & SCM_STRUCTF_ENTITY)
aa0761ec 896 {
73e10adf 897 scm_gc_mark (mem[scm_struct_i_procedure]);
e641afaf 898 scm_gc_mark (mem[scm_struct_i_setter]);
aa0761ec 899 }
ad75306c
MD
900 if (len)
901 {
902 for (x = 0; x < len - 2; x += 2, ++mem)
903 if (fields_desc[x] == 'p')
904 scm_gc_mark (*mem);
905 if (fields_desc[x] == 'p')
906 {
c209c88e 907 int j;
ad75306c 908 if (SCM_LAYOUT_TAILP (fields_desc[x + 1]))
c209c88e 909 for (j = (long int) *mem; x; --x)
ad75306c
MD
910 scm_gc_mark (*++mem);
911 else
912 scm_gc_mark (*mem);
913 }
914 }
0f2d19dd
JB
915 if (!SCM_CDR (vcell))
916 {
917 SCM_SETGCMARK (vcell);
4bfdf158 918 ptr = vtable_data[scm_vtable_index_vtable];
0f2d19dd
JB
919 goto gc_mark_loop;
920 }
921 }
922 }
923 }
924 break;
925 case scm_tcs_closures:
926 if (SCM_GCMARKP (ptr))
927 break;
928 SCM_SETGCMARK (ptr);
929 if (SCM_IMP (SCM_CDR (ptr)))
930 {
931 ptr = SCM_CLOSCAR (ptr);
932 goto gc_mark_nimp;
933 }
934 scm_gc_mark (SCM_CLOSCAR (ptr));
935 ptr = SCM_GCCDR (ptr);
936 goto gc_mark_nimp;
937 case scm_tc7_vector:
938 case scm_tc7_lvector:
939#ifdef CCLO
940 case scm_tc7_cclo:
941#endif
942 if (SCM_GC8MARKP (ptr))
943 break;
944 SCM_SETGC8MARK (ptr);
945 i = SCM_LENGTH (ptr);
946 if (i == 0)
947 break;
948 while (--i > 0)
949 if (SCM_NIMP (SCM_VELTS (ptr)[i]))
950 scm_gc_mark (SCM_VELTS (ptr)[i]);
951 ptr = SCM_VELTS (ptr)[0];
952 goto gc_mark_loop;
953 case scm_tc7_contin:
954 if SCM_GC8MARKP
955 (ptr) break;
956 SCM_SETGC8MARK (ptr);
c68296f8 957 if (SCM_VELTS (ptr))
41b0806d 958 scm_mark_locations (SCM_VELTS_AS_STACKITEMS (ptr),
c68296f8
MV
959 (scm_sizet)
960 (SCM_LENGTH (ptr) +
961 (sizeof (SCM_STACKITEM) + -1 +
962 sizeof (scm_contregs)) /
963 sizeof (SCM_STACKITEM)));
0f2d19dd 964 break;
afe5177e 965#ifdef HAVE_ARRAYS
0f2d19dd
JB
966 case scm_tc7_bvect:
967 case scm_tc7_byvect:
968 case scm_tc7_ivect:
969 case scm_tc7_uvect:
970 case scm_tc7_fvect:
971 case scm_tc7_dvect:
972 case scm_tc7_cvect:
973 case scm_tc7_svect:
5c11cc9d 974#ifdef HAVE_LONG_LONGS
0f2d19dd
JB
975 case scm_tc7_llvect:
976#endif
afe5177e 977#endif
0f2d19dd 978 case scm_tc7_string:
0f2d19dd
JB
979 SCM_SETGC8MARK (ptr);
980 break;
981
982 case scm_tc7_substring:
0f2d19dd
JB
983 if (SCM_GC8MARKP(ptr))
984 break;
985 SCM_SETGC8MARK (ptr);
986 ptr = SCM_CDR (ptr);
987 goto gc_mark_loop;
988
989 case scm_tc7_wvect:
990 if (SCM_GC8MARKP(ptr))
991 break;
ab4bef85
JB
992 SCM_WVECT_GC_CHAIN (ptr) = scm_weak_vectors;
993 scm_weak_vectors = ptr;
0f2d19dd
JB
994 SCM_SETGC8MARK (ptr);
995 if (SCM_IS_WHVEC_ANY (ptr))
996 {
997 int x;
998 int len;
999 int weak_keys;
1000 int weak_values;
1001
1002 len = SCM_LENGTH (ptr);
1003 weak_keys = SCM_IS_WHVEC (ptr) || SCM_IS_WHVEC_B (ptr);
1004 weak_values = SCM_IS_WHVEC_V (ptr) || SCM_IS_WHVEC_B (ptr);
1005
1006 for (x = 0; x < len; ++x)
1007 {
1008 SCM alist;
1009 alist = SCM_VELTS (ptr)[x];
46408039
JB
1010
1011 /* mark everything on the alist except the keys or
1012 * values, according to weak_values and weak_keys. */
0b5f3f34 1013 while ( SCM_CONSP (alist)
0f2d19dd 1014 && !SCM_GCMARKP (alist)
0f2d19dd
JB
1015 && SCM_CONSP (SCM_CAR (alist)))
1016 {
1017 SCM kvpair;
1018 SCM next_alist;
1019
1020 kvpair = SCM_CAR (alist);
1021 next_alist = SCM_CDR (alist);
1022 /*
1023 * Do not do this:
1024 * SCM_SETGCMARK (alist);
1025 * SCM_SETGCMARK (kvpair);
1026 *
1027 * It may be that either the key or value is protected by
1028 * an escaped reference to part of the spine of this alist.
1029 * If we mark the spine here, and only mark one or neither of the
1030 * key and value, they may never be properly marked.
1031 * This leads to a horrible situation in which an alist containing
1032 * freelist cells is exported.
1033 *
1034 * So only mark the spines of these arrays last of all marking.
1035 * If somebody confuses us by constructing a weak vector
1036 * with a circular alist then we are hosed, but at least we
1037 * won't prematurely drop table entries.
1038 */
1039 if (!weak_keys)
1040 scm_gc_mark (SCM_CAR (kvpair));
1041 if (!weak_values)
1042 scm_gc_mark (SCM_GCCDR (kvpair));
1043 alist = next_alist;
1044 }
1045 if (SCM_NIMP (alist))
1046 scm_gc_mark (alist);
1047 }
1048 }
1049 break;
1050
1051 case scm_tc7_msymbol:
1052 if (SCM_GC8MARKP(ptr))
1053 break;
1054 SCM_SETGC8MARK (ptr);
1055 scm_gc_mark (SCM_SYMBOL_FUNC (ptr));
1056 ptr = SCM_SYMBOL_PROPS (ptr);
1057 goto gc_mark_loop;
1058 case scm_tc7_ssymbol:
1059 if (SCM_GC8MARKP(ptr))
1060 break;
1061 SCM_SETGC8MARK (ptr);
1062 break;
1063 case scm_tcs_subrs:
9de33deb 1064 break;
0f2d19dd
JB
1065 case scm_tc7_port:
1066 i = SCM_PTOBNUM (ptr);
1067 if (!(i < scm_numptob))
1068 goto def;
1069 if (SCM_GC8MARKP (ptr))
1070 break;
dc53f026 1071 SCM_SETGC8MARK (ptr);
ebf7394e
GH
1072 if (SCM_PTAB_ENTRY(ptr))
1073 scm_gc_mark (SCM_PTAB_ENTRY(ptr)->file_name);
dc53f026
JB
1074 if (scm_ptobs[i].mark)
1075 {
1076 ptr = (scm_ptobs[i].mark) (ptr);
1077 goto gc_mark_loop;
1078 }
1079 else
1080 return;
0f2d19dd
JB
1081 break;
1082 case scm_tc7_smob:
1083 if (SCM_GC8MARKP (ptr))
1084 break;
dc53f026 1085 SCM_SETGC8MARK (ptr);
acb0a19c 1086 switch (SCM_GCTYP16 (ptr))
0f2d19dd
JB
1087 { /* should be faster than going through scm_smobs */
1088 case scm_tc_free_cell:
1089 /* printf("found free_cell %X ", ptr); fflush(stdout); */
1bbd0b84 1090 case scm_tc16_allocated:
acb0a19c
MD
1091 case scm_tc16_big:
1092 case scm_tc16_real:
1093 case scm_tc16_complex:
0f2d19dd
JB
1094 break;
1095 default:
1096 i = SCM_SMOBNUM (ptr);
1097 if (!(i < scm_numsmob))
1098 goto def;
dc53f026
JB
1099 if (scm_smobs[i].mark)
1100 {
1101 ptr = (scm_smobs[i].mark) (ptr);
1102 goto gc_mark_loop;
1103 }
1104 else
1105 return;
0f2d19dd
JB
1106 }
1107 break;
1108 default:
1109 def:scm_wta (ptr, "unknown type in ", "gc_mark");
1110 }
1111}
1112
1113
1114/* Mark a Region Conservatively
1115 */
1116
0f2d19dd 1117void
6e8d25a6 1118scm_mark_locations (SCM_STACKITEM x[], scm_sizet n)
0f2d19dd
JB
1119{
1120 register long m = n;
1121 register int i, j;
1122 register SCM_CELLPTR ptr;
1123
1124 while (0 <= --m)
c209c88e 1125 if (SCM_CELLP (*(SCM **) (& x[m])))
0f2d19dd
JB
1126 {
1127 ptr = (SCM_CELLPTR) SCM2PTR ((*(SCM **) & x[m]));
1128 i = 0;
1129 j = scm_n_heap_segs - 1;
1130 if ( SCM_PTR_LE (scm_heap_table[i].bounds[0], ptr)
1131 && SCM_PTR_GT (scm_heap_table[j].bounds[1], ptr))
1132 {
1133 while (i <= j)
1134 {
1135 int seg_id;
1136 seg_id = -1;
1137 if ( (i == j)
1138 || SCM_PTR_GT (scm_heap_table[i].bounds[1], ptr))
1139 seg_id = i;
1140 else if (SCM_PTR_LE (scm_heap_table[j].bounds[0], ptr))
1141 seg_id = j;
1142 else
1143 {
1144 int k;
1145 k = (i + j) / 2;
1146 if (k == i)
1147 break;
1148 if (SCM_PTR_GT (scm_heap_table[k].bounds[1], ptr))
1149 {
1150 j = k;
1151 ++i;
1152 if (SCM_PTR_LE (scm_heap_table[i].bounds[0], ptr))
1153 continue;
1154 else
1155 break;
1156 }
1157 else if (SCM_PTR_LE (scm_heap_table[k].bounds[0], ptr))
1158 {
1159 i = k;
1160 --j;
1161 if (SCM_PTR_GT (scm_heap_table[j].bounds[1], ptr))
1162 continue;
1163 else
1164 break;
1165 }
1166 }
1167 if ( !scm_heap_table[seg_id].valid
1168 || scm_heap_table[seg_id].valid (ptr,
1169 &scm_heap_table[seg_id]))
1170 scm_gc_mark (*(SCM *) & x[m]);
1171 break;
1172 }
1173
1174 }
1175 }
1176}
1177
1178
2e11a577
MD
1179/* The following is a C predicate which determines if an SCM value can be
1180 regarded as a pointer to a cell on the heap. The code is duplicated
1181 from scm_mark_locations. */
1182
1cc91f1b 1183
2e11a577 1184int
6e8d25a6 1185scm_cellp (SCM value)
2e11a577
MD
1186{
1187 register int i, j;
1188 register SCM_CELLPTR ptr;
1189
c209c88e 1190 if SCM_CELLP (*(SCM **) (& value))
2e11a577
MD
1191 {
1192 ptr = (SCM_CELLPTR) SCM2PTR ((*(SCM **) & value));
1193 i = 0;
1194 j = scm_n_heap_segs - 1;
1195 if ( SCM_PTR_LE (scm_heap_table[i].bounds[0], ptr)
1196 && SCM_PTR_GT (scm_heap_table[j].bounds[1], ptr))
1197 {
1198 while (i <= j)
1199 {
1200 int seg_id;
1201 seg_id = -1;
1202 if ( (i == j)
1203 || SCM_PTR_GT (scm_heap_table[i].bounds[1], ptr))
1204 seg_id = i;
1205 else if (SCM_PTR_LE (scm_heap_table[j].bounds[0], ptr))
1206 seg_id = j;
1207 else
1208 {
1209 int k;
1210 k = (i + j) / 2;
1211 if (k == i)
1212 break;
1213 if (SCM_PTR_GT (scm_heap_table[k].bounds[1], ptr))
1214 {
1215 j = k;
1216 ++i;
1217 if (SCM_PTR_LE (scm_heap_table[i].bounds[0], ptr))
1218 continue;
1219 else
1220 break;
1221 }
1222 else if (SCM_PTR_LE (scm_heap_table[k].bounds[0], ptr))
1223 {
1224 i = k;
1225 --j;
1226 if (SCM_PTR_GT (scm_heap_table[j].bounds[1], ptr))
1227 continue;
1228 else
1229 break;
1230 }
1231 }
1232 if ( !scm_heap_table[seg_id].valid
1233 || scm_heap_table[seg_id].valid (ptr,
1234 &scm_heap_table[seg_id]))
1235 return 1;
1236 break;
1237 }
1238
1239 }
1240 }
1241 return 0;
1242}
1243
1244
3b2b8760 1245static void
0f2d19dd 1246scm_mark_weak_vector_spines ()
0f2d19dd 1247{
ab4bef85 1248 SCM w;
0f2d19dd 1249
ab4bef85 1250 for (w = scm_weak_vectors; w != SCM_EOL; w = SCM_WVECT_GC_CHAIN (w))
0f2d19dd 1251 {
ab4bef85 1252 if (SCM_IS_WHVEC_ANY (w))
0f2d19dd
JB
1253 {
1254 SCM *ptr;
1255 SCM obj;
1256 int j;
1257 int n;
1258
ab4bef85
JB
1259 obj = w;
1260 ptr = SCM_VELTS (w);
1261 n = SCM_LENGTH (w);
0f2d19dd
JB
1262 for (j = 0; j < n; ++j)
1263 {
1264 SCM alist;
1265
1266 alist = ptr[j];
0b5f3f34 1267 while ( SCM_CONSP (alist)
0f2d19dd 1268 && !SCM_GCMARKP (alist)
0f2d19dd
JB
1269 && SCM_CONSP (SCM_CAR (alist)))
1270 {
1271 SCM_SETGCMARK (alist);
1272 SCM_SETGCMARK (SCM_CAR (alist));
1273 alist = SCM_GCCDR (alist);
1274 }
1275 }
1276 }
1277 }
1278}
1279
1280
1281
0f2d19dd
JB
1282void
1283scm_gc_sweep ()
0f2d19dd
JB
1284{
1285 register SCM_CELLPTR ptr;
1286#ifdef SCM_POINTERS_MUNGED
1287 register SCM scmptr;
1288#else
1289#undef scmptr
1290#define scmptr (SCM)ptr
1291#endif
1292 register SCM nfreelist;
945fec60 1293 register scm_freelist_t *hp_freelist;
0f2d19dd 1294 register long m;
0f2d19dd 1295 register int span;
15e9d186 1296 long i;
0f2d19dd
JB
1297 scm_sizet seg_size;
1298
0f2d19dd 1299 m = 0;
0f2d19dd 1300
4a4c9785
MD
1301#ifdef GUILE_NEW_GC_SCHEME
1302 /* Reset all free list pointers. We'll reconstruct them completely
1303 while scanning. */
1304 for (i = 0; i < scm_n_heap_segs; i++)
1305 {
1306 scm_heap_table[i].freelistp->cells = SCM_EOL;
1307 scm_heap_table[i].freelistp->n_objects
1308 = scm_heap_table[i].freelistp->gc_trigger;
1309 scm_heap_table[i].freelistp->clusters = SCM_EOL;
1310 scm_heap_table[i].freelistp->clustertail
1311 = &scm_heap_table[i].freelistp->clusters;
1312 scm_heap_table[i].freelistp->triggeredp = 0;
1313 }
1314#else
cf2d30f6
JB
1315 /* Reset all free list pointers. We'll reconstruct them completely
1316 while scanning. */
1317 for (i = 0; i < scm_n_heap_segs; i++)
945fec60 1318 scm_heap_table[i].freelistp->cells = SCM_EOL;
4a4c9785
MD
1319#endif
1320
cf2d30f6 1321 for (i = 0; i < scm_n_heap_segs; i++)
0f2d19dd 1322 {
15e9d186
JB
1323 register scm_sizet n = 0;
1324 register scm_sizet j;
0df07278
MD
1325#ifdef GUILE_NEW_GC_SCHEME
1326 register scm_sizet n_objects;
1327#endif
15e9d186 1328
cf2d30f6
JB
1329 /* Unmarked cells go onto the front of the freelist this heap
1330 segment points to. Rather than updating the real freelist
1331 pointer as we go along, we accumulate the new head in
1332 nfreelist. Then, if it turns out that the entire segment is
1333 free, we free (i.e., malloc's free) the whole segment, and
1334 simply don't assign nfreelist back into the real freelist. */
0f2d19dd 1335 hp_freelist = scm_heap_table[i].freelistp;
945fec60 1336 nfreelist = hp_freelist->cells;
4a4c9785
MD
1337#ifdef GUILE_NEW_GC_SCHEME
1338 n_objects = hp_freelist->n_objects;
1339#endif
945fec60
MD
1340 span = scm_heap_table[i].span;
1341 hp_freelist->collected = 0;
cf2d30f6 1342
0f2d19dd
JB
1343 ptr = CELL_UP (scm_heap_table[i].bounds[0]);
1344 seg_size = CELL_DN (scm_heap_table[i].bounds[1]) - ptr;
0f2d19dd
JB
1345 for (j = seg_size + span; j -= span; ptr += span)
1346 {
1347#ifdef SCM_POINTERS_MUNGED
1348 scmptr = PTR2SCM (ptr);
1349#endif
1350 switch SCM_TYP7 (scmptr)
1351 {
1352 case scm_tcs_cons_gloc:
1353 if (SCM_GCMARKP (scmptr))
1354 {
1355 if (SCM_CDR (SCM_CAR (scmptr) - 1) == (SCM)1)
24e68a57 1356 SCM_SETCDR (SCM_CAR (scmptr) - 1, (SCM) 0);
0f2d19dd
JB
1357 goto cmrkcontinue;
1358 }
1359 {
1360 SCM vcell;
1361 vcell = SCM_CAR (scmptr) - 1L;
1362
f1267706 1363 if ((SCM_CDR (vcell) == 0) || (SCM_UNPACK (SCM_CDR (vcell)) == 1))
0f2d19dd 1364 {
f0cb1733
MD
1365 scm_struct_free_t free
1366 = (scm_struct_free_t) ((SCM*) vcell)[scm_struct_i_free];
1367 m += free ((SCM *) vcell, (SCM *) SCM_GCCDR (scmptr));
0f2d19dd
JB
1368 }
1369 }
1370 break;
1371 case scm_tcs_cons_imcar:
1372 case scm_tcs_cons_nimcar:
1373 case scm_tcs_closures:
e641afaf 1374 case scm_tc7_pws:
0f2d19dd
JB
1375 if (SCM_GCMARKP (scmptr))
1376 goto cmrkcontinue;
1377 break;
1378 case scm_tc7_wvect:
1379 if (SCM_GC8MARKP (scmptr))
1380 {
1381 goto c8mrkcontinue;
1382 }
1383 else
1384 {
ab4bef85
JB
1385 m += (2 + SCM_LENGTH (scmptr)) * sizeof (SCM);
1386 scm_must_free ((char *)(SCM_VELTS (scmptr) - 2));
0f2d19dd
JB
1387 break;
1388 }
1389
1390 case scm_tc7_vector:
1391 case scm_tc7_lvector:
1392#ifdef CCLO
1393 case scm_tc7_cclo:
1394#endif
1395 if (SCM_GC8MARKP (scmptr))
1396 goto c8mrkcontinue;
1397
1398 m += (SCM_LENGTH (scmptr) * sizeof (SCM));
1399 freechars:
1400 scm_must_free (SCM_CHARS (scmptr));
1401 /* SCM_SETCHARS(scmptr, 0);*/
1402 break;
afe5177e 1403#ifdef HAVE_ARRAYS
0f2d19dd
JB
1404 case scm_tc7_bvect:
1405 if SCM_GC8MARKP (scmptr)
1406 goto c8mrkcontinue;
1407 m += sizeof (long) * ((SCM_HUGE_LENGTH (scmptr) + SCM_LONG_BIT - 1) / SCM_LONG_BIT);
1408 goto freechars;
1409 case scm_tc7_byvect:
1410 if SCM_GC8MARKP (scmptr)
1411 goto c8mrkcontinue;
1412 m += SCM_HUGE_LENGTH (scmptr) * sizeof (char);
1413 goto freechars;
1414 case scm_tc7_ivect:
1415 case scm_tc7_uvect:
1416 if SCM_GC8MARKP (scmptr)
1417 goto c8mrkcontinue;
1418 m += SCM_HUGE_LENGTH (scmptr) * sizeof (long);
1419 goto freechars;
1420 case scm_tc7_svect:
1421 if SCM_GC8MARKP (scmptr)
1422 goto c8mrkcontinue;
1423 m += SCM_HUGE_LENGTH (scmptr) * sizeof (short);
1424 goto freechars;
5c11cc9d 1425#ifdef HAVE_LONG_LONGS
0f2d19dd
JB
1426 case scm_tc7_llvect:
1427 if SCM_GC8MARKP (scmptr)
1428 goto c8mrkcontinue;
1429 m += SCM_HUGE_LENGTH (scmptr) * sizeof (long_long);
1430 goto freechars;
1431#endif
1432 case scm_tc7_fvect:
1433 if SCM_GC8MARKP (scmptr)
1434 goto c8mrkcontinue;
1435 m += SCM_HUGE_LENGTH (scmptr) * sizeof (float);
1436 goto freechars;
1437 case scm_tc7_dvect:
1438 if SCM_GC8MARKP (scmptr)
1439 goto c8mrkcontinue;
1440 m += SCM_HUGE_LENGTH (scmptr) * sizeof (double);
1441 goto freechars;
1442 case scm_tc7_cvect:
1443 if SCM_GC8MARKP (scmptr)
1444 goto c8mrkcontinue;
1445 m += SCM_HUGE_LENGTH (scmptr) * 2 * sizeof (double);
1446 goto freechars;
afe5177e 1447#endif
0f2d19dd 1448 case scm_tc7_substring:
0f2d19dd
JB
1449 if (SCM_GC8MARKP (scmptr))
1450 goto c8mrkcontinue;
1451 break;
1452 case scm_tc7_string:
0f2d19dd
JB
1453 if (SCM_GC8MARKP (scmptr))
1454 goto c8mrkcontinue;
1455 m += SCM_HUGE_LENGTH (scmptr) + 1;
1456 goto freechars;
1457 case scm_tc7_msymbol:
1458 if (SCM_GC8MARKP (scmptr))
1459 goto c8mrkcontinue;
1460 m += ( SCM_LENGTH (scmptr)
1461 + 1
1462 + sizeof (SCM) * ((SCM *)SCM_CHARS (scmptr) - SCM_SLOTS(scmptr)));
1463 scm_must_free ((char *)SCM_SLOTS (scmptr));
1464 break;
1465 case scm_tc7_contin:
1466 if SCM_GC8MARKP (scmptr)
1467 goto c8mrkcontinue;
0db18cf4 1468 m += SCM_LENGTH (scmptr) * sizeof (SCM_STACKITEM) + sizeof (scm_contregs);
c68296f8
MV
1469 if (SCM_VELTS (scmptr))
1470 goto freechars;
0f2d19dd
JB
1471 case scm_tc7_ssymbol:
1472 if SCM_GC8MARKP(scmptr)
1473 goto c8mrkcontinue;
1474 break;
1475 case scm_tcs_subrs:
1476 continue;
1477 case scm_tc7_port:
1478 if SCM_GC8MARKP (scmptr)
1479 goto c8mrkcontinue;
1480 if SCM_OPENP (scmptr)
1481 {
1482 int k = SCM_PTOBNUM (scmptr);
1483 if (!(k < scm_numptob))
1484 goto sweeperr;
1485 /* Keep "revealed" ports alive. */
945fec60 1486 if (scm_revealed_count (scmptr) > 0)
0f2d19dd
JB
1487 continue;
1488 /* Yes, I really do mean scm_ptobs[k].free */
1489 /* rather than ftobs[k].close. .close */
1490 /* is for explicit CLOSE-PORT by user */
84af0382 1491 m += (scm_ptobs[k].free) (scmptr);
0f2d19dd
JB
1492 SCM_SETSTREAM (scmptr, 0);
1493 scm_remove_from_port_table (scmptr);
1494 scm_gc_ports_collected++;
24e68a57 1495 SCM_SETAND_CAR (scmptr, ~SCM_OPN);
0f2d19dd
JB
1496 }
1497 break;
1498 case scm_tc7_smob:
1499 switch SCM_GCTYP16 (scmptr)
1500 {
1501 case scm_tc_free_cell:
acb0a19c 1502 case scm_tc16_real:
0f2d19dd
JB
1503 if SCM_GC8MARKP (scmptr)
1504 goto c8mrkcontinue;
1505 break;
1506#ifdef SCM_BIGDIG
acb0a19c 1507 case scm_tc16_big:
0f2d19dd
JB
1508 if SCM_GC8MARKP (scmptr)
1509 goto c8mrkcontinue;
1510 m += (SCM_NUMDIGS (scmptr) * SCM_BITSPERDIG / SCM_CHAR_BIT);
1511 goto freechars;
1512#endif /* def SCM_BIGDIG */
acb0a19c 1513 case scm_tc16_complex:
0f2d19dd
JB
1514 if SCM_GC8MARKP (scmptr)
1515 goto c8mrkcontinue;
acb0a19c
MD
1516 m += 2 * sizeof (double);
1517 goto freechars;
0f2d19dd
JB
1518 default:
1519 if SCM_GC8MARKP (scmptr)
1520 goto c8mrkcontinue;
1521
1522 {
1523 int k;
1524 k = SCM_SMOBNUM (scmptr);
1525 if (!(k < scm_numsmob))
1526 goto sweeperr;
1527 m += (scm_smobs[k].free) ((SCM) scmptr);
1528 break;
1529 }
1530 }
1531 break;
1532 default:
1533 sweeperr:scm_wta (scmptr, "unknown type in ", "gc_sweep");
1534 }
0f2d19dd
JB
1535#if 0
1536 if (SCM_CAR (scmptr) == (SCM) scm_tc_free_cell)
1537 exit (2);
1538#endif
4a4c9785
MD
1539#ifndef GUILE_NEW_GC_SCHEME
1540 n += span;
1541#else
1542 if (--n_objects < 0)
1543 {
1544 SCM_SETCAR (scmptr, nfreelist);
1545 *hp_freelist->clustertail = scmptr;
1546 hp_freelist->clustertail = SCM_CDRLOC (scmptr);
1547
1548 nfreelist = SCM_EOL;
0df07278 1549 n += span * (hp_freelist->gc_trigger - n_objects + 1);
4a4c9785 1550 n_objects = hp_freelist->gc_trigger;
4a4c9785
MD
1551 }
1552 else
1553#endif
1554 {
1555 /* Stick the new cell on the front of nfreelist. It's
1556 critical that we mark this cell as freed; otherwise, the
1557 conservative collector might trace it as some other type
1558 of object. */
1559 SCM_SETCAR (scmptr, scm_tc_free_cell);
1560 SCM_SETCDR (scmptr, nfreelist);
1561 nfreelist = scmptr;
1562 }
8ded62a3 1563
0f2d19dd
JB
1564 continue;
1565 c8mrkcontinue:
1566 SCM_CLRGC8MARK (scmptr);
1567 continue;
1568 cmrkcontinue:
1569 SCM_CLRGCMARK (scmptr);
1570 }
1571#ifdef GC_FREE_SEGMENTS
1572 if (n == seg_size)
1573 {
15e9d186
JB
1574 register long j;
1575
945fec60 1576 hp_freelist->heap_size -= seg_size;
cf2d30f6
JB
1577 free ((char *) scm_heap_table[i].bounds[0]);
1578 scm_heap_table[i].bounds[0] = 0;
1579 for (j = i + 1; j < scm_n_heap_segs; j++)
0f2d19dd
JB
1580 scm_heap_table[j - 1] = scm_heap_table[j];
1581 scm_n_heap_segs -= 1;
cf2d30f6 1582 i--; /* We need to scan the segment just moved. */
0f2d19dd
JB
1583 }
1584 else
1585#endif /* ifdef GC_FREE_SEGMENTS */
4a4c9785
MD
1586 {
1587 /* Update the real freelist pointer to point to the head of
1588 the list of free cells we've built for this segment. */
1589 hp_freelist->cells = nfreelist;
1590#ifdef GUILE_NEW_GC_SCHEME
1591 hp_freelist->n_objects = n_objects;
1592#endif
1593 }
1594
1595#ifdef GUILE_NEW_GC_SCHEME
1596 j = span * (hp_freelist->gc_trigger - n_objects);
1597 /* sum up---if this is last turn for this freelist */
1598 hp_freelist->collected += n + j;
1599 n -= j; /* compensate for the sum up */
1600#else
1601 hp_freelist->collected += n;
1602#endif
1603 scm_cells_allocated += hp_freelist->heap_size - hp_freelist->collected;
0f2d19dd 1604
fca7547b 1605#ifdef GUILE_DEBUG_FREELIST
8ded62a3
MD
1606#ifdef GUILE_NEW_GC_SCHEME
1607 scm_check_freelist (hp_freelist == &scm_master_freelist
1608 ? scm_freelist
1609 : scm_freelist2);
1610#else
945fec60 1611 scm_check_freelist (hp_freelist);
8ded62a3 1612#endif
cf2d30f6
JB
1613 scm_map_free_list ();
1614#endif
4a4c9785 1615 }
8ded62a3 1616
4a4c9785
MD
1617#ifdef GUILE_NEW_GC_SCHEME
1618 for (i = 0; i < scm_n_heap_segs; i++)
8ded62a3 1619 if (scm_heap_table[i].freelistp->clustertail != NULL)
4a4c9785 1620 {
8ded62a3
MD
1621 scm_freelist_t *hp_freelist = scm_heap_table[i].freelistp;
1622 if (hp_freelist->gc_trigger - hp_freelist->n_objects > 1)
4a4c9785 1623 {
8ded62a3
MD
1624 SCM c = hp_freelist->cells;
1625 hp_freelist->n_objects = hp_freelist->gc_trigger;
1626 SCM_SETCAR (c, SCM_CDR (c));
1627 SCM_SETCDR (c, SCM_EOL);
1628 *hp_freelist->clustertail = c;
4a4c9785 1629 }
8ded62a3
MD
1630 else
1631 *hp_freelist->clustertail = SCM_EOL;
1632 hp_freelist->clustertail = NULL;
4a4c9785 1633 }
8ded62a3
MD
1634
1635 /* When we move to POSIX threads private freelists should probably
1636 be GC-protected instead. */
1637 scm_freelist = SCM_EOL;
1638 scm_freelist2 = SCM_EOL;
4a4c9785
MD
1639#endif
1640
0f2d19dd
JB
1641 /* Scan weak vectors. */
1642 {
ab4bef85
JB
1643 SCM *ptr, w;
1644 for (w = scm_weak_vectors; w != SCM_EOL; w = SCM_WVECT_GC_CHAIN (w))
0f2d19dd 1645 {
ab4bef85 1646 if (!SCM_IS_WHVEC_ANY (w))
0f2d19dd 1647 {
15e9d186
JB
1648 register long j, n;
1649
ab4bef85
JB
1650 ptr = SCM_VELTS (w);
1651 n = SCM_LENGTH (w);
0f2d19dd 1652 for (j = 0; j < n; ++j)
0c95b57d 1653 if (SCM_FREEP (ptr[j]))
0f2d19dd
JB
1654 ptr[j] = SCM_BOOL_F;
1655 }
1656 else /* if (SCM_IS_WHVEC_ANY (scm_weak_vectors[i])) */
1657 {
ab4bef85
JB
1658 SCM obj = w;
1659 register long n = SCM_LENGTH (w);
15e9d186
JB
1660 register long j;
1661
ab4bef85 1662 ptr = SCM_VELTS (w);
15e9d186 1663
0f2d19dd
JB
1664 for (j = 0; j < n; ++j)
1665 {
1666 SCM * fixup;
1667 SCM alist;
1668 int weak_keys;
1669 int weak_values;
1670
1671 weak_keys = SCM_IS_WHVEC (obj) || SCM_IS_WHVEC_B (obj);
1672 weak_values = SCM_IS_WHVEC_V (obj) || SCM_IS_WHVEC_B (obj);
1673
1674 fixup = ptr + j;
1675 alist = *fixup;
1676
0b5f3f34 1677 while ( SCM_CONSP (alist)
0f2d19dd
JB
1678 && SCM_CONSP (SCM_CAR (alist)))
1679 {
1680 SCM key;
1681 SCM value;
1682
1683 key = SCM_CAAR (alist);
1684 value = SCM_CDAR (alist);
0c95b57d
GB
1685 if ( (weak_keys && SCM_FREEP (key))
1686 || (weak_values && SCM_FREEP (value)))
0f2d19dd
JB
1687 {
1688 *fixup = SCM_CDR (alist);
1689 }
1690 else
24e68a57 1691 fixup = SCM_CDRLOC (alist);
0f2d19dd
JB
1692 alist = SCM_CDR (alist);
1693 }
1694 }
1695 }
1696 }
1697 }
0f2d19dd
JB
1698 scm_mallocated -= m;
1699 scm_gc_malloc_collected = m;
1700}
1701
1702
1703\f
1704
1705/* {Front end to malloc}
1706 *
c68296f8 1707 * scm_must_malloc, scm_must_realloc, scm_must_free, scm_done_malloc
0f2d19dd
JB
1708 *
1709 * These functions provide services comperable to malloc, realloc, and
1710 * free. They are for allocating malloced parts of scheme objects.
1711 * The primary purpose of the front end is to impose calls to gc.
1712 */
1713
1714/* scm_must_malloc
1715 * Return newly malloced storage or throw an error.
1716 *
1717 * The parameter WHAT is a string for error reporting.
1718 * If the threshold scm_mtrigger will be passed by this
1719 * allocation, or if the first call to malloc fails,
1720 * garbage collect -- on the presumption that some objects
1721 * using malloced storage may be collected.
1722 *
1723 * The limit scm_mtrigger may be raised by this allocation.
1724 */
07806695 1725void *
e4ef2330 1726scm_must_malloc (scm_sizet size, const char *what)
0f2d19dd 1727{
07806695 1728 void *ptr;
15e9d186 1729 unsigned long nm = scm_mallocated + size;
e4ef2330
MD
1730
1731 if (nm <= scm_mtrigger)
0f2d19dd 1732 {
07806695 1733 SCM_SYSCALL (ptr = malloc (size));
0f2d19dd
JB
1734 if (NULL != ptr)
1735 {
1736 scm_mallocated = nm;
1737 return ptr;
1738 }
1739 }
6064dcc6 1740
0f2d19dd 1741 scm_igc (what);
e4ef2330 1742
0f2d19dd 1743 nm = scm_mallocated + size;
07806695 1744 SCM_SYSCALL (ptr = malloc (size));
0f2d19dd
JB
1745 if (NULL != ptr)
1746 {
1747 scm_mallocated = nm;
6064dcc6
MV
1748 if (nm > scm_mtrigger - SCM_MTRIGGER_HYSTERESIS) {
1749 if (nm > scm_mtrigger)
1750 scm_mtrigger = nm + nm / 2;
1751 else
1752 scm_mtrigger += scm_mtrigger / 2;
1753 }
0f2d19dd
JB
1754 return ptr;
1755 }
e4ef2330
MD
1756
1757 scm_wta (SCM_MAKINUM (size), (char *) SCM_NALLOC, what);
1758 return 0; /* never reached */
0f2d19dd
JB
1759}
1760
1761
1762/* scm_must_realloc
1763 * is similar to scm_must_malloc.
1764 */
07806695
JB
1765void *
1766scm_must_realloc (void *where,
e4ef2330
MD
1767 scm_sizet old_size,
1768 scm_sizet size,
3eeba8d4 1769 const char *what)
0f2d19dd 1770{
07806695 1771 void *ptr;
e4ef2330
MD
1772 scm_sizet nm = scm_mallocated + size - old_size;
1773
1774 if (nm <= scm_mtrigger)
0f2d19dd 1775 {
07806695 1776 SCM_SYSCALL (ptr = realloc (where, size));
0f2d19dd
JB
1777 if (NULL != ptr)
1778 {
1779 scm_mallocated = nm;
1780 return ptr;
1781 }
1782 }
e4ef2330 1783
0f2d19dd 1784 scm_igc (what);
e4ef2330
MD
1785
1786 nm = scm_mallocated + size - old_size;
07806695 1787 SCM_SYSCALL (ptr = realloc (where, size));
0f2d19dd
JB
1788 if (NULL != ptr)
1789 {
1790 scm_mallocated = nm;
6064dcc6
MV
1791 if (nm > scm_mtrigger - SCM_MTRIGGER_HYSTERESIS) {
1792 if (nm > scm_mtrigger)
1793 scm_mtrigger = nm + nm / 2;
1794 else
1795 scm_mtrigger += scm_mtrigger / 2;
1796 }
0f2d19dd
JB
1797 return ptr;
1798 }
e4ef2330
MD
1799
1800 scm_wta (SCM_MAKINUM (size), (char *) SCM_NALLOC, what);
1801 return 0; /* never reached */
0f2d19dd
JB
1802}
1803
0f2d19dd 1804void
07806695 1805scm_must_free (void *obj)
0f2d19dd
JB
1806{
1807 if (obj)
1808 free (obj);
1809 else
1810 scm_wta (SCM_INUM0, "already free", "");
1811}
0f2d19dd 1812
c68296f8
MV
1813/* Announce that there has been some malloc done that will be freed
1814 * during gc. A typical use is for a smob that uses some malloced
1815 * memory but can not get it from scm_must_malloc (for whatever
1816 * reason). When a new object of this smob is created you call
1817 * scm_done_malloc with the size of the object. When your smob free
1818 * function is called, be sure to include this size in the return
1819 * value. */
0f2d19dd 1820
c68296f8 1821void
6e8d25a6 1822scm_done_malloc (long size)
c68296f8
MV
1823{
1824 scm_mallocated += size;
1825
1826 if (scm_mallocated > scm_mtrigger)
1827 {
1828 scm_igc ("foreign mallocs");
1829 if (scm_mallocated > scm_mtrigger - SCM_MTRIGGER_HYSTERESIS)
1830 {
1831 if (scm_mallocated > scm_mtrigger)
1832 scm_mtrigger = scm_mallocated + scm_mallocated / 2;
1833 else
1834 scm_mtrigger += scm_mtrigger / 2;
1835 }
1836 }
1837}
1838
1839
1840\f
0f2d19dd
JB
1841
1842/* {Heap Segments}
1843 *
1844 * Each heap segment is an array of objects of a particular size.
1845 * Every segment has an associated (possibly shared) freelist.
1846 * A table of segment records is kept that records the upper and
1847 * lower extents of the segment; this is used during the conservative
1848 * phase of gc to identify probably gc roots (because they point
c68296f8 1849 * into valid segments at reasonable offsets). */
0f2d19dd
JB
1850
1851/* scm_expmem
1852 * is true if the first segment was smaller than INIT_HEAP_SEG.
1853 * If scm_expmem is set to one, subsequent segment allocations will
1854 * allocate segments of size SCM_EXPHEAP(scm_heap_size).
1855 */
1856int scm_expmem = 0;
1857
1858/* scm_heap_org
1859 * is the lowest base address of any heap segment.
1860 */
1861SCM_CELLPTR scm_heap_org;
1862
1863struct scm_heap_seg_data * scm_heap_table = 0;
1864int scm_n_heap_segs = 0;
1865
0f2d19dd
JB
1866/* init_heap_seg
1867 * initializes a new heap segment and return the number of objects it contains.
1868 *
1869 * The segment origin, segment size in bytes, and the span of objects
1870 * in cells are input parameters. The freelist is both input and output.
1871 *
1872 * This function presume that the scm_heap_table has already been expanded
1873 * to accomodate a new segment record.
1874 */
1875
1876
0f2d19dd 1877static scm_sizet
945fec60 1878init_heap_seg (SCM_CELLPTR seg_org, scm_sizet size, scm_freelist_t *freelistp)
0f2d19dd
JB
1879{
1880 register SCM_CELLPTR ptr;
1881#ifdef SCM_POINTERS_MUNGED
1882 register SCM scmptr;
1883#else
1884#undef scmptr
1885#define scmptr ptr
1886#endif
1887 SCM_CELLPTR seg_end;
15e9d186 1888 int new_seg_index;
acb0a19c 1889 int n_new_cells;
945fec60 1890 int span = freelistp->span;
0f2d19dd
JB
1891
1892 if (seg_org == NULL)
1893 return 0;
1894
1895 ptr = seg_org;
1896
945fec60 1897 size = (size / sizeof (scm_cell) / span) * span * sizeof (scm_cell);
acb0a19c 1898
0f2d19dd
JB
1899 /* Compute the ceiling on valid object pointers w/in this segment.
1900 */
1901 seg_end = CELL_DN ((char *) ptr + size);
1902
1903 /* Find the right place and insert the segment record.
1904 *
1905 */
1906 for (new_seg_index = 0;
1907 ( (new_seg_index < scm_n_heap_segs)
1908 && SCM_PTR_LE (scm_heap_table[new_seg_index].bounds[0], seg_org));
1909 new_seg_index++)
1910 ;
1911
1912 {
1913 int i;
1914 for (i = scm_n_heap_segs; i > new_seg_index; --i)
1915 scm_heap_table[i] = scm_heap_table[i - 1];
1916 }
1917
1918 ++scm_n_heap_segs;
1919
1920 scm_heap_table[new_seg_index].valid = 0;
945fec60 1921 scm_heap_table[new_seg_index].span = span;
0f2d19dd
JB
1922 scm_heap_table[new_seg_index].freelistp = freelistp;
1923 scm_heap_table[new_seg_index].bounds[0] = (SCM_CELLPTR)ptr;
1924 scm_heap_table[new_seg_index].bounds[1] = (SCM_CELLPTR)seg_end;
1925
1926
1927 /* Compute the least valid object pointer w/in this segment
1928 */
1929 ptr = CELL_UP (ptr);
1930
1931
acb0a19c
MD
1932 /*n_new_cells*/
1933 n_new_cells = seg_end - ptr;
0f2d19dd 1934
4a4c9785
MD
1935#ifdef GUILE_NEW_GC_SCHEME
1936
1937 freelistp->heap_size += n_new_cells;
1938
1939 /* Partition objects in this segment into clusters
1940 */
1941 {
1942 SCM clusters;
1943 SCM *clusterp = &clusters;
1944 int trigger = span * freelistp->gc_trigger;
1945 int n, c = 0;
1946
1947 while (n_new_cells > span)
1948 {
1949 if (n_new_cells > trigger)
1950 n = span + trigger;
1951 else
1952 n = n_new_cells;
1953 n_new_cells -= n;
1954 n -= span;
1955 c += span;
1956
1957 *clusterp = PTR2SCM (ptr);
1958 SCM_SETCAR (*clusterp, PTR2SCM (ptr + span));
1959 clusterp = SCM_CDRLOC (*clusterp);
1960
1961 ptr += span;
1962 seg_end = ptr + n;
1963 while (ptr < seg_end)
1964 {
1965#ifdef SCM_POINTERS_MUNGED
1966 scmptr = PTR2SCM (ptr);
1967#endif
1968 SCM_SETCAR (scmptr, scm_tc_free_cell);
1969 SCM_SETCDR (scmptr, PTR2SCM (ptr + span));
1970 ptr += span;
1971 }
1972 SCM_SETCDR (PTR2SCM (ptr - span), SCM_EOL);
1973 }
1974
1975 /* Correction for cluster cells + spill */
1976 freelistp->heap_size -= c + n_new_cells;
1977
1978 /* Patch up the last cluster pointer in the segment
1979 * to join it to the input freelist.
1980 */
1981 *clusterp = freelistp->clusters;
1982 freelistp->clusters = clusters;
1983 }
1984
1985#else /* GUILE_NEW_GC_SCHEME */
1986
0f2d19dd
JB
1987 /* Prepend objects in this segment to the freelist.
1988 */
1989 while (ptr < seg_end)
1990 {
1991#ifdef SCM_POINTERS_MUNGED
1992 scmptr = PTR2SCM (ptr);
1993#endif
24e68a57 1994 SCM_SETCAR (scmptr, (SCM) scm_tc_free_cell);
945fec60
MD
1995 SCM_SETCDR (scmptr, PTR2SCM (ptr + span));
1996 ptr += span;
0f2d19dd
JB
1997 }
1998
945fec60 1999 ptr -= span;
0f2d19dd
JB
2000
2001 /* Patch up the last freelist pointer in the segment
2002 * to join it to the input freelist.
2003 */
945fec60
MD
2004 SCM_SETCDR (PTR2SCM (ptr), freelistp->cells);
2005 freelistp->cells = PTR2SCM (CELL_UP (seg_org));
0f2d19dd 2006
945fec60 2007 freelistp->heap_size += n_new_cells;
4a4c9785
MD
2008
2009#endif /* GUILE_NEW_GC_SCHEME */
2010
0f2d19dd
JB
2011 return size;
2012#ifdef scmptr
2013#undef scmptr
2014#endif
2015}
2016
2017
0f2d19dd 2018static void
945fec60 2019alloc_some_heap (scm_freelist_t *freelistp)
0f2d19dd
JB
2020{
2021 struct scm_heap_seg_data * tmptable;
2022 SCM_CELLPTR ptr;
2023 scm_sizet len;
2024
2025 /* Critical code sections (such as the garbage collector)
2026 * aren't supposed to add heap segments.
2027 */
2028 if (scm_gc_heap_lock)
2029 scm_wta (SCM_UNDEFINED, "need larger initial", "heap");
2030
2031 /* Expand the heap tables to have room for the new segment.
2032 * Do not yet increment scm_n_heap_segs -- that is done by init_heap_seg
2033 * only if the allocation of the segment itself succeeds.
2034 */
2035 len = (1 + scm_n_heap_segs) * sizeof (struct scm_heap_seg_data);
2036
2037 SCM_SYSCALL (tmptable = ((struct scm_heap_seg_data *)
2038 realloc ((char *)scm_heap_table, len)));
2039 if (!tmptable)
2040 scm_wta (SCM_UNDEFINED, "could not grow", "hplims");
2041 else
2042 scm_heap_table = tmptable;
2043
2044
2045 /* Pick a size for the new heap segment.
2046 * The rule for picking the size of a segment is explained in
2047 * gc.h
2048 */
2049 if (scm_expmem)
2050 {
945fec60
MD
2051 len = (scm_sizet) SCM_EXPHEAP (freelistp->heap_size * sizeof (scm_cell));
2052 if ((scm_sizet) SCM_EXPHEAP (freelistp->heap_size * sizeof (scm_cell))
2053 != len)
0f2d19dd
JB
2054 len = 0;
2055 }
2056 else
2057 len = SCM_HEAP_SEG_SIZE;
2058
2059 {
2060 scm_sizet smallest;
2061
945fec60 2062 smallest = (freelistp->span * sizeof (scm_cell));
0f2d19dd 2063 if (len < smallest)
945fec60 2064 len = (freelistp->span * sizeof (scm_cell));
0f2d19dd
JB
2065
2066 /* Allocate with decaying ambition. */
2067 while ((len >= SCM_MIN_HEAP_SEG_SIZE)
2068 && (len >= smallest))
2069 {
2070 SCM_SYSCALL (ptr = (SCM_CELLPTR) malloc (len));
2071 if (ptr)
2072 {
945fec60 2073 init_heap_seg (ptr, len, freelistp);
0f2d19dd
JB
2074 return;
2075 }
2076 len /= 2;
2077 }
2078 }
2079
2080 scm_wta (SCM_UNDEFINED, "could not grow", "heap");
2081}
2082
2083
2084
a1ec6916 2085SCM_DEFINE (scm_unhash_name, "unhash-name", 1, 0, 0,
1bbd0b84 2086 (SCM name),
b380b885 2087 "")
1bbd0b84 2088#define FUNC_NAME s_scm_unhash_name
0f2d19dd
JB
2089{
2090 int x;
2091 int bound;
3b3b36dd 2092 SCM_VALIDATE_SYMBOL (1,name);
0f2d19dd
JB
2093 SCM_DEFER_INTS;
2094 bound = scm_n_heap_segs;
2095 for (x = 0; x < bound; ++x)
2096 {
2097 SCM_CELLPTR p;
2098 SCM_CELLPTR pbound;
2099 p = (SCM_CELLPTR)scm_heap_table[x].bounds[0];
2100 pbound = (SCM_CELLPTR)scm_heap_table[x].bounds[1];
2101 while (p < pbound)
2102 {
2103 SCM incar;
2104 incar = p->car;
2105 if (1 == (7 & (int)incar))
2106 {
2107 --incar;
2108 if ( ((name == SCM_BOOL_T) || (SCM_CAR (incar) == name))
2109 && (SCM_CDR (incar) != 0)
f1267706 2110 && (SCM_UNPACK (SCM_CDR (incar)) != 1))
0f2d19dd
JB
2111 {
2112 p->car = name;
2113 }
2114 }
2115 ++p;
2116 }
2117 }
2118 SCM_ALLOW_INTS;
2119 return name;
2120}
1bbd0b84 2121#undef FUNC_NAME
0f2d19dd
JB
2122
2123
2124\f
2125/* {GC Protection Helper Functions}
2126 */
2127
2128
0f2d19dd 2129void
6e8d25a6
GB
2130scm_remember (SCM *ptr)
2131{ /* empty */ }
0f2d19dd 2132
1cc91f1b 2133
c209c88e 2134/*
41b0806d
GB
2135 These crazy functions prevent garbage collection
2136 of arguments after the first argument by
2137 ensuring they remain live throughout the
2138 function because they are used in the last
2139 line of the code block.
2140 It'd be better to have a nice compiler hint to
2141 aid the conservative stack-scanning GC. --03/09/00 gjb */
0f2d19dd
JB
2142SCM
2143scm_return_first (SCM elt, ...)
0f2d19dd
JB
2144{
2145 return elt;
2146}
2147
41b0806d
GB
2148int
2149scm_return_first_int (int i, ...)
2150{
2151 return i;
2152}
2153
0f2d19dd 2154
0f2d19dd 2155SCM
6e8d25a6 2156scm_permanent_object (SCM obj)
0f2d19dd
JB
2157{
2158 SCM_REDEFER_INTS;
2159 scm_permobjs = scm_cons (obj, scm_permobjs);
2160 SCM_REALLOW_INTS;
2161 return obj;
2162}
2163
2164
ef290276
JB
2165/* Protect OBJ from the garbage collector. OBJ will not be freed,
2166 even if all other references are dropped, until someone applies
2167 scm_unprotect_object to it. This function returns OBJ.
2168
c209c88e
GB
2169 Calls to scm_protect_object nest. For every object OBJ, there is a
2170 counter which scm_protect_object(OBJ) increments and
2171 scm_unprotect_object(OBJ) decrements, if it is greater than zero. If
dab7f566
JB
2172 an object's counter is greater than zero, the garbage collector
2173 will not free it.
2174
2175 Of course, that's not how it's implemented. scm_protect_object and
2176 scm_unprotect_object just maintain a list of references to things.
2177 Since the GC knows about this list, all objects it mentions stay
2178 alive. scm_protect_object adds its argument to the list;
2179 scm_unprotect_object removes the first occurrence of its argument
2180 to the list. */
ef290276 2181SCM
6e8d25a6 2182scm_protect_object (SCM obj)
ef290276 2183{
ef290276
JB
2184 scm_protects = scm_cons (obj, scm_protects);
2185
2186 return obj;
2187}
2188
2189
2190/* Remove any protection for OBJ established by a prior call to
dab7f566 2191 scm_protect_object. This function returns OBJ.
ef290276 2192
dab7f566 2193 See scm_protect_object for more information. */
ef290276 2194SCM
6e8d25a6 2195scm_unprotect_object (SCM obj)
ef290276 2196{
dab7f566
JB
2197 SCM *tail_ptr = &scm_protects;
2198
0c95b57d 2199 while (SCM_CONSP (*tail_ptr))
dab7f566
JB
2200 if (SCM_CAR (*tail_ptr) == obj)
2201 {
2202 *tail_ptr = SCM_CDR (*tail_ptr);
2203 break;
2204 }
2205 else
2206 tail_ptr = SCM_CDRLOC (*tail_ptr);
ef290276
JB
2207
2208 return obj;
2209}
2210
c45acc34
JB
2211int terminating;
2212
2213/* called on process termination. */
e52ceaac
MD
2214#ifdef HAVE_ATEXIT
2215static void
2216cleanup (void)
2217#else
2218#ifdef HAVE_ON_EXIT
51157deb
MD
2219extern int on_exit (void (*procp) (), int arg);
2220
e52ceaac
MD
2221static void
2222cleanup (int status, void *arg)
2223#else
2224#error Dont know how to setup a cleanup handler on your system.
2225#endif
2226#endif
c45acc34
JB
2227{
2228 terminating = 1;
2229 scm_flush_all_ports ();
2230}
ef290276 2231
0f2d19dd 2232\f
acb0a19c 2233static int
945fec60 2234make_initial_segment (scm_sizet init_heap_size, scm_freelist_t *freelistp)
acb0a19c
MD
2235{
2236 if (0L == init_heap_size)
2237 init_heap_size = SCM_INIT_HEAP_SIZE;
2238 if (!init_heap_seg ((SCM_CELLPTR) malloc (init_heap_size),
2239 init_heap_size,
acb0a19c
MD
2240 freelistp))
2241 {
2242 init_heap_size = SCM_HEAP_SEG_SIZE;
2243 if (!init_heap_seg ((SCM_CELLPTR) malloc (init_heap_size),
2244 init_heap_size,
acb0a19c
MD
2245 freelistp))
2246 return 1;
2247 }
2248 else
2249 scm_expmem = 1;
2250
2251 return 0;
2252}
2253
2254\f
4a4c9785
MD
2255#ifdef GUILE_NEW_GC_SCHEME
2256int
dd45c0df
MD
2257scm_init_storage (scm_sizet init_heap_size, int gc_trigger,
2258 scm_sizet init_heap2_size, int gc_trigger2)
4a4c9785 2259#else
0f2d19dd 2260int
acb0a19c 2261scm_init_storage (scm_sizet init_heap_size, scm_sizet init_heap2_size)
4a4c9785 2262#endif
0f2d19dd
JB
2263{
2264 scm_sizet j;
2265
2266 j = SCM_NUM_PROTECTS;
2267 while (j)
2268 scm_sys_protects[--j] = SCM_BOOL_F;
2269 scm_block_gc = 1;
4a4c9785
MD
2270
2271#ifdef GUILE_NEW_GC_SCHEME
2272 scm_freelist = SCM_EOL;
2273 scm_master_freelist.clusters = SCM_EOL;
2274 scm_master_freelist.triggeredp = 0;
4a4c9785
MD
2275 scm_master_freelist.gc_trigger
2276 = gc_trigger ? gc_trigger : SCM_GC_TRIGGER;
2277 scm_master_freelist.span = 1;
2278 scm_master_freelist.collected = 0;
2279 scm_master_freelist.heap_size = 0;
2280#else
945fec60
MD
2281 scm_freelist.cells = SCM_EOL;
2282 scm_freelist.span = 1;
2283 scm_freelist.collected = 0;
2284 scm_freelist.heap_size = 0;
4a4c9785
MD
2285#endif
2286
2287#ifdef GUILE_NEW_GC_SCHEME
2288 scm_freelist2 = SCM_EOL;
2289 scm_master_freelist2.clusters = SCM_EOL;
2290 scm_master_freelist2.triggeredp = 0;
4a4c9785
MD
2291 scm_master_freelist2.gc_trigger
2292 = gc_trigger2 ? gc_trigger2 : SCM_GC_TRIGGER2;
2293 scm_master_freelist2.span = 2;
2294 scm_master_freelist2.collected = 0;
2295 scm_master_freelist2.heap_size = 0;
2296#else
945fec60
MD
2297 scm_freelist2.cells = SCM_EOL;
2298 scm_freelist2.span = 2;
2299 scm_freelist2.collected = 0;
2300 scm_freelist2.heap_size = 0;
4a4c9785
MD
2301#endif
2302
0f2d19dd
JB
2303 scm_expmem = 0;
2304
2305 j = SCM_HEAP_SEG_SIZE;
2306 scm_mtrigger = SCM_INIT_MALLOC_LIMIT;
2307 scm_heap_table = ((struct scm_heap_seg_data *)
acb0a19c
MD
2308 scm_must_malloc (sizeof (struct scm_heap_seg_data) * 2, "hplims"));
2309
4a4c9785
MD
2310#ifdef GUILE_NEW_GC_SCHEME
2311 if (make_initial_segment (init_heap_size, &scm_master_freelist) ||
2312 make_initial_segment (init_heap2_size, &scm_master_freelist2))
2313 return 1;
2314#else
945fec60
MD
2315 if (make_initial_segment (init_heap_size, &scm_freelist) ||
2316 make_initial_segment (init_heap2_size, &scm_freelist2))
acb0a19c 2317 return 1;
4a4c9785 2318#endif
acb0a19c 2319
0f2d19dd 2320 scm_heap_org = CELL_UP (scm_heap_table[0].bounds[0]);
acb0a19c 2321
0f2d19dd 2322 /* scm_hplims[0] can change. do not remove scm_heap_org */
ab4bef85 2323 scm_weak_vectors = SCM_EOL;
0f2d19dd
JB
2324
2325 /* Initialise the list of ports. */
840ae05d
JB
2326 scm_port_table = (scm_port **)
2327 malloc (sizeof (scm_port *) * scm_port_table_room);
0f2d19dd
JB
2328 if (!scm_port_table)
2329 return 1;
2330
a18bcd0e 2331#ifdef HAVE_ATEXIT
c45acc34 2332 atexit (cleanup);
e52ceaac
MD
2333#else
2334#ifdef HAVE_ON_EXIT
2335 on_exit (cleanup, 0);
2336#endif
a18bcd0e 2337#endif
0f2d19dd
JB
2338
2339 scm_undefineds = scm_cons (SCM_UNDEFINED, SCM_EOL);
24e68a57 2340 SCM_SETCDR (scm_undefineds, scm_undefineds);
0f2d19dd
JB
2341
2342 scm_listofnull = scm_cons (SCM_EOL, SCM_EOL);
2343 scm_nullstr = scm_makstr (0L, 0);
a8741caa
MD
2344 scm_nullvect = scm_make_vector (SCM_INUM0, SCM_UNDEFINED);
2345 scm_symhash = scm_make_vector ((SCM) SCM_MAKINUM (scm_symhash_dim), SCM_EOL);
4037ac5f 2346 scm_weak_symhash = scm_make_weak_key_hash_table ((SCM) SCM_MAKINUM (scm_symhash_dim));
a8741caa 2347 scm_symhash_vars = scm_make_vector ((SCM) SCM_MAKINUM (scm_symhash_dim), SCM_EOL);
8960e0a0 2348 scm_stand_in_procs = SCM_EOL;
0f2d19dd 2349 scm_permobjs = SCM_EOL;
ef290276 2350 scm_protects = SCM_EOL;
3b2b8760 2351 scm_asyncs = SCM_EOL;
0f2d19dd
JB
2352 scm_sysintern ("most-positive-fixnum", (SCM) SCM_MAKINUM (SCM_MOST_POSITIVE_FIXNUM));
2353 scm_sysintern ("most-negative-fixnum", (SCM) SCM_MAKINUM (SCM_MOST_NEGATIVE_FIXNUM));
2354#ifdef SCM_BIGDIG
2355 scm_sysintern ("bignum-radix", SCM_MAKINUM (SCM_BIGRAD));
2356#endif
2357 return 0;
2358}
2359\f
2360
0f2d19dd
JB
2361void
2362scm_init_gc ()
0f2d19dd
JB
2363{
2364#include "gc.x"
2365}