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