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