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