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