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