Mercurial > hg > xemacs-beta
diff src/alloc.c @ 3092:141c2920ea48
[xemacs-hg @ 2005-11-25 01:41:31 by crestani]
Incremental Garbage Collector
author | crestani |
---|---|
date | Fri, 25 Nov 2005 01:42:08 +0000 |
parents | d30cd499e445 |
children | db0631f96757 |
line wrap: on
line diff
--- a/src/alloc.c Thu Nov 24 22:51:25 2005 +0000 +++ b/src/alloc.c Fri Nov 25 01:42:08 2005 +0000 @@ -52,6 +52,7 @@ #include "extents-impl.h" #include "file-coding.h" #include "frame-impl.h" +#include "gc.h" #include "glyphs.h" #include "opaque.h" #include "lstream.h" @@ -62,6 +63,9 @@ #include "sysfile.h" #include "sysdep.h" #include "window.h" +#ifdef NEW_GC +#include "vdb.h" +#endif /* NEW_GC */ #include "console-stream.h" #ifdef DOUG_LEA_MALLOC @@ -70,8 +74,6 @@ EXFUN (Fgarbage_collect, 0); -static void recompute_need_to_garbage_collect (void); - #if 0 /* this is _way_ too slow to be part of the standard debug options */ #if defined(DEBUG_XEMACS) && defined(MULE) #define VERIFY_STRING_CHARS_INTEGRITY @@ -91,13 +93,6 @@ static Fixnum debug_allocation_backtrace_length; #endif -/* Number of bytes of consing done since the last gc */ -static EMACS_INT consing_since_gc; -EMACS_UINT total_consing; -EMACS_INT total_gc_usage; -int total_gc_usage_set; - -int need_to_garbage_collect; int need_to_check_c_alloca; int need_to_signal_post_gc; int funcall_allocation_flag; @@ -149,6 +144,20 @@ INCREMENT_CONS_COUNTER_1 (size) #endif +#ifdef NEW_GC +/* The call to recompute_need_to_garbage_collect is moved to + free_lrecord, since DECREMENT_CONS_COUNTER is extensively called + during sweep and recomputing need_to_garbage_collect all the time + is not needed. */ +#define DECREMENT_CONS_COUNTER(size) do { \ + consing_since_gc -= (size); \ + total_consing -= (size); \ + if (profiling_active) \ + profile_record_unconsing (size); \ + if (consing_since_gc < 0) \ + consing_since_gc = 0; \ +} while (0) +#else /* not NEW_GC */ #define DECREMENT_CONS_COUNTER(size) do { \ consing_since_gc -= (size); \ total_consing -= (size); \ @@ -158,51 +167,11 @@ consing_since_gc = 0; \ recompute_need_to_garbage_collect (); \ } while (0) - -/* Number of bytes of consing since gc before another gc should be done. */ -static EMACS_INT gc_cons_threshold; - -/* Percentage of consing of total data size before another GC. */ -static EMACS_INT gc_cons_percentage; - -#ifdef ERROR_CHECK_GC -int always_gc; /* Debugging hack; equivalent to - (setq gc-cons-thresold -1) */ -#else -#define always_gc 0 -#endif - -/* Nonzero during gc */ -int gc_in_progress; - -/* Nonzero means display messages at beginning and end of GC. */ - -int garbage_collection_messages; - -/* Number of times GC has happened at this level or below. - * Level 0 is most volatile, contrary to usual convention. - * (Of course, there's only one level at present) */ -EMACS_INT gc_generation_number[1]; +#endif /*not NEW_GC */ /* This is just for use by the printer, to allow things to print uniquely */ int lrecord_uid_counter; -/* Nonzero when calling certain hooks or doing other things where - a GC would be bad */ -int gc_currently_forbidden; - -/* Hooks. */ -Lisp_Object Vpre_gc_hook, Qpre_gc_hook; -Lisp_Object Vpost_gc_hook, Qpost_gc_hook; - -/* "Garbage collecting" */ -Lisp_Object Vgc_message; -Lisp_Object Vgc_pointer_glyph; -static const Ascbyte gc_default_message[] = "Garbage collecting"; -Lisp_Object Qgarbage_collecting; - -static Lisp_Object QSin_garbage_collection; - /* Non-zero means we're in the process of doing the dump */ int purify_flag; @@ -248,7 +217,7 @@ #ifndef MC_ALLOC -static void *breathing_space; +void *breathing_space; void release_breathing_space (void) @@ -282,6 +251,7 @@ DOESNT_RETURN memory_full (void) { + fprintf (stderr, "##### M E M O R Y F U L L #####\n"); /* Force a GC next time eval is called. It's better to loop garbage-collecting (we might reclaim enough to win) than to loop beeping and barfing "Memory exhausted" @@ -521,33 +491,10 @@ } lrecord_stats [countof (lrecord_implementations_table) + MODULE_DEFINABLE_TYPE_COUNT]; -int lrecord_string_data_instances_in_use; -int lrecord_string_data_bytes_in_use; -int lrecord_string_data_bytes_in_use_including_overhead; - void init_lrecord_stats () { xzero (lrecord_stats); - lrecord_string_data_instances_in_use = 0; - lrecord_string_data_bytes_in_use = 0; - lrecord_string_data_bytes_in_use_including_overhead = 0; -} - -void -inc_lrecord_string_data_stats (Bytecount size) -{ - lrecord_string_data_instances_in_use++; - lrecord_string_data_bytes_in_use += size; - lrecord_string_data_bytes_in_use_including_overhead += size; -} - -void -dec_lrecord_string_data_stats (Bytecount size) -{ - lrecord_string_data_instances_in_use--; - lrecord_string_data_bytes_in_use -= size; - lrecord_string_data_bytes_in_use_including_overhead -= size; } void @@ -581,6 +528,17 @@ DECREMENT_CONS_COUNTER (size); } + +int +lrecord_stats_heap_size (void) +{ + int i; + int size = 0; + for (i = 0; i < (countof (lrecord_implementations_table) + + MODULE_DEFINABLE_TYPE_COUNT); i++) + size += lrecord_stats[i].bytes_in_use; + return size; +} #endif /* not (MC_ALLOC && ALLOC_TYPE_STATS) */ #ifndef MC_ALLOC @@ -613,6 +571,7 @@ return lheader; } + void * noseeum_alloc_lrecord (Bytecount size, const struct lrecord_implementation *implementation) @@ -634,15 +593,59 @@ return lheader; } +#ifdef NEW_GC +void * +alloc_lrecord_array (Bytecount size, int elemcount, + const struct lrecord_implementation *implementation) +{ + struct lrecord_header *lheader; + Rawbyte *start, *stop; + + type_checking_assert + ((implementation->static_size == 0 ? + implementation->size_in_bytes_method != NULL : + implementation->static_size == size)); + + lheader = (struct lrecord_header *) mc_alloc_array (size, elemcount); + gc_checking_assert (LRECORD_FREE_P (lheader)); + + for (start = (Rawbyte *) lheader, + stop = ((Rawbyte *) lheader) + (size * elemcount -1); + start < stop; start += size) + { + struct lrecord_header *lh = (struct lrecord_header *) start; + set_lheader_implementation (lh, implementation); + lh->uid = lrecord_uid_counter++; +#ifdef ALLOC_TYPE_STATS + inc_lrecord_stats (size, lh); +#endif /* not ALLOC_TYPE_STATS */ + } + INCREMENT_CONS_COUNTER (size * elemcount, implementation->name); + return lheader; +} +#endif /* NEW_GC */ + void free_lrecord (Lisp_Object lrecord) { +#ifndef NEW_GC gc_checking_assert (!gc_in_progress); +#endif /* not NEW_GC */ gc_checking_assert (!LRECORD_FREE_P (XRECORD_LHEADER (lrecord))); gc_checking_assert (!XRECORD_LHEADER (lrecord)->free); +#ifdef NEW_GC + GC_STAT_EXPLICITLY_TRIED_FREED; + /* Ignore requests to manual free objects while in garbage collection. */ + if (write_barrier_enabled || gc_in_progress) + return; + + GC_STAT_EXPLICITLY_FREED; +#endif /* NEW_GC */ + MC_ALLOC_CALL_FINALIZER (XPNTR (lrecord)); mc_free (XPNTR (lrecord)); + recompute_need_to_garbage_collect (); } #else /* not MC_ALLOC */ @@ -955,16 +958,6 @@ remain free for the next 1000 (or whatever) times that an object of that type is allocated. */ -#ifndef MALLOC_OVERHEAD -#ifdef GNU_MALLOC -#define MALLOC_OVERHEAD 0 -#elif defined (rcheck) -#define MALLOC_OVERHEAD 20 -#else -#define MALLOC_OVERHEAD 8 -#endif -#endif /* MALLOC_OVERHEAD */ - #if !defined(HAVE_MMAP) || defined(DOUG_LEA_MALLOC) /* If we released our reserve (due to running out of memory), and we have a fair amount free once again, @@ -1832,7 +1825,11 @@ f->instructions = Qzero; f->constants = Qzero; f->arglist = Qnil; +#ifdef NEW_GC + f->arguments = Qnil; +#else /* not NEW_GC */ f->args = NULL; +#endif /* not NEW_GC */ f->max_args = f->min_args = f->args_in_array = 0; f->doc_and_interactive = Qnil; #ifdef COMPILED_FUNCTION_ANNOTATION_HACK @@ -2238,8 +2235,12 @@ } static const struct memory_description string_description[] = { +#ifdef NEW_GC + { XD_LISP_OBJECT, offsetof (Lisp_String, data_object) }, +#else /* not NEW_GC */ { XD_BYTECOUNT, offsetof (Lisp_String, size_) }, { XD_OPAQUE_DATA_PTR, offsetof (Lisp_String, data_), XD_INDIRECT(0, 1) }, +#endif /* not NEW_GC */ { XD_LISP_OBJECT, offsetof (Lisp_String, plist) }, { XD_END } }; @@ -2310,6 +2311,10 @@ Lisp_String); #endif /* not MC_ALLOC */ +#ifdef NEW_GC +#define STRING_FULLSIZE(size) \ + ALIGN_SIZE (FLEXIBLE_ARRAY_STRUCT_SIZEOF (Lisp_String_Direct_Data, Lisp_Object, data, (size) + 1), sizeof (Lisp_Object *)); +#else /* not NEW_GC */ /* String blocks contain this many useful bytes. */ #define STRING_CHARS_BLOCK_SIZE \ ((Bytecount) (8192 - MALLOC_OVERHEAD - \ @@ -2341,8 +2346,10 @@ #define STRING_CHARS_FREE_P(ptr) ((ptr)->string == NULL) #define MARK_STRING_CHARS_AS_FREE(ptr) ((void) ((ptr)->string = NULL)) +#endif /* not NEW_GC */ #ifdef MC_ALLOC +#ifndef NEW_GC static void finalize_string (void *header, int for_disksave) { @@ -2350,9 +2357,6 @@ { Lisp_String *s = (Lisp_String *) header; Bytecount size = s->size_; -#ifdef ALLOC_TYPE_STATS - dec_lrecord_string_data_stats (size); -#endif /* ALLOC_TYPE_STATS */ if (BIG_STRING_SIZE_P (size)) xfree (s->data_, Ibyte *); } @@ -2369,9 +2373,58 @@ string_remprop, string_plist, Lisp_String); - +#else /* NEW_GC */ +DEFINE_LRECORD_IMPLEMENTATION_WITH_PROPS ("string", string, + 1, /*dumpable-flag*/ + mark_string, print_string, + 0, + string_equal, 0, + string_description, + string_getprop, + string_putprop, + string_remprop, + string_plist, + Lisp_String); + + +static const struct memory_description string_direct_data_description[] = { + { XD_BYTECOUNT, offsetof (Lisp_String_Indirect_Data, size) }, + { XD_END } +}; + +static Bytecount +size_string_direct_data (const void *lheader) +{ + return STRING_FULLSIZE (((Lisp_String_Direct_Data *) lheader)->size); +} + + +DEFINE_LRECORD_SEQUENCE_IMPLEMENTATION ("string-direct-data", + string_direct_data, + 1, /*dumpable-flag*/ + 0, 0, 0, 0, 0, + string_direct_data_description, + size_string_direct_data, + Lisp_String_Direct_Data); + + +static const struct memory_description string_indirect_data_description[] = { + { XD_BYTECOUNT, offsetof (Lisp_String_Indirect_Data, size) }, + { XD_OPAQUE_DATA_PTR, offsetof (Lisp_String_Indirect_Data, data), + XD_INDIRECT(0, 1) }, + { XD_END } +}; + +DEFINE_LRECORD_IMPLEMENTATION ("string-indirect-data", + string_indirect_data, + 1, /*dumpable-flag*/ + 0, 0, 0, 0, 0, + string_indirect_data_description, + Lisp_String_Indirect_Data); +#endif /* NEW_GC */ #endif /* MC_ALLOC */ +#ifndef NEW_GC struct string_chars { Lisp_String *string; @@ -2438,6 +2491,7 @@ return s_chars; } +#endif /* not NEW_GC */ #ifdef SLEDGEHAMMER_CHECK_ASCII_BEGIN void @@ -2472,9 +2526,6 @@ #ifdef MC_ALLOC s = alloc_lrecord_type (Lisp_String, &lrecord_string); -#ifdef ALLOC_TYPE_STATS - inc_lrecord_string_data_stats (length); -#endif /* ALLOC_TYPE_STATS */ #else /* not MC_ALLOC */ /* Allocate the string header */ ALLOCATE_FIXED_TYPE (string, Lisp_String, s); @@ -2486,10 +2537,16 @@ ascii-length field, to some non-zero value. We need to zero it. */ XSET_STRING_ASCII_BEGIN (wrap_string (s), 0); +#ifdef NEW_GC + STRING_DATA_OBJECT (s) = + wrap_string_direct_data (alloc_lrecord (fullsize, + &lrecord_string_direct_data)); +#else /* not NEW_GC */ set_lispstringp_data (s, BIG_STRING_FULLSIZE_P (fullsize) ? allocate_big_string_chars (length + 1) : allocate_string_chars_struct (wrap_string (s), fullsize)->chars); +#endif /* not NEW_GC */ set_lispstringp_length (s, length); s->plist = Qnil; @@ -2511,7 +2568,11 @@ void resize_string (Lisp_Object s, Bytecount pos, Bytecount delta) { +#ifdef NEW_GC + Bytecount newfullsize, len; +#else /* not NEW_GC */ Bytecount oldfullsize, newfullsize; +#endif /* not NEW_GC */ #ifdef VERIFY_STRING_CHARS_INTEGRITY verify_string_chars_integrity (); #endif @@ -2539,6 +2600,23 @@ so convert this to the appropriate form. */ pos += -delta; +#ifdef NEW_GC + newfullsize = STRING_FULLSIZE (XSTRING_LENGTH (s) + delta); + + len = XSTRING_LENGTH (s) + 1 - pos; + + if (delta < 0 && pos >= 0) + memmove (XSTRING_DATA (s) + pos + delta, + XSTRING_DATA (s) + pos, len); + + XSTRING_DATA_OBJECT (s) = + wrap_string_direct_data (mc_realloc (XPNTR (XSTRING_DATA_OBJECT (s)), + newfullsize)); + if (delta > 0 && pos >= 0) + memmove (XSTRING_DATA (s) + pos + delta, XSTRING_DATA (s) + pos, + len); + +#else /* NEW_GC */ oldfullsize = STRING_FULLSIZE (XSTRING_LENGTH (s)); newfullsize = STRING_FULLSIZE (XSTRING_LENGTH (s) + delta); @@ -2631,6 +2709,7 @@ } } } +#endif /* not NEW_GC */ XSET_STRING_LENGTH (s, XSTRING_LENGTH (s) + delta); /* If pos < 0, the string won't be zero-terminated. @@ -2852,9 +2931,6 @@ #ifdef MC_ALLOC s = alloc_lrecord_type (Lisp_String, &lrecord_string); -#ifdef ALLOC_TYPE_STATS - inc_lrecord_string_data_stats (length); -#endif /* ALLOC_TYPE_STATS */ mcpro (wrap_pointer_1 (s)); /* otherwise nocopy_strings get collected and static data is tried to be freed. */ @@ -2867,8 +2943,18 @@ /* Don't need to XSET_STRING_ASCII_BEGIN() here because it happens in init_string_ascii_begin(). */ s->plist = Qnil; +#ifdef NEW_GC + set_lispstringp_indirect (s); + STRING_DATA_OBJECT (s) = + wrap_string_indirect_data + (alloc_lrecord_type (Lisp_String_Indirect_Data, + &lrecord_string_indirect_data)); + XSTRING_INDIRECT_DATA_DATA (STRING_DATA_OBJECT (s)) = (Ibyte *) contents; + XSTRING_INDIRECT_DATA_SIZE (STRING_DATA_OBJECT (s)) = length; +#else /* not NEW_GC */ set_lispstringp_data (s, (Ibyte *) contents); set_lispstringp_length (s, length); +#endif /* not NEW_GC */ val = wrap_string (s); init_string_ascii_begin (val); sledgehammer_check_ascii_begin (val); @@ -3337,787 +3423,6 @@ #endif /* not DEBUG_XEMACS */ #endif /* MC_ALLOC */ -#ifdef ERROR_CHECK_GC -#ifdef MC_ALLOC -#define GC_CHECK_LHEADER_INVARIANTS(lheader) do { \ - struct lrecord_header * GCLI_lh = (lheader); \ - assert (GCLI_lh != 0); \ - assert (GCLI_lh->type < (unsigned int) lrecord_type_count); \ -} while (0) -#else /* not MC_ALLOC */ -#define GC_CHECK_LHEADER_INVARIANTS(lheader) do { \ - struct lrecord_header * GCLI_lh = (lheader); \ - assert (GCLI_lh != 0); \ - assert (GCLI_lh->type < (unsigned int) lrecord_type_count); \ - assert (! C_READONLY_RECORD_HEADER_P (GCLI_lh) || \ - (MARKED_RECORD_HEADER_P (GCLI_lh) && \ - LISP_READONLY_RECORD_HEADER_P (GCLI_lh))); \ -} while (0) -#endif /* not MC_ALLOC */ -#else -#define GC_CHECK_LHEADER_INVARIANTS(lheader) -#endif - - -static const struct memory_description lisp_object_description_1[] = { - { XD_LISP_OBJECT, 0 }, - { XD_END } -}; - -const struct sized_memory_description lisp_object_description = { - sizeof (Lisp_Object), - lisp_object_description_1 -}; - -#if defined (USE_KKCC) || defined (PDUMP) - -/* This function extracts the value of a count variable described somewhere - else in the description. It is converted corresponding to the type */ -EMACS_INT -lispdesc_indirect_count_1 (EMACS_INT code, - const struct memory_description *idesc, - const void *idata) -{ - EMACS_INT count; - const void *irdata; - - int line = XD_INDIRECT_VAL (code); - int delta = XD_INDIRECT_DELTA (code); - - irdata = ((char *) idata) + - lispdesc_indirect_count (idesc[line].offset, idesc, idata); - switch (idesc[line].type) - { - case XD_BYTECOUNT: - count = * (Bytecount *) irdata; - break; - case XD_ELEMCOUNT: - count = * (Elemcount *) irdata; - break; - case XD_HASHCODE: - count = * (Hashcode *) irdata; - break; - case XD_INT: - count = * (int *) irdata; - break; - case XD_LONG: - count = * (long *) irdata; - break; - default: - stderr_out ("Unsupported count type : %d (line = %d, code = %ld)\n", - idesc[line].type, line, (long) code); -#if defined(USE_KKCC) && defined(DEBUG_XEMACS) - if (gc_in_progress) - kkcc_backtrace (); -#endif -#ifdef PDUMP - if (in_pdump) - pdump_backtrace (); -#endif - count = 0; /* warning suppression */ - ABORT (); - } - count += delta; - return count; -} - -/* SDESC is a "description map" (basically, a list of offsets used for - successive indirections) and OBJ is the first object to indirect off of. - Return the description ultimately found. */ - -const struct sized_memory_description * -lispdesc_indirect_description_1 (const void *obj, - const struct sized_memory_description *sdesc) -{ - int pos; - - for (pos = 0; sdesc[pos].size >= 0; pos++) - obj = * (const void **) ((const char *) obj + sdesc[pos].size); - - return (const struct sized_memory_description *) obj; -} - -/* Compute the size of the data at RDATA, described by a single entry - DESC1 in a description array. OBJ and DESC are used for - XD_INDIRECT references. */ - -static Bytecount -lispdesc_one_description_line_size (void *rdata, - const struct memory_description *desc1, - const void *obj, - const struct memory_description *desc) -{ - union_switcheroo: - switch (desc1->type) - { - case XD_LISP_OBJECT_ARRAY: - { - EMACS_INT val = lispdesc_indirect_count (desc1->data1, desc, obj); - return (val * sizeof (Lisp_Object)); - } - case XD_LISP_OBJECT: - case XD_LO_LINK: - return sizeof (Lisp_Object); - case XD_OPAQUE_PTR: - return sizeof (void *); - case XD_BLOCK_PTR: - { - EMACS_INT val = lispdesc_indirect_count (desc1->data1, desc, obj); - return val * sizeof (void *); - } - case XD_BLOCK_ARRAY: - { - EMACS_INT val = lispdesc_indirect_count (desc1->data1, desc, obj); - - return (val * - lispdesc_block_size - (rdata, - lispdesc_indirect_description (obj, desc1->data2.descr))); - } - case XD_OPAQUE_DATA_PTR: - return sizeof (void *); - case XD_UNION_DYNAMIC_SIZE: - { - /* If an explicit size was given in the first-level structure - description, use it; else compute size based on current union - constant. */ - const struct sized_memory_description *sdesc = - lispdesc_indirect_description (obj, desc1->data2.descr); - if (sdesc->size) - return sdesc->size; - else - { - desc1 = lispdesc_process_xd_union (desc1, desc, obj); - if (desc1) - goto union_switcheroo; - break; - } - } - case XD_UNION: - { - /* If an explicit size was given in the first-level structure - description, use it; else compute size based on maximum of all - possible structures. */ - const struct sized_memory_description *sdesc = - lispdesc_indirect_description (obj, desc1->data2.descr); - if (sdesc->size) - return sdesc->size; - else - { - int count; - Bytecount max_size = -1, size; - - desc1 = sdesc->description; - - for (count = 0; desc1[count].type != XD_END; count++) - { - size = lispdesc_one_description_line_size (rdata, - &desc1[count], - obj, desc); - if (size > max_size) - max_size = size; - } - return max_size; - } - } - case XD_ASCII_STRING: - return sizeof (void *); - case XD_DOC_STRING: - return sizeof (void *); - case XD_INT_RESET: - return sizeof (int); - case XD_BYTECOUNT: - return sizeof (Bytecount); - case XD_ELEMCOUNT: - return sizeof (Elemcount); - case XD_HASHCODE: - return sizeof (Hashcode); - case XD_INT: - return sizeof (int); - case XD_LONG: - return sizeof (long); - default: - stderr_out ("Unsupported dump type : %d\n", desc1->type); - ABORT (); - } - - return 0; -} - - -/* Return the size of the memory block (NOT necessarily a structure!) - described by SDESC and pointed to by OBJ. If SDESC records an - explicit size (i.e. non-zero), it is simply returned; otherwise, - the size is calculated by the maximum offset and the size of the - object at that offset, rounded up to the maximum alignment. In - this case, we may need the object, for example when retrieving an - "indirect count" of an inlined array (the count is not constant, - but is specified by one of the elements of the memory block). (It - is generally not a problem if we return an overly large size -- we - will simply end up reserving more space than necessary; but if the - size is too small we could be in serious trouble, in particular - with nested inlined structures, where there may be alignment - padding in the middle of a block. #### In fact there is an (at - least theoretical) problem with an overly large size -- we may - trigger a protection fault when reading from invalid memory. We - need to handle this -- perhaps in a stupid but dependable way, - i.e. by trapping SIGSEGV and SIGBUS.) */ - -Bytecount -lispdesc_block_size_1 (const void *obj, Bytecount size, - const struct memory_description *desc) -{ - EMACS_INT max_offset = -1; - int max_offset_pos = -1; - int pos; - - if (size) - return size; - - for (pos = 0; desc[pos].type != XD_END; pos++) - { - EMACS_INT offset = lispdesc_indirect_count (desc[pos].offset, desc, obj); - if (offset == max_offset) - { - stderr_out ("Two relocatable elements at same offset?\n"); - ABORT (); - } - else if (offset > max_offset) - { - max_offset = offset; - max_offset_pos = pos; - } - } - - if (max_offset_pos < 0) - return 0; - - { - Bytecount size_at_max; - size_at_max = - lispdesc_one_description_line_size ((char *) obj + max_offset, - &desc[max_offset_pos], obj, desc); - - /* We have no way of knowing the required alignment for this structure, - so just make it maximally aligned. */ - return MAX_ALIGN_SIZE (max_offset + size_at_max); - } -} - -#endif /* defined (USE_KKCC) || defined (PDUMP) */ - -#ifdef MC_ALLOC -#define GC_CHECK_NOT_FREE(lheader) \ - gc_checking_assert (! LRECORD_FREE_P (lheader)); -#else /* MC_ALLOC */ -#define GC_CHECK_NOT_FREE(lheader) \ - gc_checking_assert (! LRECORD_FREE_P (lheader)); \ - gc_checking_assert (LHEADER_IMPLEMENTATION (lheader)->basic_p || \ - ! ((struct old_lcrecord_header *) lheader)->free) -#endif /* MC_ALLOC */ - -#ifdef USE_KKCC -/* The following functions implement the new mark algorithm. - They mark objects according to their descriptions. They - are modeled on the corresponding pdumper procedures. */ - -#ifdef DEBUG_XEMACS -/* The backtrace for the KKCC mark functions. */ -#define KKCC_INIT_BT_STACK_SIZE 4096 - -typedef struct -{ - void *obj; - const struct memory_description *desc; - int pos; -} kkcc_bt_stack_entry; - -static kkcc_bt_stack_entry *kkcc_bt; -static int kkcc_bt_stack_size; -static int kkcc_bt_depth = 0; - -static void -kkcc_bt_init (void) -{ - kkcc_bt_depth = 0; - kkcc_bt_stack_size = KKCC_INIT_BT_STACK_SIZE; - kkcc_bt = (kkcc_bt_stack_entry *) - malloc (kkcc_bt_stack_size * sizeof (kkcc_bt_stack_entry)); - if (!kkcc_bt) - { - stderr_out ("KKCC backtrace stack init failed for size %d\n", - kkcc_bt_stack_size); - ABORT (); - } -} - -void -kkcc_backtrace (void) -{ - int i; - stderr_out ("KKCC mark stack backtrace :\n"); - for (i = kkcc_bt_depth - 1; i >= 0; i--) - { - Lisp_Object obj = wrap_pointer_1 (kkcc_bt[i].obj); - stderr_out (" [%d]", i); -#ifdef MC_ALLOC - if ((XRECORD_LHEADER (obj)->type >= lrecord_type_last_built_in_type) -#else /* not MC_ALLOC */ - if ((XRECORD_LHEADER (obj)->type >= lrecord_type_free) -#endif /* not MC_ALLOC */ - || (!LRECORDP (obj)) - || (!XRECORD_LHEADER_IMPLEMENTATION (obj))) - { - stderr_out (" non Lisp Object"); - } - else - { - stderr_out (" %s", - XRECORD_LHEADER_IMPLEMENTATION (obj)->name); - } - stderr_out (" (addr: 0x%x, desc: 0x%x, ", - (int) kkcc_bt[i].obj, - (int) kkcc_bt[i].desc); - if (kkcc_bt[i].pos >= 0) - stderr_out ("pos: %d)\n", kkcc_bt[i].pos); - else - stderr_out ("root set)\n"); - } -} - -static void -kkcc_bt_stack_realloc (void) -{ - kkcc_bt_stack_size *= 2; - kkcc_bt = (kkcc_bt_stack_entry *) - realloc (kkcc_bt, kkcc_bt_stack_size * sizeof (kkcc_bt_stack_entry)); - if (!kkcc_bt) - { - stderr_out ("KKCC backtrace stack realloc failed for size %d\n", - kkcc_bt_stack_size); - ABORT (); - } -} - -static void -kkcc_bt_free (void) -{ - free (kkcc_bt); - kkcc_bt = 0; - kkcc_bt_stack_size = 0; -} - -static void -kkcc_bt_push (void *obj, const struct memory_description *desc, - int level, int pos) -{ - kkcc_bt_depth = level; - kkcc_bt[kkcc_bt_depth].obj = obj; - kkcc_bt[kkcc_bt_depth].desc = desc; - kkcc_bt[kkcc_bt_depth].pos = pos; - kkcc_bt_depth++; - if (kkcc_bt_depth >= kkcc_bt_stack_size) - kkcc_bt_stack_realloc (); -} - -#else /* not DEBUG_XEMACS */ -#define kkcc_bt_init() -#define kkcc_bt_push(obj, desc, level, pos) -#endif /* not DEBUG_XEMACS */ - -/* Object memory descriptions are in the lrecord_implementation structure. - But copying them to a parallel array is much more cache-friendly. */ -const struct memory_description *lrecord_memory_descriptions[countof (lrecord_implementations_table)]; - -/* the initial stack size in kkcc_gc_stack_entries */ -#define KKCC_INIT_GC_STACK_SIZE 16384 - -typedef struct -{ - void *data; - const struct memory_description *desc; -#ifdef DEBUG_XEMACS - int level; - int pos; -#endif -} kkcc_gc_stack_entry; - -static kkcc_gc_stack_entry *kkcc_gc_stack_ptr; -static kkcc_gc_stack_entry *kkcc_gc_stack_top; -static kkcc_gc_stack_entry *kkcc_gc_stack_last_entry; -static int kkcc_gc_stack_size; - -static void -kkcc_gc_stack_init (void) -{ - kkcc_gc_stack_size = KKCC_INIT_GC_STACK_SIZE; - kkcc_gc_stack_ptr = (kkcc_gc_stack_entry *) - malloc (kkcc_gc_stack_size * sizeof (kkcc_gc_stack_entry)); - if (!kkcc_gc_stack_ptr) - { - stderr_out ("stack init failed for size %d\n", kkcc_gc_stack_size); - ABORT (); - } - kkcc_gc_stack_top = kkcc_gc_stack_ptr - 1; - kkcc_gc_stack_last_entry = kkcc_gc_stack_ptr + kkcc_gc_stack_size - 1; -} - -static void -kkcc_gc_stack_free (void) -{ - free (kkcc_gc_stack_ptr); - kkcc_gc_stack_ptr = 0; - kkcc_gc_stack_top = 0; - kkcc_gc_stack_size = 0; -} - -static void -kkcc_gc_stack_realloc (void) -{ - int current_offset = (int)(kkcc_gc_stack_top - kkcc_gc_stack_ptr); - kkcc_gc_stack_size *= 2; - kkcc_gc_stack_ptr = (kkcc_gc_stack_entry *) - realloc (kkcc_gc_stack_ptr, - kkcc_gc_stack_size * sizeof (kkcc_gc_stack_entry)); - if (!kkcc_gc_stack_ptr) - { - stderr_out ("stack realloc failed for size %d\n", kkcc_gc_stack_size); - ABORT (); - } - kkcc_gc_stack_top = kkcc_gc_stack_ptr + current_offset; - kkcc_gc_stack_last_entry = kkcc_gc_stack_ptr + kkcc_gc_stack_size - 1; -} - -#define KKCC_GC_STACK_FULL (kkcc_gc_stack_top >= kkcc_gc_stack_last_entry) -#define KKCC_GC_STACK_EMPTY (kkcc_gc_stack_top < kkcc_gc_stack_ptr) - -static void -#ifdef DEBUG_XEMACS -kkcc_gc_stack_push_1 (void *data, const struct memory_description *desc, - int level, int pos) -#else -kkcc_gc_stack_push_1 (void *data, const struct memory_description *desc) -#endif -{ - if (KKCC_GC_STACK_FULL) - kkcc_gc_stack_realloc(); - kkcc_gc_stack_top++; - kkcc_gc_stack_top->data = data; - kkcc_gc_stack_top->desc = desc; -#ifdef DEBUG_XEMACS - kkcc_gc_stack_top->level = level; - kkcc_gc_stack_top->pos = pos; -#endif -} - -#ifdef DEBUG_XEMACS -#define kkcc_gc_stack_push(data, desc, level, pos) \ - kkcc_gc_stack_push_1 (data, desc, level, pos) -#else -#define kkcc_gc_stack_push(data, desc, level, pos) \ - kkcc_gc_stack_push_1 (data, desc) -#endif - -static kkcc_gc_stack_entry * -kkcc_gc_stack_pop (void) -{ - if (KKCC_GC_STACK_EMPTY) - return 0; - kkcc_gc_stack_top--; - return kkcc_gc_stack_top + 1; -} - -void -#ifdef DEBUG_XEMACS -kkcc_gc_stack_push_lisp_object_1 (Lisp_Object obj, int level, int pos) -#else -kkcc_gc_stack_push_lisp_object_1 (Lisp_Object obj) -#endif -{ - if (XTYPE (obj) == Lisp_Type_Record) - { - struct lrecord_header *lheader = XRECORD_LHEADER (obj); - const struct memory_description *desc; - GC_CHECK_LHEADER_INVARIANTS (lheader); - desc = RECORD_DESCRIPTION (lheader); - if (! MARKED_RECORD_HEADER_P (lheader)) - { - MARK_RECORD_HEADER (lheader); - kkcc_gc_stack_push ((void*) lheader, desc, level, pos); - } - } -} - -#ifdef DEBUG_XEMACS -#define kkcc_gc_stack_push_lisp_object(obj, level, pos) \ - kkcc_gc_stack_push_lisp_object_1 (obj, level, pos) -#else -#define kkcc_gc_stack_push_lisp_object(obj, level, pos) \ - kkcc_gc_stack_push_lisp_object_1 (obj) -#endif - -#ifdef ERROR_CHECK_GC -#define KKCC_DO_CHECK_FREE(obj, allow_free) \ -do \ -{ \ - if (!allow_free && XTYPE (obj) == Lisp_Type_Record) \ - { \ - struct lrecord_header *lheader = XRECORD_LHEADER (obj); \ - GC_CHECK_NOT_FREE (lheader); \ - } \ -} while (0) -#else -#define KKCC_DO_CHECK_FREE(obj, allow_free) -#endif - -#ifdef ERROR_CHECK_GC -#ifdef DEBUG_XEMACS -static void -mark_object_maybe_checking_free_1 (Lisp_Object obj, int allow_free, - int level, int pos) -#else -static void -mark_object_maybe_checking_free_1 (Lisp_Object obj, int allow_free) -#endif -{ - KKCC_DO_CHECK_FREE (obj, allow_free); - kkcc_gc_stack_push_lisp_object (obj, level, pos); -} - -#ifdef DEBUG_XEMACS -#define mark_object_maybe_checking_free(obj, allow_free, level, pos) \ - mark_object_maybe_checking_free_1 (obj, allow_free, level, pos) -#else -#define mark_object_maybe_checking_free(obj, allow_free, level, pos) \ - mark_object_maybe_checking_free_1 (obj, allow_free) -#endif -#else /* not ERROR_CHECK_GC */ -#define mark_object_maybe_checking_free(obj, allow_free, level, pos) \ - kkcc_gc_stack_push_lisp_object (obj, level, pos) -#endif /* not ERROR_CHECK_GC */ - - -/* This function loops all elements of a struct pointer and calls - mark_with_description with each element. */ -static void -#ifdef DEBUG_XEMACS -mark_struct_contents_1 (const void *data, - const struct sized_memory_description *sdesc, - int count, int level, int pos) -#else -mark_struct_contents_1 (const void *data, - const struct sized_memory_description *sdesc, - int count) -#endif -{ - int i; - Bytecount elsize; - elsize = lispdesc_block_size (data, sdesc); - - for (i = 0; i < count; i++) - { - kkcc_gc_stack_push (((char *) data) + elsize * i, sdesc->description, - level, pos); - } -} - -#ifdef DEBUG_XEMACS -#define mark_struct_contents(data, sdesc, count, level, pos) \ - mark_struct_contents_1 (data, sdesc, count, level, pos) -#else -#define mark_struct_contents(data, sdesc, count, level, pos) \ - mark_struct_contents_1 (data, sdesc, count) -#endif - -/* This function implements the KKCC mark algorithm. - Instead of calling mark_object, all the alive Lisp_Objects are pushed - on the kkcc_gc_stack. This function processes all elements on the stack - according to their descriptions. */ -static void -kkcc_marking (void) -{ - kkcc_gc_stack_entry *stack_entry = 0; - void *data = 0; - const struct memory_description *desc = 0; - int pos; -#ifdef DEBUG_XEMACS - int level = 0; - kkcc_bt_init (); -#endif - - while ((stack_entry = kkcc_gc_stack_pop ()) != 0) - { - data = stack_entry->data; - desc = stack_entry->desc; -#ifdef DEBUG_XEMACS - level = stack_entry->level + 1; -#endif - - kkcc_bt_push (data, desc, stack_entry->level, stack_entry->pos); - - gc_checking_assert (data); - gc_checking_assert (desc); - - for (pos = 0; desc[pos].type != XD_END; pos++) - { - const struct memory_description *desc1 = &desc[pos]; - const void *rdata = - (const char *) data + lispdesc_indirect_count (desc1->offset, - desc, data); - union_switcheroo: - - /* If the flag says don't mark, then don't mark. */ - if ((desc1->flags) & XD_FLAG_NO_KKCC) - continue; - - switch (desc1->type) - { - case XD_BYTECOUNT: - case XD_ELEMCOUNT: - case XD_HASHCODE: - case XD_INT: - case XD_LONG: - case XD_INT_RESET: - case XD_LO_LINK: - case XD_OPAQUE_PTR: - case XD_OPAQUE_DATA_PTR: - case XD_ASCII_STRING: - case XD_DOC_STRING: - break; - case XD_LISP_OBJECT: - { - const Lisp_Object *stored_obj = (const Lisp_Object *) rdata; - - /* Because of the way that tagged objects work (pointers and - Lisp_Objects have the same representation), XD_LISP_OBJECT - can be used for untagged pointers. They might be NULL, - though. */ - if (EQ (*stored_obj, Qnull_pointer)) - break; -#ifdef MC_ALLOC - mark_object_maybe_checking_free (*stored_obj, 0, level, pos); -#else /* not MC_ALLOC */ - mark_object_maybe_checking_free - (*stored_obj, (desc1->flags) & XD_FLAG_FREE_LISP_OBJECT, - level, pos); -#endif /* not MC_ALLOC */ - break; - } - case XD_LISP_OBJECT_ARRAY: - { - int i; - EMACS_INT count = - lispdesc_indirect_count (desc1->data1, desc, data); - - for (i = 0; i < count; i++) - { - const Lisp_Object *stored_obj = - (const Lisp_Object *) rdata + i; - - if (EQ (*stored_obj, Qnull_pointer)) - break; -#ifdef MC_ALLOC - mark_object_maybe_checking_free (*stored_obj, 0, level, pos); -#else /* not MC_ALLOC */ - mark_object_maybe_checking_free - (*stored_obj, (desc1->flags) & XD_FLAG_FREE_LISP_OBJECT, - level, pos); -#endif /* not MC_ALLOC */ - } - break; - } - case XD_BLOCK_PTR: - { - EMACS_INT count = lispdesc_indirect_count (desc1->data1, desc, - data); - const struct sized_memory_description *sdesc = - lispdesc_indirect_description (data, desc1->data2.descr); - const char *dobj = * (const char **) rdata; - if (dobj) - mark_struct_contents (dobj, sdesc, count, level, pos); - break; - } - case XD_BLOCK_ARRAY: - { - EMACS_INT count = lispdesc_indirect_count (desc1->data1, desc, - data); - const struct sized_memory_description *sdesc = - lispdesc_indirect_description (data, desc1->data2.descr); - - mark_struct_contents (rdata, sdesc, count, level, pos); - break; - } - case XD_UNION: - case XD_UNION_DYNAMIC_SIZE: - desc1 = lispdesc_process_xd_union (desc1, desc, data); - if (desc1) - goto union_switcheroo; - break; - - default: - stderr_out ("Unsupported description type : %d\n", desc1->type); - kkcc_backtrace (); - ABORT (); - } - } - } -#ifdef DEBUG_XEMACS - kkcc_bt_free (); -#endif -} -#endif /* USE_KKCC */ - -/* Mark reference to a Lisp_Object. If the object referred to has not been - seen yet, recursively mark all the references contained in it. */ - -void -mark_object ( -#ifdef USE_KKCC - Lisp_Object UNUSED (obj) -#else - Lisp_Object obj -#endif - ) -{ -#ifdef USE_KKCC - /* this code should never be reached when configured for KKCC */ - stderr_out ("KKCC: Invalid mark_object call.\n"); - stderr_out ("Replace mark_object with kkcc_gc_stack_push_lisp_object.\n"); - ABORT (); -#else /* not USE_KKCC */ - - tail_recurse: - - /* Checks we used to perform */ - /* if (EQ (obj, Qnull_pointer)) return; */ - /* if (!POINTER_TYPE_P (XGCTYPE (obj))) return; */ - /* if (PURIFIED (XPNTR (obj))) return; */ - - if (XTYPE (obj) == Lisp_Type_Record) - { - struct lrecord_header *lheader = XRECORD_LHEADER (obj); - - GC_CHECK_LHEADER_INVARIANTS (lheader); - - /* We handle this separately, above, so we can mark free objects */ - GC_CHECK_NOT_FREE (lheader); - - /* All c_readonly objects have their mark bit set, - so that we only need to check the mark bit here. */ - if (! MARKED_RECORD_HEADER_P (lheader)) - { - MARK_RECORD_HEADER (lheader); - - if (RECORD_MARKER (lheader)) - { - obj = RECORD_MARKER (lheader) (obj); - if (!NILP (obj)) goto tail_recurse; - } - } - } -#endif /* not KKCC */ -} - #ifndef MC_ALLOC static int gc_count_num_short_string_in_use; @@ -4795,9 +4100,10 @@ #endif /* defined (MULE) && defined (VERIFY_STRING_CHARS_INTEGRITY) */ +#ifndef NEW_GC /* Compactify string chars, relocating the reference to each -- free any empty string_chars_block we see. */ -static void +void compact_string_chars (void) { struct string_chars_block *to_sb = first_string_chars_block; @@ -4893,6 +4199,7 @@ current_string_chars_block->next = 0; } } +#endif /* not NEW_GC */ #ifndef MC_ALLOC #if 1 /* Hack to debug missing purecopy's */ @@ -4954,28 +4261,9 @@ } #endif /* not MC_ALLOC */ -/* I hate duplicating all this crap! */ -int -marked_p (Lisp_Object obj) -{ - /* Checks we used to perform. */ - /* if (EQ (obj, Qnull_pointer)) return 1; */ - /* if (!POINTER_TYPE_P (XGCTYPE (obj))) return 1; */ - /* if (PURIFIED (XPNTR (obj))) return 1; */ - - if (XTYPE (obj) == Lisp_Type_Record) - { - struct lrecord_header *lheader = XRECORD_LHEADER (obj); - - GC_CHECK_LHEADER_INVARIANTS (lheader); - - return MARKED_RECORD_HEADER_P (lheader); - } - return 1; -} - -static void -gc_sweep (void) +#ifndef NEW_GC +void +gc_sweep_1 (void) { #ifdef MC_ALLOC compact_string_chars (); @@ -5064,6 +4352,7 @@ #endif #endif /* not MC_ALLOC */ } +#endif /* not NEW_GC */ /* Clearing for disksave. */ @@ -5101,11 +4390,16 @@ #endif Vshell_file_name = Qnil; +#ifdef NEW_GC + gc_full (); +#else /* not NEW_GC */ garbage_collect_1 (); +#endif /* not NEW_GC */ /* Run the disksave finalization methods of all live objects. */ disksave_object_finalization_1 (); +#ifndef NEW_GC /* Zero out the uninitialized (really, unused) part of the containers for the live strings. */ { @@ -5122,405 +4416,12 @@ } } } +#endif /* not NEW_GC */ /* There, that ought to be enough... */ } - -int -begin_gc_forbidden (void) -{ - return internal_bind_int (&gc_currently_forbidden, 1); -} - -void -end_gc_forbidden (int count) -{ - unbind_to (count); -} - -/* Maybe we want to use this when doing a "panic" gc after memory_full()? */ -static int gc_hooks_inhibited; - -struct post_gc_action -{ - void (*fun) (void *); - void *arg; -}; - -typedef struct post_gc_action post_gc_action; - -typedef struct -{ - Dynarr_declare (post_gc_action); -} post_gc_action_dynarr; - -static post_gc_action_dynarr *post_gc_actions; - -/* Register an action to be called at the end of GC. - gc_in_progress is 0 when this is called. - This is used when it is discovered that an action needs to be taken, - but it's during GC, so it's not safe. (e.g. in a finalize method.) - - As a general rule, do not use Lisp objects here. - And NEVER signal an error. -*/ - -void -register_post_gc_action (void (*fun) (void *), void *arg) -{ - post_gc_action action; - - if (!post_gc_actions) - post_gc_actions = Dynarr_new (post_gc_action); - - action.fun = fun; - action.arg = arg; - - Dynarr_add (post_gc_actions, action); -} - -static void -run_post_gc_actions (void) -{ - int i; - - if (post_gc_actions) - { - for (i = 0; i < Dynarr_length (post_gc_actions); i++) - { - post_gc_action action = Dynarr_at (post_gc_actions, i); - (action.fun) (action.arg); - } - - Dynarr_reset (post_gc_actions); - } -} - - -void -garbage_collect_1 (void) -{ -#if MAX_SAVE_STACK > 0 - char stack_top_variable; - extern char *stack_bottom; -#endif - struct frame *f; - int speccount; - int cursor_changed; - Lisp_Object pre_gc_cursor; - struct gcpro gcpro1; - PROFILE_DECLARE (); - - assert (!in_display || gc_currently_forbidden); - - if (gc_in_progress - || gc_currently_forbidden - || in_display - || preparing_for_armageddon) - return; - - PROFILE_RECORD_ENTERING_SECTION (QSin_garbage_collection); - - /* We used to call selected_frame() here. - - The following functions cannot be called inside GC - so we move to after the above tests. */ - { - Lisp_Object frame; - Lisp_Object device = Fselected_device (Qnil); - if (NILP (device)) /* Could happen during startup, eg. if always_gc */ - return; - frame = Fselected_frame (device); - if (NILP (frame)) - invalid_state ("No frames exist on device", device); - f = XFRAME (frame); - } - - pre_gc_cursor = Qnil; - cursor_changed = 0; - - GCPRO1 (pre_gc_cursor); - - /* Very important to prevent GC during any of the following - stuff that might run Lisp code; otherwise, we'll likely - have infinite GC recursion. */ - speccount = begin_gc_forbidden (); - - need_to_signal_post_gc = 0; - recompute_funcall_allocation_flag (); - - if (!gc_hooks_inhibited) - run_hook_trapping_problems - (Qgarbage_collecting, Qpre_gc_hook, - INHIBIT_EXISTING_PERMANENT_DISPLAY_OBJECT_DELETION); - - /* Now show the GC cursor/message. */ - if (!noninteractive) - { - if (FRAME_WIN_P (f)) - { - Lisp_Object frame = wrap_frame (f); - Lisp_Object cursor = glyph_image_instance (Vgc_pointer_glyph, - FRAME_SELECTED_WINDOW (f), - ERROR_ME_NOT, 1); - pre_gc_cursor = f->pointer; - if (POINTER_IMAGE_INSTANCEP (cursor) - /* don't change if we don't know how to change back. */ - && POINTER_IMAGE_INSTANCEP (pre_gc_cursor)) - { - cursor_changed = 1; - Fset_frame_pointer (frame, cursor); - } - } - - /* Don't print messages to the stream device. */ - if (!cursor_changed && !FRAME_STREAM_P (f)) - { - if (garbage_collection_messages) - { - Lisp_Object args[2], whole_msg; - args[0] = (STRINGP (Vgc_message) ? Vgc_message : - build_msg_string (gc_default_message)); - args[1] = build_string ("..."); - whole_msg = Fconcat (2, args); - echo_area_message (f, (Ibyte *) 0, whole_msg, 0, -1, - Qgarbage_collecting); - } - } - } - - /***** Now we actually start the garbage collection. */ - - gc_in_progress = 1; - inhibit_non_essential_conversion_operations = 1; - - gc_generation_number[0]++; - -#if MAX_SAVE_STACK > 0 - - /* Save a copy of the contents of the stack, for debugging. */ - if (!purify_flag) - { - /* Static buffer in which we save a copy of the C stack at each GC. */ - static char *stack_copy; - static Bytecount stack_copy_size; - - ptrdiff_t stack_diff = &stack_top_variable - stack_bottom; - Bytecount stack_size = (stack_diff > 0 ? stack_diff : -stack_diff); - if (stack_size < MAX_SAVE_STACK) - { - if (stack_copy_size < stack_size) - { - stack_copy = (char *) xrealloc (stack_copy, stack_size); - stack_copy_size = stack_size; - } - - memcpy (stack_copy, - stack_diff > 0 ? stack_bottom : &stack_top_variable, - stack_size); - } - } -#endif /* MAX_SAVE_STACK > 0 */ - - /* Do some totally ad-hoc resource clearing. */ - /* #### generalize this? */ - clear_event_resource (); - cleanup_specifiers (); - cleanup_buffer_undo_lists (); - - /* Mark all the special slots that serve as the roots of accessibility. */ - -#ifdef USE_KKCC - /* initialize kkcc stack */ - kkcc_gc_stack_init(); -#define mark_object(obj) kkcc_gc_stack_push_lisp_object (obj, 0, -1) -#endif /* USE_KKCC */ - - { /* staticpro() */ - Lisp_Object **p = Dynarr_begin (staticpros); - Elemcount count; - for (count = Dynarr_length (staticpros); count; count--) - mark_object (**p++); - } - - { /* staticpro_nodump() */ - Lisp_Object **p = Dynarr_begin (staticpros_nodump); - Elemcount count; - for (count = Dynarr_length (staticpros_nodump); count; count--) - mark_object (**p++); - } - -#ifdef MC_ALLOC - { /* mcpro () */ - Lisp_Object *p = Dynarr_begin (mcpros); - Elemcount count; - for (count = Dynarr_length (mcpros); count; count--) - mark_object (*p++); - } -#endif /* MC_ALLOC */ - - { /* GCPRO() */ - struct gcpro *tail; - int i; - for (tail = gcprolist; tail; tail = tail->next) - for (i = 0; i < tail->nvars; i++) - mark_object (tail->var[i]); - } - - { /* specbind() */ - struct specbinding *bind; - for (bind = specpdl; bind != specpdl_ptr; bind++) - { - mark_object (bind->symbol); - mark_object (bind->old_value); - } - } - - { - struct catchtag *c; - for (c = catchlist; c; c = c->next) - { - mark_object (c->tag); - mark_object (c->val); - mark_object (c->actual_tag); - mark_object (c->backtrace); - } - } - - { - struct backtrace *backlist; - for (backlist = backtrace_list; backlist; backlist = backlist->next) - { - int nargs = backlist->nargs; - int i; - - mark_object (*backlist->function); - if (nargs < 0 /* nargs == UNEVALLED || nargs == MANY */ - /* might be fake (internal profiling entry) */ - && backlist->args) - mark_object (backlist->args[0]); - else - for (i = 0; i < nargs; i++) - mark_object (backlist->args[i]); - } - } - - mark_profiling_info (); - - /* OK, now do the after-mark stuff. This is for things that - are only marked when something else is marked (e.g. weak hash tables). - There may be complex dependencies between such objects -- e.g. - a weak hash table might be unmarked, but after processing a later - weak hash table, the former one might get marked. So we have to - iterate until nothing more gets marked. */ -#ifdef USE_KKCC - kkcc_marking (); -#endif /* USE_KKCC */ - init_marking_ephemerons (); - while (finish_marking_weak_hash_tables () > 0 || - finish_marking_weak_lists () > 0 || - continue_marking_ephemerons () > 0) -#ifdef USE_KKCC - { - kkcc_marking (); - } -#else /* NOT USE_KKCC */ - ; -#endif /* USE_KKCC */ - - /* At this point, we know which objects need to be finalized: we - still need to resurrect them */ - - while (finish_marking_ephemerons () > 0 || - finish_marking_weak_lists () > 0 || - finish_marking_weak_hash_tables () > 0) -#ifdef USE_KKCC - { - kkcc_marking (); - } - kkcc_gc_stack_free (); -#undef mark_object -#else /* NOT USE_KKCC */ - ; -#endif /* USE_KKCC */ - - /* And prune (this needs to be called after everything else has been - marked and before we do any sweeping). */ - /* #### this is somewhat ad-hoc and should probably be an object - method */ - prune_weak_hash_tables (); - prune_weak_lists (); - prune_specifiers (); - prune_syntax_tables (); - - prune_ephemerons (); - prune_weak_boxes (); - - gc_sweep (); - - consing_since_gc = 0; -#ifndef DEBUG_XEMACS - /* Allow you to set it really fucking low if you really want ... */ - if (gc_cons_threshold < 10000) - gc_cons_threshold = 10000; -#endif - recompute_need_to_garbage_collect (); - - inhibit_non_essential_conversion_operations = 0; - gc_in_progress = 0; - - run_post_gc_actions (); - - /******* End of garbage collection ********/ - - /* Now remove the GC cursor/message */ - if (!noninteractive) - { - if (cursor_changed) - Fset_frame_pointer (wrap_frame (f), pre_gc_cursor); - else if (!FRAME_STREAM_P (f)) - { - /* Show "...done" only if the echo area would otherwise be empty. */ - if (NILP (clear_echo_area (selected_frame (), - Qgarbage_collecting, 0))) - { - if (garbage_collection_messages) - { - Lisp_Object args[2], whole_msg; - args[0] = (STRINGP (Vgc_message) ? Vgc_message : - build_msg_string (gc_default_message)); - args[1] = build_msg_string ("... done"); - whole_msg = Fconcat (2, args); - echo_area_message (selected_frame (), (Ibyte *) 0, - whole_msg, 0, -1, - Qgarbage_collecting); - } - } - } - } - - /* now stop inhibiting GC */ - unbind_to (speccount); - -#ifndef MC_ALLOC - if (!breathing_space) - { - breathing_space = malloc (4096 - MALLOC_OVERHEAD); - } -#endif /* not MC_ALLOC */ - - UNGCPRO; - - need_to_signal_post_gc = 1; - funcall_allocation_flag = 1; - - PROFILE_RECORD_EXITING_SECTION (QSin_garbage_collection); - - return; -} - #ifdef ALLOC_TYPE_STATS static Lisp_Object @@ -5573,13 +4474,6 @@ pl = gc_plist_hack (buf, lrecord_stats[i].instances_in_use, pl); } } - pl = gc_plist_hack ("string-data-storage-including-overhead", - lrecord_string_data_bytes_in_use_including_overhead, pl); - pl = gc_plist_hack ("string-data-storage-additional", - lrecord_string_data_bytes_in_use, pl); - pl = gc_plist_hack ("string-data-used", - lrecord_string_data_instances_in_use, pl); - tgu_val += lrecord_string_data_bytes_in_use_including_overhead; #else /* not MC_ALLOC */ @@ -5720,7 +4614,11 @@ ()) { /* Record total usage for purposes of determining next GC */ +#ifdef NEW_GC + gc_full (); +#else /* not NEW_GC */ garbage_collect_1 (); +#endif /* not NEW_GC */ /* This will get set to 1, and total_gc_usage computed, as part of the call to object_memory_usage_stats() -- if ALLOC_TYPE_STATS is enabled. */ @@ -5819,28 +4717,6 @@ need_to_signal_post_gc; } -/* True if it's time to garbage collect now. */ -static void -recompute_need_to_garbage_collect (void) -{ - if (always_gc) - need_to_garbage_collect = 1; - else - need_to_garbage_collect = - (consing_since_gc > gc_cons_threshold - && -#if 0 /* #### implement this better */ - (100 * consing_since_gc) / total_data_usage () >= - gc_cons_percentage -#else - (!total_gc_usage_set || - (100 * consing_since_gc) / total_gc_usage >= - gc_cons_percentage) -#endif - ); - recompute_funcall_allocation_flag (); -} - int object_dead_p (Lisp_Object obj) @@ -6007,11 +4883,9 @@ Qnull_pointer = wrap_pointer_1 (0); #endif - gc_generation_number[0] = 0; #ifndef MC_ALLOC breathing_space = 0; #endif /* not MC_ALLOC */ - Vgc_message = Qzero; #ifndef MC_ALLOC all_lcrecords = 0; #endif /* not MC_ALLOC */ @@ -6023,7 +4897,9 @@ mallopt (M_MMAP_MAX, 64); /* max. number of mmap'ed areas */ #endif #endif +#ifndef NEW_GC init_string_chars_alloc (); +#endif /* not NEW_GC */ #ifndef MC_ALLOC init_string_alloc (); init_string_chars_alloc (); @@ -6081,26 +4957,15 @@ #endif /* MC_ALLOC */ consing_since_gc = 0; - need_to_garbage_collect = always_gc; need_to_check_c_alloca = 0; funcall_allocation_flag = 0; funcall_alloca_count = 0; -#if 1 - gc_cons_threshold = 2000000; /* XEmacs change */ -#else - gc_cons_threshold = 15000; /* debugging */ -#endif - gc_cons_percentage = 40; /* #### what is optimal? */ - total_gc_usage_set = 0; lrecord_uid_counter = 259; #ifndef MC_ALLOC debug_string_purity = 0; #endif /* not MC_ALLOC */ - gc_currently_forbidden = 0; - gc_hooks_inhibited = 0; - #ifdef ERROR_CHECK_TYPES ERROR_ME.really_unlikely_name_to_have_accidentally_in_a_non_errb_structure = 666; @@ -6167,6 +5032,10 @@ INIT_LRECORD_IMPLEMENTATION (cons); INIT_LRECORD_IMPLEMENTATION (vector); INIT_LRECORD_IMPLEMENTATION (string); +#ifdef NEW_GC + INIT_LRECORD_IMPLEMENTATION (string_indirect_data); + INIT_LRECORD_IMPLEMENTATION (string_direct_data); +#endif /* NEW_GC */ #ifndef MC_ALLOC INIT_LRECORD_IMPLEMENTATION (lcrecord_list); INIT_LRECORD_IMPLEMENTATION (free); @@ -6200,8 +5069,6 @@ void syms_of_alloc (void) { - DEFSYMBOL (Qpre_gc_hook); - DEFSYMBOL (Qpost_gc_hook); DEFSYMBOL (Qgarbage_collecting); DEFSUBR (Fcons); @@ -6232,49 +5099,6 @@ void vars_of_alloc (void) { - QSin_garbage_collection = build_msg_string ("(in garbage collection)"); - staticpro (&QSin_garbage_collection); - - DEFVAR_INT ("gc-cons-threshold", &gc_cons_threshold /* -*Number of bytes of consing between garbage collections. -\"Consing\" is a misnomer in that this actually counts allocation -of all different kinds of objects, not just conses. -Garbage collection can happen automatically once this many bytes have been -allocated since the last garbage collection. All data types count. - -Garbage collection happens automatically when `eval' or `funcall' are -called. (Note that `funcall' is called implicitly as part of evaluation.) -By binding this temporarily to a large number, you can effectively -prevent garbage collection during a part of the program. - -Normally, you cannot set this value less than 10,000 (if you do, it is -automatically reset during the next garbage collection). However, if -XEmacs was compiled with DEBUG_XEMACS, this does not happen, allowing -you to set this value very low to track down problems with insufficient -GCPRO'ing. If you set this to a negative number, garbage collection will -happen at *EVERY* call to `eval' or `funcall'. This is an extremely -effective way to check GCPRO problems, but be warned that your XEmacs -will be unusable! You almost certainly won't have the patience to wait -long enough to be able to set it back. - -See also `consing-since-gc' and `gc-cons-percentage'. -*/ ); - - DEFVAR_INT ("gc-cons-percentage", &gc_cons_percentage /* -*Percentage of memory allocated between garbage collections. - -Garbage collection will happen if this percentage of the total amount of -memory used for data (see `lisp-object-memory-usage') has been allocated -since the last garbage collection. However, it will not happen if less -than `gc-cons-threshold' bytes have been allocated -- this sets an absolute -minimum in case very little data has been allocated or the percentage is -set very low. Set this to 0 to have garbage collection always happen after -`gc-cons-threshold' bytes have been allocated, regardless of current memory -usage. - -See also `consing-since-gc' and `gc-cons-threshold'. -*/ ); - #ifdef DEBUG_XEMACS DEFVAR_INT ("debug-allocation", &debug_allocation /* If non-zero, print out information to stderr about all objects allocated. @@ -6293,49 +5117,4 @@ Non-nil means loading Lisp code in order to dump an executable. This means that certain objects should be allocated in readonly space. */ ); - - DEFVAR_BOOL ("garbage-collection-messages", &garbage_collection_messages /* - Non-nil means display messages at start and end of garbage collection. -*/ ); - garbage_collection_messages = 0; - - DEFVAR_LISP ("pre-gc-hook", &Vpre_gc_hook /* -Function or functions to be run just before each garbage collection. -Interrupts, garbage collection, and errors are inhibited while this hook -runs, so be extremely careful in what you add here. In particular, avoid -consing, and do not interact with the user. -*/ ); - Vpre_gc_hook = Qnil; - - DEFVAR_LISP ("post-gc-hook", &Vpost_gc_hook /* -Function or functions to be run just after each garbage collection. -Interrupts, garbage collection, and errors are inhibited while this hook -runs. Each hook is called with one argument which is an alist with -finalization data. -*/ ); - Vpost_gc_hook = Qnil; - - DEFVAR_LISP ("gc-message", &Vgc_message /* -String to print to indicate that a garbage collection is in progress. -This is printed in the echo area. If the selected frame is on a -window system and `gc-pointer-glyph' specifies a value (i.e. a pointer -image instance) in the domain of the selected frame, the mouse pointer -will change instead of this message being printed. -*/ ); - Vgc_message = build_string (gc_default_message); - - DEFVAR_LISP ("gc-pointer-glyph", &Vgc_pointer_glyph /* -Pointer glyph used to indicate that a garbage collection is in progress. -If the selected window is on a window system and this glyph specifies a -value (i.e. a pointer image instance) in the domain of the selected -window, the pointer will be changed as specified during garbage collection. -Otherwise, a message will be printed in the echo area, as controlled -by `gc-message'. -*/ ); } - -void -complex_vars_of_alloc (void) -{ - Vgc_pointer_glyph = Fmake_glyph_internal (Qpointer); -}