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