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