123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474 |
- /* Copyright (C) 1995,1996,1997,1998,1999,2000,2001, 2002, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
- #ifdef HAVE_CONFIG_H
- # include <config.h>
- #endif
- #include <stdio.h>
- #include <gmp.h>
- #include "libguile/_scm.h"
- #include "libguile/eval.h"
- #include "libguile/numbers.h"
- #include "libguile/stime.h"
- #include "libguile/stackchk.h"
- #include "libguile/struct.h"
- #include "libguile/smob.h"
- #include "libguile/unif.h"
- #include "libguile/async.h"
- #include "libguile/ports.h"
- #include "libguile/root.h"
- #include "libguile/strings.h"
- #include "libguile/vectors.h"
- #include "libguile/weaks.h"
- #include "libguile/hashtab.h"
- #include "libguile/tags.h"
- #include "libguile/private-gc.h"
- #include "libguile/validate.h"
- #include "libguile/deprecation.h"
- #include "libguile/gc.h"
- #include "libguile/srfi-4.h"
- #include "libguile/private-gc.h"
- long int scm_i_deprecated_memory_return;
- /* During collection, this accumulates structures which are to be freed.
- */
- SCM scm_i_structs_to_free;
- /*
- Init all the free cells in CARD, prepending to *FREE_LIST.
- Return: number of free cells found in this card.
- It would be cleaner to have a separate function sweep_value(), but
- that is too slow (functions with switch statements can't be
- inlined).
-
- NOTE:
- This function is quite efficient. However, for many types of cells,
- allocation and a de-allocation involves calling malloc() and
- free().
- This is costly for small objects (due to malloc/free overhead.)
- (should measure this).
- It might also be bad for threads: if several threads are allocating
- strings concurrently, then mallocs for both threads may have to
- fiddle with locks.
- It might be interesting to add a separate memory pool for small
- objects to each freelist.
- --hwn.
- */
- int
- scm_i_sweep_card (scm_t_cell * p, SCM *free_list, scm_t_heap_segment*seg)
- #define FUNC_NAME "sweep_card"
- {
- scm_t_c_bvec_long *bitvec = SCM_GC_CARD_BVEC(p);
- scm_t_cell * end = p + SCM_GC_CARD_N_CELLS;
- int span = seg->span;
- int offset =SCM_MAX (SCM_GC_CARD_N_HEADER_CELLS, span);
- int free_count = 0;
- /*
- I tried something fancy with shifting by one bit every word from
- the bitvec in turn, but it wasn't any faster, but quite a bit
- hairier.
- */
- for (p += offset; p < end; p += span, offset += span)
- {
- SCM scmptr = PTR2SCM (p);
- if (SCM_C_BVEC_GET (bitvec, offset))
- continue;
- switch (SCM_TYP7 (scmptr))
- {
- case scm_tcs_struct:
- /* The card can be swept more than once. Check that it's
- * the first time!
- */
- if (!SCM_STRUCT_GC_CHAIN (scmptr))
- {
- /* Structs need to be freed in a special order.
- * This is handled by GC C hooks in struct.c.
- */
- SCM_SET_STRUCT_GC_CHAIN (scmptr, scm_i_structs_to_free);
- scm_i_structs_to_free = scmptr;
- }
- continue;
-
- case scm_tcs_cons_imcar:
- case scm_tcs_cons_nimcar:
- case scm_tcs_closures:
- case scm_tc7_pws:
- break;
- case scm_tc7_wvect:
- case scm_tc7_vector:
- scm_i_vector_free (scmptr);
- break;
- #ifdef CCLO
- case scm_tc7_cclo:
- scm_gc_free (SCM_CCLO_BASE (scmptr),
- SCM_CCLO_LENGTH (scmptr) * sizeof (SCM),
- "compiled closure");
- break;
- #endif
- case scm_tc7_number:
- switch SCM_TYP16 (scmptr)
- {
- case scm_tc16_real:
- break;
- case scm_tc16_big:
- mpz_clear (SCM_I_BIG_MPZ (scmptr));
- /* nothing else to do here since the mpz is in a double cell */
- break;
- case scm_tc16_complex:
- scm_gc_free (SCM_COMPLEX_MEM (scmptr), sizeof (scm_t_complex),
- "complex");
- break;
- case scm_tc16_fraction:
- /* nothing to do here since the num/denum of a fraction
- are proper SCM objects themselves. */
- break;
- }
- break;
- case scm_tc7_string:
- scm_i_string_free (scmptr);
- break;
- case scm_tc7_stringbuf:
- scm_i_stringbuf_free (scmptr);
- break;
- case scm_tc7_symbol:
- scm_i_symbol_free (scmptr);
- break;
- case scm_tc7_variable:
- break;
- case scm_tcs_subrs:
- /* the various "subrs" (primitives) are never freed */
- continue;
- case scm_tc7_port:
- if SCM_OPENP (scmptr)
- {
- int k = SCM_PTOBNUM (scmptr);
- size_t mm;
- #if (SCM_DEBUG_CELL_ACCESSES == 1)
- if (!(k < scm_numptob))
- {
- fprintf (stderr, "undefined port type");
- abort();
- }
- #endif
- /* Keep "revealed" ports alive. */
- if (scm_revealed_count (scmptr) > 0)
- continue;
-
- /* Yes, I really do mean scm_ptobs[k].free */
- /* rather than ftobs[k].close. .close */
- /* is for explicit CLOSE-PORT by user */
- mm = scm_ptobs[k].free (scmptr);
- if (mm != 0)
- {
- #if SCM_ENABLE_DEPRECATED == 1
- scm_c_issue_deprecation_warning
- ("Returning non-0 from a port free function is "
- "deprecated. Use scm_gc_free et al instead.");
- scm_c_issue_deprecation_warning_fmt
- ("(You just returned non-0 while freeing a %s.)",
- SCM_PTOBNAME (k));
- scm_i_deprecated_memory_return += mm;
- #else
- abort ();
- #endif
- }
- SCM_SETSTREAM (scmptr, 0);
- scm_remove_from_port_table (scmptr);
- scm_gc_ports_collected++;
- SCM_CLR_PORT_OPEN_FLAG (scmptr);
- }
- break;
- case scm_tc7_smob:
- switch SCM_TYP16 (scmptr)
- {
- case scm_tc_free_cell:
- free_count --;
- break;
- default:
- {
- int k;
- k = SCM_SMOBNUM (scmptr);
- #if (SCM_DEBUG_CELL_ACCESSES == 1)
- if (!(k < scm_numsmob))
- {
- fprintf (stderr, "undefined smob type");
- abort();
- }
- #endif
- if (scm_smobs[k].free)
- {
- size_t mm;
- mm = scm_smobs[k].free (scmptr);
- if (mm != 0)
- {
- #if SCM_ENABLE_DEPRECATED == 1
- scm_c_issue_deprecation_warning
- ("Returning non-0 from a smob free function is "
- "deprecated. Use scm_gc_free et al instead.");
- scm_c_issue_deprecation_warning_fmt
- ("(You just returned non-0 while freeing a %s.)",
- SCM_SMOBNAME (k));
- scm_i_deprecated_memory_return += mm;
- #else
- abort();
- #endif
- }
- }
- break;
- }
- }
- break;
- default:
- fprintf (stderr, "unknown type");
- abort();
- }
- SCM_GC_SET_CELL_WORD (scmptr, 0, scm_tc_free_cell);
- SCM_SET_FREE_CELL_CDR (scmptr, PTR2SCM (*free_list));
- *free_list = scmptr;
- free_count ++;
- }
- return free_count;
- }
- #undef FUNC_NAME
- /*
- Like sweep, but no complicated logic to do the sweeping.
- */
- int
- scm_i_init_card_freelist (scm_t_cell * card, SCM *free_list,
- scm_t_heap_segment*seg)
- {
- int span = seg->span;
- scm_t_cell *end = card + SCM_GC_CARD_N_CELLS;
- scm_t_cell *p = end - span;
- scm_t_c_bvec_long * bvec_ptr = (scm_t_c_bvec_long* ) seg->bounds[1];
- int idx = (card - seg->bounds[0]) / SCM_GC_CARD_N_CELLS;
- bvec_ptr += idx *SCM_GC_CARD_BVEC_SIZE_IN_LONGS;
- SCM_GC_SET_CELL_BVEC (card, bvec_ptr);
-
- /*
- ASSUMPTION: n_header_cells <= 2.
- */
- for (; p > card; p -= span)
- {
- const SCM scmptr = PTR2SCM (p);
- SCM_GC_SET_CELL_WORD (scmptr, 0, scm_tc_free_cell);
- SCM_SET_FREE_CELL_CDR (scmptr, PTR2SCM (*free_list));
- *free_list = scmptr;
- }
- return SCM_GC_CARD_N_CELLS - SCM_MAX(span, SCM_GC_CARD_N_HEADER_CELLS);
- }
- void
- scm_i_card_statistics (scm_t_cell *p, SCM hashtab, scm_t_heap_segment *seg)
- {
- scm_t_c_bvec_long *bitvec = SCM_GC_CARD_BVEC(p);
- scm_t_cell * end = p + SCM_GC_CARD_N_CELLS;
- int span = seg->span;
- int offset = SCM_MAX (SCM_GC_CARD_N_HEADER_CELLS, span);
- if (!bitvec)
- /* Card P hasn't been initialized yet by `scm_i_init_card_freelist ()'. */
- return;
- for (p += offset; p < end; p += span, offset += span)
- {
- scm_t_bits tag = -1;
- SCM scmptr = PTR2SCM (p);
- if (!SCM_C_BVEC_GET (bitvec, offset))
- continue;
- tag = SCM_TYP7 (scmptr);
- if (tag == scm_tc7_smob || tag == scm_tc7_number)
- {
- /* Record smobs and numbers under 16 bits of the tag, so the
- different smob objects are distinguished, and likewise the
- different numbers big, real, complex and fraction. */
- tag = SCM_TYP16(scmptr);
- }
- else
- switch (tag)
- {
- case scm_tcs_cons_imcar:
- tag = scm_tc2_int;
- break;
- case scm_tcs_cons_nimcar:
- tag = scm_tc3_cons;
- break;
- case scm_tcs_struct:
- tag = scm_tc3_struct;
- break;
- case scm_tcs_closures:
- tag = scm_tc3_closure;
- break;
- case scm_tcs_subrs:
- tag = scm_tc7_asubr;
- break;
- }
- {
- SCM handle = scm_hashq_create_handle_x (hashtab,
- scm_from_int (tag), SCM_INUM0);
- SCM_SETCDR (handle, scm_from_int (scm_to_int (SCM_CDR (handle)) + 1));
- }
- }
- }
- /* TAG is the tag word of a cell, return a string which is its name, or NULL
- if unknown. Currently this is only used by gc-live-object-stats and the
- distinctions between types are oriented towards what that code records
- while scanning what's alive. */
- char const *
- scm_i_tag_name (scm_t_bits tag)
- {
- switch (tag & 0x7F) /* 7 bits */
- {
- case scm_tcs_struct:
- return "struct";
- case scm_tcs_cons_imcar:
- return "cons (immediate car)";
- case scm_tcs_cons_nimcar:
- return "cons (non-immediate car)";
- case scm_tcs_closures:
- return "closures";
- case scm_tc7_pws:
- return "pws";
- case scm_tc7_wvect:
- return "weak vector";
- case scm_tc7_vector:
- return "vector";
- #ifdef CCLO
- case scm_tc7_cclo:
- return "compiled closure";
- #endif
- case scm_tc7_number:
- switch (tag)
- {
- case scm_tc16_real:
- return "real";
- case scm_tc16_big:
- return "bignum";
- case scm_tc16_complex:
- return "complex number";
- case scm_tc16_fraction:
- return "fraction";
- }
- /* shouldn't reach here unless there's a new class of numbers */
- return "number";
- case scm_tc7_string:
- return "string";
- case scm_tc7_stringbuf:
- return "string buffer";
- case scm_tc7_symbol:
- return "symbol";
- case scm_tc7_variable:
- return "variable";
- case scm_tcs_subrs:
- return "subrs";
- case scm_tc7_port:
- return "port";
- case scm_tc7_smob:
- /* scm_tc_free_cell is smob 0, the name field in that scm_smobs[]
- entry should be ok for our return here */
- return scm_smobs[SCM_TC2SMOBNUM(tag)].name;
- }
- return NULL;
- }
- #if (SCM_DEBUG_DEBUGGING_SUPPORT == 1)
- typedef struct scm_dbg_t_list_cell {
- scm_t_bits car;
- struct scm_dbg_t_list_cell * cdr;
- } scm_dbg_t_list_cell;
- typedef struct scm_dbg_t_double_cell {
- scm_t_bits word_0;
- scm_t_bits word_1;
- scm_t_bits word_2;
- scm_t_bits word_3;
- } scm_dbg_t_double_cell;
- int scm_dbg_gc_marked_p (SCM obj);
- scm_t_cell * scm_dbg_gc_get_card (SCM obj);
- scm_t_c_bvec_long * scm_dbg_gc_get_bvec (SCM obj);
- int
- scm_dbg_gc_marked_p (SCM obj)
- {
- if (!SCM_IMP (obj))
- return SCM_GC_MARK_P(obj);
- else
- return 0;
- }
- scm_t_cell *
- scm_dbg_gc_get_card (SCM obj)
- {
- if (!SCM_IMP (obj))
- return SCM_GC_CELL_CARD(obj);
- else
- return NULL;
- }
- scm_t_c_bvec_long *
- scm_dbg_gc_get_bvec (SCM obj)
- {
- if (!SCM_IMP (obj))
- return SCM_GC_CARD_BVEC (SCM_GC_CELL_CARD (obj));
- else
- return NULL;
- }
- #endif
|