* print.h: Added selector SCM_PRINT_STATE.
[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 {
353 pos = &SCM_CDR (type_list);
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);
519 mem = (SCM *)SCM_GCCDR (ptr); /* like struct_data but removes mark */
520
ad75306c
MD
521 if (len)
522 {
523 for (x = 0; x < len - 2; x += 2, ++mem)
524 if (fields_desc[x] == 'p')
525 scm_gc_mark (*mem);
526 if (fields_desc[x] == 'p')
527 {
528 if (SCM_LAYOUT_TAILP (fields_desc[x + 1]))
529 for (x = *mem; x; --x)
530 scm_gc_mark (*++mem);
531 else
532 scm_gc_mark (*mem);
533 }
534 }
0f2d19dd
JB
535 if (!SCM_CDR (vcell))
536 {
537 SCM_SETGCMARK (vcell);
538 ptr = vtable_data[scm_struct_i_vtable];
539 goto gc_mark_loop;
540 }
541 }
542 }
543 }
544 break;
545 case scm_tcs_closures:
546 if (SCM_GCMARKP (ptr))
547 break;
548 SCM_SETGCMARK (ptr);
549 if (SCM_IMP (SCM_CDR (ptr)))
550 {
551 ptr = SCM_CLOSCAR (ptr);
552 goto gc_mark_nimp;
553 }
554 scm_gc_mark (SCM_CLOSCAR (ptr));
555 ptr = SCM_GCCDR (ptr);
556 goto gc_mark_nimp;
557 case scm_tc7_vector:
558 case scm_tc7_lvector:
559#ifdef CCLO
560 case scm_tc7_cclo:
561#endif
562 if (SCM_GC8MARKP (ptr))
563 break;
564 SCM_SETGC8MARK (ptr);
565 i = SCM_LENGTH (ptr);
566 if (i == 0)
567 break;
568 while (--i > 0)
569 if (SCM_NIMP (SCM_VELTS (ptr)[i]))
570 scm_gc_mark (SCM_VELTS (ptr)[i]);
571 ptr = SCM_VELTS (ptr)[0];
572 goto gc_mark_loop;
573 case scm_tc7_contin:
574 if SCM_GC8MARKP
575 (ptr) break;
576 SCM_SETGC8MARK (ptr);
577 scm_mark_locations (SCM_VELTS (ptr),
578 (scm_sizet) (SCM_LENGTH (ptr) + sizeof (regs) / sizeof (SCM_STACKITEM)));
579 break;
580 case scm_tc7_bvect:
581 case scm_tc7_byvect:
582 case scm_tc7_ivect:
583 case scm_tc7_uvect:
584 case scm_tc7_fvect:
585 case scm_tc7_dvect:
586 case scm_tc7_cvect:
587 case scm_tc7_svect:
588#ifdef LONGLONGS
589 case scm_tc7_llvect:
590#endif
591
592 case scm_tc7_string:
593 case scm_tc7_mb_string:
594 SCM_SETGC8MARK (ptr);
595 break;
596
597 case scm_tc7_substring:
598 case scm_tc7_mb_substring:
599 if (SCM_GC8MARKP(ptr))
600 break;
601 SCM_SETGC8MARK (ptr);
602 ptr = SCM_CDR (ptr);
603 goto gc_mark_loop;
604
605 case scm_tc7_wvect:
606 if (SCM_GC8MARKP(ptr))
607 break;
608 scm_weak_vectors[scm_n_weak++] = ptr;
609 if (scm_n_weak >= scm_weak_size)
610 {
611 SCM_SYSCALL (scm_weak_vectors =
612 (SCM *) realloc ((char *) scm_weak_vectors,
613 sizeof (SCM *) * (scm_weak_size *= 2)));
614 if (scm_weak_vectors == NULL)
615 {
616 scm_gen_puts (scm_regular_string,
617 "weak vector table",
618 scm_cur_errp);
619 scm_gen_puts (scm_regular_string,
620 "\nFATAL ERROR DURING CRITICAL SCM_CODE SECTION\n",
621 scm_cur_errp);
622 exit(SCM_EXIT_FAILURE);
623 }
624 }
625 SCM_SETGC8MARK (ptr);
626 if (SCM_IS_WHVEC_ANY (ptr))
627 {
628 int x;
629 int len;
630 int weak_keys;
631 int weak_values;
632
633 len = SCM_LENGTH (ptr);
634 weak_keys = SCM_IS_WHVEC (ptr) || SCM_IS_WHVEC_B (ptr);
635 weak_values = SCM_IS_WHVEC_V (ptr) || SCM_IS_WHVEC_B (ptr);
636
637 for (x = 0; x < len; ++x)
638 {
639 SCM alist;
640 alist = SCM_VELTS (ptr)[x];
641 /* mark everything on the alist
642 * except the keys or values, according to weak_values and weak_keys.
643 */
644 while ( SCM_NIMP (alist)
645 && SCM_CONSP (alist)
646 && !SCM_GCMARKP (alist)
647 && SCM_NIMP (SCM_CAR (alist))
648 && SCM_CONSP (SCM_CAR (alist)))
649 {
650 SCM kvpair;
651 SCM next_alist;
652
653 kvpair = SCM_CAR (alist);
654 next_alist = SCM_CDR (alist);
655 /*
656 * Do not do this:
657 * SCM_SETGCMARK (alist);
658 * SCM_SETGCMARK (kvpair);
659 *
660 * It may be that either the key or value is protected by
661 * an escaped reference to part of the spine of this alist.
662 * If we mark the spine here, and only mark one or neither of the
663 * key and value, they may never be properly marked.
664 * This leads to a horrible situation in which an alist containing
665 * freelist cells is exported.
666 *
667 * So only mark the spines of these arrays last of all marking.
668 * If somebody confuses us by constructing a weak vector
669 * with a circular alist then we are hosed, but at least we
670 * won't prematurely drop table entries.
671 */
672 if (!weak_keys)
673 scm_gc_mark (SCM_CAR (kvpair));
674 if (!weak_values)
675 scm_gc_mark (SCM_GCCDR (kvpair));
676 alist = next_alist;
677 }
678 if (SCM_NIMP (alist))
679 scm_gc_mark (alist);
680 }
681 }
682 break;
683
684 case scm_tc7_msymbol:
685 if (SCM_GC8MARKP(ptr))
686 break;
687 SCM_SETGC8MARK (ptr);
688 scm_gc_mark (SCM_SYMBOL_FUNC (ptr));
689 ptr = SCM_SYMBOL_PROPS (ptr);
690 goto gc_mark_loop;
691 case scm_tc7_ssymbol:
692 if (SCM_GC8MARKP(ptr))
693 break;
694 SCM_SETGC8MARK (ptr);
695 break;
696 case scm_tcs_subrs:
697 ptr = (SCM)(scm_heap_org + (((unsigned long)SCM_CAR (ptr)) >> 8));
698 goto gc_mark_loop;
699 case scm_tc7_port:
700 i = SCM_PTOBNUM (ptr);
701 if (!(i < scm_numptob))
702 goto def;
703 if (SCM_GC8MARKP (ptr))
704 break;
ebf7394e
GH
705 if (SCM_PTAB_ENTRY(ptr))
706 scm_gc_mark (SCM_PTAB_ENTRY(ptr)->file_name);
0f2d19dd
JB
707 ptr = (scm_ptobs[i].mark) (ptr);
708 goto gc_mark_loop;
709 break;
710 case scm_tc7_smob:
711 if (SCM_GC8MARKP (ptr))
712 break;
713 switch SCM_TYP16 (ptr)
714 { /* should be faster than going through scm_smobs */
715 case scm_tc_free_cell:
716 /* printf("found free_cell %X ", ptr); fflush(stdout); */
717 SCM_SETGC8MARK (ptr);
718 SCM_CDR (ptr) = SCM_EOL;
719 break;
720 case scm_tcs_bignums:
721 case scm_tc16_flo:
722 SCM_SETGC8MARK (ptr);
723 break;
724 default:
725 i = SCM_SMOBNUM (ptr);
726 if (!(i < scm_numsmob))
727 goto def;
728 ptr = (scm_smobs[i].mark) (ptr);
729 goto gc_mark_loop;
730 }
731 break;
732 default:
733 def:scm_wta (ptr, "unknown type in ", "gc_mark");
734 }
735}
736
737
738/* Mark a Region Conservatively
739 */
740
0f2d19dd
JB
741void
742scm_mark_locations (x, n)
743 SCM_STACKITEM x[];
744 scm_sizet n;
0f2d19dd
JB
745{
746 register long m = n;
747 register int i, j;
748 register SCM_CELLPTR ptr;
749
750 while (0 <= --m)
751 if SCM_CELLP (*(SCM **) & x[m])
752 {
753 ptr = (SCM_CELLPTR) SCM2PTR ((*(SCM **) & x[m]));
754 i = 0;
755 j = scm_n_heap_segs - 1;
756 if ( SCM_PTR_LE (scm_heap_table[i].bounds[0], ptr)
757 && SCM_PTR_GT (scm_heap_table[j].bounds[1], ptr))
758 {
759 while (i <= j)
760 {
761 int seg_id;
762 seg_id = -1;
763 if ( (i == j)
764 || SCM_PTR_GT (scm_heap_table[i].bounds[1], ptr))
765 seg_id = i;
766 else if (SCM_PTR_LE (scm_heap_table[j].bounds[0], ptr))
767 seg_id = j;
768 else
769 {
770 int k;
771 k = (i + j) / 2;
772 if (k == i)
773 break;
774 if (SCM_PTR_GT (scm_heap_table[k].bounds[1], ptr))
775 {
776 j = k;
777 ++i;
778 if (SCM_PTR_LE (scm_heap_table[i].bounds[0], ptr))
779 continue;
780 else
781 break;
782 }
783 else if (SCM_PTR_LE (scm_heap_table[k].bounds[0], ptr))
784 {
785 i = k;
786 --j;
787 if (SCM_PTR_GT (scm_heap_table[j].bounds[1], ptr))
788 continue;
789 else
790 break;
791 }
792 }
793 if ( !scm_heap_table[seg_id].valid
794 || scm_heap_table[seg_id].valid (ptr,
795 &scm_heap_table[seg_id]))
796 scm_gc_mark (*(SCM *) & x[m]);
797 break;
798 }
799
800 }
801 }
802}
803
804
2e11a577
MD
805/* The following is a C predicate which determines if an SCM value can be
806 regarded as a pointer to a cell on the heap. The code is duplicated
807 from scm_mark_locations. */
808
1cc91f1b 809
2e11a577
MD
810int
811scm_cellp (value)
812 SCM value;
2e11a577
MD
813{
814 register int i, j;
815 register SCM_CELLPTR ptr;
816
817 if SCM_CELLP (*(SCM **) & value)
818 {
819 ptr = (SCM_CELLPTR) SCM2PTR ((*(SCM **) & value));
820 i = 0;
821 j = scm_n_heap_segs - 1;
822 if ( SCM_PTR_LE (scm_heap_table[i].bounds[0], ptr)
823 && SCM_PTR_GT (scm_heap_table[j].bounds[1], ptr))
824 {
825 while (i <= j)
826 {
827 int seg_id;
828 seg_id = -1;
829 if ( (i == j)
830 || SCM_PTR_GT (scm_heap_table[i].bounds[1], ptr))
831 seg_id = i;
832 else if (SCM_PTR_LE (scm_heap_table[j].bounds[0], ptr))
833 seg_id = j;
834 else
835 {
836 int k;
837 k = (i + j) / 2;
838 if (k == i)
839 break;
840 if (SCM_PTR_GT (scm_heap_table[k].bounds[1], ptr))
841 {
842 j = k;
843 ++i;
844 if (SCM_PTR_LE (scm_heap_table[i].bounds[0], ptr))
845 continue;
846 else
847 break;
848 }
849 else if (SCM_PTR_LE (scm_heap_table[k].bounds[0], ptr))
850 {
851 i = k;
852 --j;
853 if (SCM_PTR_GT (scm_heap_table[j].bounds[1], ptr))
854 continue;
855 else
856 break;
857 }
858 }
859 if ( !scm_heap_table[seg_id].valid
860 || scm_heap_table[seg_id].valid (ptr,
861 &scm_heap_table[seg_id]))
862 return 1;
863 break;
864 }
865
866 }
867 }
868 return 0;
869}
870
871
3b2b8760 872static void
0f2d19dd 873scm_mark_weak_vector_spines ()
0f2d19dd
JB
874{
875 int i;
876
877 for (i = 0; i < scm_n_weak; ++i)
878 {
879 if (SCM_IS_WHVEC_ANY (scm_weak_vectors[i]))
880 {
881 SCM *ptr;
882 SCM obj;
883 int j;
884 int n;
885
886 obj = scm_weak_vectors[i];
887 ptr = SCM_VELTS (scm_weak_vectors[i]);
888 n = SCM_LENGTH (scm_weak_vectors[i]);
889 for (j = 0; j < n; ++j)
890 {
891 SCM alist;
892
893 alist = ptr[j];
894 while ( SCM_NIMP (alist)
895 && SCM_CONSP (alist)
896 && !SCM_GCMARKP (alist)
897 && SCM_NIMP (SCM_CAR (alist))
898 && SCM_CONSP (SCM_CAR (alist)))
899 {
900 SCM_SETGCMARK (alist);
901 SCM_SETGCMARK (SCM_CAR (alist));
902 alist = SCM_GCCDR (alist);
903 }
904 }
905 }
906 }
907}
908
909
910
0f2d19dd
JB
911void
912scm_gc_sweep ()
0f2d19dd
JB
913{
914 register SCM_CELLPTR ptr;
915#ifdef SCM_POINTERS_MUNGED
916 register SCM scmptr;
917#else
918#undef scmptr
919#define scmptr (SCM)ptr
920#endif
921 register SCM nfreelist;
922 register SCM *hp_freelist;
923 register long n;
924 register long m;
925 register scm_sizet j;
926 register int span;
927 scm_sizet i;
928 scm_sizet seg_size;
929
930 n = 0;
931 m = 0;
932 i = 0;
933
934 while (i < scm_n_heap_segs)
935 {
936 hp_freelist = scm_heap_table[i].freelistp;
937 nfreelist = SCM_EOL;
938 span = scm_heap_table[i].ncells;
939 ptr = CELL_UP (scm_heap_table[i].bounds[0]);
940 seg_size = CELL_DN (scm_heap_table[i].bounds[1]) - ptr;
941 ++i;
942 for (j = seg_size + span; j -= span; ptr += span)
943 {
944#ifdef SCM_POINTERS_MUNGED
945 scmptr = PTR2SCM (ptr);
946#endif
947 switch SCM_TYP7 (scmptr)
948 {
949 case scm_tcs_cons_gloc:
950 if (SCM_GCMARKP (scmptr))
951 {
952 if (SCM_CDR (SCM_CAR (scmptr) - 1) == (SCM)1)
953 SCM_CDR (SCM_CAR (scmptr) - 1) = (SCM)0;
954 goto cmrkcontinue;
955 }
956 {
957 SCM vcell;
958 vcell = SCM_CAR (scmptr) - 1L;
959
960 if ((SCM_CDR (vcell) == 0) || (SCM_CDR (vcell) == 1))
961 {
962 SCM * mem;
963 SCM amt;
964 mem = (SCM *)SCM_CDR (scmptr);
ad75306c
MD
965 amt = mem[- scm_struct_n_extra_words];
966 free (mem - scm_struct_n_extra_words);
0f2d19dd
JB
967 m += amt * sizeof (SCM);
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;
1067 m += SCM_LENGTH (scmptr) * sizeof (SCM_STACKITEM) + sizeof (regs);
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++;
1093 SCM_CAR (scmptr) &= ~SCM_OPN;
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
1149 SCM_CAR (scmptr) = (SCM) scm_tc_free_cell;
1150 SCM_CDR (scmptr) = nfreelist;
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
1230 fixup = &SCM_CDR (alist);
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
1456 SCM_CAR (scmptr) = (SCM) scm_tc_free_cell;
1457 SCM_CDR (scmptr) = PTR2SCM (ptr + ncells);
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 */
1466 SCM_CDR (PTR2SCM (ptr)) = *freelistp;
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);
1662 SCM_CDR (scm_undefineds) = scm_undefineds;
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
JB
1669 scm_symhash_vars = scm_make_vector ((SCM) SCM_MAKINUM (scm_symhash_dim), SCM_EOL, SCM_UNDEFINED);
1670 scm_permobjs = SCM_EOL;
3b2b8760 1671 scm_asyncs = SCM_EOL;
0f2d19dd
JB
1672 scm_sysintern ("most-positive-fixnum", (SCM) SCM_MAKINUM (SCM_MOST_POSITIVE_FIXNUM));
1673 scm_sysintern ("most-negative-fixnum", (SCM) SCM_MAKINUM (SCM_MOST_NEGATIVE_FIXNUM));
1674#ifdef SCM_BIGDIG
1675 scm_sysintern ("bignum-radix", SCM_MAKINUM (SCM_BIGRAD));
1676#endif
1677 return 0;
1678}
1679\f
1680
0f2d19dd
JB
1681void
1682scm_init_gc ()
0f2d19dd
JB
1683{
1684#include "gc.x"
1685}