Mercurial > hg > xemacs-beta
changeset 5172:be6e5ea38dda
merge
author | Ben Wing <ben@xemacs.org> |
---|---|
date | Mon, 29 Mar 2010 00:11:03 -0500 |
parents | 8cd17b2131a1 (diff) b50624d3ae55 (current diff) |
children | bd1e25975cdc 14fda1dbdb26 |
files | lisp/ChangeLog src/ChangeLog src/alloc.c src/window.c |
diffstat | 53 files changed, 4003 insertions(+), 2851 deletions(-) [+] |
line wrap: on
line diff
--- a/lisp/ChangeLog Fri Mar 26 15:06:28 2010 +0000 +++ b/lisp/ChangeLog Mon Mar 29 00:11:03 2010 -0500 @@ -1,3 +1,12 @@ +2010-03-25 Ben Wing <ben@xemacs.org> + + * diagnose.el (show-memory-usage): + * diagnose.el (show-object-memory-usage-stats): + Further changes to correspond with changes in the C code; + add an additional column in show-object-memory-usage-stats showing + the ancillary Lisp overhead used with each type; shrink columns for + windows in show-memory-usage to get it to fit in 79 chars. + 2010-03-26 Aidan Kehoe <kehoea@parhasard.net> * descr-text.el (describe-char-display):
--- a/lisp/diagnose.el Fri Mar 26 15:06:28 2010 +0000 +++ b/lisp/diagnose.el Mon Mar 29 00:11:03 2010 -0500 @@ -35,11 +35,12 @@ "Show statistics about memory usage of various sorts in XEmacs." (interactive) (garbage-collect) - (flet ((show-foo-stats (objtypename cleanfun objlist) + (flet ((show-foo-stats (objtypename statname-plist cleanfun objlist + &optional objnamelen) (let* ((hash (make-hash-table)) (first t) - types fmt - (objnamelen 25) + types origtypes fmt + (objnamelen (or objnamelen 25)) (linelen objnamelen) (totaltotal 0)) (loop for obj in objlist do @@ -54,19 +55,22 @@ ;; the memory grouped by type (while (and stats (pop stats))) - (loop for (type . num) in stats while type do + (loop for (type . num) in (remq t stats) while type do + (if first (push type origtypes)) + (setq type (getf statname-plist type type)) (puthash type (+ num (or (gethash type hash) 0)) hash) (incf total num) (if first (push type types))) (incf totaltotal total) (when first (setq types (nreverse types)) + (setq origtypes (nreverse origtypes)) (setq fmt (concat (format "%%-%ds" objnamelen) (mapconcat #'(lambda (type) (let ((fieldlen - (max 8 (+ 2 (length + (max 7 (+ 2 (length (symbol-name type)))))) (incf linelen fieldlen) (format "%%%ds" fieldlen))) @@ -83,7 +87,7 @@ (1- objnamelen))) (nconc (mapcar #'(lambda (type) (cdr (assq type stats))) - types) + origtypes) (list total))))) (setq first nil))) (princ "\n") @@ -103,7 +107,7 @@ (when-fboundp 'charset-list (setq begin (point)) (incf grandtotal - (show-foo-stats 'charset 'charset-name + (show-foo-stats 'charset nil 'charset-name (mapcar 'get-charset (charset-list)))) (when-fboundp 'sort-numeric-fields (sort-numeric-fields -1 @@ -117,7 +121,7 @@ (princ "\n")) (setq begin (point)) (incf grandtotal - (show-foo-stats 'buffer 'buffer-name (buffer-list))) + (show-foo-stats 'buffer nil 'buffer-name (buffer-list))) (when-fboundp 'sort-numeric-fields (sort-numeric-fields -1 (save-excursion @@ -130,11 +134,19 @@ (princ "\n") (setq begin (point)) (incf grandtotal - (show-foo-stats 'window #'(lambda (x) - (buffer-name (window-buffer x))) + (show-foo-stats 'window + '(line-start-cache line-st. + face-cache face + glyph-cache glyph + redisplay-structs redisplay + scrollbar-instances scrollbar + window-mirror mirror) + #'(lambda (x) + (buffer-name (window-buffer x))) (mapcan #'(lambda (fr) (window-list fr t)) - (frame-list)))) + (frame-list)) + 16)) (when-fboundp #'sort-numeric-fields (sort-numeric-fields -1 (save-excursion @@ -152,9 +164,14 @@ (princ (make-string 40 ?-)) (princ "\n") (map-plist #'(lambda (stat num) - (when (string-match - "\\(.*\\)-storage$" - (symbol-name stat)) + (when (and + (not + (string-match + "\\(.*\\)-ancillary-storage$" + (symbol-name stat))) + (string-match + "\\(.*\\)-storage$" + (symbol-name stat))) (incf total num) (princ (format fmt (match-string 1 (symbol-name stat)) @@ -184,12 +201,14 @@ (garbage-collect) (let ((buffer "*object memory usage statistics*") (plist (object-memory-usage-stats)) - (fmt "%-30s%10s%10s%10s%18s\n") + (fmt "%-28s%10s%10s%10s%10s%10s\n") (grandtotal 0) begin) (flet ((show-stats (match-string) - (princ (format fmt "object" "count" "storage" "overhead" - "non-Lisp storage")) + (princ (format "%28s%10s%40s\n" "" "" + "--------------storage---------------")) + (princ (format fmt "object" "count" "object" "overhead" + "non-Lisp" "ancillary")) (princ (make-string 78 ?-)) (princ "\n") (let ((total-use 0) @@ -202,9 +221,13 @@ (let ((symmatch (and (string-match match-string (symbol-name stat)) (match-string 1 (symbol-name stat))))) - (when (and symmatch (or (< (length symmatch) 9) - (not (equal (substring symmatch -9) - "-non-lisp")))) + (when (and symmatch + (or (< (length symmatch) 9) + (not (equal (substring symmatch -9) + "-non-lisp"))) + (or (< (length symmatch) 15) + (not (equal (substring symmatch -15) + "-lisp-ancillary")))) (let* ((storage-use num) (storage-use-overhead (or (plist-get @@ -227,6 +250,12 @@ (intern (concat symmatch "-non-lisp-storage"))) 0)) + (lisp-ancillary-storage + (or (plist-get + plist + (intern (concat symmatch + "-lisp-ancillary-storage"))) + 0)) (storage-count (or (loop for str in '("s-used" "es-used" "-used") for val = (plist-get @@ -251,19 +280,20 @@ (or storage-count "unknown") storage-use storage-use-overhead - non-lisp-storage))))))) + non-lisp-storage + lisp-ancillary-storage))))))) plist) (princ "\n") (princ (format fmt "total" total-count total-use total-use-overhead - total-non-lisp-use)) + total-non-lisp-use "")) (incf grandtotal total-use-with-overhead) (incf grandtotal total-non-lisp-use) (when-fboundp #'sort-numeric-fields - (sort-numeric-fields -3 + (sort-numeric-fields -4 (save-excursion (goto-char begin) - (forward-line 3) + (forward-line 4) (point)) (save-excursion (forward-line -2)
--- a/src/ChangeLog Fri Mar 26 15:06:28 2010 +0000 +++ b/src/ChangeLog Mon Mar 29 00:11:03 2010 -0500 @@ -1,3 +1,325 @@ +2010-03-28 Ben Wing <ben@xemacs.org> + + * window.c (find_window_mirror_internal): + Stop looking if no window mirror, and return 0. + + * window.c (window_display_lines): + * window.c (window_display_buffer): + * window.c (set_window_display_buffer): + Don't need to update window mirror before calling find_window_mirror + because does the updating automatically. + +2010-03-25 Ben Wing <ben@xemacs.org> + + * alloc.c: + * alloc.c (struct): + * alloc.c (finish_object_memory_usage_stats): + * alloc.c (object_memory_usage_stats): + * alloc.c (Fobject_memory_usage): + * alloc.c (lisp_object_memory_usage_full): + * alloc.c (compute_memusage_stats_length): + * lrecord.h: + * lrecord.h (struct lrecord_implementation): + Add fields to the `lrecord_implementation' structure to list an + offset into the array of extra statistics in a + `struct generic_usage_stats' and a length, listing the first slice + of ancillary Lisp-object memory. Compute automatically in + compute_memusage_stats_length(). Use to add an entry + `FOO-lisp-ancillary-storage' for object type FOO. + + Don't crash when an int or char is given to object-memory-usage, + signal an error instead. + + Add functions lisp_object_memory_usage_full() and + lisp_object_memory_usage() to compute the total memory usage of an + object (sum of object, non-Lisp attached, and Lisp ancillary + memory). + + * array.c: + * array.c (gap_array_memory_usage): + * array.h: + Add function to return memory usage of a gap array. + + * buffer.c (struct buffer_stats): + * buffer.c (compute_buffer_usage): + * buffer.c (vars_of_buffer): + * extents.c (compute_buffer_extent_usage): + * marker.c: + * marker.c (compute_buffer_marker_usage): + * extents.h: + * lisp.h: + Remove `struct usage_stats' arg from compute_buffer_marker_usage() + and compute_buffer_extent_usage() -- these are ancillary Lisp + objects and don't get accumulated into `struct usage_stats'; + change the value of `memusage_stats_list' so that `markers' and + `extents' memory is in Lisp-ancillary, where it belongs. + + In compute_buffer_marker_usage(), use lisp_object_memory_usage() + rather than lisp_object_storage_size(). + + * casetab.c: + * casetab.c (case_table_memory_usage): + * casetab.c (vars_of_casetab): + * emacs.c (main_1): + Add memory usage stats for case tables. + + * lisp.h: + Add comment explaining the `struct generic_usage_stats' more, + as well as the new fields in lrecord_implementation. + + * console-impl.h: + * console-impl.h (struct console_methods): + * scrollbar-gtk.c: + * scrollbar-gtk.c (gtk_compute_scrollbar_instance_usage): + * scrollbar-msw.c: + * scrollbar-msw.c (mswindows_compute_scrollbar_instance_usage): + * scrollbar-x.c: + * scrollbar-x.c (x_compute_scrollbar_instance_usage): + * scrollbar.c: + * scrollbar.c (struct scrollbar_instance_stats): + * scrollbar.c (compute_all_scrollbar_instance_usage): + * scrollbar.c (scrollbar_instance_memory_usage): + * scrollbar.c (scrollbar_objects_create): + * scrollbar.c (vars_of_scrollbar): + * scrollbar.h: + * symsinit.h: + * window.c: + * window.c (find_window_mirror_maybe): + * window.c (struct window_mirror_stats): + * window.c (compute_window_mirror_usage): + * window.c (window_mirror_memory_usage): + * window.c (compute_window_usage): + * window.c (window_objects_create): + * window.c (syms_of_window): + * window.c (vars_of_window): + Redo memory-usage associated with windows, window mirrors, and + scrollbar instances. Should fix crash in find_window_mirror, + among other things. Properly assign memo ry to object memory, + non-Lisp extra memory, and Lisp ancillary memory. For example, + redisplay structures are non-Lisp memory hanging off a window + mirror, not a window; make it an ancillary Lisp-object field. + Window mirrors and scrollbar instances have their own statistics, + among other things. + +2010-03-24 Ben Wing <ben@xemacs.org> + + * array.h: + * array.h (XD_LISP_DYNARR_DESC): + * dumper.c (pdump_register_sub): + * dumper.c (pdump_store_new_pointer_offsets): + * dumper.c (pdump_reloc_one_mc): + * elhash.c: + * gc.c (lispdesc_one_description_line_size): + * gc.c (kkcc_marking): + * lrecord.h: + * lrecord.h (IF_NEW_GC): + * lrecord.h (enum memory_description_type): + * lrecord.h (enum data_description_entry_flags): + * lrecord.h (struct opaque_convert_functions): + Rename XD_LISP_OBJECT_BLOCK_PTR to XD_INLINE_LISP_OBJECT_BLOCK_PTR + and document it in lrecord.h. + + * data.c: + * data.c (finish_marking_weak_lists): + * data.c (continue_marking_ephemerons): + * data.c (finish_marking_ephemerons): + * elhash.c (MARK_OBJ): + * gc.c: + * gc.c (lispdesc_indirect_count_1): + * gc.c (struct): + * gc.c (kkcc_bt_push): + * gc.c (kkcc_gc_stack_push): + * gc.c (kkcc_gc_stack_push_lisp_object): + * gc.c (kkcc_gc_stack_repush_dirty_object): + * gc.c (KKCC_DO_CHECK_FREE): + * gc.c (mark_object_maybe_checking_free): + * gc.c (mark_struct_contents): + * gc.c (mark_lisp_object_block_contents): + * gc.c (register_for_finalization): + * gc.c (mark_object): + * gc.h: + * lisp.h: + * profile.c: + * profile.c (mark_profiling_info_maphash): + Clean up KKCC code related to DEBUG_XEMACS. Rename + kkcc_backtrace() to kkcc_backtrace_1() and add two params: a + `size' arg to control how many stack elements to print and a + `detailed' arg to control whether Lisp objects are printed using + `debug_print()'. Create front-ends to kkcc_backtrace_1() -- + kkcc_detailed_backtrace(), kkcc_short_backtrace(), + kkcc_detailed_backtrace_full(), kkcc_short_backtrace_full(), as + well as shortened versions kbt(), kbts(), kbtf(), kbtsf() -- to + call it with various parameter values. Add an `is_lisp' field to + the stack and backtrace structures and use it to keep track of + whether an object pushed onto the stack is a Lisp object or a + non-Lisp structure; in kkcc_backtrace_1(), don't try to print a + non-Lisp structure as a Lisp object. + + * elhash.c: + * extents.c: + * file-coding.c: + * lrecord.h: + * lrecord.h (IF_NEW_GC): + * marker.c: + * marker.c (Fmarker_buffer): + * mule-coding.c: + * number.c: + * rangetab.c: + * specifier.c: + New macros IF_OLD_GC(), IF_NEW_GC() to simplify declaration of + Lisp objects when a finalizer may exist in one but not the other. + Use them appropriately. + + * extents.c (finalize_extent_info): + Don't zero out data->soe and data->extents before trying to free, + else we get memory leaks. + + * lrecord.h (enum lrecord_type): + Make the first lrecord type have value 1 not 0 so that 0 remains + without implementation and attempts to interpret zeroed memory + as a Lisp object will be more obvious. + + * array.c (Dynarr_free): + * device-msw.c (msprinter_delete_device): + * device-tty.c (free_tty_device_struct): + * device-tty.c (tty_delete_device): + * dialog-msw.c (handle_directory_dialog_box): + * dialog-x.c: + * emacs.c (free_argc_argv): + * emodules.c (attempt_module_delete): + * file-coding.c (chain_finalize_coding_stream_1): + * file-coding.c (chain_finalize_coding_stream): + * glyphs-eimage.c: + * glyphs-eimage.c (jpeg_instantiate_unwind): + * glyphs-eimage.c (gif_instantiate_unwind): + * glyphs-eimage.c (png_instantiate_unwind): + * glyphs-eimage.c (tiff_instantiate_unwind): + * imgproc.c: + * imgproc.c (build_EImage_quantable): + * insdel.c (uninit_buffer_text): + * mule-coding.c (iso2022_finalize_detection_state): + * objects-tty.c (tty_finalize_color_instance): + * objects-tty.c (tty_finalize_font_instance): + * objects-tty.c (tty_font_list): + * process.c: + * process.c (finalize_process): + * redisplay.c (add_propagation_runes): + * scrollbar-gtk.c: + * scrollbar-gtk.c (gtk_free_scrollbar_instance): + * scrollbar-gtk.c (gtk_release_scrollbar_instance): + * scrollbar-msw.c: + * scrollbar-msw.c (mswindows_free_scrollbar_instance): + * scrollbar-msw.c (unshow_that_mofo): + * scrollbar-x.c (x_free_scrollbar_instance): + * scrollbar-x.c (x_release_scrollbar_instance): + * select-x.c: + * select-x.c (x_handle_selection_request): + * syntax.c: + * syntax.c (uninit_buffer_syntax_cache): + * text.h (eifree): + If possible, whenever we call xfree() on a field in a structure, + set the field to 0 afterwards. A lot of code is written so that + it checks the value being freed to see if it is non-zero before + freeing it -- doing this and setting the value to 0 afterwards + ensures (a) we won't try to free twice if the cleanup code is + called twice; (b) if the object itself stays around, KKCC won't + crash when attempting to mark the freed field. + + * rangetab.c: + Add a finalization method when not NEW_GC to avoid memory leaks. + (#### We still get memory leaks when NEW_GC; need to convert gap + array to Lisp object). + +2010-03-22 Ben Wing <ben@xemacs.org> + + * Makefile.in.in (objs): + * array.c: + * array.c (gap_array_adjust_markers): + * array.c (gap_array_move_gap): + * array.c (gap_array_make_gap): + * array.c (gap_array_insert_els): + * array.c (gap_array_delete_els): + * array.c (gap_array_make_marker): + * array.c (gap_array_delete_marker): + * array.c (gap_array_delete_all_markers): + * array.c (gap_array_clone): + * array.h: + * depend: + * emacs.c (main_1): + * extents.c: + * extents.c (EXTENT_GAP_ARRAY_AT): + * extents.c (extent_list_num_els): + * extents.c (extent_list_locate): + * extents.c (extent_list_at): + * extents.c (extent_list_delete_all): + * extents.c (allocate_extent_list): + * extents.c (syms_of_extents): + * extents.h: + * extents.h (XEXTENT_LIST_MARKER): + * lisp.h: + * rangetab.c: + * rangetab.c (mark_range_table): + * rangetab.c (print_range_table): + * rangetab.c (range_table_equal): + * rangetab.c (range_table_hash): + * rangetab.c (verify_range_table): + * rangetab.c (get_range_table_pos): + * rangetab.c (Fmake_range_table): + * rangetab.c (Fcopy_range_table): + * rangetab.c (Fget_range_table): + * rangetab.c (put_range_table): + * rangetab.c (Fclear_range_table): + * rangetab.c (Fmap_range_table): + * rangetab.c (unified_range_table_bytes_needed): + * rangetab.c (unified_range_table_copy_data): + * rangetab.c (unified_range_table_lookup): + * rangetab.h: + * rangetab.h (struct range_table_entry): + * rangetab.h (struct Lisp_Range_Table): + * rangetab.h (rangetab_gap_array_at): + * symsinit.h: + Rename dynarr.c to array.c. Move gap array from extents.c to array.c. + Extract dynarr, gap array and stack-like malloc into new file array.h. + Rename GAP_ARRAY_NUM_ELS -> gap_array_length(). Add gap_array_at(), + gap_array_atp(). + + Rewrite range table code to use gap arrays. Make put_range_table() + smarter so that its operation is O(log n) for adding a localized + range. + + * gc.c (lispdesc_block_size_1): + Don't ABORT() when two elements are located at the same place. + This will happen with a size-0 gap array -- both parts of the array + (before and after gap) are in the same place. + +2010-03-21 Ben Wing <ben@xemacs.org> + + * alloc.c: + * alloc.c (assert_proper_sizing): + * alloc.c (c_readonly): + * alloc.c (malloced_storage_size): + * alloc.c (fixed_type_block_overhead): + * alloc.c (lisp_object_storage_size): + * alloc.c (inc_lrecord_stats): + * alloc.c (dec_lrecord_stats): + * alloc.c (pluralize_word): + * alloc.c (object_memory_usage_stats): + * alloc.c (Fobject_memory_usage): + * alloc.c (compute_memusage_stats_length): + * alloc.c (disksave_object_finalization_1): + * alloc.c (Fgarbage_collect): + * mc-alloc.c: + * mc-alloc.c (mc_alloced_storage_size): + * mc-alloc.h: + No functionality change here. Collect the allocations-statistics + code that was scattered throughout alloc.c into one place. Add + remaining section headings so that all sections have headings + clearly identifying the start of the section and its purpose. + Expose mc_alloced_storage_size() even when not MEMORY_USAGE_STATS; + this fixes build problems and is related to the export of + lisp_object_storage_size() and malloced_storage_size() when + non-MEMORY_USAGE_STATS in the previous change set. + 2010-03-22 Vin Shelton <acs@xemacs.org> * window.c (vars_of_window): Move HAVE_SCROLLBARS test so the code
--- a/src/Makefile.in.in Fri Mar 26 15:06:28 2010 +0000 +++ b/src/Makefile.in.in Mon Mar 29 00:11:03 2010 -0500 @@ -274,13 +274,12 @@ ## if they all come out null. objs=\ - abbrev.o alloc.o alloca.o \ + abbrev.o alloc.o alloca.o array.o \ $(balloon_help_objs) blocktype.o buffer.o bytecode.o \ callint.o casefiddle.o casetab.o chartab.o \ $(clash_detection_objs) cmdloop.o cmds.o $(coding_system_objs) console.o \ console-stream.o\ data.o $(database_objs) $(debug_objs) device.o dired.o doc.o doprnt.o\ - dynarr.o \ editfns.o elhash.o emacs.o emodules.o eval.o events.o\ event-stream.o $(event_unixoid_objs) $(extra_objs) extents.o\ faces.o file-coding.o fileio.o $(LOCK_OBJ) filemode.o floatfns.o fns.o \
--- a/src/alloc.c Fri Mar 26 15:06:28 2010 +0000 +++ b/src/alloc.c Mon Mar 29 00:11:03 2010 -0500 @@ -142,96 +142,67 @@ Lisp_Object Qother_memory_dynarr_overhead, Qother_memory_gap_overhead; #endif /* MEMORY_USAGE_STATS */ +#ifndef NEW_GC +static int gc_count_num_short_string_in_use; +static Bytecount gc_count_string_total_size; +static Bytecount gc_count_short_string_total_size; +static Bytecount gc_count_long_string_storage_including_overhead; +#endif /* not NEW_GC */ + +/* static int gc_count_total_records_used, gc_count_records_total_size; */ + +/* stats on objects in use */ + +#ifdef NEW_GC + +static struct +{ + int instances_in_use; + int bytes_in_use; + int bytes_in_use_including_overhead; +} lrecord_stats [countof (lrecord_implementations_table)]; + +#else /* not NEW_GC */ + +static struct +{ + Elemcount instances_in_use; + Bytecount bytes_in_use; + Bytecount bytes_in_use_overhead; + Elemcount instances_freed; + Bytecount bytes_freed; + Bytecount bytes_freed_overhead; + Elemcount instances_on_free_list; + Bytecount bytes_on_free_list; + Bytecount bytes_on_free_list_overhead; +#ifdef MEMORY_USAGE_STATS + Bytecount nonlisp_bytes_in_use; + Bytecount lisp_ancillary_bytes_in_use; + struct generic_usage_stats stats; +#endif +} lrecord_stats [countof (lrecord_implementations_table)]; + +#endif /* (not) NEW_GC */ + /* Very cheesy ways of figuring out how much memory is being used for data. #### Need better (system-dependent) ways. */ void *minimum_address_seen; void *maximum_address_seen; -/* Determine now whether we need to garbage collect or not, to make - Ffuncall() faster */ -#define INCREMENT_CONS_COUNTER_1(size) \ -do \ -{ \ - consing_since_gc += (size); \ - total_consing += (size); \ - if (profiling_active) \ - profile_record_consing (size); \ - recompute_need_to_garbage_collect (); \ -} while (0) - -#define debug_allocation_backtrace() \ -do { \ - if (debug_allocation_backtrace_length > 0) \ - debug_short_backtrace (debug_allocation_backtrace_length); \ -} while (0) - -#ifdef DEBUG_XEMACS -#define INCREMENT_CONS_COUNTER(foosize, type) \ - do { \ - if (debug_allocation) \ - { \ - stderr_out ("allocating %s (size %ld)\n", type, \ - (long) foosize); \ - debug_allocation_backtrace (); \ - } \ - INCREMENT_CONS_COUNTER_1 (foosize); \ - } while (0) -#define NOSEEUM_INCREMENT_CONS_COUNTER(foosize, type) \ - do { \ - if (debug_allocation > 1) \ - { \ - stderr_out ("allocating noseeum %s (size %ld)\n", type, \ - (long) foosize); \ - debug_allocation_backtrace (); \ - } \ - INCREMENT_CONS_COUNTER_1 (foosize); \ - } while (0) -#else -#define INCREMENT_CONS_COUNTER(size, type) INCREMENT_CONS_COUNTER_1 (size) -#define NOSEEUM_INCREMENT_CONS_COUNTER(size, type) \ - INCREMENT_CONS_COUNTER_1 (size) -#endif - -#ifdef NEW_GC -/* [[ The call to recompute_need_to_garbage_collect is moved to - free_normal_lisp_object, since DECREMENT_CONS_COUNTER is extensively called - during sweep and recomputing need_to_garbage_collect all the time - is not needed. ]] -- not accurate! */ -#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); \ - if (profiling_active) \ - profile_record_unconsing (size); \ - if (consing_since_gc < 0) \ - consing_since_gc = 0; \ - recompute_need_to_garbage_collect (); \ -} while (0) -#endif /*not NEW_GC */ - -#ifndef NEW_GC -int -c_readonly (Lisp_Object obj) -{ - return POINTER_TYPE_P (XTYPE (obj)) && C_READONLY (obj); -} -#endif /* not NEW_GC */ - -int -lisp_readonly (Lisp_Object obj) -{ - return POINTER_TYPE_P (XTYPE (obj)) && LISP_READONLY (obj); -} - +/************************************************************************/ +/* Low-level allocation */ +/************************************************************************/ + +void +recompute_funcall_allocation_flag (void) +{ + funcall_allocation_flag = + need_to_garbage_collect || + need_to_check_c_alloca || + need_to_signal_post_gc; +} + /* Maximum amount of C stack to save when a GC happens. */ #ifndef MAX_SAVE_STACK @@ -255,6 +226,22 @@ xfree (tmp); } } + +#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, + try to set aside another reserve in case we run out once more. + + This is called when a relocatable block is freed in ralloc.c. */ +void refill_memory_reserve (void); +void +refill_memory_reserve (void) +{ + if (breathing_space == 0) + breathing_space = (char *) malloc (4096 - MALLOC_OVERHEAD); +} +#endif /* !defined(HAVE_MMAP) || defined(DOUG_LEA_MALLOC) */ + #endif /* not NEW_GC */ static void @@ -490,6 +477,80 @@ #endif /* NEED_STRDUP */ +/************************************************************************/ +/* Lisp object allocation */ +/************************************************************************/ + +/* Determine now whether we need to garbage collect or not, to make + Ffuncall() faster */ +#define INCREMENT_CONS_COUNTER_1(size) \ +do \ +{ \ + consing_since_gc += (size); \ + total_consing += (size); \ + if (profiling_active) \ + profile_record_consing (size); \ + recompute_need_to_garbage_collect (); \ +} while (0) + +#define debug_allocation_backtrace() \ +do { \ + if (debug_allocation_backtrace_length > 0) \ + debug_short_backtrace (debug_allocation_backtrace_length); \ +} while (0) + +#ifdef DEBUG_XEMACS +#define INCREMENT_CONS_COUNTER(foosize, type) \ + do { \ + if (debug_allocation) \ + { \ + stderr_out ("allocating %s (size %ld)\n", type, \ + (long) foosize); \ + debug_allocation_backtrace (); \ + } \ + INCREMENT_CONS_COUNTER_1 (foosize); \ + } while (0) +#define NOSEEUM_INCREMENT_CONS_COUNTER(foosize, type) \ + do { \ + if (debug_allocation > 1) \ + { \ + stderr_out ("allocating noseeum %s (size %ld)\n", type, \ + (long) foosize); \ + debug_allocation_backtrace (); \ + } \ + INCREMENT_CONS_COUNTER_1 (foosize); \ + } while (0) +#else +#define INCREMENT_CONS_COUNTER(size, type) INCREMENT_CONS_COUNTER_1 (size) +#define NOSEEUM_INCREMENT_CONS_COUNTER(size, type) \ + INCREMENT_CONS_COUNTER_1 (size) +#endif + +#ifdef NEW_GC +/* [[ The call to recompute_need_to_garbage_collect is moved to + free_normal_lisp_object, since DECREMENT_CONS_COUNTER is extensively called + during sweep and recomputing need_to_garbage_collect all the time + is not needed. ]] -- not accurate! */ +#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); \ + if (profiling_active) \ + profile_record_unconsing (size); \ + if (consing_since_gc < 0) \ + consing_since_gc = 0; \ + recompute_need_to_garbage_collect (); \ +} while (0) +#endif /*not NEW_GC */ + #ifndef NEW_GC static void * allocate_lisp_storage (Bytecount size) @@ -517,63 +578,6 @@ } #endif /* not NEW_GC */ -#if defined (NEW_GC) && defined (ALLOC_TYPE_STATS) -static struct -{ - int instances_in_use; - int bytes_in_use; - int bytes_in_use_including_overhead; -} lrecord_stats [countof (lrecord_implementations_table)]; - -void -init_lrecord_stats (void) -{ - xzero (lrecord_stats); -} - -void -inc_lrecord_stats (Bytecount size, const struct lrecord_header *h) -{ - int type_index = h->type; - if (!size) - size = detagged_lisp_object_size (h); - - lrecord_stats[type_index].instances_in_use++; - lrecord_stats[type_index].bytes_in_use += size; - lrecord_stats[type_index].bytes_in_use_including_overhead -#ifdef MEMORY_USAGE_STATS - += mc_alloced_storage_size (size, 0); -#else /* not MEMORY_USAGE_STATS */ - += size; -#endif /* not MEMORY_USAGE_STATS */ -} - -void -dec_lrecord_stats (Bytecount size_including_overhead, - const struct lrecord_header *h) -{ - int type_index = h->type; - int size = detagged_lisp_object_size (h); - - lrecord_stats[type_index].instances_in_use--; - lrecord_stats[type_index].bytes_in_use -= size; - lrecord_stats[type_index].bytes_in_use_including_overhead - -= size_including_overhead; - - DECREMENT_CONS_COUNTER (size); -} - -int -lrecord_stats_heap_size (void) -{ - int i; - int size = 0; - for (i = 0; i < countof (lrecord_implementations_table); i++) - size += lrecord_stats[i].bytes_in_use; - return size; -} -#endif /* NEW_GC && ALLOC_TYPE_STATS */ - #define assert_proper_sizing(size) \ type_checking_assert \ (implementation->static_size == 0 ? \ @@ -755,32 +759,6 @@ #endif /* Unused */ #endif /* not NEW_GC */ - -static void -disksave_object_finalization_1 (void) -{ -#ifdef NEW_GC - mc_finalize_for_disksave (); -#else /* not NEW_GC */ - struct old_lcrecord_header *header; - - for (header = all_lcrecords; header; header = header->next) - { - struct lrecord_header *objh = &header->lheader; - const struct lrecord_implementation *imp = LHEADER_IMPLEMENTATION (objh); -#if 0 /* possibly useful for debugging */ - if (!RECORD_DUMPABLE (objh) && !objh->free) - { - stderr_out ("Disksaving a non-dumpable object: "); - debug_print (wrap_pointer_1 (header)); - } -#endif - if (imp->disksave && !objh->free) - (imp->disksave) (wrap_pointer_1 (header)); - } -#endif /* not NEW_GC */ -} - /* Bitwise copy all parts of a Lisp object other than the header */ void @@ -872,9 +850,37 @@ #endif } +#ifndef NEW_GC +int +c_readonly (Lisp_Object obj) +{ + return POINTER_TYPE_P (XTYPE (obj)) && C_READONLY (obj); +} +#endif /* not NEW_GC */ + +int +lisp_readonly (Lisp_Object obj) +{ + return POINTER_TYPE_P (XTYPE (obj)) && LISP_READONLY (obj); +} + +/* #### Should be made into an object method */ + +int +object_dead_p (Lisp_Object obj) +{ + return ((BUFFERP (obj) && !BUFFER_LIVE_P (XBUFFER (obj))) || + (FRAMEP (obj) && !FRAME_LIVE_P (XFRAME (obj))) || + (WINDOWP (obj) && !WINDOW_LIVE_P (XWINDOW (obj))) || + (DEVICEP (obj) && !DEVICE_LIVE_P (XDEVICE (obj))) || + (CONSOLEP (obj) && !CONSOLE_LIVE_P (XCONSOLE (obj))) || + (EVENTP (obj) && !EVENT_LIVE_P (XEVENT (obj))) || + (EXTENTP (obj) && !EXTENT_LIVE_P (XEXTENT (obj)))); +} + /************************************************************************/ -/* Debugger support */ +/* Debugger support */ /************************************************************************/ /* Give gdb/dbx enough information to decode Lisp Objects. We make sure certain symbols are always defined, so gdb doesn't complain @@ -921,7 +927,7 @@ #define DECLARE_FIXED_TYPE_ALLOC(type, structture) struct __foo__ #else /************************************************************************/ -/* Fixed-size type macros */ +/* Fixed-size type macros */ /************************************************************************/ /* For fixed-size types that are commonly used, we malloc() large blocks @@ -1061,21 +1067,6 @@ remain free for the next 1000 (or whatever) times that an object of that type is allocated. */ -#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, - try to set aside another reserve in case we run out once more. - - This is called when a relocatable block is freed in ralloc.c. */ -void refill_memory_reserve (void); -void -refill_memory_reserve (void) -{ - if (breathing_space == 0) - breathing_space = (char *) malloc (4096 - MALLOC_OVERHEAD); -} -#endif - #ifdef ALLOC_NO_POOLS # define TYPE_ALLOC_SIZE(type, structtype) 1 #else @@ -3569,38 +3560,208 @@ #endif /* not DEBUG_XEMACS */ #endif /* NEW_GC */ - -/************************************************************************/ -/* Allocation Statistics */ -/************************************************************************/ - -#ifndef NEW_GC -static int gc_count_num_short_string_in_use; -static Bytecount gc_count_string_total_size; -static Bytecount gc_count_short_string_total_size; -static Bytecount gc_count_long_string_storage_including_overhead; - -/* static int gc_count_total_records_used, gc_count_records_total_size; */ +#ifdef ALLOC_TYPE_STATS -/* stats on objects in use */ - -static struct -{ - Elemcount instances_in_use; - Bytecount bytes_in_use; - Bytecount bytes_in_use_overhead; - Elemcount instances_freed; - Bytecount bytes_freed; - Bytecount bytes_freed_overhead; - Elemcount instances_on_free_list; - Bytecount bytes_on_free_list; - Bytecount bytes_on_free_list_overhead; +/************************************************************************/ +/* Determining allocation overhead */ +/************************************************************************/ + +/* Attempt to determine the actual amount of space that is used for + the block allocated starting at PTR, supposedly of size "CLAIMED_SIZE". + + It seems that the following holds: + + 1. When using the old allocator (malloc.c): + + -- blocks are always allocated in chunks of powers of two. For + each block, there is an overhead of 8 bytes if rcheck is not + defined, 20 bytes if it is defined. In other words, a + one-byte allocation needs 8 bytes of overhead for a total of + 9 bytes, and needs to have 16 bytes of memory chunked out for + it. + + 2. When using the new allocator (gmalloc.c): + + -- blocks are always allocated in chunks of powers of two up + to 4096 bytes. Larger blocks are allocated in chunks of + an integral multiple of 4096 bytes. The minimum block + size is 2*sizeof (void *), or 16 bytes if SUNOS_LOCALTIME_BUG + is defined. There is no per-block overhead, but there + is an overhead of 3*sizeof (size_t) for each 4096 bytes + allocated. + + 3. When using the system malloc, anything goes, but they are + generally slower and more space-efficient than the GNU + allocators. One possibly reasonable assumption to make + for want of better data is that sizeof (void *), or maybe + 2 * sizeof (void *), is required as overhead and that + blocks are allocated in the minimum required size except + that some minimum block size is imposed (e.g. 16 bytes). */ + +Bytecount +malloced_storage_size (void * UNUSED (ptr), Bytecount claimed_size, + struct usage_stats *stats) +{ + Bytecount orig_claimed_size = claimed_size; + +#ifndef SYSTEM_MALLOC + if (claimed_size < (Bytecount) (2 * sizeof (void *))) + claimed_size = 2 * sizeof (void *); +# ifdef SUNOS_LOCALTIME_BUG + if (claimed_size < 16) + claimed_size = 16; +# endif + if (claimed_size < 4096) + { + /* fxg: rename log->log2 to supress gcc3 shadow warning */ + int log2 = 1; + + /* compute the log base two, more or less, then use it to compute + the block size needed. */ + claimed_size--; + /* It's big, it's heavy, it's wood! */ + while ((claimed_size /= 2) != 0) + ++log2; + claimed_size = 1; + /* It's better than bad, it's good! */ + while (log2 > 0) + { + claimed_size *= 2; + log2--; + } + /* We have to come up with some average about the amount of + blocks used. */ + if ((Bytecount) (rand () & 4095) < claimed_size) + claimed_size += 3 * sizeof (void *); + } + else + { + claimed_size += 4095; + claimed_size &= ~4095; + claimed_size += (claimed_size / 4096) * 3 * sizeof (size_t); + } + +#else + + if (claimed_size < 16) + claimed_size = 16; + claimed_size += 2 * sizeof (void *); + +#endif /* system allocator */ + + if (stats) + { + stats->was_requested += orig_claimed_size; + stats->malloc_overhead += claimed_size - orig_claimed_size; + } + return claimed_size; +} + +#ifndef NEW_GC +static Bytecount +fixed_type_block_overhead (Bytecount size, Bytecount per_block) +{ + Bytecount overhead = 0; + Bytecount storage_size = malloced_storage_size (0, per_block, 0); + while (size >= per_block) + { + size -= per_block; + overhead += storage_size - per_block; + } + if (rand () % per_block < size) + overhead += storage_size - per_block; + return overhead; +} +#endif /* not NEW_GC */ + +Bytecount +lisp_object_storage_size (Lisp_Object obj, struct usage_stats *ustats) +{ +#ifndef NEW_GC + const struct lrecord_implementation *imp = + XRECORD_LHEADER_IMPLEMENTATION (obj); +#endif /* not NEW_GC */ + Bytecount size = lisp_object_size (obj); + +#ifdef NEW_GC + return mc_alloced_storage_size (size, ustats); +#else + if (imp->frob_block_p) + { + Bytecount overhead = + /* #### Always using cons_block is incorrect but close; only + string_chars_block is significantly different in size, and + it won't ever be seen in this function */ + fixed_type_block_overhead (size, sizeof (struct cons_block)); + if (ustats) + { + ustats->was_requested += size; + ustats->malloc_overhead += overhead; + } + return size + overhead; + } + else + return malloced_storage_size (XPNTR (obj), size, ustats); +#endif +} + + +/************************************************************************/ +/* Allocation Statistics: Accumulate */ +/************************************************************************/ + +#ifdef NEW_GC + +void +init_lrecord_stats (void) +{ + xzero (lrecord_stats); +} + +void +inc_lrecord_stats (Bytecount size, const struct lrecord_header *h) +{ + int type_index = h->type; + if (!size) + size = detagged_lisp_object_size (h); + + lrecord_stats[type_index].instances_in_use++; + lrecord_stats[type_index].bytes_in_use += size; + lrecord_stats[type_index].bytes_in_use_including_overhead #ifdef MEMORY_USAGE_STATS - Bytecount nonlisp_bytes_in_use; - struct generic_usage_stats stats; -#endif -} lrecord_stats [countof (lrecord_implementations_table)]; + += mc_alloced_storage_size (size, 0); +#else /* not MEMORY_USAGE_STATS */ + += size; +#endif /* not MEMORY_USAGE_STATS */ +} + +void +dec_lrecord_stats (Bytecount size_including_overhead, + const struct lrecord_header *h) +{ + int type_index = h->type; + int size = detagged_lisp_object_size (h); + + lrecord_stats[type_index].instances_in_use--; + lrecord_stats[type_index].bytes_in_use -= size; + lrecord_stats[type_index].bytes_in_use_including_overhead + -= size_including_overhead; + + DECREMENT_CONS_COUNTER (size); +} + +int +lrecord_stats_heap_size (void) +{ + int i; + int size = 0; + for (i = 0; i < countof (lrecord_implementations_table); i++) + size += lrecord_stats[i].bytes_in_use; + return size; +} + +#else /* not NEW_GC */ static void clear_lrecord_stats (void) @@ -3705,7 +3866,547 @@ tick_lrecord_stats (h, free_p ? ALLOC_FREE : ALLOC_IN_USE); } +#endif /* (not) NEW_GC */ + +void +finish_object_memory_usage_stats (void) +{ + /* Here we add up the aggregate values for each statistic, previously + computed during tick_lrecord_stats(), to get a single combined value + of non-Lisp memory usage for all objects of each type. We can't + do this if NEW_GC because nothing like tick_lrecord_stats() gets + called -- instead, statistics are computed when objects are allocated, + which is too early to be calling the memory_usage() method. */ +#if defined (MEMORY_USAGE_STATS) && !defined (NEW_GC) + int i; + for (i = 0; i < countof (lrecord_implementations_table); i++) + { + struct lrecord_implementation *imp = lrecord_implementations_table[i]; + if (imp && imp->num_extra_nonlisp_memusage_stats) + { + int j; + for (j = 0; j < imp->num_extra_nonlisp_memusage_stats; j++) + lrecord_stats[i].nonlisp_bytes_in_use += + lrecord_stats[i].stats.othervals[j]; + } + if (imp && imp->num_extra_lisp_ancillary_memusage_stats) + { + int j; + for (j = 0; j < imp->num_extra_lisp_ancillary_memusage_stats; j++) + lrecord_stats[i].lisp_ancillary_bytes_in_use += + lrecord_stats[i].stats.othervals + [j + imp->offset_lisp_ancillary_memusage_stats]; + } + } +#endif /* defined (MEMORY_USAGE_STATS) && !defined (NEW_GC) */ +} + +#define COUNT_FROB_BLOCK_USAGE(type) \ + EMACS_INT s = 0; \ + EMACS_INT s_overhead = 0; \ + struct type##_block *x = current_##type##_block; \ + while (x) { s += sizeof (*x) + MALLOC_OVERHEAD; x = x->prev; } \ + s_overhead = fixed_type_block_overhead (s, sizeof (struct type##_block)); \ + DO_NOTHING + +#define COPY_INTO_LRECORD_STATS(type) \ +do { \ + COUNT_FROB_BLOCK_USAGE (type); \ + lrecord_stats[lrecord_type_##type].bytes_in_use += s; \ + lrecord_stats[lrecord_type_##type].bytes_in_use_overhead += \ + s_overhead; \ + lrecord_stats[lrecord_type_##type].instances_on_free_list += \ + gc_count_num_##type##_freelist; \ + lrecord_stats[lrecord_type_##type].instances_in_use += \ + gc_count_num_##type##_in_use; \ +} while (0) + + +/************************************************************************/ +/* Allocation statistics: format nicely */ +/************************************************************************/ + +static Lisp_Object +gc_plist_hack (const Ascbyte *name, EMACS_INT value, Lisp_Object tail) +{ + /* C doesn't have local functions (or closures, or GC, or readable syntax, + or portable numeric datatypes, or bit-vectors, or characters, or + arrays, or exceptions, or ...) */ + return cons3 (intern (name), make_int (value), tail); +} + +/* Pluralize a lowercase English word stored in BUF, assuming BUF has + enough space to hold the extra letters (at most 2). */ +static void +pluralize_word (Ascbyte *buf) +{ + Bytecount len = strlen (buf); + int upper = 0; + Ascbyte d, e; + + if (len == 0 || len == 1) + goto pluralize_apostrophe_s; + e = buf[len - 1]; + d = buf[len - 2]; + upper = isupper (e); + e = tolower (e); + d = tolower (d); + if (e == 'y') + { + switch (d) + { + case 'a': + case 'e': + case 'i': + case 'o': + case 'u': + goto pluralize_s; + default: + buf[len - 1] = (upper ? 'I' : 'i'); + goto pluralize_es; + } + } + else if (e == 's' || e == 'x' || (e == 'h' && (d == 's' || d == 'c'))) + { + pluralize_es: + buf[len++] = (upper ? 'E' : 'e'); + } + pluralize_s: + buf[len++] = (upper ? 'S' : 's'); + buf[len] = '\0'; + return; + + pluralize_apostrophe_s: + buf[len++] = '\''; + goto pluralize_s; +} + +static void +pluralize_and_append (Ascbyte *buf, const Ascbyte *name, const Ascbyte *suffix) +{ + strcpy (buf, name); + pluralize_word (buf); + strcat (buf, suffix); +} + +static Lisp_Object +object_memory_usage_stats (int set_total_gc_usage) +{ + Lisp_Object pl = Qnil; + int i; + EMACS_INT tgu_val = 0; + +#ifdef NEW_GC + for (i = 0; i < countof (lrecord_implementations_table); i++) + { + if (lrecord_stats[i].instances_in_use != 0) + { + Ascbyte buf[255]; + const Ascbyte *name = lrecord_implementations_table[i]->name; + + if (lrecord_stats[i].bytes_in_use_including_overhead != + lrecord_stats[i].bytes_in_use) + { + sprintf (buf, "%s-storage-including-overhead", name); + pl = gc_plist_hack (buf, + lrecord_stats[i] + .bytes_in_use_including_overhead, + pl); + } + + sprintf (buf, "%s-storage", name); + pl = gc_plist_hack (buf, + lrecord_stats[i].bytes_in_use, + pl); + tgu_val += lrecord_stats[i].bytes_in_use_including_overhead; + + pluralize_and_append (buf, name, "-used"); + pl = gc_plist_hack (buf, lrecord_stats[i].instances_in_use, pl); + } + } + +#else /* not NEW_GC */ + + for (i = 0; i < lrecord_type_count; i++) + { + if (lrecord_stats[i].bytes_in_use != 0 + || lrecord_stats[i].bytes_freed != 0 + || lrecord_stats[i].instances_on_free_list != 0) + { + Ascbyte buf[255]; + const Ascbyte *name = lrecord_implementations_table[i]->name; + + sprintf (buf, "%s-storage-overhead", name); + pl = gc_plist_hack (buf, lrecord_stats[i].bytes_in_use_overhead, pl); + tgu_val += lrecord_stats[i].bytes_in_use_overhead; + sprintf (buf, "%s-storage", name); + pl = gc_plist_hack (buf, lrecord_stats[i].bytes_in_use, pl); + tgu_val += lrecord_stats[i].bytes_in_use; +#ifdef MEMORY_USAGE_STATS + if (lrecord_stats[i].nonlisp_bytes_in_use) + { + sprintf (buf, "%s-non-lisp-storage", name); + pl = gc_plist_hack (buf, lrecord_stats[i].nonlisp_bytes_in_use, + pl); + tgu_val += lrecord_stats[i].nonlisp_bytes_in_use; + } + if (lrecord_stats[i].lisp_ancillary_bytes_in_use) + { + sprintf (buf, "%s-lisp-ancillary-storage", name); + pl = gc_plist_hack (buf, lrecord_stats[i]. + lisp_ancillary_bytes_in_use, + pl); + tgu_val += lrecord_stats[i].lisp_ancillary_bytes_in_use; + } +#endif /* MEMORY_USAGE_STATS */ + pluralize_and_append (buf, name, "-freed"); + if (lrecord_stats[i].instances_freed != 0) + pl = gc_plist_hack (buf, lrecord_stats[i].instances_freed, pl); + pluralize_and_append (buf, name, "-on-free-list"); + if (lrecord_stats[i].instances_on_free_list != 0) + pl = gc_plist_hack (buf, lrecord_stats[i].instances_on_free_list, + pl); + pluralize_and_append (buf, name, "-used"); + pl = gc_plist_hack (buf, lrecord_stats[i].instances_in_use, pl); + } + } + + pl = gc_plist_hack ("long-string-chars-storage-overhead", + gc_count_long_string_storage_including_overhead - + (gc_count_string_total_size + - gc_count_short_string_total_size), pl); + pl = gc_plist_hack ("long-string-chars-storage", + gc_count_string_total_size + - gc_count_short_string_total_size, pl); + do + { + COUNT_FROB_BLOCK_USAGE (string_chars); + tgu_val += s + s_overhead; + pl = gc_plist_hack ("short-string-chars-storage-overhead", s_overhead, pl); + pl = gc_plist_hack ("short-string-chars-storage", s, pl); + } + while (0); + + pl = gc_plist_hack ("long-strings-total-length", + gc_count_string_total_size + - gc_count_short_string_total_size, pl); + pl = gc_plist_hack ("short-strings-total-length", + gc_count_short_string_total_size, pl); + pl = gc_plist_hack ("long-strings-used", + gc_count_num_string_in_use + - gc_count_num_short_string_in_use, pl); + pl = gc_plist_hack ("short-strings-used", + gc_count_num_short_string_in_use, pl); + +#endif /* NEW_GC */ + + if (set_total_gc_usage) + { + total_gc_usage = tgu_val; + total_gc_usage_set = 1; + } + + return pl; +} + +static Lisp_Object +garbage_collection_statistics (void) +{ + /* The things we do for backwards-compatibility */ +#ifdef NEW_GC + return + list6 + (Fcons (make_int (lrecord_stats[lrecord_type_cons].instances_in_use), + make_int (lrecord_stats[lrecord_type_cons] + .bytes_in_use_including_overhead)), + Fcons (make_int (lrecord_stats[lrecord_type_symbol].instances_in_use), + make_int (lrecord_stats[lrecord_type_symbol] + .bytes_in_use_including_overhead)), + Fcons (make_int (lrecord_stats[lrecord_type_marker].instances_in_use), + make_int (lrecord_stats[lrecord_type_marker] + .bytes_in_use_including_overhead)), + make_int (lrecord_stats[lrecord_type_string] + .bytes_in_use_including_overhead), + make_int (lrecord_stats[lrecord_type_vector] + .bytes_in_use_including_overhead), + object_memory_usage_stats (1)); +#else /* not NEW_GC */ + return + list6 (Fcons (make_int (gc_count_num_cons_in_use), + make_int (gc_count_num_cons_freelist)), + Fcons (make_int (gc_count_num_symbol_in_use), + make_int (gc_count_num_symbol_freelist)), + Fcons (make_int (gc_count_num_marker_in_use), + make_int (gc_count_num_marker_freelist)), + make_int (gc_count_string_total_size), + make_int (lrecord_stats[lrecord_type_vector].bytes_in_use + + lrecord_stats[lrecord_type_vector].bytes_freed + + lrecord_stats[lrecord_type_vector].bytes_on_free_list), + object_memory_usage_stats (1)); #endif /* not NEW_GC */ +} + +DEFUN ("object-memory-usage-stats", Fobject_memory_usage_stats, 0, 0, 0, /* +Return statistics about memory usage of Lisp objects. +*/ + ()) +{ + return object_memory_usage_stats (0); +} + +#endif /* ALLOC_TYPE_STATS */ + +#ifdef MEMORY_USAGE_STATS + +DEFUN ("object-memory-usage", Fobject_memory_usage, 1, 1, 0, /* +Return stats about the memory usage of OBJECT. +The values returned are in the form of an alist of usage types and byte +counts. The byte counts attempt to encompass all the memory used +by the object (separate from the memory logically associated with any +other object), including internal structures and any malloc() +overhead associated with them. In practice, the byte counts are +underestimated because certain memory usage is very hard to determine +\(e.g. the amount of memory used inside the Xt library or inside the +X server). + +Multiple slices of the total memory usage may be returned, separated +by a nil. Each slice represents a particular view of the memory, a +particular way of partitioning it into groups. Within a slice, there +is no overlap between the groups of memory, and each slice collectively +represents all the memory concerned. The rightmost slice typically +represents the total memory used plus malloc and dynarr overhead. + +Slices describing other Lisp objects logically associated with the +object may be included, separated from other slices by `t' and from +each other by nil if there is more than one. + +#### We have to figure out how to handle the memory used by the object +itself vs. the memory used by substructures. Probably the memory_usage +method should return info only about substructures and related Lisp +objects, since the caller can always find and all info about the object +itself. +*/ + (object)) +{ + struct generic_usage_stats gustats; + struct usage_stats object_stats; + int i; + Lisp_Object val = Qnil; + Lisp_Object stats_list; + + if (INTP (object) || CHARP (object)) + invalid_argument ("No memory associated with immediate objects (int or char)", + object); + + stats_list = OBJECT_PROPERTY (object, memusage_stats_list); + + xzero (object_stats); + lisp_object_storage_size (object, &object_stats); + + val = acons (Qobject_actually_requested, + make_int (object_stats.was_requested), val); + val = acons (Qobject_malloc_overhead, + make_int (object_stats.malloc_overhead), val); + assert (!object_stats.dynarr_overhead); + assert (!object_stats.gap_overhead); + + if (!NILP (stats_list)) + { + xzero (gustats); + MAYBE_OBJECT_METH (object, memory_usage, (object, &gustats)); + + val = Fcons (Qt, val); + val = acons (Qother_memory_actually_requested, + make_int (gustats.u.was_requested), val); + val = acons (Qother_memory_malloc_overhead, + make_int (gustats.u.malloc_overhead), val); + if (gustats.u.dynarr_overhead) + val = acons (Qother_memory_dynarr_overhead, + make_int (gustats.u.dynarr_overhead), val); + if (gustats.u.gap_overhead) + val = acons (Qother_memory_gap_overhead, + make_int (gustats.u.gap_overhead), val); + val = Fcons (Qnil, val); + + i = 0; + { + LIST_LOOP_2 (item, stats_list) + { + if (NILP (item) || EQ (item, Qt)) + val = Fcons (item, val); + else + { + val = acons (item, make_int (gustats.othervals[i]), val); + i++; + } + } + } + } + + return Fnreverse (val); +} + +/* Compute total memory usage associated with an object, including + + (a) Storage (including overhead) allocated to the object itself + (b) Storage (including overhead) for ancillary non-Lisp structures attached + to the object + (c) Storage (including overhead) for ancillary Lisp objects attached + to the object + + Store the three types of memory into the return values provided they + aren't NULL, and return a sum of the three values. Also store the + structure of individual statistics into STATS if non-zero. + + Note that the value for type (c) is the sum of all three types of + memory associated with the ancillary Lisp objects. +*/ + +Bytecount +lisp_object_memory_usage_full (Lisp_Object object, Bytecount *storage_size, + Bytecount *extra_nonlisp_storage, + Bytecount *extra_lisp_ancillary_storage, + struct generic_usage_stats *stats) +{ + Bytecount total; + struct lrecord_implementation *imp = XRECORD_LHEADER_IMPLEMENTATION (object); + + total = lisp_object_storage_size (object, NULL); + if (storage_size) + *storage_size = total; + + if (HAS_OBJECT_METH_P (object, memory_usage)) + { + int i; + struct generic_usage_stats gustats; + Bytecount sum; + + xzero (gustats); + OBJECT_METH (object, memory_usage, (object, &gustats)); + + if (stats) + *stats = gustats; + + sum = 0; + for (i = 0; i < imp->num_extra_nonlisp_memusage_stats; i++) + sum += gustats.othervals[i]; + total += sum; + if (extra_nonlisp_storage) + *extra_nonlisp_storage = sum; + + sum = 0; + for (i = 0; i < imp->num_extra_lisp_ancillary_memusage_stats; i++) + sum += gustats.othervals[imp->offset_lisp_ancillary_memusage_stats + + i]; + total += sum; + if (extra_lisp_ancillary_storage) + *extra_lisp_ancillary_storage = sum; + } + else + { + if (extra_nonlisp_storage) + *extra_nonlisp_storage = 0; + if (extra_lisp_ancillary_storage) + *extra_lisp_ancillary_storage = 0; + } + + return total; +} + + +Bytecount +lisp_object_memory_usage (Lisp_Object object) +{ + return lisp_object_memory_usage_full (object, NULL, NULL, NULL, NULL); +} + +#endif /* MEMORY_USAGE_STATS */ + +#ifdef ALLOC_TYPE_STATS + +DEFUN ("total-object-memory-usage", Ftotal_object_memory_usage, 0, 0, 0, /* +Return total number of bytes used for object storage in XEmacs. +This may be helpful in debugging XEmacs's memory usage. +See also `consing-since-gc' and `object-memory-usage-stats'. +*/ + ()) +{ + return make_int (total_gc_usage + consing_since_gc); +} + +#endif /* ALLOC_TYPE_STATS */ + + +/************************************************************************/ +/* Allocation statistics: Initialization */ +/************************************************************************/ +#ifdef MEMORY_USAGE_STATS + +/* Compute the number of extra memory-usage statistics associated with an + object. We can't compute this at the time INIT_LISP_OBJECT() is called + because the value of the `memusage_stats_list' property is generally + set afterwards. So we compute the values for all types of objects + after all objects have been initialized. */ + +static void +compute_memusage_stats_length (void) +{ + int i; + + for (i = 0; i < countof (lrecord_implementations_table); i++) + { + struct lrecord_implementation *imp = lrecord_implementations_table[i]; + + if (!imp) + continue; + /* For some of the early objects, Qnil was not yet initialized at + the time of object initialization, so it came up as Qnull_pointer. + Fix that now. */ + if (EQ (imp->memusage_stats_list, Qnull_pointer)) + imp->memusage_stats_list = Qnil; + { + Elemcount len = 0; + Elemcount nonlisp_len = 0; + Elemcount lisp_len = 0; + Elemcount lisp_offset = 0; + int group_num = 0; + int slice_num = 0; + + LIST_LOOP_2 (item, imp->memusage_stats_list) + { + if (EQ (item, Qt)) + { + group_num++; + if (group_num == 1) + lisp_offset = len; + slice_num = 0; + } + else if (EQ (item, Qnil)) + { + slice_num++; + } + else + { + if (slice_num == 0) + { + if (group_num == 0) + nonlisp_len++; + else if (group_num == 1) + lisp_len++; + } + len++; + } + } + + imp->num_extra_memusage_stats = len; + imp->num_extra_nonlisp_memusage_stats = nonlisp_len; + imp->num_extra_lisp_ancillary_memusage_stats = lisp_len; + imp->offset_lisp_ancillary_memusage_stats = lisp_offset; + } + } +} + +#endif /* MEMORY_USAGE_STATS */ /************************************************************************/ @@ -3772,32 +4473,9 @@ /* *total = total_size; */ } -static Bytecount fixed_type_block_overhead (Bytecount size, - Bytecount per_block); - /* And the Lord said: Thou shalt use the `c-backslash-region' command to make macros prettier. */ -#define COUNT_FROB_BLOCK_USAGE(type) \ - EMACS_INT s = 0; \ - EMACS_INT s_overhead = 0; \ - struct type##_block *x = current_##type##_block; \ - while (x) { s += sizeof (*x) + MALLOC_OVERHEAD; x = x->prev; } \ - s_overhead = fixed_type_block_overhead (s, sizeof (struct type##_block)); \ - DO_NOTHING - -#define COPY_INTO_LRECORD_STATS(type) \ -do { \ - COUNT_FROB_BLOCK_USAGE (type); \ - lrecord_stats[lrecord_type_##type].bytes_in_use += s; \ - lrecord_stats[lrecord_type_##type].bytes_in_use_overhead += \ - s_overhead; \ - lrecord_stats[lrecord_type_##type].instances_on_free_list += \ - gc_count_num_##type##_freelist; \ - lrecord_stats[lrecord_type_##type].instances_in_use += \ - gc_count_num_##type##_in_use; \ -} while (0) - #ifdef ERROR_CHECK_GC #define SWEEP_FIXED_TYPE_BLOCK_1(typename, obj_type, lheader) \ @@ -4570,6 +5248,31 @@ /* "Disksave Finalization" -- Preparing for Dumping */ /************************************************************************/ +static void +disksave_object_finalization_1 (void) +{ +#ifdef NEW_GC + mc_finalize_for_disksave (); +#else /* not NEW_GC */ + struct old_lcrecord_header *header; + + for (header = all_lcrecords; header; header = header->next) + { + struct lrecord_header *objh = &header->lheader; + const struct lrecord_implementation *imp = LHEADER_IMPLEMENTATION (objh); +#if 0 /* possibly useful for debugging */ + if (!RECORD_DUMPABLE (objh) && !objh->free) + { + stderr_out ("Disksaving a non-dumpable object: "); + debug_print (wrap_pointer_1 (header)); + } +#endif + if (imp->disksave && !objh->free) + (imp->disksave) (wrap_pointer_1 (header)); + } +#endif /* not NEW_GC */ +} + void disksave_object_finalization (void) { @@ -4636,348 +5339,10 @@ } -#ifdef ALLOC_TYPE_STATS - -static Lisp_Object -gc_plist_hack (const Ascbyte *name, EMACS_INT value, Lisp_Object tail) -{ - /* C doesn't have local functions (or closures, or GC, or readable syntax, - or portable numeric datatypes, or bit-vectors, or characters, or - arrays, or exceptions, or ...) */ - return cons3 (intern (name), make_int (value), tail); -} - -/* Pluralize a lowercase English word stored in BUF, assuming BUF has - enough space to hold the extra letters (at most 2). */ -static void -pluralize_word (Ascbyte *buf) -{ - Bytecount len = strlen (buf); - int upper = 0; - Ascbyte d, e; - - if (len == 0 || len == 1) - goto pluralize_apostrophe_s; - e = buf[len - 1]; - d = buf[len - 2]; - upper = isupper (e); - e = tolower (e); - d = tolower (d); - if (e == 'y') - { - switch (d) - { - case 'a': - case 'e': - case 'i': - case 'o': - case 'u': - goto pluralize_s; - default: - buf[len - 1] = (upper ? 'I' : 'i'); - goto pluralize_es; - } - } - else if (e == 's' || e == 'x' || (e == 'h' && (d == 's' || d == 'c'))) - { - pluralize_es: - buf[len++] = (upper ? 'E' : 'e'); - } - pluralize_s: - buf[len++] = (upper ? 'S' : 's'); - buf[len] = '\0'; - return; - - pluralize_apostrophe_s: - buf[len++] = '\''; - goto pluralize_s; -} - -static void -pluralize_and_append (Ascbyte *buf, const Ascbyte *name, const Ascbyte *suffix) -{ - strcpy (buf, name); - pluralize_word (buf); - strcat (buf, suffix); -} - -void -finish_object_memory_usage_stats (void) -{ - /* Here we add up the aggregate values for each statistic, previously - computed during tick_lrecord_stats(), to get a single combined value - of non-Lisp memory usage for all objects of each type. We can't - do this if NEW_GC because nothing like tick_lrecord_stats() gets - called -- instead, statistics are computed when objects are allocated, - which is too early to be calling the memory_usage() method. */ -#if defined (MEMORY_USAGE_STATS) && !defined (NEW_GC) - int i; - for (i = 0; i < countof (lrecord_implementations_table); i++) - { - struct lrecord_implementation *imp = lrecord_implementations_table[i]; - if (imp && imp->num_extra_nonlisp_memusage_stats) - { - int j; - for (j = 0; j < imp->num_extra_nonlisp_memusage_stats; j++) - lrecord_stats[i].nonlisp_bytes_in_use += - lrecord_stats[i].stats.othervals[j]; - } - } -#endif /* defined (MEMORY_USAGE_STATS) && !defined (NEW_GC) */ -} - -static Lisp_Object -object_memory_usage_stats (int set_total_gc_usage) -{ - Lisp_Object pl = Qnil; - int i; - EMACS_INT tgu_val = 0; - -#ifdef NEW_GC - for (i = 0; i < countof (lrecord_implementations_table); i++) - { - if (lrecord_stats[i].instances_in_use != 0) - { - Ascbyte buf[255]; - const Ascbyte *name = lrecord_implementations_table[i]->name; - - if (lrecord_stats[i].bytes_in_use_including_overhead != - lrecord_stats[i].bytes_in_use) - { - sprintf (buf, "%s-storage-including-overhead", name); - pl = gc_plist_hack (buf, - lrecord_stats[i] - .bytes_in_use_including_overhead, - pl); - } - - sprintf (buf, "%s-storage", name); - pl = gc_plist_hack (buf, - lrecord_stats[i].bytes_in_use, - pl); - tgu_val += lrecord_stats[i].bytes_in_use_including_overhead; - - pluralize_and_append (buf, name, "-used"); - pl = gc_plist_hack (buf, lrecord_stats[i].instances_in_use, pl); - } - } - -#else /* not NEW_GC */ - - for (i = 0; i < lrecord_type_count; i++) - { - if (lrecord_stats[i].bytes_in_use != 0 - || lrecord_stats[i].bytes_freed != 0 - || lrecord_stats[i].instances_on_free_list != 0) - { - Ascbyte buf[255]; - const Ascbyte *name = lrecord_implementations_table[i]->name; - - sprintf (buf, "%s-storage-overhead", name); - pl = gc_plist_hack (buf, lrecord_stats[i].bytes_in_use_overhead, pl); - tgu_val += lrecord_stats[i].bytes_in_use_overhead; - sprintf (buf, "%s-storage", name); - pl = gc_plist_hack (buf, lrecord_stats[i].bytes_in_use, pl); - tgu_val += lrecord_stats[i].bytes_in_use; -#ifdef MEMORY_USAGE_STATS - if (lrecord_stats[i].nonlisp_bytes_in_use) - { - sprintf (buf, "%s-non-lisp-storage", name); - pl = gc_plist_hack (buf, lrecord_stats[i].nonlisp_bytes_in_use, - pl); - tgu_val += lrecord_stats[i].nonlisp_bytes_in_use; - } -#endif /* MEMORY_USAGE_STATS */ - pluralize_and_append (buf, name, "-freed"); - if (lrecord_stats[i].instances_freed != 0) - pl = gc_plist_hack (buf, lrecord_stats[i].instances_freed, pl); - pluralize_and_append (buf, name, "-on-free-list"); - if (lrecord_stats[i].instances_on_free_list != 0) - pl = gc_plist_hack (buf, lrecord_stats[i].instances_on_free_list, - pl); - pluralize_and_append (buf, name, "-used"); - pl = gc_plist_hack (buf, lrecord_stats[i].instances_in_use, pl); - } - } - - pl = gc_plist_hack ("long-string-chars-storage-overhead", - gc_count_long_string_storage_including_overhead - - (gc_count_string_total_size - - gc_count_short_string_total_size), pl); - pl = gc_plist_hack ("long-string-chars-storage", - gc_count_string_total_size - - gc_count_short_string_total_size, pl); - do - { - COUNT_FROB_BLOCK_USAGE (string_chars); - tgu_val += s + s_overhead; - pl = gc_plist_hack ("short-string-chars-storage-overhead", s_overhead, pl); - pl = gc_plist_hack ("short-string-chars-storage", s, pl); - } - while (0); - - pl = gc_plist_hack ("long-strings-total-length", - gc_count_string_total_size - - gc_count_short_string_total_size, pl); - pl = gc_plist_hack ("short-strings-total-length", - gc_count_short_string_total_size, pl); - pl = gc_plist_hack ("long-strings-used", - gc_count_num_string_in_use - - gc_count_num_short_string_in_use, pl); - pl = gc_plist_hack ("short-strings-used", - gc_count_num_short_string_in_use, pl); - -#endif /* NEW_GC */ - - if (set_total_gc_usage) - { - total_gc_usage = tgu_val; - total_gc_usage_set = 1; - } - - return pl; -} - -DEFUN ("object-memory-usage-stats", Fobject_memory_usage_stats, 0, 0, 0, /* -Return statistics about memory usage of Lisp objects. -*/ - ()) -{ - return object_memory_usage_stats (0); -} - -#endif /* ALLOC_TYPE_STATS */ - -#ifdef MEMORY_USAGE_STATS - -/* Compute the number of extra memory-usage statistics associated with an - object. We can't compute this at the time INIT_LISP_OBJECT() is called - because the value of the `memusage_stats_list' property is generally - set afterwards. So we compute the values for all types of objects - after all objects have been initialized. */ - -static void -compute_memusage_stats_length (void) -{ - int i; - - for (i = 0; i < countof (lrecord_implementations_table); i++) - { - int len = 0; - int nonlisp_len = 0; - int seen_break = 0; - - struct lrecord_implementation *imp = lrecord_implementations_table[i]; - - if (!imp) - continue; - /* For some of the early objects, Qnil was not yet initialized at - the time of object initialization, so it came up as Qnull_pointer. - Fix that now. */ - if (EQ (imp->memusage_stats_list, Qnull_pointer)) - imp->memusage_stats_list = Qnil; - { - LIST_LOOP_2 (item, imp->memusage_stats_list) - { - if (!NILP (item) && !EQ (item, Qt)) - { - len++; - if (!seen_break) - nonlisp_len++; - } - else - seen_break++; - } - } - - imp->num_extra_memusage_stats = len; - imp->num_extra_nonlisp_memusage_stats = nonlisp_len; - } -} - -DEFUN ("object-memory-usage", Fobject_memory_usage, 1, 1, 0, /* -Return stats about the memory usage of OBJECT. -The values returned are in the form of an alist of usage types and byte -counts. The byte counts attempt to encompass all the memory used -by the object (separate from the memory logically associated with any -other object), including internal structures and any malloc() -overhead associated with them. In practice, the byte counts are -underestimated because certain memory usage is very hard to determine -\(e.g. the amount of memory used inside the Xt library or inside the -X server). - -Multiple slices of the total memory usage may be returned, separated -by a nil. Each slice represents a particular view of the memory, a -particular way of partitioning it into groups. Within a slice, there -is no overlap between the groups of memory, and each slice collectively -represents all the memory concerned. The rightmost slice typically -represents the total memory used plus malloc and dynarr overhead. - -Slices describing other Lisp objects logically associated with the -object may be included, separated from other slices by `t' and from -each other by nil if there is more than one. - -#### We have to figure out how to handle the memory used by the object -itself vs. the memory used by substructures. Probably the memory_usage -method should return info only about substructures and related Lisp -objects, since the caller can always find and all info about the object -itself. -*/ - (object)) -{ - struct generic_usage_stats gustats; - struct usage_stats object_stats; - int i; - Lisp_Object val = Qnil; - Lisp_Object stats_list = OBJECT_PROPERTY (object, memusage_stats_list); - - xzero (object_stats); - lisp_object_storage_size (object, &object_stats); - - val = acons (Qobject_actually_requested, - make_int (object_stats.was_requested), val); - val = acons (Qobject_malloc_overhead, - make_int (object_stats.malloc_overhead), val); - assert (!object_stats.dynarr_overhead); - assert (!object_stats.gap_overhead); - - if (!NILP (stats_list)) - { - xzero (gustats); - MAYBE_OBJECT_METH (object, memory_usage, (object, &gustats)); - - val = Fcons (Qt, val); - val = acons (Qother_memory_actually_requested, - make_int (gustats.u.was_requested), val); - val = acons (Qother_memory_malloc_overhead, - make_int (gustats.u.malloc_overhead), val); - if (gustats.u.dynarr_overhead) - val = acons (Qother_memory_dynarr_overhead, - make_int (gustats.u.dynarr_overhead), val); - if (gustats.u.gap_overhead) - val = acons (Qother_memory_gap_overhead, - make_int (gustats.u.gap_overhead), val); - val = Fcons (Qnil, val); - - i = 0; - { - LIST_LOOP_2 (item, stats_list) - { - if (NILP (item) || EQ (item, Qt)) - val = Fcons (item, val); - else - { - val = acons (item, make_int (gustats.othervals[i]), val); - i++; - } - } - } - } - - return Fnreverse (val); -} - -#endif /* MEMORY_USAGE_STATS */ + +/************************************************************************/ +/* Lisp interface onto garbage collection */ +/************************************************************************/ /* Debugging aids. */ @@ -5005,41 +5370,10 @@ call to object_memory_usage_stats() -- if ALLOC_TYPE_STATS is enabled. */ total_gc_usage_set = 0; #ifdef ALLOC_TYPE_STATS - /* The things we do for backwards-compatibility */ -#ifdef NEW_GC - return - list6 - (Fcons (make_int (lrecord_stats[lrecord_type_cons].instances_in_use), - make_int (lrecord_stats[lrecord_type_cons] - .bytes_in_use_including_overhead)), - Fcons (make_int (lrecord_stats[lrecord_type_symbol].instances_in_use), - make_int (lrecord_stats[lrecord_type_symbol] - .bytes_in_use_including_overhead)), - Fcons (make_int (lrecord_stats[lrecord_type_marker].instances_in_use), - make_int (lrecord_stats[lrecord_type_marker] - .bytes_in_use_including_overhead)), - make_int (lrecord_stats[lrecord_type_string] - .bytes_in_use_including_overhead), - make_int (lrecord_stats[lrecord_type_vector] - .bytes_in_use_including_overhead), - object_memory_usage_stats (1)); -#else /* not NEW_GC */ - return - list6 (Fcons (make_int (gc_count_num_cons_in_use), - make_int (gc_count_num_cons_freelist)), - Fcons (make_int (gc_count_num_symbol_in_use), - make_int (gc_count_num_symbol_freelist)), - Fcons (make_int (gc_count_num_marker_in_use), - make_int (gc_count_num_marker_freelist)), - make_int (gc_count_string_total_size), - make_int (lrecord_stats[lrecord_type_vector].bytes_in_use + - lrecord_stats[lrecord_type_vector].bytes_freed + - lrecord_stats[lrecord_type_vector].bytes_on_free_list), - object_memory_usage_stats (1)); -#endif /* not NEW_GC */ -#else /* not ALLOC_TYPE_STATS */ + return garbage_collection_statistics (); +#else return Qnil; -#endif /* ALLOC_TYPE_STATS */ +#endif } DEFUN ("consing-since-gc", Fconsing_since_gc, 0, 0, "", /* @@ -5078,18 +5412,6 @@ return make_int (total_data_usage ()); } -#ifdef ALLOC_TYPE_STATS -DEFUN ("total-object-memory-usage", Ftotal_object_memory_usage, 0, 0, 0, /* -Return total number of bytes used for object storage in XEmacs. -This may be helpful in debugging XEmacs's memory usage. -See also `consing-since-gc' and `object-memory-usage-stats'. -*/ - ()) -{ - return make_int (total_gc_usage + consing_since_gc); -} -#endif /* ALLOC_TYPE_STATS */ - #ifdef USE_VALGRIND DEFUN ("valgrind-leak-check", Fvalgrind_leak_check, 0, 0, "", /* Ask valgrind to perform a memory leak check. @@ -5113,170 +5435,6 @@ } #endif /* USE_VALGRIND */ -void -recompute_funcall_allocation_flag (void) -{ - funcall_allocation_flag = - need_to_garbage_collect || - need_to_check_c_alloca || - need_to_signal_post_gc; -} - -int -object_dead_p (Lisp_Object obj) -{ - return ((BUFFERP (obj) && !BUFFER_LIVE_P (XBUFFER (obj))) || - (FRAMEP (obj) && !FRAME_LIVE_P (XFRAME (obj))) || - (WINDOWP (obj) && !WINDOW_LIVE_P (XWINDOW (obj))) || - (DEVICEP (obj) && !DEVICE_LIVE_P (XDEVICE (obj))) || - (CONSOLEP (obj) && !CONSOLE_LIVE_P (XCONSOLE (obj))) || - (EVENTP (obj) && !EVENT_LIVE_P (XEVENT (obj))) || - (EXTENTP (obj) && !EXTENT_LIVE_P (XEXTENT (obj)))); -} - -#ifdef ALLOC_TYPE_STATS - -/* Attempt to determine the actual amount of space that is used for - the block allocated starting at PTR, supposedly of size "CLAIMED_SIZE". - - It seems that the following holds: - - 1. When using the old allocator (malloc.c): - - -- blocks are always allocated in chunks of powers of two. For - each block, there is an overhead of 8 bytes if rcheck is not - defined, 20 bytes if it is defined. In other words, a - one-byte allocation needs 8 bytes of overhead for a total of - 9 bytes, and needs to have 16 bytes of memory chunked out for - it. - - 2. When using the new allocator (gmalloc.c): - - -- blocks are always allocated in chunks of powers of two up - to 4096 bytes. Larger blocks are allocated in chunks of - an integral multiple of 4096 bytes. The minimum block - size is 2*sizeof (void *), or 16 bytes if SUNOS_LOCALTIME_BUG - is defined. There is no per-block overhead, but there - is an overhead of 3*sizeof (size_t) for each 4096 bytes - allocated. - - 3. When using the system malloc, anything goes, but they are - generally slower and more space-efficient than the GNU - allocators. One possibly reasonable assumption to make - for want of better data is that sizeof (void *), or maybe - 2 * sizeof (void *), is required as overhead and that - blocks are allocated in the minimum required size except - that some minimum block size is imposed (e.g. 16 bytes). */ - -Bytecount -malloced_storage_size (void * UNUSED (ptr), Bytecount claimed_size, - struct usage_stats *stats) -{ - Bytecount orig_claimed_size = claimed_size; - -#ifndef SYSTEM_MALLOC - if (claimed_size < (Bytecount) (2 * sizeof (void *))) - claimed_size = 2 * sizeof (void *); -# ifdef SUNOS_LOCALTIME_BUG - if (claimed_size < 16) - claimed_size = 16; -# endif - if (claimed_size < 4096) - { - /* fxg: rename log->log2 to supress gcc3 shadow warning */ - int log2 = 1; - - /* compute the log base two, more or less, then use it to compute - the block size needed. */ - claimed_size--; - /* It's big, it's heavy, it's wood! */ - while ((claimed_size /= 2) != 0) - ++log2; - claimed_size = 1; - /* It's better than bad, it's good! */ - while (log2 > 0) - { - claimed_size *= 2; - log2--; - } - /* We have to come up with some average about the amount of - blocks used. */ - if ((Bytecount) (rand () & 4095) < claimed_size) - claimed_size += 3 * sizeof (void *); - } - else - { - claimed_size += 4095; - claimed_size &= ~4095; - claimed_size += (claimed_size / 4096) * 3 * sizeof (size_t); - } - -#else - - if (claimed_size < 16) - claimed_size = 16; - claimed_size += 2 * sizeof (void *); - -#endif /* system allocator */ - - if (stats) - { - stats->was_requested += orig_claimed_size; - stats->malloc_overhead += claimed_size - orig_claimed_size; - } - return claimed_size; -} - -#ifndef NEW_GC -static Bytecount -fixed_type_block_overhead (Bytecount size, Bytecount per_block) -{ - Bytecount overhead = 0; - Bytecount storage_size = malloced_storage_size (0, per_block, 0); - while (size >= per_block) - { - size -= per_block; - overhead += storage_size - per_block; - } - if (rand () % per_block < size) - overhead += storage_size - per_block; - return overhead; -} -#endif /* not NEW_GC */ - -Bytecount -lisp_object_storage_size (Lisp_Object obj, struct usage_stats *ustats) -{ -#ifndef NEW_GC - const struct lrecord_implementation *imp = - XRECORD_LHEADER_IMPLEMENTATION (obj); -#endif /* not NEW_GC */ - Bytecount size = lisp_object_size (obj); - -#ifdef NEW_GC - return mc_alloced_storage_size (size, ustats); -#else - if (imp->frob_block_p) - { - Bytecount overhead = - /* #### Always using cons_block is incorrect but close; only - string_chars_block is significantly different in size, and - it won't ever be seen in this function */ - fixed_type_block_overhead (size, sizeof (struct cons_block)); - if (ustats) - { - ustats->was_requested += size; - ustats->malloc_overhead += overhead; - } - return size + overhead; - } - else - return malloced_storage_size (XPNTR (obj), size, ustats); -#endif -} - -#endif /* ALLOC_TYPE_STATS */ - /************************************************************************/ /* Initialization */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/array.c Mon Mar 29 00:11:03 2010 -0500 @@ -0,0 +1,1009 @@ +/* Support for dynarrs and other types of dynamic arrays. + Copyright (c) 1994, 1995 Free Software Foundation, Inc. + Copyright (c) 1993, 1995 Sun Microsystems, Inc. + Copyright (c) 1995, 1996, 2000, 2002, 2003, 2004, 2005, 2010 Ben Wing. + +This file is part of XEmacs. + +XEmacs is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +XEmacs 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 General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with XEmacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Synched up with: Not in FSF. */ + +/* Written by Ben Wing, December 1993. */ + +#include <config.h> +#include "lisp.h" + +#include "insdel.h" + + +/*****************************************************************************/ +/* "dynarr" a.k.a. dynamic array */ +/*****************************************************************************/ + +/* +A "dynamic array" or "dynarr" is a contiguous array of fixed-size elements +where there is no upper limit (except available memory) on the number of +elements in the array. Because the elements are maintained contiguously, +space is used efficiently (no per-element pointers necessary) and random +access to a particular element is in constant time. At any one point, the +block of memory that holds the array has an upper limit; if this limit is +exceeded, the memory is realloc()ed into a new array that is twice as big. +Assuming that the time to grow the array is on the order of the new size of +the array block, this scheme has a provably constant amortized time +\(i.e. average time over all additions). + +When you add elements or retrieve elements, pointers are used. Note that +the element itself (of whatever size it is), and not the pointer to it, +is stored in the array; thus you do not have to allocate any heap memory +on your own. Also, returned pointers are only guaranteed to be valid +until the next operation that changes the length of the array. + +This is a container object. Declare a dynamic array of a specific type +as follows: + + typedef struct + { + Dynarr_declare (mytype); + } mytype_dynarr; + +Use the following functions/macros: + + + ************* Dynarr creation ************* + + void *Dynarr_new(type) + [MACRO] Create a new dynamic-array object, with each element of the + specified type. The return value is cast to (type##_dynarr). + This requires following the convention that types are declared in + such a way that this type concatenation works. In particular, TYPE + must be a symbol, not an arbitrary C type. To make dynarrs of + complex types, a typedef must be declared, e.g. + + typedef unsigned char *unsigned_char_ptr; + + and then you can say + + unsigned_char_ptr_dynarr *dyn = Dynarr_new (unsigned_char_ptr); + + void *Dynarr_new2(dynarr_type, type) + [MACRO] Create a new dynamic-array object, with each element of the + specified type. The array itself is of type DYNARR_TYPE. This makes + it possible to create dynarrs over complex types without the need + to create typedefs, as described above. Use is as follows: + + ucharptr_dynarr *dyn = Dynarr_new2 (ucharptr_dynarr *, unsigned char *); + + Dynarr_free(d) + Destroy a dynamic array and the memory allocated to it. + + ************* Dynarr access ************* + + type Dynarr_at(d, i) + [MACRO] Return the element at the specified index. The index must be + between 0 and Dynarr_largest(d), inclusive. With error-checking + enabled, bounds checking on the index is in the form of asserts() -- + an out-of-bounds index causes an abort. The element itself is + returned, not a pointer to it. + + type *Dynarr_atp(d, i) + [MACRO] Return a pointer to the element at the specified index. + Restrictions and bounds checking on the index is as for Dynarr_at. + The pointer may not be valid after an element is added to or + (conceivably) removed from the array, because this may trigger a + realloc() performed on the underlying dynarr storage, which may + involve moving the entire underlying storage to a new location in + memory. + + type *Dynarr_begin(d) + [MACRO] Return a pointer to the first element in the dynarr. See + Dynarr_atp() for warnings about when the pointer might become invalid. + + type *Dynarr_lastp(d) + [MACRO] Return a pointer to the last element in the dynarr. See + Dynarr_atp() for warnings about when the pointer might become invalid. + + type *Dynarr_past_lastp(d) + [MACRO] Return a pointer to the beginning of the element just past the + last one. WARNING: This may not point to valid memory; however, the + byte directly before will be pointer will be valid memory. This macro + might be useful for various reasons, e.g. as a stopping point in a loop + (although Dynarr_lastp() could be used just as well) or as a place to + start writing elements if Dynarr_length() < Dynarr_largest(). + + ************* Dynarr length/size retrieval and setting ************* + + int Dynarr_length(d) + [MACRO] Return the number of elements currently in a dynamic array. + + int Dynarr_largest(d) + [MACRO] Return the maximum value that Dynarr_length(d) would + ever have returned. This is used esp. in the redisplay code, + which reuses dynarrs for performance reasons. + + int Dynarr_max(d) + [MACRO] Return the maximum number of elements that can fit in the + dynarr before it needs to be resized. + + Note that Dynarr_length(d) <= Dynarr_largest(d) <= Dynarr_max(d). + + Bytecount Dynarr_sizeof(d) + [MACRO] Return the total size of the elements currently in dynarr + D. This + + Dynarr_set_lengthr(d, len) + [MACRO] Set the length of D to LEN, which must be between 0 and + Dynarr_largest(d), inclusive. With error-checking enabled, an + assertion failure will result from trying to set the length + to less than zero or greater than Dynarr_largest(d). The + restriction to Dynarr_largest() is to ensure that + + Dynarr_set_length(d, len) + [MACRO] Set the length of D to LEN, resizing the dynarr as + necessary to make sure enough space is available. there are no + restrictions on LEN other than available memory and that it must + be at least 0. Note that + + Dynarr_set_length_and_zero(d, len) + [MACRO] Like Dynarr_set_length(d, len) but also, if increasing + the length, zero out the memory between the old and new lengths, + i.e. starting just past the previous last element and up through + the new last element. + + Dynarr_incrementr(d) + [MACRO] Increments the length of D by 1. Equivalent to + Dynarr_set_lengthr(d, Dynarr_length(d) + 1). + + Dynarr_increment(d) + [MACRO] Increments the length of D by 1. Equivalent to + Dynarr_set_length(d, Dynarr_length(d) + 1). + + Dynarr_reset(d) + [MACRO] Reset the length of a dynamic array to 0. + + Dynarr_resize(d, maxval) + Resize the internal dynarr storage to so that it can hold at least + MAXVAL elements. Resizing is done using a geometric series + (repeatedly multiply the old maximum by a constant, normally 1.5, + till a large enough size is reached), so this will be efficient + even if resizing larger by one element at a time. This is mostly + an internal function. + + + + ************* Adding/deleting elements to/from a dynarr ************* + + Dynarr_add(d, el) + [MACRO] Add an element to the end of a dynamic array. EL is a pointer + to the element; the element itself is stored in the array, however. + No function call is performed unless the array needs to be resized. + + Dynarr_add_many(d, base, len) + [MACRO] Add LEN elements to the end of the dynamic array. The elements + should be contiguous in memory, starting at BASE. If BASE if NULL, + just make space for the elements; don't actually add them. + + Dynarr_prepend_many(d, base, len) + [MACRO] Prepend LEN elements to the beginning of the dynamic array. + The elements should be contiguous in memory, starting at BASE. + If BASE if NULL, just make space for the elements; don't actually + add them. + + Dynarr_insert_many(d, base, len, pos) + Insert LEN elements to the dynamic array starting at position + POS. The elements should be contiguous in memory, starting at BASE. + If BASE if NULL, just make space for the elements; don't actually + add them. + + type Dynarr_pop(d) + [MACRO] Pop the last element off the dynarr and return it. + + Dynarr_delete(d, i) + [MACRO] Delete an element from the dynamic array at position I. + + Dynarr_delete_many(d, pos, len) + Delete LEN elements from the dynamic array starting at position + POS. + + Dynarr_zero_many(d, pos, len) + Zero out LEN elements in the dynarr D starting at position POS. + + Dynarr_delete_by_pointer(d, p) + [MACRO] Delete an element from the dynamic array at pointer P, + which must point within the block of memory that stores the data. + P should be obtained using Dynarr_atp(). + + ************* Dynarr locking ************* + + Dynarr_lock(d) + Lock the dynarr against further locking or writing. With error-checking + enabled, any attempts to write into a locked dynarr or re-lock an + already locked one will cause an assertion failure and abort. + + Dynarr_unlock(d) + Unlock a locked dynarr, allowing writing into it. + + ************* Dynarr global variables ************* + + Dynarr_min_size + Minimum allowable size for a dynamic array when it is resized. + +*/ + +static const struct memory_description const_Ascbyte_ptr_description_1[] = { + { XD_ASCII_STRING, 0 }, + { XD_END } +}; + +const struct sized_memory_description const_Ascbyte_ptr_description = { + sizeof (const Ascbyte *), + const_Ascbyte_ptr_description_1 +}; + +static const struct memory_description const_Ascbyte_ptr_dynarr_description_1[] = { + XD_DYNARR_DESC (const_Ascbyte_ptr_dynarr, &const_Ascbyte_ptr_description), + { XD_END } +}; + +const struct sized_memory_description const_Ascbyte_ptr_dynarr_description = { + sizeof (const_Ascbyte_ptr_dynarr), + const_Ascbyte_ptr_dynarr_description_1 +}; + + +static Elemcount Dynarr_min_size = 8; + +static void +Dynarr_realloc (Dynarr *dy, Elemcount new_size) +{ + if (DUMPEDP (dy->base)) + { + void *new_base = malloc (new_size * Dynarr_elsize (dy)); + memcpy (new_base, dy->base, + (Dynarr_max (dy) < new_size ? Dynarr_max (dy) : new_size) * + Dynarr_elsize (dy)); + dy->base = new_base; + } + else + dy->base = xrealloc (dy->base, new_size * Dynarr_elsize (dy)); +} + +void * +Dynarr_newf (Bytecount elsize) +{ + Dynarr *d = xnew_and_zero (Dynarr); + d->elsize_ = elsize; + + return d; +} + +#ifdef NEW_GC +DEFINE_DUMPABLE_INTERNAL_LISP_OBJECT ("dynarr", dynarr, + 0, 0, + Dynarr); + +static void +Dynarr_lisp_realloc (Dynarr *dy, Elemcount new_size) +{ + void *new_base = + XPNTR (alloc_sized_lrecord_array (Dynarr_elsize (dy), new_size, + dy->lisp_imp)); + if (dy->base) + memcpy (new_base, dy->base, + (Dynarr_max (dy) < new_size ? Dynarr_max (dy) : new_size) * + Dynarr_elsize (dy)); + dy->base = new_base; +} + +void * +Dynarr_lisp_newf (Bytecount elsize, + const struct lrecord_implementation *dynarr_imp, + const struct lrecord_implementation *imp) +{ + Dynarr *d = (Dynarr *) XPNTR (alloc_sized_lrecord (sizeof (Dynarr), + dynarr_imp)); + d->elsize_ = elsize; + d->lisp_imp = imp; + + return d; +} +#endif /* not NEW_GC */ + +void +Dynarr_resize (void *d, Elemcount size) +{ + Elemcount newsize; + double multiplier; + Dynarr *dy = (Dynarr *) Dynarr_verify (d); + + if (Dynarr_max (dy) <= 8) + multiplier = 2; + else + multiplier = 1.5; + + for (newsize = Dynarr_max (dy); newsize < size;) + newsize = max (Dynarr_min_size, (Elemcount) (multiplier * newsize)); + + /* Don't do anything if the array is already big enough. */ + if (newsize > Dynarr_max (dy)) + { +#ifdef NEW_GC + if (dy->lisp_imp) + Dynarr_lisp_realloc (dy, newsize); + else + Dynarr_realloc (dy, newsize); +#else /* not NEW_GC */ + Dynarr_realloc (dy, newsize); +#endif /* not NEW_GC */ + dy->max_ = newsize; + } +} + +/* Add a number of contiguous elements to the array starting at POS. */ + +void +Dynarr_insert_many (void *d, const void *base, Elemcount len, Elemcount pos) +{ + Dynarr *dy = Dynarr_verify_mod (d); + Elemcount old_len = Dynarr_length (dy); + + /* #### This could conceivably be wrong, if code wants to access stuff + between len and largest. */ + dynarr_checking_assert (pos >= 0 && pos <= old_len); + dynarr_checking_assert (len >= 0); + Dynarr_increase_length (dy, old_len + len); + + if (pos != old_len) + { + memmove ((Rawbyte *) dy->base + (pos + len)*Dynarr_elsize (dy), + (Rawbyte *) dy->base + pos*Dynarr_elsize (dy), + (old_len - pos)*Dynarr_elsize (dy)); + } + /* Some functions call us with a value of 0 to mean "reserve space but + don't write into it" */ + if (base) + memcpy ((Rawbyte *) dy->base + pos*Dynarr_elsize (dy), base, + len*Dynarr_elsize (dy)); +} + +void +Dynarr_delete_many (void *d, Elemcount pos, Elemcount len) +{ + Dynarr *dy = Dynarr_verify_mod (d); + + dynarr_checking_assert (pos >= 0 && len >= 0 && + pos + len <= Dynarr_length (dy)); + + memmove ((Rawbyte *) dy->base + pos*Dynarr_elsize (dy), + (Rawbyte *) dy->base + (pos + len)*Dynarr_elsize (dy), + (Dynarr_length (dy) - pos - len)*Dynarr_elsize (dy)); + + Dynarr_set_length_1 (dy, Dynarr_length (dy) - len); +} + +void +Dynarr_free (void *d) +{ + Dynarr *dy = (Dynarr *) d; + +#ifdef NEW_GC + if (dy->base && !DUMPEDP (dy->base)) + { + if (!dy->lisp_imp) + { + xfree (dy->base); + dy->base = 0; + } + } + if (!DUMPEDP (dy)) + { + if (!dy->lisp_imp) + xfree (dy); + } +#else /* not NEW_GC */ + if (dy->base && !DUMPEDP (dy->base)) + { + xfree (dy->base); + dy->base = 0; + } + if(!DUMPEDP (dy)) + xfree (dy); +#endif /* not NEW_GC */ +} + +#ifdef MEMORY_USAGE_STATS + +/* Return memory usage for dynarr D. The returned value is the total + amount of bytes actually being used for the dynarr, including all + overhead. The extra amount of space in the dynarr that is + allocated beyond what was requested is returned in DYNARR_OVERHEAD + in STATS. The extra amount of space that malloc() allocates beyond + what was requested of it is returned in MALLOC_OVERHEAD in STATS. + See the comment above the definition of this structure. */ + +Bytecount +Dynarr_memory_usage (void *d, struct usage_stats *stats) +{ + Bytecount total = 0; + Dynarr *dy = (Dynarr *) d; + + /* We have to be a bit tricky here because not all of the + memory that malloc() will claim as "requested" was actually + requested. */ + + if (dy->base) + { + Bytecount malloc_used = + malloced_storage_size (dy->base, Dynarr_elsize (dy) * Dynarr_max (dy), + 0); + /* #### This may or may not be correct. Some dynarrs would + prefer that we use dy->len instead of dy->largest here. */ + Bytecount was_requested = Dynarr_elsize (dy) * Dynarr_largest (dy); + Bytecount dynarr_overhead = + Dynarr_elsize (dy) * (Dynarr_max (dy) - Dynarr_largest (dy)); + + total += malloc_used; + stats->was_requested += was_requested; + stats->dynarr_overhead += dynarr_overhead; + /* And the remainder must be malloc overhead. */ + stats->malloc_overhead += + malloc_used - was_requested - dynarr_overhead; + } + + total += malloced_storage_size (d, sizeof (*dy), stats); + + return total; +} + +#endif /* MEMORY_USAGE_STATS */ + + +/*****************************************************************************/ +/* stack-like allocation */ +/*****************************************************************************/ + +/* Version of malloc() that will be extremely efficient when allocation + nearly always occurs in LIFO (stack) order. + + #### Perhaps shouldn't be in this file, but where else? */ + +typedef struct +{ + Dynarr_declare (char_dynarr *); +} char_dynarr_dynarr; + +char_dynarr_dynarr *stack_like_free_list; +char_dynarr_dynarr *stack_like_in_use_list; + +void * +stack_like_malloc (Bytecount size) +{ + char_dynarr *this_one; + if (!stack_like_free_list) + { + stack_like_free_list = Dynarr_new2 (char_dynarr_dynarr, + char_dynarr *); + stack_like_in_use_list = Dynarr_new2 (char_dynarr_dynarr, + char_dynarr *); + } + + if (Dynarr_length (stack_like_free_list) > 0) + this_one = Dynarr_pop (stack_like_free_list); + else + this_one = Dynarr_new (char); + Dynarr_add (stack_like_in_use_list, this_one); + Dynarr_reset (this_one); + Dynarr_add_many (this_one, 0, size); + return Dynarr_begin (this_one); +} + +void +stack_like_free (void *val) +{ + Elemcount len = Dynarr_length (stack_like_in_use_list); + assert (len > 0); + /* The vast majority of times, we will be called in a last-in first-out + order, and the item at the end of the list will be the one we're + looking for, so just check for this first and avoid any function + calls. */ + if (Dynarr_begin (Dynarr_at (stack_like_in_use_list, len - 1)) == val) + { + char_dynarr *this_one = Dynarr_pop (stack_like_in_use_list); + Dynarr_add (stack_like_free_list, this_one); + } + else + { + /* Find the item and delete it. */ + int i; + assert (len >= 2); + for (i = len - 2; i >= 0; i--) + if (Dynarr_begin (Dynarr_at (stack_like_in_use_list, i)) == + val) + { + char_dynarr *this_one = Dynarr_at (stack_like_in_use_list, i); + Dynarr_add (stack_like_free_list, this_one); + Dynarr_delete (stack_like_in_use_list, i); + return; + } + + ABORT (); + } +} + + +/*****************************************************************************/ +/* Generalized gap array */ +/*****************************************************************************/ + +/* A "gap array" is an array that has a "gap" somewhere in the middle of it, + so that insertions and deletions near the gap -- or in general, highly + localized insertions and deletions -- are very fast. Inserting or + deleting works by first moving the gap to the insertion or deletion + position and then shortening or lengthening the gap as necessary. The + idea comes from the gap used in storing text in a buffer. + + The gap array interface differs in a number of ways from dynarrs (#### + and should be changed so that it works the same as dynarrs): + + (1) There aren't separate type-specific gap array types. As a result, + operations like gap_array_at() require that the type be specified as + one of the arguments. It is often more convenient to use a macro + wrapper around this operation. + + (2) The gap array type is itself a stretchy array rather than using a + separate block of memory to store the array. This means that certain + operations (especially insertions) may relocate the the gap array, + and as a result return a pointer to the (possibly) moved gap array, + which must be stored back into the location where the gap array + pointer resides. This also means that the caller must worry about + cloning the gap array in the case where it has been dumped, or you + will get an ABORT() inside of xrealloc(). + + (3) Fewer operations are available than for dynarrs, and may have + different names and/or different calling conventions. + + (4) The mechanism for creating "Lisp-object gap arrays" isn't completely + developed. Currently it's only possible to create a gap-array Lisp + object that wraps Lisp_Object pointers (not Lisp object structures + directly), and only under NEW_GC. + + (5) Gap arrays have a concept of a "gap array marker" that properly + tracks insertions and deletions; no such thing exists in dynarrs. + It exists in gap arrays because it's necessary for their use in + implementing extent lists. + */ + +extern const struct sized_memory_description gap_array_marker_description; + +static const struct memory_description gap_array_marker_description_1[] = { +#ifdef NEW_GC + { XD_LISP_OBJECT, offsetof (Gap_Array_Marker, next) }, +#else /* not NEW_GC */ + { XD_BLOCK_PTR, offsetof (Gap_Array_Marker, next), 1, + { &gap_array_marker_description } }, +#endif /* not NEW_GC */ + { XD_END } +}; + +#ifdef NEW_GC +DEFINE_NODUMP_INTERNAL_LISP_OBJECT ("gap-array-marker", gap_array_marker, + 0, gap_array_marker_description_1, + struct gap_array_marker); +#else /* not NEW_GC */ +const struct sized_memory_description gap_array_marker_description = { + sizeof (Gap_Array_Marker), + gap_array_marker_description_1 +}; +#endif /* not NEW_GC */ + +static const struct memory_description lispobj_gap_array_description_1[] = { + XD_GAP_ARRAY_DESC (&lisp_object_description), + { XD_END } +}; + +#ifdef NEW_GC + +static Bytecount +size_gap_array (Lisp_Object obj) +{ + Gap_Array *ga = XGAP_ARRAY (obj); + return gap_array_byte_size (ga); +} + +DEFINE_DUMPABLE_SIZABLE_INTERNAL_LISP_OBJECT ("gap-array", gap_array, + 0, + lispobj_gap_array_description_1, + size_gap_array, + struct gap_array); +#else /* not NEW_GC */ +const struct sized_memory_description lispobj_gap_array_description = { + 0, lispobj_gap_array_description_1 +}; +#endif /* (not) NEW_GC */ + +#ifndef NEW_GC +static Gap_Array_Marker *gap_array_marker_freelist; +#endif /* not NEW_GC */ + +/* This generalizes the "array with a gap" model used to store buffer + characters. This is based on the stuff in insdel.c and should + probably be merged with it. This is not extent-specific and should + perhaps be moved into a separate file. */ + +/* ------------------------------- */ +/* internal functions */ +/* ------------------------------- */ + +/* Adjust the gap array markers in the range (FROM, TO]. Parallel to + adjust_markers() in insdel.c. */ + +static void +gap_array_adjust_markers (Gap_Array *ga, Memxpos from, + Memxpos to, Elemcount amount) +{ + Gap_Array_Marker *m; + + for (m = ga->markers; m; m = m->next) + m->pos = do_marker_adjustment (m->pos, from, to, amount); +} + +static void +gap_array_recompute_derived_values (Gap_Array *ga) +{ + ga->offset_past_gap = ga->elsize * (ga->gap + ga->gapsize); + ga->els_past_gap = ga->numels - ga->gap; +} + +/* Move the gap to array position POS. Parallel to move_gap() in + insdel.c but somewhat simplified. */ + +static void +gap_array_move_gap (Gap_Array *ga, Elemcount pos) +{ + Elemcount gap = ga->gap; + Elemcount gapsize = ga->gapsize; + + if (pos < gap) + { + memmove (GAP_ARRAY_MEMEL_ADDR (ga, pos + gapsize), + GAP_ARRAY_MEMEL_ADDR (ga, pos), + (gap - pos)*ga->elsize); + gap_array_adjust_markers (ga, (Memxpos) pos, (Memxpos) gap, + gapsize); + } + else if (pos > gap) + { + memmove (GAP_ARRAY_MEMEL_ADDR (ga, gap), + GAP_ARRAY_MEMEL_ADDR (ga, gap + gapsize), + (pos - gap)*ga->elsize); + gap_array_adjust_markers (ga, (Memxpos) (gap + gapsize), + (Memxpos) (pos + gapsize), - gapsize); + } + ga->gap = pos; + + gap_array_recompute_derived_values (ga); +} + +/* Make the gap INCREMENT characters longer. Parallel to make_gap() in + insdel.c. The gap array may be moved, so assign the return value back + to the array pointer. */ + +static Gap_Array * +gap_array_make_gap (Gap_Array *ga, Elemcount increment) +{ + Elemcount real_gap_loc; + Elemcount old_gap_size; + + /* If we have to get more space, get enough to last a while. We use + a geometric progression that saves on realloc space. */ + increment += 100 + ga->numels / 8; + +#ifdef NEW_GC + if (ga->is_lisp) + ga = (Gap_Array *) mc_realloc (ga, + offsetof (Gap_Array, array) + + (ga->numels + ga->gapsize + increment) * + ga->elsize); + else +#endif /* not NEW_GC */ + ga = (Gap_Array *) xrealloc (ga, + offsetof (Gap_Array, array) + + (ga->numels + ga->gapsize + increment) * + ga->elsize); + if (ga == 0) + memory_full (); + + real_gap_loc = ga->gap; + old_gap_size = ga->gapsize; + + /* Call the newly allocated space a gap at the end of the whole space. */ + ga->gap = ga->numels + ga->gapsize; + ga->gapsize = increment; + + /* Move the new gap down to be consecutive with the end of the old one. + This adjusts the markers properly too. */ + gap_array_move_gap (ga, real_gap_loc + old_gap_size); + + /* Now combine the two into one large gap. */ + ga->gapsize += old_gap_size; + ga->gap = real_gap_loc; + + gap_array_recompute_derived_values (ga); + + return ga; +} + +/* ------------------------------- */ +/* external functions */ +/* ------------------------------- */ + +Bytecount +gap_array_byte_size (Gap_Array *ga) +{ + return offsetof (Gap_Array, array) + (ga->numels + ga->gapsize) * ga->elsize; +} + +/* Insert NUMELS elements (pointed to by ELPTR) into the specified + gap array at POS. The gap array may be moved, so assign the + return value back to the array pointer. */ + +Gap_Array * +gap_array_insert_els (Gap_Array *ga, Elemcount pos, void *elptr, + Elemcount numels) +{ + assert (pos >= 0 && pos <= ga->numels); + if (ga->gapsize < numels) + ga = gap_array_make_gap (ga, numels - ga->gapsize); + if (pos != ga->gap) + gap_array_move_gap (ga, pos); + + memcpy (GAP_ARRAY_MEMEL_ADDR (ga, ga->gap), (char *) elptr, + numels*ga->elsize); + ga->gapsize -= numels; + ga->gap += numels; + ga->numels += numels; + gap_array_recompute_derived_values (ga); + /* This is the equivalent of insert-before-markers. + + #### Should only happen if marker is "moves forward at insert" type. + */ + + gap_array_adjust_markers (ga, pos - 1, pos, numels); + return ga; +} + +/* Delete NUMELS elements from the specified gap array, starting at FROM. */ + +void +gap_array_delete_els (Gap_Array *ga, Elemcount from, Elemcount numdel) +{ + Elemcount to = from + numdel; + Elemcount gapsize = ga->gapsize; + + assert (from >= 0); + assert (numdel >= 0); + assert (to <= ga->numels); + + /* Make sure the gap is somewhere in or next to what we are deleting. */ + if (to < ga->gap) + gap_array_move_gap (ga, to); + if (from > ga->gap) + gap_array_move_gap (ga, from); + + /* Relocate all markers pointing into the new, larger gap + to point at the end of the text before the gap. */ + gap_array_adjust_markers (ga, to + gapsize, to + gapsize, + - numdel - gapsize); + + ga->gapsize += numdel; + ga->numels -= numdel; + ga->gap = from; + gap_array_recompute_derived_values (ga); +} + +Gap_Array_Marker * +gap_array_make_marker (Gap_Array *ga, Elemcount pos) +{ + Gap_Array_Marker *m; + + assert (pos >= 0 && pos <= ga->numels); +#ifdef NEW_GC + m = XGAP_ARRAY_MARKER (ALLOC_NORMAL_LISP_OBJECT (gap_array_marker)); +#else /* not NEW_GC */ + if (gap_array_marker_freelist) + { + m = gap_array_marker_freelist; + gap_array_marker_freelist = gap_array_marker_freelist->next; + } + else + m = xnew (Gap_Array_Marker); +#endif /* not NEW_GC */ + + m->pos = GAP_ARRAY_ARRAY_TO_MEMORY_POS (ga, pos); + m->next = ga->markers; + ga->markers = m; + return m; +} + +void +gap_array_delete_marker (Gap_Array *ga, Gap_Array_Marker *m) +{ + Gap_Array_Marker *p, *prev; + + for (prev = 0, p = ga->markers; p && p != m; prev = p, p = p->next) + ; + assert (p); + if (prev) + prev->next = p->next; + else + ga->markers = p->next; +#ifndef NEW_GC + m->next = gap_array_marker_freelist; + m->pos = 0xDEADBEEF; /* -559038737 base 10 */ + gap_array_marker_freelist = m; +#endif /* not NEW_GC */ +} + +#ifndef NEW_GC +void +gap_array_delete_all_markers (Gap_Array *ga) +{ + Gap_Array_Marker *p, *next; + + for (p = ga->markers; p; p = next) + { + next = p->next; + p->next = gap_array_marker_freelist; + p->pos = 0xDEADBEEF; /* -559038737 as an int */ + gap_array_marker_freelist = p; + } +} +#endif /* not NEW_GC */ + +void +gap_array_move_marker (Gap_Array *ga, Gap_Array_Marker *m, Elemcount pos) +{ + assert (pos >= 0 && pos <= ga->numels); + m->pos = GAP_ARRAY_ARRAY_TO_MEMORY_POS (ga, pos); +} + +Gap_Array * +make_gap_array (Elemcount elsize, int USED_IF_NEW_GC (do_lisp)) +{ + Gap_Array *ga; +#ifdef NEW_GC + /* #### I don't quite understand why it's necessary to make all these + internal objects into Lisp objects under NEW_GC. It's a pain in the + ass to code around this. I'm proceeding on the assumption that it's + not really necessary to do it after all, and so we only make a Lisp- + object gap array when the object being held is a Lisp_Object, i.e. a + pointer to a Lisp object. In the case where instead we hold a `struct + range_table_entry', just blow it off. Otherwise we either need to do + a bunch of painful and/or boring rewriting. --ben */ + if (do_lisp) + { + ga = XGAP_ARRAY (ALLOC_SIZED_LISP_OBJECT (sizeof (Gap_Array), + gap_array)); + ga->is_lisp = 1; + } + else +#endif /* not NEW_GC */ + ga = xnew_and_zero (Gap_Array); + ga->elsize = elsize; + return ga; +} + +Gap_Array * +gap_array_clone (Gap_Array *ga) +{ + Bytecount size = gap_array_byte_size (ga); + Gap_Array *ga2; + Gap_Array_Marker *m; + +#ifdef NEW_GC + if (ga->is_lisp) + { + ga2 = XGAP_ARRAY (ALLOC_SIZED_LISP_OBJECT (size, gap_array)); + copy_lisp_object (wrap_gap_array (ga2), wrap_gap_array (ga)); + } + else +#endif + { + ga2 = (Gap_Array *) xmalloc (size); + memcpy (ga2, ga, size); + } + ga2->markers = NULL; + for (m = ga->markers; m; m = m->next) + gap_array_make_marker (ga2, m->pos); + return ga2; +} + +#ifndef NEW_GC +void +free_gap_array (Gap_Array *ga) +{ + gap_array_delete_all_markers (ga); + xfree (ga); +} +#endif /* not NEW_GC */ + +#ifdef MEMORY_USAGE_STATS + +/* Return memory usage for gap array GA. The returned value is the total + amount of bytes actually being used for the gap array, including all + overhead. The extra amount of space in the gap array that is used + for the gap is counted in GAP_OVERHEAD, not in WAS_REQUESTED. + If NEW_GC, space for gap-array markers is returned through MARKER_ANCILLARY; + otherwise it's added into the gap array usage. */ + +Bytecount +gap_array_memory_usage (Gap_Array *ga, struct usage_stats *stats, + Bytecount *marker_ancillary) +{ + Bytecount total = 0; + + /* We have to be a bit tricky here because not all of the + memory that malloc() will claim as "requested" was actually + requested -- some of it makes up the gap. */ + + Bytecount size = gap_array_byte_size (ga); + Bytecount gap_size = ga->gapsize * ga->elsize; + Bytecount malloc_used = malloced_storage_size (ga, size, 0); + total += malloc_used; + stats->was_requested += size - gap_size; + stats->gap_overhead += gap_size; + stats->malloc_overhead += malloc_used - size; + +#ifdef NEW_GC + { + Bytecount marker_usage = 0; + Gap_Array_Marker *p; + + for (p = ga->markers; p; p = p->next) + marker_usage += lisp_object_memory_usage (wrap_gap_array_marker (p)); + if (marker_ancillary) + *marker_ancillary = marker_usage; + } +#else + { + Gap_Array_Marker *p; + + for (p = ga->markers; p; p = p->next) + total += malloced_storage_size (p, sizeof (p), stats); + if (marker_ancillary) + *marker_ancillary = 0; + } +#endif /* (not) NEW_GC */ + + return total; +} + +#endif /* MEMORY_USAGE_STATS */ + + +/*****************************************************************************/ +/* Initialization */ +/*****************************************************************************/ + +void +syms_of_array (void) +{ +#ifdef NEW_GC + INIT_LISP_OBJECT (gap_array_marker); + INIT_LISP_OBJECT (gap_array); +#endif /* NEW_GC */ +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/array.h Mon Mar 29 00:11:03 2010 -0500 @@ -0,0 +1,769 @@ +/* Header for arrays (dynarrs, gap arrays, etc.). + Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc. + Copyright (C) 1996, 2001, 2002, 2004, 2005, 2009, 2010 Ben Wing. + +This file is part of XEmacs. + +XEmacs is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +XEmacs 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 General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with XEmacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Synched up with: Not in FSF. */ + +/* This file has been Mule-ized, Ben Wing, 10-13-04. */ + +#ifndef INCLUDED_array_h_ +#define INCLUDED_array_h_ + +/************************************************************************/ +/** Definition of dynamic arrays (dynarrs) **/ +/************************************************************************/ + +BEGIN_C_DECLS + +/************* Dynarr declaration *************/ + +#ifdef NEW_GC +#define DECLARE_DYNARR_LISP_IMP() \ + const struct lrecord_implementation *lisp_imp; +#else +#define DECLARE_DYNARR_LISP_IMP() +#endif + +#ifdef ERROR_CHECK_DYNARR +#define DECLARE_DYNARR_LOCKED() \ + int locked; +#else +#define DECLARE_DYNARR_LOCKED() +#endif + +#define Dynarr_declare(type) \ + struct lrecord_header header; \ + type *base; \ + DECLARE_DYNARR_LISP_IMP () \ + DECLARE_DYNARR_LOCKED () \ + int elsize_; \ + int len_; \ + int largest_; \ + int max_ + +typedef struct dynarr +{ + Dynarr_declare (void); +} Dynarr; + +#define XD_DYNARR_DESC(base_type, sub_desc) \ + { XD_BLOCK_PTR, offsetof (base_type, base), \ + XD_INDIRECT(1, 0), {sub_desc} }, \ + { XD_INT, offsetof (base_type, len_) }, \ + { XD_INT_RESET, offsetof (base_type, largest_), XD_INDIRECT(1, 0) }, \ + { XD_INT_RESET, offsetof (base_type, max_), XD_INDIRECT(1, 0) } + +#ifdef NEW_GC +#define XD_LISP_DYNARR_DESC(base_type, sub_desc) \ + { XD_INLINE_LISP_OBJECT_BLOCK_PTR, offsetof (base_type, base), \ + XD_INDIRECT(1, 0), {sub_desc} }, \ + { XD_INT, offsetof (base_type, len_) }, \ + { XD_INT_RESET, offsetof (base_type, largest_), XD_INDIRECT(1, 0) }, \ + { XD_INT_RESET, offsetof (base_type, max_), XD_INDIRECT(1, 0) } +#endif /* NEW_GC */ + +/************* Dynarr verification *************/ + +/* Dynarr locking and verification. + + [I] VERIFICATION + + Verification routines simply return their basic argument, possibly + casted, but in the process perform some verification on it, aborting if + the verification fails. The verification routines take FILE and LINE + parameters, and use them to output the file and line of the caller + when an abort occurs, rather than the file and line of the inline + function, which is less than useful. + + There are three basic types of verification routines: + + (1) Verify the dynarr itself. This verifies the basic invariant + involving the length/size values: + + 0 <= Dynarr_length(d) <= Dynarr_largest(d) <= Dynarr_max(d) + + (2) Verify the dynarr itself prior to modifying it. This performs + the same verification as previously, but also checks that the + dynarr is not locked (see below). + + (3) Verify a dynarr position. Unfortunately we have to have + different verification routines depending on which kind of operation + is being performed: + + (a) For Dynarr_at(), we check that the POS is bounded by Dynarr_largest(), + i.e. 0 <= POS < Dynarr_largest(). + (b) For Dynarr_atp_allow_end(), we also have to allow + POS == Dynarr_largest(). + (c) For Dynarr_atp(), we behave largely like Dynarr_at() but make a + special exception when POS == 0 and Dynarr_largest() == 0 -- see + comment below. + (d) Some other routines contain the POS verification within their code, + and make the check 0 <= POS < Dynarr_length() or + 0 <= POS <= Dynarr_length(). + + #### It is not well worked-out whether and in what circumstances it's + allowed to use a position that is between Dynarr_length() and + Dynarr_largest(). The ideal solution is to never allow this, and require + instead that code first change the length before accessing higher + positions. That would require looking through all the code that accesses + dynarrs and fixing it appropriately (especially redisplay code, and + especially redisplay code in the vicinity of a reference to + Dynarr_largest(), since such code usually checks explicitly to see whether + there is extra stuff between Dynarr_length() and Dynarr_largest().) + + [II] LOCKING + + The idea behind dynarr locking is simple: Locking a dynarr prevents + any modification from occurring, or rather, leads to an abort upon + any attempt to modify a dynarr. + + Dynarr locking was originally added to catch some sporadic and hard-to- + debug crashes in the redisplay code where dynarrs appeared to be getting + corrupted in an unexpected fashion. The solution was to lock the + dynarrs that were getting corrupted (in this case, the display-line + dynarrs) around calls to routines that weren't supposed to be changing + these dynarrs but might somehow be calling code that modified them. + This eventually revealed that there was a reentrancy problem with + redisplay that involved the QUIT mechanism and the processing done in + order to determine whether C-g had been pressed -- this processing + involves retrieving, processing and queueing pending events to see + whether any of them result in a C-g keypress. However, at least under + MS Windows this can result in redisplay being called reentrantly. + For more info:-- + + (Info-goto-node "(internals)Critical Redisplay Sections") + +*/ + +#ifdef ERROR_CHECK_DYNARR +DECLARE_INLINE_HEADER ( +int +Dynarr_verify_pos_at (void *d, Elemcount pos, const Ascbyte *file, int line) +) +{ + Dynarr *dy = (Dynarr *) d; + /* We use `largest', not `len', because the redisplay code often + accesses stuff between len and largest. */ + assert_at_line (pos >= 0 && pos < dy->largest_, file, line); + return pos; +} + +DECLARE_INLINE_HEADER ( +int +Dynarr_verify_pos_atp (void *d, Elemcount pos, const Ascbyte *file, int line) +) +{ + Dynarr *dy = (Dynarr *) d; + /* We use `largest', not `len', because the redisplay code often + accesses stuff between len and largest. */ + /* [[ Code will often do something like ... + + val = make_bit_vector_from_byte_vector (Dynarr_atp (dyn, 0), + Dynarr_length (dyn)); + + which works fine when the Dynarr_length is non-zero, but when zero, + the result of Dynarr_atp() not only points past the end of the + allocated array, but the array may not have ever been allocated and + hence the return value is NULL. But the length of 0 causes the + pointer to never get checked. These can occur throughout the code + so we put in a special check. --ben ]] + + Update: The common idiom `Dynarr_atp (dyn, 0)' has been changed to + `Dynarr_begin (dyn)'. Possibly this special check at POS 0 can be + done only for Dynarr_begin() not for general Dynarr_atp(). --ben */ + if (pos == 0 && dy->len_ == 0) + return pos; + /* #### It's vaguely possible that some code could legitimately want to + retrieve a pointer to the position just past the end of dynarr memory. + This could happen with Dynarr_atp() but not Dynarr_at(). If so, it + will trigger this assert(). In such cases, it should be obvious that + the code wants to do this; rather than relaxing the assert, we should + probably create a new macro Dynarr_atp_allow_end() which is like + Dynarr_atp() but which allows for pointing at invalid addresses -- we + really want to check for cases of accessing just past the end of + memory, which is a likely off-by-one problem to occur and will usually + not trigger a protection fault (instead, you'll just get random + behavior, possibly overwriting other memory, which is bad). --ben */ + assert_at_line (pos >= 0 && pos < dy->largest_, file, line); + return pos; +} + +DECLARE_INLINE_HEADER ( +int +Dynarr_verify_pos_atp_allow_end (void *d, Elemcount pos, const Ascbyte *file, + int line) +) +{ + Dynarr *dy = (Dynarr *) d; + /* We use `largest', not `len', because the redisplay code often + accesses stuff between len and largest. + We also allow referencing the very end, past the end of allocated + legitimately space. See comments in Dynarr_verify_pos_atp.()*/ + assert_at_line (pos >= 0 && pos <= dy->largest_, file, line); + return pos; +} + +#else +#define Dynarr_verify_pos_at(d, pos, file, line) (pos) +#define Dynarr_verify_pos_atp(d, pos, file, line) (pos) +#define Dynarr_verify_pos_atp_allow_end(d, pos, file, line) (pos) +#endif /* ERROR_CHECK_DYNARR */ + +#ifdef ERROR_CHECK_DYNARR +DECLARE_INLINE_HEADER ( +Dynarr * +Dynarr_verify_1 (void *d, const Ascbyte *file, int line) +) +{ + Dynarr *dy = (Dynarr *) d; + assert_at_line (dy->len_ >= 0 && dy->len_ <= dy->largest_ && + dy->largest_ <= dy->max_, file, line); + return dy; +} + +DECLARE_INLINE_HEADER ( +Dynarr * +Dynarr_verify_mod_1 (void *d, const Ascbyte *file, int line) +) +{ + Dynarr *dy = (Dynarr *) d; + assert_at_line (!dy->locked, file, line); + return Dynarr_verify_1 (d, file, line); +} + +#define Dynarr_verify(d) Dynarr_verify_1 (d, __FILE__, __LINE__) +#define Dynarr_verify_mod(d) Dynarr_verify_mod_1 (d, __FILE__, __LINE__) + +DECLARE_INLINE_HEADER ( +void +Dynarr_lock (void *d) +) +{ + Dynarr *dy = Dynarr_verify_mod (d); + dy->locked = 1; +} + +DECLARE_INLINE_HEADER ( +void +Dynarr_unlock (void *d) +) +{ + Dynarr *dy = Dynarr_verify (d); + assert (dy->locked); + dy->locked = 0; +} + +#else /* not ERROR_CHECK_DYNARR */ + +#define Dynarr_verify(d) ((Dynarr *) d) +#define Dynarr_verify_mod(d) ((Dynarr *) d) +#define Dynarr_lock(d) DO_NOTHING +#define Dynarr_unlock(d) DO_NOTHING + +#endif /* ERROR_CHECK_DYNARR */ + +/************* Dynarr creation *************/ + +MODULE_API void *Dynarr_newf (Bytecount elsize); +MODULE_API void Dynarr_free (void *d); + +#ifdef NEW_GC +MODULE_API void *Dynarr_lisp_newf (Bytecount elsize, + const struct lrecord_implementation + *dynarr_imp, + const struct lrecord_implementation *imp); + +#define Dynarr_lisp_new(type, dynarr_imp, imp) \ + ((type##_dynarr *) Dynarr_lisp_newf (sizeof (type), dynarr_imp, imp)) +#define Dynarr_lisp_new2(dynarr_type, type, dynarr_imp, imp) \ + ((dynarr_type *) Dynarr_lisp_newf (sizeof (type)), dynarr_imp, imp) +#endif /* NEW_GC */ +#define Dynarr_new(type) ((type##_dynarr *) Dynarr_newf (sizeof (type))) +#define Dynarr_new2(dynarr_type, type) \ + ((dynarr_type *) Dynarr_newf (sizeof (type))) + +/************* Dynarr access *************/ + +#ifdef ERROR_CHECK_DYNARR +#define Dynarr_at(d, pos) \ + ((d)->base[Dynarr_verify_pos_at (d, pos, __FILE__, __LINE__)]) +#define Dynarr_atp_allow_end(d, pos) \ + (&((d)->base[Dynarr_verify_pos_atp_allow_end (d, pos, __FILE__, __LINE__)])) +#define Dynarr_atp(d, pos) \ + (&((d)->base[Dynarr_verify_pos_atp (d, pos, __FILE__, __LINE__)])) +#else +#define Dynarr_at(d, pos) ((d)->base[pos]) +#define Dynarr_atp(d, pos) (&Dynarr_at (d, pos)) +#define Dynarr_atp_allow_end(d, pos) Dynarr_atp (d, pos) +#endif + +/* Old #define Dynarr_atp(d, pos) (&Dynarr_at (d, pos)) */ +#define Dynarr_begin(d) Dynarr_atp (d, 0) +#define Dynarr_lastp(d) Dynarr_atp (d, Dynarr_length (d) - 1) +#define Dynarr_past_lastp(d) Dynarr_atp_allow_end (d, Dynarr_length (d)) + + +/************* Dynarr length/size retrieval and setting *************/ + +/* Retrieve the length of a dynarr. The `+ 0' is to ensure that this cannot + be used as an lvalue. */ +#define Dynarr_length(d) (Dynarr_verify (d)->len_ + 0) +/* Retrieve the largest ever length seen of a dynarr. The `+ 0' is to + ensure that this cannot be used as an lvalue. */ +#define Dynarr_largest(d) (Dynarr_verify (d)->largest_ + 0) +/* Retrieve the number of elements that fit in the currently allocated + space. The `+ 0' is to ensure that this cannot be used as an lvalue. */ +#define Dynarr_max(d) (Dynarr_verify (d)->max_ + 0) +/* Return the size in bytes of an element in a dynarr. */ +#define Dynarr_elsize(d) (Dynarr_verify (d)->elsize_ + 0) +/* Retrieve the advertised memory usage of a dynarr, i.e. the number of + bytes occupied by the elements in the dynarr, not counting any overhead. */ +#define Dynarr_sizeof(d) (Dynarr_length (d) * Dynarr_elsize (d)) + +/* Actually set the length of a dynarr. This is a low-level routine that + should not be directly used; use Dynarr_set_length() or + Dynarr_set_lengthr() instead. */ +DECLARE_INLINE_HEADER ( +void +Dynarr_set_length_1 (void *d, Elemcount len) +) +{ + Dynarr *dy = Dynarr_verify_mod (d); + dynarr_checking_assert (len >= 0 && len <= Dynarr_max (dy)); + /* Use the raw field references here otherwise we get a crash because + we've set the length but not yet fixed up the largest value. */ + dy->len_ = len; + if (dy->len_ > dy->largest_) + dy->largest_ = dy->len_; + (void) Dynarr_verify_mod (d); +} + +/* "Restricted set-length": Set the length of dynarr D to LEN, + which must be in the range [0, Dynarr_largest(d)]. */ + +DECLARE_INLINE_HEADER ( +void +Dynarr_set_lengthr (void *d, Elemcount len) +) +{ + Dynarr *dy = Dynarr_verify_mod (d); + dynarr_checking_assert (len >= 0 && len <= Dynarr_largest (dy)); + Dynarr_set_length_1 (dy, len); +} + +/* "Restricted increment": Increment the length of dynarr D by 1; the resulting + length must be in the range [0, Dynarr_largest(d)]. */ + +#define Dynarr_incrementr(d) Dynarr_set_lengthr (d, Dynarr_length (d) + 1) + + +MODULE_API void Dynarr_resize (void *d, Elemcount size); + +DECLARE_INLINE_HEADER ( +void +Dynarr_resize_to_fit (void *d, Elemcount size) +) +{ + Dynarr *dy = Dynarr_verify_mod (d); + if (size > Dynarr_max (dy)) + Dynarr_resize (dy, size); +} + +#define Dynarr_resize_to_add(d, numels) \ + Dynarr_resize_to_fit (d, Dynarr_length (d) + numels) + +/* This is an optimization. This is like Dynarr_set_length() but the length + is guaranteed to be at least as big as the existing length. */ + +DECLARE_INLINE_HEADER ( +void +Dynarr_increase_length (void *d, Elemcount len) +) +{ + Dynarr *dy = Dynarr_verify_mod (d); + dynarr_checking_assert (len >= Dynarr_length (dy)); + Dynarr_resize_to_fit (dy, len); + Dynarr_set_length_1 (dy, len); +} + +/* Set the length of dynarr D to LEN. If the length increases, resize as + necessary to fit. (NOTE: This will leave uninitialized memory. If you + aren't planning on immediately overwriting the memory, use + Dynarr_set_length_and_zero() to zero out all the memory that would + otherwise be uninitialized.) */ + +DECLARE_INLINE_HEADER ( +void +Dynarr_set_length (void *d, Elemcount len) +) +{ + Dynarr *dy = Dynarr_verify_mod (d); + Elemcount old_len = Dynarr_length (dy); + if (old_len >= len) + Dynarr_set_lengthr (dy, len); + else + Dynarr_increase_length (d, len); +} + +#define Dynarr_increment(d) Dynarr_increase_length (d, Dynarr_length (d) + 1) + +/* Zero LEN contiguous elements starting at POS. */ + +DECLARE_INLINE_HEADER ( +void +Dynarr_zero_many (void *d, Elemcount pos, Elemcount len) +) +{ + Dynarr *dy = Dynarr_verify_mod (d); + memset ((Rawbyte *) dy->base + pos*Dynarr_elsize (dy), 0, + len*Dynarr_elsize (dy)); +} + +/* This is an optimization. This is like Dynarr_set_length_and_zero() but + the length is guaranteed to be at least as big as the existing + length. */ + +DECLARE_INLINE_HEADER ( +void +Dynarr_increase_length_and_zero (void *d, Elemcount len) +) +{ + Dynarr *dy = Dynarr_verify_mod (d); + Elemcount old_len = Dynarr_length (dy); + Dynarr_increase_length (dy, len); + Dynarr_zero_many (dy, old_len, len - old_len); +} + +/* Set the length of dynarr D to LEN. If the length increases, resize as + necessary to fit and zero out all the elements between the old and new + lengths. */ + +DECLARE_INLINE_HEADER ( +void +Dynarr_set_length_and_zero (void *d, Elemcount len) +) +{ + Dynarr *dy = Dynarr_verify_mod (d); + Elemcount old_len = Dynarr_length (dy); + if (old_len >= len) + Dynarr_set_lengthr (dy, len); + else + Dynarr_increase_length_and_zero (d, len); +} + +/* Reset the dynarr's length to 0. */ +#define Dynarr_reset(d) Dynarr_set_lengthr (d, 0) + +#ifdef MEMORY_USAGE_STATS +struct usage_stats; +Bytecount Dynarr_memory_usage (void *d, struct usage_stats *stats); +#endif + +/************* Adding/deleting elements to/from a dynarr *************/ + +/* Set the Lisp implementation of the element at POS in dynarr D. Only + does this if the dynarr holds Lisp objects of a particular type (the + objects themselves, not pointers to them), and only under NEW_GC. */ + +#ifdef NEW_GC +#define DYNARR_SET_LISP_IMP(d, pos) \ +do { \ + if ((d)->lisp_imp) \ + set_lheader_implementation \ + ((struct lrecord_header *)&(((d)->base)[pos]), (d)->lisp_imp); \ +} while (0) +#else +#define DYNARR_SET_LISP_IMP(d, pos) DO_NOTHING +#endif /* (not) NEW_GC */ + +/* Add Element EL to the end of dynarr D. */ + +#define Dynarr_add(d, el) \ +do { \ + Elemcount _da_pos = Dynarr_length (d); \ + (void) Dynarr_verify_mod (d); \ + Dynarr_increment (d); \ + ((d)->base)[_da_pos] = (el); \ + DYNARR_SET_LISP_IMP (d, _da_pos); \ +} while (0) + +/* Set EL as the element at position POS in dynarr D. + Expand the dynarr as necessary so that its length is enough to include + position POS within it, and zero out any new elements created as a + result of expansion, other than the one at POS. */ + +#define Dynarr_set(d, pos, el) \ +do { \ + Elemcount _ds_pos = (pos); \ + (void) Dynarr_verify_mod (d); \ + if (Dynarr_length (d) < _ds_pos + 1) \ + Dynarr_increase_length_and_zero (d, _ds_pos + 1); \ + ((d)->base)[_ds_pos] = (el); \ + DYNARR_SET_LISP_IMP (d, _ds_pos); \ +} while (0) + +/* Add LEN contiguous elements, stored at BASE, to dynarr D. If BASE is + NULL, reserve space but don't store anything. */ + +DECLARE_INLINE_HEADER ( +void +Dynarr_add_many (void *d, const void *base, Elemcount len) +) +{ + /* This duplicates Dynarr_insert_many to some extent; but since it is + called so often, it seemed useful to remove the unnecessary stuff + from that function and to make it inline */ + Dynarr *dy = Dynarr_verify_mod (d); + Elemcount pos = Dynarr_length (dy); + Dynarr_increase_length (dy, Dynarr_length (dy) + len); + if (base) + memcpy ((Rawbyte *) dy->base + pos*Dynarr_elsize (dy), base, + len*Dynarr_elsize (dy)); +} + +/* Insert LEN elements, currently pointed to by BASE, into dynarr D + starting at position POS. */ + +MODULE_API void Dynarr_insert_many (void *d, const void *base, Elemcount len, + Elemcount pos); + +/* Prepend LEN elements, currently pointed to by BASE, to the beginning. */ + +#define Dynarr_prepend_many(d, base, len) Dynarr_insert_many (d, base, len, 0) + +/* Add literal string S to dynarr D, which should hold chars or unsigned + chars. The final zero byte is not stored. */ + +#define Dynarr_add_literal_string(d, s) Dynarr_add_many (d, s, sizeof (s) - 1) + +/* Convert Lisp string S to an external encoding according to CODESYS and + add to dynarr D, which should hold chars or unsigned chars. No final + zero byte is appended. */ + +/* #### This should be an inline function but LISP_STRING_TO_SIZED_EXTERNAL + isn't declared yet. */ + +#define Dynarr_add_ext_lisp_string(d, s, codesys) \ +do { \ + Lisp_Object dyna_ls_s = (s); \ + Lisp_Object dyna_ls_cs = (codesys); \ + Extbyte *dyna_ls_eb; \ + Bytecount dyna_ls_bc; \ + \ + LISP_STRING_TO_SIZED_EXTERNAL (dyna_ls_s, dyna_ls_eb, \ + dyna_ls_bc, dyna_ls_cs); \ + Dynarr_add_many (d, dyna_ls_eb, dyna_ls_bc); \ +} while (0) + +/* Delete LEN elements starting at position POS. */ + +MODULE_API void Dynarr_delete_many (void *d, Elemcount pos, Elemcount len); + +/* Pop off (i.e. delete) the last element from the dynarr and return it */ + +#define Dynarr_pop(d) \ + (dynarr_checking_assert (Dynarr_length (d) > 0), \ + Dynarr_verify_mod (d)->len_--, \ + Dynarr_at (d, Dynarr_length (d))) + +/* Delete the item at POS */ + +#define Dynarr_delete(d, pos) Dynarr_delete_many (d, pos, 1) + +/* Delete the item located at memory address P, which must be a `type *' + pointer, where `type' is the type of the elements of the dynarr. */ +#define Dynarr_delete_by_pointer(d, p) \ + Dynarr_delete_many (d, (p) - ((d)->base), 1) + +/* Delete all elements that are numerically equal to EL. */ + +#define Dynarr_delete_object(d, el) \ +do \ +{ \ + REGISTER int i; \ + for (i = Dynarr_length (d) - 1; i >= 0; i--) \ + { \ + if (el == Dynarr_at (d, i)) \ + Dynarr_delete_many (d, i, 1); \ + } \ +} while (0) + + +/************************************************************************/ +/** Stack-like malloc/free **/ +/************************************************************************/ + +void *stack_like_malloc (Bytecount size); +void stack_like_free (void *val); + + + +/************************************************************************/ +/** Gap array **/ +/************************************************************************/ + +/* Holds a marker that moves as elements in the array are inserted and + deleted, similar to standard markers. */ + +typedef struct gap_array_marker +{ +#ifdef NEW_GC + NORMAL_LISP_OBJECT_HEADER header; +#endif /* NEW_GC */ + int pos; + struct gap_array_marker *next; +} Gap_Array_Marker; + + +/* Holds a "gap array", which is an array of elements with a gap located + in it. Insertions and deletions with a high degree of locality + are very fast, essentially in constant time. Array positions as + used and returned in the gap array functions are independent of + the gap. */ + +/* Layout of gap array: + + <------ gap ------><---- gapsize ----><----- numels - gap ----> + <---------------------- numels + gapsize ---------------------> + + For marking purposes, we use two extra variables computed from + the others -- the offset to the data past the gap, plus the number + of elements in that data: + + offset_past_gap = elsize * (gap + gapsize) + els_past_gap = numels - gap +*/ + + +typedef struct gap_array +{ +#ifdef NEW_GC + NORMAL_LISP_OBJECT_HEADER header; + int is_lisp; +#endif /* NEW_GC */ + Elemcount gap; + Elemcount gapsize; + Elemcount numels; + Bytecount elsize; + /* Redundant numbers computed from the others, for marking purposes */ + Bytecount offset_past_gap; + Elemcount els_past_gap; + Gap_Array_Marker *markers; + /* this is a stretchy array */ + char array[1]; +} Gap_Array; + +#ifdef NEW_GC +struct gap_array_marker; + +DECLARE_LISP_OBJECT (gap_array_marker, struct gap_array_marker); +#define XGAP_ARRAY_MARKER(x) \ + XRECORD (x, gap_array_marker, struct gap_array_marker) +#define wrap_gap_array_marker(p) wrap_record (p, gap_array_marker) +#define GAP_ARRAY_MARKERP(x) RECORDP (x, gap_array_marker) +#define CHECK_GAP_ARRAY_MARKER(x) CHECK_RECORD (x, gap_array_marker) +#define CONCHECK_GAP_ARRAY_MARKER(x) CONCHECK_RECORD (x, gap_array_marker) + +struct gap_array; + +DECLARE_LISP_OBJECT (gap_array, struct gap_array); +#define XGAP_ARRAY(x) XRECORD (x, gap_array, struct gap_array) +#define wrap_gap_array(p) wrap_record (p, gap_array) +#define GAP_ARRAYP(x) RECORDP (x, gap_array) +#define CHECK_GAP_ARRAY(x) CHECK_RECORD (x, gap_array) +#define CONCHECK_GAP_ARRAY(x) CONCHECK_RECORD (x, gap_array) +#endif /* NEW_GC */ + +#ifdef NEW_GC +#define XD_GAP_ARRAY_MARKER_DESC \ + { XD_LISP_OBJECT, offsetof (Gap_Array, markers) } +#else /* not NEW_GC */ +#define XD_GAP_ARRAY_MARKER_DESC \ + { XD_BLOCK_PTR, offsetof (Gap_Array, markers), 1, \ + { &gap_array_marker_description }, XD_FLAG_NO_KKCC } +#endif /* not NEW_GC */ + +#define XD_GAP_ARRAY_DESC(sub_desc) \ + { XD_ELEMCOUNT, offsetof (Gap_Array, gap) }, \ + { XD_BYTECOUNT, offsetof (Gap_Array, offset_past_gap) }, \ + { XD_ELEMCOUNT, offsetof (Gap_Array, els_past_gap) }, \ + XD_GAP_ARRAY_MARKER_DESC, \ + { XD_BLOCK_ARRAY, offsetof (Gap_Array, array), XD_INDIRECT (0, 0), \ + { sub_desc } }, \ + { XD_BLOCK_ARRAY, XD_INDIRECT (1, offsetof (Gap_Array, array)), \ + XD_INDIRECT (2, 0), { sub_desc } } + +/* Convert a "memory position" (i.e. taking the gap into account) into + the address of the element at (i.e. after) that position. "Memory + positions" are only used internally and are of type Memxpos. + "Array positions" are used externally and are of type Elemcount. */ +#define GAP_ARRAY_MEMEL_ADDR(ga, memel) ((ga)->array + (ga)->elsize*(memel)) + +/* Number of elements currently in a gap array */ +#define gap_array_length(ga) ((ga)->numels) + +#define gap_array_gappos(ga) ((ga)->gap) +#define gap_array_gapsize(ga) ((ga)->gapsize) + +#define GAP_ARRAY_ARRAY_TO_MEMORY_POS_1(pos, gappos, gapsize) \ + ((pos) < gappos ? (pos) : (pos) + gapsize) + +#define GAP_ARRAY_ARRAY_TO_MEMORY_POS(ga, pos) \ + GAP_ARRAY_ARRAY_TO_MEMORY_POS_1 (pos, (ga)->gap, (ga)->gapsize) + +#define GAP_ARRAY_MEMORY_TO_ARRAY_POS(ga, pos) \ + ((pos) <= (ga)->gap ? (pos) : (pos) - (ga)->gapsize) + +/* Return a pointer to the element at a given position. */ +#define gap_array_atp(ga, pos, type) \ + ((type *) GAP_ARRAY_MEMEL_ADDR (ga, GAP_ARRAY_ARRAY_TO_MEMORY_POS (ga, pos))) + +/* Return the element at a given position. */ +#define gap_array_at(ga, pos, type) (*gap_array_atp (ga, pos, type)) + +/* Return a pointer to the beginning of memory storage for the gap array. + Note this is NOT the same as gap_array_atp(ga, 0, type) because that + will skip forward past the gap if the gap is at position 0. */ +#define gap_array_begin(ga, type) ((type *) ((ga)->array)) + +#ifndef NEW_GC +extern const struct sized_memory_description lispobj_gap_array_description; +extern const struct sized_memory_description gap_array_marker_description; +#endif + +Bytecount gap_array_byte_size (Gap_Array *ga); +Gap_Array *gap_array_insert_els (Gap_Array *ga, Elemcount pos, void *elptr, + Elemcount numels); +void gap_array_delete_els (Gap_Array *ga, Elemcount from, Elemcount numdel); +#define gap_array_delete_all_els(ga) \ + gap_array_delete_els (ga, 0, gap_array_length (ga)) +Gap_Array_Marker *gap_array_make_marker (Gap_Array *ga, Elemcount pos); +void gap_array_delete_marker (Gap_Array *ga, Gap_Array_Marker *m); +void gap_array_delete_all_markers (Gap_Array *ga); +void gap_array_move_marker (Gap_Array *ga, Gap_Array_Marker *m, Elemcount pos); +#define gap_array_marker_pos(ga, m) \ + GAP_ARRAY_MEMORY_TO_ARRAY_POS (ga, (m)->pos) +Gap_Array *make_gap_array (Elemcount elsize, int USED_IF_NEW_GC (do_lisp)); +Gap_Array *gap_array_clone (Gap_Array *ga); +void free_gap_array (Gap_Array *ga); +Bytecount gap_array_memory_usage (Gap_Array *ga, struct usage_stats *stats, + Bytecount *marker_ancillary); + +#endif /* INCLUDED_array_h_ */
--- a/src/buffer.c Fri Mar 26 15:06:28 2010 +0000 +++ b/src/buffer.c Mon Mar 29 00:11:03 2010 -0500 @@ -1754,6 +1754,7 @@ { struct usage_stats u; Bytecount text; + /* Ancillary Lisp */ Bytecount markers; Bytecount extents; }; @@ -1787,8 +1788,8 @@ struct usage_stats *ustats) { stats->text += compute_buffer_text_usage (b, ustats); - stats->markers += compute_buffer_marker_usage (b, ustats); - stats->extents += compute_buffer_extent_usage (b, ustats); + stats->markers += compute_buffer_marker_usage (b); + stats->extents += compute_buffer_extent_usage (b); } static void @@ -1976,7 +1977,7 @@ /* This function can GC */ #ifdef MEMORY_USAGE_STATS OBJECT_HAS_PROPERTY - (buffer, memusage_stats_list, list3 (Qtext, Qmarkers, Qextents)); + (buffer, memusage_stats_list, list4 (Qtext, Qt, Qmarkers, Qextents)); #endif /* MEMORY_USAGE_STATS */ staticpro (&QSFundamental);
--- a/src/casetab.c Fri Mar 26 15:06:28 2010 +0000 +++ b/src/casetab.c Mon Mar 29 00:11:03 2010 -0500 @@ -508,6 +508,38 @@ } +#ifdef MEMORY_USAGE_STATS + +struct case_table_stats +{ + struct usage_stats u; + /* Ancillary Lisp */ + Bytecount downcase, upcase, case_canon, case_eqv; +}; + +static void +case_table_memory_usage (Lisp_Object casetab, + struct generic_usage_stats *gustats) +{ + struct case_table_stats *stats = (struct case_table_stats *) gustats; + + stats->downcase = lisp_object_memory_usage (XCASE_TABLE_DOWNCASE (casetab)); + stats->upcase = lisp_object_memory_usage (XCASE_TABLE_UPCASE (casetab)); + stats->case_canon = lisp_object_memory_usage (XCASE_TABLE_CANON (casetab)); + stats->case_eqv = lisp_object_memory_usage (XCASE_TABLE_EQV (casetab)); +} + +#endif /* MEMORY_USAGE_STATS */ + + +void +casetab_objects_create (void) +{ +#ifdef MEMORY_USAGE_STATS + OBJECT_HAS_METHOD (case_table, memory_usage); +#endif +} + void syms_of_casetab (void) { @@ -530,6 +562,19 @@ } void +vars_of_casetab (void) +{ +#ifdef MEMORY_USAGE_STATS + OBJECT_HAS_PROPERTY (case_table, memusage_stats_list, + list5 (Qt, + intern ("downcase"), + intern ("upcase"), + intern ("case-canon"), + intern ("case-eqv"))); +#endif /* MEMORY_USAGE_STATS */ +} + +void complex_vars_of_casetab (void) { REGISTER Ichar i;
--- a/src/console-impl.h Fri Mar 26 15:06:28 2010 +0000 +++ b/src/console-impl.h Mon Mar 29 00:11:03 2010 -0500 @@ -1,5 +1,5 @@ /* Define console object for XEmacs. - Copyright (C) 1996, 2002, 2003, 2005 Ben Wing + Copyright (C) 1996, 2002, 2003, 2005, 2010 Ben Wing This file is part of XEmacs. @@ -290,9 +290,10 @@ scrollbar_instance *); void (*scrollbar_pointer_changed_in_window_method) (struct window *w); #ifdef MEMORY_USAGE_STATS - int (*compute_scrollbar_instance_usage_method) (struct device *, - struct scrollbar_instance *, - struct usage_stats *); + Bytecount (*compute_scrollbar_instance_usage_method) + (struct device *, + struct scrollbar_instance *, + struct usage_stats *); #endif /* Paint the window's deadbox, a rectangle between window borders and two short edges of both scrollbars. */
--- a/src/data.c Fri Mar 26 15:06:28 2010 +0000 +++ b/src/data.c Mon Mar 29 00:11:03 2010 -0500 @@ -1,7 +1,7 @@ /* Primitive operations on Lisp data types for XEmacs Lisp interpreter. Copyright (C) 1985, 1986, 1988, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. - Copyright (C) 2000, 2001, 2002, 2003, 2005 Ben Wing. + Copyright (C) 2000, 2001, 2002, 2003, 2005, 2010 Ben Wing. This file is part of XEmacs. @@ -30,6 +30,7 @@ #include "buffer.h" #include "bytecode.h" +#include "gc.h" #include "syssignal.h" #include "sysfloat.h" @@ -2804,7 +2805,7 @@ if (need_to_mark_elem && ! marked_p (elem)) { #ifdef USE_KKCC - kkcc_gc_stack_push_lisp_object (elem, 0, -1); + kkcc_gc_stack_push_lisp_object_0 (elem); #else /* NOT USE_KKCC */ mark_object (elem); #endif /* NOT USE_KKCC */ @@ -2832,7 +2833,7 @@ if (!NILP (rest2) && ! marked_p (rest2)) { #ifdef USE_KKCC - kkcc_gc_stack_push_lisp_object (rest2, 0, -1); + kkcc_gc_stack_push_lisp_object_0 (rest2); #else /* NOT USE_KKCC */ mark_object (rest2); #endif /* NOT USE_KKCC */ @@ -3208,8 +3209,8 @@ if (marked_p (XEPHEMERON (rest)->key)) { #ifdef USE_KKCC - kkcc_gc_stack_push_lisp_object - (XCAR (XEPHEMERON (rest)->cons_chain), 0, -1); + kkcc_gc_stack_push_lisp_object_0 + (XCAR (XEPHEMERON (rest)->cons_chain)); #else /* NOT USE_KKCC */ mark_object (XCAR (XEPHEMERON (rest)->cons_chain)); #endif /* NOT USE_KKCC */ @@ -3258,8 +3259,8 @@ { MARK_CONS (XCONS (XEPHEMERON (rest)->cons_chain)); #ifdef USE_KKCC - kkcc_gc_stack_push_lisp_object - (XCAR (XEPHEMERON (rest)->cons_chain), 0, -1); + kkcc_gc_stack_push_lisp_object_0 + (XCAR (XEPHEMERON (rest)->cons_chain)); #else /* NOT USE_KKCC */ mark_object (XCAR (XEPHEMERON (rest)->cons_chain)); #endif /* NOT USE_KKCC */
--- a/src/depend Fri Mar 26 15:06:28 2010 +0000 +++ b/src/depend Mon Mar 29 00:11:03 2010 -0500 @@ -11,7 +11,7 @@ LISP_H= #else CONFIG_H=config.h -LISP_H=lisp.h compiler.h config.h dumper.h gc.h general-slots.h lisp.h lrecord.h mc-alloc.h number-gmp.h number-mp.h number.h symeval.h symsinit.h text.h vdb.h $(LISP_UNION_H) +LISP_H=lisp.h array.h compiler.h config.h dumper.h gc.h general-slots.h lisp.h lrecord.h mc-alloc.h number-gmp.h number-mp.h number.h symeval.h symsinit.h text.h vdb.h $(LISP_UNION_H) #endif #if defined(HAVE_MS_WINDOWS) @@ -111,6 +111,7 @@ alloc.o: $(CONFIG_H) $(LISP_H) backtrace.h buffer.h bufslots.h bytecode.h casetab.h charset.h chartab.h coding-system-slots.h conslots.h console-impl.h console-stream.h console.h device.h elhash.h events.h extents-impl.h extents.h file-coding.h frame-impl.h frame.h frameslots.h glyphs.h intl-auto-encap-win32.h keymap-buttons.h lstream.h opaque.h process.h profile.h redisplay.h scrollbar.h specifier.h sysdep.h sysfile.h systime.h syswindows.h window-impl.h window.h winslots.h alloca.o: $(CONFIG_H) $(LISP_H) alsaplay.o: $(CONFIG_H) $(LISP_H) buffer.h bufslots.h casetab.h charset.h chartab.h intl-auto-encap-win32.h sound.h sysfile.h syswindows.h +array.o: $(CONFIG_H) $(LISP_H) insdel.h blocktype.o: $(CONFIG_H) $(LISP_H) blocktype.h buffer.o: $(CONFIG_H) $(LISP_H) buffer.h bufslots.h casetab.h charset.h chartab.h coding-system-slots.h commands.h conslots.h console-impl.h console.h device-impl.h device.h devslots.h elhash.h extents.h faces.h file-coding.h frame-impl.h frame.h frameslots.h insdel.h intl-auto-encap-win32.h lstream.h ndir.h process.h redisplay.h scrollbar.h select.h specifier.h syntax.h sysdir.h sysfile.h syswindows.h window.h bytecode.o: $(CONFIG_H) $(LISP_H) backtrace.h buffer.h bufslots.h bytecode-ops.h bytecode.h casetab.h charset.h chartab.h opaque.h redisplay.h scrollbar.h syntax.h window.h @@ -133,7 +134,6 @@ dragdrop.o: $(CONFIG_H) $(LISP_H) dragdrop.h dump-data.o: $(CONFIG_H) $(LISP_H) dump-data.h dumper.o: $(CONFIG_H) $(LISP_H) coding-system-slots.h console-stream.h console.h dump-data.h elhash.h file-coding.h intl-auto-encap-win32.h lstream.h specifier.h sysfile.h syswindows.h -dynarr.o: $(CONFIG_H) $(LISP_H) ecrt0.o: $(CONFIG_H) editfns.o: $(CONFIG_H) $(LISP_H) buffer.h bufslots.h casetab.h charset.h chartab.h commands.h console.h device.h events.h frame.h insdel.h intl-auto-encap-win32.h keymap-buttons.h line-number.h ndir.h process.h redisplay.h scrollbar.h sysdep.h sysdir.h sysfile.h sysproc.h syspwd.h syssignal.h systime.h syswindows.h window.h elhash.o: $(CONFIG_H) $(LISP_H) bytecode.h elhash.h opaque.h @@ -172,7 +172,7 @@ hpplay.o: $(CONFIG_H) $(LISP_H) buffer.h bufslots.h casetab.h charset.h chartab.h sound.h imgproc.o: $(CONFIG_H) $(LISP_H) imgproc.h indent.o: $(CONFIG_H) $(LISP_H) buffer.h bufslots.h casetab.h charset.h chartab.h console.h device.h extents.h faces.h frame.h glyphs.h insdel.h redisplay.h scrollbar.h specifier.h window-impl.h window.h winslots.h -inline.o: $(CONFIG_H) $(LISP_H) $(LWLIB_SRCDIR)/lwlib.h buffer.h bufslots.h bytecode.h casetab.h charset.h chartab.h coding-system-slots.h conslots.h console-gtk.h console-impl.h console-msw.h console.h database.h device-impl.h device.h devslots.h elhash.h events.h extents-impl.h extents.h faces.h file-coding.h font-mgr.h frame-impl.h frame.h frameslots.h glyphs-x.h glyphs.h gui.h intl-auto-encap-win32.h keymap-buttons.h keymap.h lstream.h objects-impl.h objects.h opaque.h process.h rangetab.h redisplay.h scrollbar.h specifier.h syntax.h sysdll.h sysfile.h sysgtk.h systime.h syswindows.h toolbar.h tooltalk.h ui-gtk.h window-impl.h window.h winslots.h xintrinsic.h +inline.o: $(CONFIG_H) $(LISP_H) $(LWLIB_SRCDIR)/lwlib.h buffer.h bufslots.h bytecode.h casetab.h charset.h chartab.h coding-system-slots.h conslots.h console-gtk-impl.h console-gtk.h console-impl.h console-msw-impl.h console-msw.h console-stream-impl.h console-stream.h console-tty-impl.h console-tty.h console-x-impl.h console-x.h console.h database.h device-impl.h device.h devslots.h elhash.h events.h extents-impl.h extents.h faces.h file-coding.h font-mgr.h frame-impl.h frame.h frameslots.h glyphs.h gui.h intl-auto-encap-win32.h keymap-buttons.h keymap.h lstream.h objects-impl.h objects-tty-impl.h objects-tty.h objects.h opaque.h process.h rangetab.h redisplay.h scrollbar.h specifier.h syntax.h sysdll.h sysfile.h sysgtk.h systime.h systty.h syswindows.h toolbar.h tooltalk.h ui-gtk.h window-impl.h window.h winslots.h xintrinsic.h input-method-motif.o: $(CONFIG_H) $(LISP_H) $(LWLIB_SRCDIR)/lwlib.h EmacsFrame.h conslots.h console-impl.h console-x-impl.h console-x.h console.h device.h frame-impl.h frame.h frameslots.h redisplay.h specifier.h xintrinsic.h xmotif.h input-method-xlib.o: $(CONFIG_H) $(LISP_H) $(LWLIB_SRCDIR)/lwlib.h EmacsFrame.h buffer.h bufslots.h casetab.h charset.h chartab.h conslots.h console-impl.h console-x-impl.h console-x.h console.h device-impl.h device.h devslots.h events.h frame-impl.h frame.h frameslots.h keymap-buttons.h redisplay.h scrollbar.h specifier.h systime.h window-impl.h window.h winslots.h xintrinsic.h insdel.o: $(CONFIG_H) $(LISP_H) buffer.h bufslots.h casetab.h charset.h chartab.h console.h device.h extents.h frame.h insdel.h line-number.h lstream.h redisplay.h
--- a/src/device-msw.c Fri Mar 26 15:06:28 2010 +0000 +++ b/src/device-msw.c Mon Mar 29 00:11:03 2010 -0500 @@ -574,6 +574,7 @@ #ifndef NEW_GC xfree (d->device_data); + d->device_data = 0; #endif /* not NEW_GC */ } }
--- a/src/device-tty.c Fri Mar 26 15:06:28 2010 +0000 +++ b/src/device-tty.c Mon Mar 29 00:11:03 2010 -0500 @@ -116,7 +116,10 @@ free_tty_device_struct (struct device *d) { if (d->device_data) - xfree (d->device_data); + { + xfree (d->device_data); + d->device_data = 0; + } } static void
--- a/src/dialog-msw.c Fri Mar 26 15:06:28 2010 +0000 +++ b/src/dialog-msw.c Mon Mar 29 00:11:03 2010 -0500 @@ -441,6 +441,7 @@ { ret = tstr_to_local_file_format (pd.unknown_fname); xfree (pd.unknown_fname); + pd.unknown_fname = 0; } else while (1) signal_quit ();
--- a/src/dialog-x.c Fri Mar 26 15:06:28 2010 +0000 +++ b/src/dialog-x.c Mon Mar 29 00:11:03 2010 -0500 @@ -1,7 +1,7 @@ /* Implements elisp-programmable dialog boxes -- X interface. Copyright (C) 1993, 1994 Free Software Foundation, Inc. Copyright (C) 1995 Tinker Systems and INS Engineering Corp. - Copyright (C) 2000, 2002, 2003 Ben Wing. + Copyright (C) 2000, 2002, 2003, 2010 Ben Wing. This file is part of XEmacs.
--- a/src/dumper.c Fri Mar 26 15:06:28 2010 +0000 +++ b/src/dumper.c Mon Mar 29 00:11:03 2010 -0500 @@ -800,7 +800,7 @@ break; } #ifdef NEW_GC - case XD_LISP_OBJECT_BLOCK_PTR: + case XD_INLINE_LISP_OBJECT_BLOCK_PTR: { EMACS_INT count = lispdesc_indirect_count (desc1->data1, desc, data); @@ -1073,7 +1073,7 @@ break; } #ifdef NEW_GC - case XD_LISP_OBJECT_BLOCK_PTR: + case XD_INLINE_LISP_OBJECT_BLOCK_PTR: #endif /* NEW_GC */ case XD_OPAQUE_DATA_PTR: case XD_ASCII_STRING: @@ -1314,7 +1314,7 @@ case XD_LONG: case XD_INT_RESET: break; - case XD_LISP_OBJECT_BLOCK_PTR: + case XD_INLINE_LISP_OBJECT_BLOCK_PTR: case XD_OPAQUE_DATA_PTR: case XD_ASCII_STRING: case XD_BLOCK_PTR:
--- a/src/dynarr.c Fri Mar 26 15:06:28 2010 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,526 +0,0 @@ -/* Support for dynamic arrays. - Copyright (C) 1993 Sun Microsystems, Inc. - Copyright (C) 2002, 2003, 2004, 2005, 2010 Ben Wing. - -This file is part of XEmacs. - -XEmacs is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 2, or (at your option) any -later version. - -XEmacs 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 General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with XEmacs; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ - -/* Synched up with: Not in FSF. */ - -/* Written by Ben Wing, December 1993. */ - -/* - -A "dynamic array" or "dynarr" is a contiguous array of fixed-size elements -where there is no upper limit (except available memory) on the number of -elements in the array. Because the elements are maintained contiguously, -space is used efficiently (no per-element pointers necessary) and random -access to a particular element is in constant time. At any one point, the -block of memory that holds the array has an upper limit; if this limit is -exceeded, the memory is realloc()ed into a new array that is twice as big. -Assuming that the time to grow the array is on the order of the new size of -the array block, this scheme has a provably constant amortized time -\(i.e. average time over all additions). - -When you add elements or retrieve elements, pointers are used. Note that -the element itself (of whatever size it is), and not the pointer to it, -is stored in the array; thus you do not have to allocate any heap memory -on your own. Also, returned pointers are only guaranteed to be valid -until the next operation that changes the length of the array. - -This is a container object. Declare a dynamic array of a specific type -as follows: - - typedef struct - { - Dynarr_declare (mytype); - } mytype_dynarr; - -Use the following functions/macros: - - - ************* Dynarr creation ************* - - void *Dynarr_new(type) - [MACRO] Create a new dynamic-array object, with each element of the - specified type. The return value is cast to (type##_dynarr). - This requires following the convention that types are declared in - such a way that this type concatenation works. In particular, TYPE - must be a symbol, not an arbitrary C type. To make dynarrs of - complex types, a typedef must be declared, e.g. - - typedef unsigned char *unsigned_char_ptr; - - and then you can say - - unsigned_char_ptr_dynarr *dyn = Dynarr_new (unsigned_char_ptr); - - void *Dynarr_new2(dynarr_type, type) - [MACRO] Create a new dynamic-array object, with each element of the - specified type. The array itself is of type DYNARR_TYPE. This makes - it possible to create dynarrs over complex types without the need - to create typedefs, as described above. Use is as follows: - - ucharptr_dynarr *dyn = Dynarr_new2 (ucharptr_dynarr *, unsigned char *); - - Dynarr_free(d) - Destroy a dynamic array and the memory allocated to it. - - ************* Dynarr access ************* - - type Dynarr_at(d, i) - [MACRO] Return the element at the specified index. The index must be - between 0 and Dynarr_largest(d), inclusive. With error-checking - enabled, bounds checking on the index is in the form of asserts() -- - an out-of-bounds index causes an abort. The element itself is - returned, not a pointer to it. - - type *Dynarr_atp(d, i) - [MACRO] Return a pointer to the element at the specified index. - Restrictions and bounds checking on the index is as for Dynarr_at. - The pointer may not be valid after an element is added to or - (conceivably) removed from the array, because this may trigger a - realloc() performed on the underlying dynarr storage, which may - involve moving the entire underlying storage to a new location in - memory. - - type *Dynarr_begin(d) - [MACRO] Return a pointer to the first element in the dynarr. See - Dynarr_atp() for warnings about when the pointer might become invalid. - - type *Dynarr_lastp(d) - [MACRO] Return a pointer to the last element in the dynarr. See - Dynarr_atp() for warnings about when the pointer might become invalid. - - type *Dynarr_past_lastp(d) - [MACRO] Return a pointer to the beginning of the element just past the - last one. WARNING: This may not point to valid memory; however, the - byte directly before will be pointer will be valid memory. This macro - might be useful for various reasons, e.g. as a stopping point in a loop - (although Dynarr_lastp() could be used just as well) or as a place to - start writing elements if Dynarr_length() < Dynarr_largest(). - - ************* Dynarr length/size retrieval and setting ************* - - int Dynarr_length(d) - [MACRO] Return the number of elements currently in a dynamic array. - - int Dynarr_largest(d) - [MACRO] Return the maximum value that Dynarr_length(d) would - ever have returned. This is used esp. in the redisplay code, - which reuses dynarrs for performance reasons. - - int Dynarr_max(d) - [MACRO] Return the maximum number of elements that can fit in the - dynarr before it needs to be resized. - - Note that Dynarr_length(d) <= Dynarr_largest(d) <= Dynarr_max(d). - - Bytecount Dynarr_sizeof(d) - [MACRO] Return the total size of the elements currently in dynarr - D. This - - Dynarr_set_lengthr(d, len) - [MACRO] Set the length of D to LEN, which must be between 0 and - Dynarr_largest(d), inclusive. With error-checking enabled, an - assertion failure will result from trying to set the length - to less than zero or greater than Dynarr_largest(d). The - restriction to Dynarr_largest() is to ensure that - - Dynarr_set_length(d, len) - [MACRO] Set the length of D to LEN, resizing the dynarr as - necessary to make sure enough space is available. there are no - restrictions on LEN other than available memory and that it must - be at least 0. Note that - - Dynarr_set_length_and_zero(d, len) - [MACRO] Like Dynarr_set_length(d, len) but also, if increasing - the length, zero out the memory between the old and new lengths, - i.e. starting just past the previous last element and up through - the new last element. - - Dynarr_incrementr(d) - [MACRO] Increments the length of D by 1. Equivalent to - Dynarr_set_lengthr(d, Dynarr_length(d) + 1). - - Dynarr_increment(d) - [MACRO] Increments the length of D by 1. Equivalent to - Dynarr_set_length(d, Dynarr_length(d) + 1). - - Dynarr_reset(d) - [MACRO] Reset the length of a dynamic array to 0. - - Dynarr_resize(d, maxval) - Resize the internal dynarr storage to so that it can hold at least - MAXVAL elements. Resizing is done using a geometric series - (repeatedly multiply the old maximum by a constant, normally 1.5, - till a large enough size is reached), so this will be efficient - even if resizing larger by one element at a time. This is mostly - an internal function. - - - - ************* Adding/deleting elements to/from a dynarr ************* - - Dynarr_add(d, el) - [MACRO] Add an element to the end of a dynamic array. EL is a pointer - to the element; the element itself is stored in the array, however. - No function call is performed unless the array needs to be resized. - - Dynarr_add_many(d, base, len) - [MACRO] Add LEN elements to the end of the dynamic array. The elements - should be contiguous in memory, starting at BASE. If BASE if NULL, - just make space for the elements; don't actually add them. - - Dynarr_prepend_many(d, base, len) - [MACRO] Prepend LEN elements to the beginning of the dynamic array. - The elements should be contiguous in memory, starting at BASE. - If BASE if NULL, just make space for the elements; don't actually - add them. - - Dynarr_insert_many(d, base, len, pos) - Insert LEN elements to the dynamic array starting at position - POS. The elements should be contiguous in memory, starting at BASE. - If BASE if NULL, just make space for the elements; don't actually - add them. - - type Dynarr_pop(d) - [MACRO] Pop the last element off the dynarr and return it. - - Dynarr_delete(d, i) - [MACRO] Delete an element from the dynamic array at position I. - - Dynarr_delete_many(d, pos, len) - Delete LEN elements from the dynamic array starting at position - POS. - - Dynarr_zero_many(d, pos, len) - Zero out LEN elements in the dynarr D starting at position POS. - - Dynarr_delete_by_pointer(d, p) - [MACRO] Delete an element from the dynamic array at pointer P, - which must point within the block of memory that stores the data. - P should be obtained using Dynarr_atp(). - - ************* Dynarr locking ************* - - Dynarr_lock(d) - Lock the dynarr against further locking or writing. With error-checking - enabled, any attempts to write into a locked dynarr or re-lock an - already locked one will cause an assertion failure and abort. - - Dynarr_unlock(d) - Unlock a locked dynarr, allowing writing into it. - - ************* Dynarr global variables ************* - - Dynarr_min_size - Minimum allowable size for a dynamic array when it is resized. - -*/ - -#include <config.h> -#include "lisp.h" - -static const struct memory_description const_Ascbyte_ptr_description_1[] = { - { XD_ASCII_STRING, 0 }, - { XD_END } -}; - -const struct sized_memory_description const_Ascbyte_ptr_description = { - sizeof (const Ascbyte *), - const_Ascbyte_ptr_description_1 -}; - -static const struct memory_description const_Ascbyte_ptr_dynarr_description_1[] = { - XD_DYNARR_DESC (const_Ascbyte_ptr_dynarr, &const_Ascbyte_ptr_description), - { XD_END } -}; - -const struct sized_memory_description const_Ascbyte_ptr_dynarr_description = { - sizeof (const_Ascbyte_ptr_dynarr), - const_Ascbyte_ptr_dynarr_description_1 -}; - - -static Elemcount Dynarr_min_size = 8; - -static void -Dynarr_realloc (Dynarr *dy, Elemcount new_size) -{ - if (DUMPEDP (dy->base)) - { - void *new_base = malloc (new_size * Dynarr_elsize (dy)); - memcpy (new_base, dy->base, - (Dynarr_max (dy) < new_size ? Dynarr_max (dy) : new_size) * - Dynarr_elsize (dy)); - dy->base = new_base; - } - else - dy->base = xrealloc (dy->base, new_size * Dynarr_elsize (dy)); -} - -void * -Dynarr_newf (Bytecount elsize) -{ - Dynarr *d = xnew_and_zero (Dynarr); - d->elsize_ = elsize; - - return d; -} - -#ifdef NEW_GC -DEFINE_DUMPABLE_INTERNAL_LISP_OBJECT ("dynarr", dynarr, - 0, 0, - Dynarr); - -static void -Dynarr_lisp_realloc (Dynarr *dy, Elemcount new_size) -{ - void *new_base = - XPNTR (alloc_sized_lrecord_array (Dynarr_elsize (dy), new_size, - dy->lisp_imp)); - if (dy->base) - memcpy (new_base, dy->base, - (Dynarr_max (dy) < new_size ? Dynarr_max (dy) : new_size) * - Dynarr_elsize (dy)); - dy->base = new_base; -} - -void * -Dynarr_lisp_newf (Bytecount elsize, - const struct lrecord_implementation *dynarr_imp, - const struct lrecord_implementation *imp) -{ - Dynarr *d = (Dynarr *) XPNTR (alloc_sized_lrecord (sizeof (Dynarr), - dynarr_imp)); - d->elsize_ = elsize; - d->lisp_imp = imp; - - return d; -} -#endif /* not NEW_GC */ - -void -Dynarr_resize (void *d, Elemcount size) -{ - Elemcount newsize; - double multiplier; - Dynarr *dy = (Dynarr *) Dynarr_verify (d); - - if (Dynarr_max (dy) <= 8) - multiplier = 2; - else - multiplier = 1.5; - - for (newsize = Dynarr_max (dy); newsize < size;) - newsize = max (Dynarr_min_size, (Elemcount) (multiplier * newsize)); - - /* Don't do anything if the array is already big enough. */ - if (newsize > Dynarr_max (dy)) - { -#ifdef NEW_GC - if (dy->lisp_imp) - Dynarr_lisp_realloc (dy, newsize); - else - Dynarr_realloc (dy, newsize); -#else /* not NEW_GC */ - Dynarr_realloc (dy, newsize); -#endif /* not NEW_GC */ - dy->max_ = newsize; - } -} - -/* Add a number of contiguous elements to the array starting at POS. */ - -void -Dynarr_insert_many (void *d, const void *base, Elemcount len, Elemcount pos) -{ - Dynarr *dy = Dynarr_verify_mod (d); - Elemcount old_len = Dynarr_length (dy); - - /* #### This could conceivably be wrong, if code wants to access stuff - between len and largest. */ - dynarr_checking_assert (pos >= 0 && pos <= old_len); - dynarr_checking_assert (len >= 0); - Dynarr_increase_length (dy, old_len + len); - - if (pos != old_len) - { - memmove ((Rawbyte *) dy->base + (pos + len)*Dynarr_elsize (dy), - (Rawbyte *) dy->base + pos*Dynarr_elsize (dy), - (old_len - pos)*Dynarr_elsize (dy)); - } - /* Some functions call us with a value of 0 to mean "reserve space but - don't write into it" */ - if (base) - memcpy ((Rawbyte *) dy->base + pos*Dynarr_elsize (dy), base, - len*Dynarr_elsize (dy)); -} - -void -Dynarr_delete_many (void *d, Elemcount pos, Elemcount len) -{ - Dynarr *dy = Dynarr_verify_mod (d); - - dynarr_checking_assert (pos >= 0 && len >= 0 && - pos + len <= Dynarr_length (dy)); - - memmove ((Rawbyte *) dy->base + pos*Dynarr_elsize (dy), - (Rawbyte *) dy->base + (pos + len)*Dynarr_elsize (dy), - (Dynarr_length (dy) - pos - len)*Dynarr_elsize (dy)); - - Dynarr_set_length_1 (dy, Dynarr_length (dy) - len); -} - -void -Dynarr_free (void *d) -{ - Dynarr *dy = (Dynarr *) d; - -#ifdef NEW_GC - if (dy->base && !DUMPEDP (dy->base)) - { - if (!dy->lisp_imp) - xfree (dy->base); - } - if(!DUMPEDP (dy)) - { - if (!dy->lisp_imp) - xfree (dy); - } -#else /* not NEW_GC */ - if (dy->base && !DUMPEDP (dy->base)) - xfree (dy->base); - if(!DUMPEDP (dy)) - xfree (dy); -#endif /* not NEW_GC */ -} - -#ifdef MEMORY_USAGE_STATS - -/* Return memory usage for dynarr D. The returned value is the total - amount of bytes actually being used for the dynarr, including all - overhead. The extra amount of space in the dynarr that is - allocated beyond what was requested is returned in DYNARR_OVERHEAD - in STATS. The extra amount of space that malloc() allocates beyond - what was requested of it is returned in MALLOC_OVERHEAD in STATS. - See the comment above the definition of this structure. */ - -Bytecount -Dynarr_memory_usage (void *d, struct usage_stats *stats) -{ - Bytecount total = 0; - Dynarr *dy = (Dynarr *) d; - - /* We have to be a bit tricky here because not all of the - memory that malloc() will claim as "requested" was actually - requested. */ - - if (dy->base) - { - Bytecount malloc_used = - malloced_storage_size (dy->base, Dynarr_elsize (dy) * Dynarr_max (dy), - 0); - /* #### This may or may not be correct. Some dynarrs would - prefer that we use dy->len instead of dy->largest here. */ - Bytecount was_requested = Dynarr_elsize (dy) * Dynarr_largest (dy); - Bytecount dynarr_overhead = - Dynarr_elsize (dy) * (Dynarr_max (dy) - Dynarr_largest (dy)); - - total += malloc_used; - stats->was_requested += was_requested; - stats->dynarr_overhead += dynarr_overhead; - /* And the remainder must be malloc overhead. */ - stats->malloc_overhead += - malloc_used - was_requested - dynarr_overhead; - } - - total += malloced_storage_size (d, sizeof (*dy), stats); - - return total; -} - -#endif /* MEMORY_USAGE_STATS */ - -/* Version of malloc() that will be extremely efficient when allocation - nearly always occurs in LIFO (stack) order. - - #### Perhaps shouldn't be in this file, but where else? */ - -typedef struct -{ - Dynarr_declare (char_dynarr *); -} char_dynarr_dynarr; - -char_dynarr_dynarr *stack_like_free_list; -char_dynarr_dynarr *stack_like_in_use_list; - -void * -stack_like_malloc (Bytecount size) -{ - char_dynarr *this_one; - if (!stack_like_free_list) - { - stack_like_free_list = Dynarr_new2 (char_dynarr_dynarr, - char_dynarr *); - stack_like_in_use_list = Dynarr_new2 (char_dynarr_dynarr, - char_dynarr *); - } - - if (Dynarr_length (stack_like_free_list) > 0) - this_one = Dynarr_pop (stack_like_free_list); - else - this_one = Dynarr_new (char); - Dynarr_add (stack_like_in_use_list, this_one); - Dynarr_reset (this_one); - Dynarr_add_many (this_one, 0, size); - return Dynarr_begin (this_one); -} - -void -stack_like_free (void *val) -{ - Elemcount len = Dynarr_length (stack_like_in_use_list); - assert (len > 0); - /* The vast majority of times, we will be called in a last-in first-out - order, and the item at the end of the list will be the one we're - looking for, so just check for this first and avoid any function - calls. */ - if (Dynarr_begin (Dynarr_at (stack_like_in_use_list, len - 1)) == val) - { - char_dynarr *this_one = Dynarr_pop (stack_like_in_use_list); - Dynarr_add (stack_like_free_list, this_one); - } - else - { - /* Find the item and delete it. */ - int i; - assert (len >= 2); - for (i = len - 2; i >= 0; i--) - if (Dynarr_begin (Dynarr_at (stack_like_in_use_list, i)) == - val) - { - char_dynarr *this_one = Dynarr_at (stack_like_in_use_list, i); - Dynarr_add (stack_like_free_list, this_one); - Dynarr_delete (stack_like_in_use_list, i); - return; - } - - ABORT (); - } -}
--- a/src/elhash.c Fri Mar 26 15:06:28 2010 +0000 +++ b/src/elhash.c Mon Mar 29 00:11:03 2010 -0500 @@ -81,6 +81,7 @@ #include "lisp.h" #include "bytecode.h" #include "elhash.h" +#include "gc.h" #include "opaque.h" Lisp_Object Qhash_tablep; @@ -420,15 +421,16 @@ write_fmt_string (printcharfun, " 0x%x>", LISP_OBJECT_UID (obj)); } +#ifdef ERROR_CHECK_STRUCTURES +#define USED_IF_ERROR_CHECK_STRUCTURES(x) x +#else +#define USED_IF_ERROR_CHECK_STRUCTURES(x) UNUSED (x) +#endif + #ifndef NEW_GC static void free_hentries (htentry *hentries, -#ifdef ERROR_CHECK_STRUCTURES - Elemcount size -#else /* not ERROR_CHECK_STRUCTURES) */ - Elemcount UNUSED (size) -#endif /* not ERROR_CHECK_STRUCTURES) */ - ) + Elemcount USED_IF_ERROR_CHECK_STRUCTURES (size)) { #ifdef ERROR_CHECK_STRUCTURES /* Ensure a crash if other code uses the discarded entries afterwards. */ @@ -481,9 +483,9 @@ /* Note: XD_INDIRECT in this table refers to the surrounding table, and so this will work. */ #ifdef NEW_GC - { XD_LISP_OBJECT_BLOCK_PTR, HASH_TABLE_NON_WEAK, + { XD_INLINE_LISP_OBJECT_BLOCK_PTR, HASH_TABLE_NON_WEAK, XD_INDIRECT (0, 1), { &htentry_description } }, - { XD_LISP_OBJECT_BLOCK_PTR, 0, XD_INDIRECT (0, 1), + { XD_INLINE_LISP_OBJECT_BLOCK_PTR, 0, XD_INDIRECT (0, 1), { &htentry_weak_description }, XD_FLAG_UNION_DEFAULT_ENTRY }, #else /* not NEW_GC */ { XD_BLOCK_PTR, HASH_TABLE_NON_WEAK, XD_INDIRECT (0, 1), @@ -508,20 +510,12 @@ { XD_END } }; -#ifdef NEW_GC DEFINE_DUMPABLE_LISP_OBJECT ("hash-table", hash_table, mark_hash_table, print_hash_table, - 0, hash_table_equal, hash_table_hash, - hash_table_description, - Lisp_Hash_Table); -#else /* not NEW_GC */ -DEFINE_DUMPABLE_LISP_OBJECT ("hash-table", hash_table, - mark_hash_table, print_hash_table, - finalize_hash_table, + IF_OLD_GC (finalize_hash_table), hash_table_equal, hash_table_hash, hash_table_description, Lisp_Hash_Table); -#endif /* not NEW_GC */ static Lisp_Hash_Table * xhash_table (Lisp_Object hash_table) @@ -1558,7 +1552,7 @@ Lisp_Object mo_obj = (obj); \ if (!marked_p (mo_obj)) \ { \ - kkcc_gc_stack_push_lisp_object (mo_obj, 0, -1); \ + kkcc_gc_stack_push_lisp_object_0 (mo_obj); \ did_mark = 1; \ } \ } while (0)
--- a/src/emacs.c Fri Mar 26 15:06:28 2010 +0000 +++ b/src/emacs.c Mon Mar 29 00:11:03 2010 -0500 @@ -766,6 +766,7 @@ while (argv[elt]) { xfree (argv[elt]); + argv[elt] = 0; elt++; } xfree (argv); @@ -1508,6 +1509,7 @@ #ifdef NEW_GC syms_of_vdb (); #endif /* NEW_GC */ + syms_of_array (); syms_of_buffer (); syms_of_bytecode (); syms_of_callint (); @@ -1761,6 +1763,7 @@ ) { buffer_objects_create (); + casetab_objects_create (); extent_objects_create (); face_objects_create (); frame_objects_create (); @@ -1770,6 +1773,9 @@ #ifdef MULE mule_charset_objects_create (); #endif +#ifdef HAVE_SCROLLBARS + scrollbar_objects_create (); +#endif #ifdef HAVE_GTK ui_gtk_objects_create (); #endif @@ -2092,6 +2098,7 @@ vars_of_buffer (); vars_of_bytecode (); vars_of_callint (); + vars_of_casetab (); vars_of_chartab (); vars_of_cmdloop (); vars_of_cmds ();
--- a/src/emodules.c Fri Mar 26 15:06:28 2010 +0000 +++ b/src/emodules.c Mon Mar 29 00:11:03 2010 -0500 @@ -257,9 +257,13 @@ if (dll_close (modules[mod].dlhandle) == 0) { xfree (modules[mod].soname); + modules[mod].soname = 0; xfree (modules[mod].modname); + modules[mod].modname = 0; xfree (modules[mod].modver); + modules[mod].modver = 0; xfree (modules[mod].modtitle); + modules[mod].modtitle = 0; modules[mod].dlhandle = 0; modules[mod].used = 0; }
--- a/src/extents.c Fri Mar 26 15:06:28 2010 +0000 +++ b/src/extents.c Mon Mar 29 00:11:03 2010 -0500 @@ -231,88 +231,6 @@ #include "gutter.h" /* ------------------------------- */ -/* gap array */ -/* ------------------------------- */ - -/* Note that this object is not extent-specific and should perhaps be - moved into another file. */ - -/* Holds a marker that moves as elements in the array are inserted and - deleted, similar to standard markers. */ - -typedef struct gap_array_marker -{ -#ifdef NEW_GC - NORMAL_LISP_OBJECT_HEADER header; -#endif /* NEW_GC */ - int pos; - struct gap_array_marker *next; -} Gap_Array_Marker; - - -/* Holds a "gap array", which is an array of elements with a gap located - in it. Insertions and deletions with a high degree of locality - are very fast, essentially in constant time. Array positions as - used and returned in the gap array functions are independent of - the gap. */ - -/* Layout of gap array: - - <------ gap ------><---- gapsize ----><----- numels - gap ----> - <---------------------- numels + gapsize ---------------------> - - For marking purposes, we use two extra variables computed from - the others -- the offset to the data past the gap, plus the number - of elements in that data: - - offset_past_gap = elsize * (gap + gapsize) - els_past_gap = numels - gap -*/ - - -typedef struct gap_array -{ -#ifdef NEW_GC - NORMAL_LISP_OBJECT_HEADER header; -#endif /* NEW_GC */ - Elemcount gap; - Elemcount gapsize; - Elemcount numels; - Bytecount elsize; - /* Redundant numbers computed from the others, for marking purposes */ - Bytecount offset_past_gap; - Elemcount els_past_gap; - Gap_Array_Marker *markers; - /* this is a stretchy array */ - char array[1]; -} Gap_Array; - -#ifndef NEW_GC -static Gap_Array_Marker *gap_array_marker_freelist; -#endif /* not NEW_GC */ - -/* Convert a "memory position" (i.e. taking the gap into account) into - the address of the element at (i.e. after) that position. "Memory - positions" are only used internally and are of type Memxpos. - "Array positions" are used externally and are of type int. */ -#define GAP_ARRAY_MEMEL_ADDR(ga, memel) ((ga)->array + (ga)->elsize*(memel)) - -/* Number of elements currently in a gap array */ -#define GAP_ARRAY_NUM_ELS(ga) ((ga)->numels) - -#define GAP_ARRAY_ARRAY_TO_MEMORY_POS(ga, pos) \ - ((pos) <= (ga)->gap ? (pos) : (pos) + (ga)->gapsize) - -#define GAP_ARRAY_MEMORY_TO_ARRAY_POS(ga, pos) \ - ((pos) <= (ga)->gap ? (pos) : (pos) - (ga)->gapsize) - -/* Convert an array position into the address of the element at - (i.e. after) that position. */ -#define GAP_ARRAY_EL_ADDR(ga, pos) ((pos) < (ga)->gap ? \ - GAP_ARRAY_MEMEL_ADDR(ga, pos) : \ - GAP_ARRAY_MEMEL_ADDR(ga, (pos) + (ga)->gapsize)) - -/* ------------------------------- */ /* extent list */ /* ------------------------------- */ @@ -379,7 +297,7 @@ #define EXTENT_E_LESS_EQUAL(e1,e2) \ EXTENT_E_LESS_EQUAL_VALS (e1, extent_start (e2), extent_end (e2)) -#define EXTENT_GAP_ARRAY_AT(ga, pos) (* (EXTENT *) GAP_ARRAY_EL_ADDR(ga, pos)) +#define EXTENT_GAP_ARRAY_AT(ga, pos) gap_array_at (ga, pos, EXTENT) /* ------------------------------- */ /* buffer-extent primitives */ @@ -510,271 +428,6 @@ /************************************************************************/ -/* Generalized gap array */ -/************************************************************************/ - -/* This generalizes the "array with a gap" model used to store buffer - characters. This is based on the stuff in insdel.c and should - probably be merged with it. This is not extent-specific and should - perhaps be moved into a separate file. */ - -/* ------------------------------- */ -/* internal functions */ -/* ------------------------------- */ - -/* Adjust the gap array markers in the range (FROM, TO]. Parallel to - adjust_markers() in insdel.c. */ - -static void -gap_array_adjust_markers (Gap_Array *ga, Memxpos from, - Memxpos to, Elemcount amount) -{ - Gap_Array_Marker *m; - - for (m = ga->markers; m; m = m->next) - m->pos = do_marker_adjustment (m->pos, from, to, amount); -} - -static void -gap_array_recompute_derived_values (Gap_Array *ga) -{ - ga->offset_past_gap = ga->elsize * (ga->gap + ga->gapsize); - ga->els_past_gap = ga->numels - ga->gap; -} - -/* Move the gap to array position POS. Parallel to move_gap() in - insdel.c but somewhat simplified. */ - -static void -gap_array_move_gap (Gap_Array *ga, Elemcount pos) -{ - Elemcount gap = ga->gap; - Elemcount gapsize = ga->gapsize; - - if (pos < gap) - { - memmove (GAP_ARRAY_MEMEL_ADDR (ga, pos + gapsize), - GAP_ARRAY_MEMEL_ADDR (ga, pos), - (gap - pos)*ga->elsize); - gap_array_adjust_markers (ga, (Memxpos) pos, (Memxpos) gap, - gapsize); - } - else if (pos > gap) - { - memmove (GAP_ARRAY_MEMEL_ADDR (ga, gap), - GAP_ARRAY_MEMEL_ADDR (ga, gap + gapsize), - (pos - gap)*ga->elsize); - gap_array_adjust_markers (ga, (Memxpos) (gap + gapsize), - (Memxpos) (pos + gapsize), - gapsize); - } - ga->gap = pos; - - gap_array_recompute_derived_values (ga); -} - -/* Make the gap INCREMENT characters longer. Parallel to make_gap() in - insdel.c. The gap array may be moved, so assign the return value back - to the array pointer. */ - -static Gap_Array * -gap_array_make_gap (Gap_Array *ga, Elemcount increment) -{ - Elemcount real_gap_loc; - Elemcount old_gap_size; - - /* If we have to get more space, get enough to last a while. We use - a geometric progression that saves on realloc space. */ - increment += 100 + ga->numels / 8; - -#ifdef NEW_GC - ga = (Gap_Array *) mc_realloc (ga, - offsetof (Gap_Array, array) + - (ga->numels + ga->gapsize + increment) * - ga->elsize); -#else /* not NEW_GC */ - ga = (Gap_Array *) xrealloc (ga, - offsetof (Gap_Array, array) + - (ga->numels + ga->gapsize + increment) * - ga->elsize); -#endif /* not NEW_GC */ - if (ga == 0) - memory_full (); - - real_gap_loc = ga->gap; - old_gap_size = ga->gapsize; - - /* Call the newly allocated space a gap at the end of the whole space. */ - ga->gap = ga->numels + ga->gapsize; - ga->gapsize = increment; - - /* Move the new gap down to be consecutive with the end of the old one. - This adjusts the markers properly too. */ - gap_array_move_gap (ga, real_gap_loc + old_gap_size); - - /* Now combine the two into one large gap. */ - ga->gapsize += old_gap_size; - ga->gap = real_gap_loc; - - gap_array_recompute_derived_values (ga); - - return ga; -} - -/* ------------------------------- */ -/* external functions */ -/* ------------------------------- */ - -/* Insert NUMELS elements (pointed to by ELPTR) into the specified - gap array at POS. The gap array may be moved, so assign the - return value back to the array pointer. */ - -static Gap_Array * -gap_array_insert_els (Gap_Array *ga, Elemcount pos, void *elptr, - Elemcount numels) -{ - assert (pos >= 0 && pos <= ga->numels); - if (ga->gapsize < numels) - ga = gap_array_make_gap (ga, numels - ga->gapsize); - if (pos != ga->gap) - gap_array_move_gap (ga, pos); - - memcpy (GAP_ARRAY_MEMEL_ADDR (ga, ga->gap), (char *) elptr, - numels*ga->elsize); - ga->gapsize -= numels; - ga->gap += numels; - ga->numels += numels; - gap_array_recompute_derived_values (ga); - /* This is the equivalent of insert-before-markers. - - #### Should only happen if marker is "moves forward at insert" type. - */ - - gap_array_adjust_markers (ga, pos - 1, pos, numels); - return ga; -} - -/* Delete NUMELS elements from the specified gap array, starting at FROM. */ - -static void -gap_array_delete_els (Gap_Array *ga, Elemcount from, Elemcount numdel) -{ - Elemcount to = from + numdel; - Elemcount gapsize = ga->gapsize; - - assert (from >= 0); - assert (numdel >= 0); - assert (to <= ga->numels); - - /* Make sure the gap is somewhere in or next to what we are deleting. */ - if (to < ga->gap) - gap_array_move_gap (ga, to); - if (from > ga->gap) - gap_array_move_gap (ga, from); - - /* Relocate all markers pointing into the new, larger gap - to point at the end of the text before the gap. */ - gap_array_adjust_markers (ga, to + gapsize, to + gapsize, - - numdel - gapsize); - - ga->gapsize += numdel; - ga->numels -= numdel; - ga->gap = from; - gap_array_recompute_derived_values (ga); -} - -static Gap_Array_Marker * -gap_array_make_marker (Gap_Array *ga, Elemcount pos) -{ - Gap_Array_Marker *m; - - assert (pos >= 0 && pos <= ga->numels); -#ifdef NEW_GC - m = XGAP_ARRAY_MARKER (ALLOC_NORMAL_LISP_OBJECT (gap_array_marker)); -#else /* not NEW_GC */ - if (gap_array_marker_freelist) - { - m = gap_array_marker_freelist; - gap_array_marker_freelist = gap_array_marker_freelist->next; - } - else - m = xnew (Gap_Array_Marker); -#endif /* not NEW_GC */ - - m->pos = GAP_ARRAY_ARRAY_TO_MEMORY_POS (ga, pos); - m->next = ga->markers; - ga->markers = m; - return m; -} - -static void -gap_array_delete_marker (Gap_Array *ga, Gap_Array_Marker *m) -{ - Gap_Array_Marker *p, *prev; - - for (prev = 0, p = ga->markers; p && p != m; prev = p, p = p->next) - ; - assert (p); - if (prev) - prev->next = p->next; - else - ga->markers = p->next; -#ifndef NEW_GC - m->next = gap_array_marker_freelist; - m->pos = 0xDEADBEEF; /* -559038737 base 10 */ - gap_array_marker_freelist = m; -#endif /* not NEW_GC */ -} - -#ifndef NEW_GC -static void -gap_array_delete_all_markers (Gap_Array *ga) -{ - Gap_Array_Marker *p, *next; - - for (p = ga->markers; p; p = next) - { - next = p->next; - p->next = gap_array_marker_freelist; - p->pos = 0xDEADBEEF; /* -559038737 as an int */ - gap_array_marker_freelist = p; - } -} -#endif /* not NEW_GC */ - -static void -gap_array_move_marker (Gap_Array *ga, Gap_Array_Marker *m, Elemcount pos) -{ - assert (pos >= 0 && pos <= ga->numels); - m->pos = GAP_ARRAY_ARRAY_TO_MEMORY_POS (ga, pos); -} - -#define gap_array_marker_pos(ga, m) \ - GAP_ARRAY_MEMORY_TO_ARRAY_POS (ga, (m)->pos) - -static Gap_Array * -make_gap_array (Elemcount elsize) -{ -#ifdef NEW_GC - Gap_Array *ga = XGAP_ARRAY (ALLOC_SIZED_LISP_OBJECT (sizeof (Gap_Array), - gap_array)); -#else /* not NEW_GC */ - Gap_Array *ga = xnew_and_zero (Gap_Array); -#endif /* not NEW_GC */ - ga->elsize = elsize; - return ga; -} - -#ifndef NEW_GC -static void -free_gap_array (Gap_Array *ga) -{ - gap_array_delete_all_markers (ga); - xfree (ga); -} -#endif /* not NEW_GC */ - - -/************************************************************************/ /* Extent list primitives */ /************************************************************************/ @@ -791,7 +444,7 @@ */ /* Number of elements in an extent list */ -#define extent_list_num_els(el) GAP_ARRAY_NUM_ELS (el->start) +#define extent_list_num_els(el) gap_array_length (el->start) /* Return the position at which EXTENT is located in the specified extent list (in the display order if ENDP is 0, in the e-order otherwise). @@ -805,7 +458,7 @@ extent_list_locate (Extent_List *el, EXTENT extent, int endp, int *foundp) { Gap_Array *ga = endp ? el->end : el->start; - int left = 0, right = GAP_ARRAY_NUM_ELS (ga); + int left = 0, right = gap_array_length (ga); int oldfoundpos, foundpos; int found; @@ -825,7 +478,7 @@ /* Now we're at the beginning of all equal extents. */ found = 0; oldfoundpos = foundpos = left; - while (foundpos < GAP_ARRAY_NUM_ELS (ga)) + while (foundpos < gap_array_length (ga)) { EXTENT e = EXTENT_GAP_ARRAY_AT (ga, foundpos); if (e == extent) @@ -880,7 +533,7 @@ { Gap_Array *ga = endp ? el->end : el->start; - assert (pos >= 0 && pos < GAP_ARRAY_NUM_ELS (ga)); + assert (pos >= 0 && pos < gap_array_length (ga)); return EXTENT_GAP_ARRAY_AT (ga, pos); } @@ -917,8 +570,8 @@ static void extent_list_delete_all (Extent_List *el) { - gap_array_delete_els (el->start, 0, GAP_ARRAY_NUM_ELS (el->start)); - gap_array_delete_els (el->end, 0, GAP_ARRAY_NUM_ELS (el->end)); + gap_array_delete_els (el->start, 0, gap_array_length (el->start)); + gap_array_delete_els (el->end, 0, gap_array_length (el->end)); } static Extent_List_Marker * @@ -980,8 +633,8 @@ #else /* not NEW_GC */ Extent_List *el = xnew (Extent_List); #endif /* not NEW_GC */ - el->start = make_gap_array (sizeof (EXTENT)); - el->end = make_gap_array (sizeof (EXTENT)); + el->start = make_gap_array (sizeof (EXTENT), 1); + el->end = make_gap_array (sizeof (EXTENT), 1); el->markers = 0; return el; } @@ -1080,66 +733,7 @@ #endif /* not NEW_GC */ static void soe_invalidate (Lisp_Object obj); -extern const struct sized_memory_description gap_array_marker_description; - -static const struct memory_description gap_array_marker_description_1[] = { -#ifdef NEW_GC - { XD_LISP_OBJECT, offsetof (Gap_Array_Marker, next) }, -#else /* not NEW_GC */ - { XD_BLOCK_PTR, offsetof (Gap_Array_Marker, next), 1, - { &gap_array_marker_description } }, -#endif /* not NEW_GC */ - { XD_END } -}; - -#ifdef NEW_GC -DEFINE_NODUMP_INTERNAL_LISP_OBJECT ("gap-array-marker", gap_array_marker, - 0, gap_array_marker_description_1, - struct gap_array_marker); -#else /* not NEW_GC */ -const struct sized_memory_description gap_array_marker_description = { - sizeof (Gap_Array_Marker), - gap_array_marker_description_1 -}; -#endif /* not NEW_GC */ - -static const struct memory_description lispobj_gap_array_description_1[] = { - { XD_ELEMCOUNT, offsetof (Gap_Array, gap) }, - { XD_BYTECOUNT, offsetof (Gap_Array, offset_past_gap) }, - { XD_ELEMCOUNT, offsetof (Gap_Array, els_past_gap) }, -#ifdef NEW_GC - { XD_LISP_OBJECT, offsetof (Gap_Array, markers) }, -#else /* not NEW_GC */ - { XD_BLOCK_PTR, offsetof (Gap_Array, markers), 1, - { &gap_array_marker_description }, XD_FLAG_NO_KKCC }, -#endif /* not NEW_GC */ - { XD_BLOCK_ARRAY, offsetof (Gap_Array, array), XD_INDIRECT (0, 0), - { &lisp_object_description } }, - { XD_BLOCK_ARRAY, XD_INDIRECT (1, offsetof (Gap_Array, array)), - XD_INDIRECT (2, 0), { &lisp_object_description } }, - { XD_END } -}; - -#ifdef NEW_GC - -static Bytecount -size_gap_array (Lisp_Object obj) -{ - Gap_Array *ga = XGAP_ARRAY (obj); - return offsetof (Gap_Array, array) + (ga->numels + ga->gapsize) * ga->elsize; -} - -DEFINE_NODUMP_SIZABLE_INTERNAL_LISP_OBJECT ("gap-array", gap_array, - 0, - lispobj_gap_array_description_1, - size_gap_array, - struct gap_array); -#else /* not NEW_GC */ -static const struct sized_memory_description lispobj_gap_array_description = { - sizeof (Gap_Array), - lispobj_gap_array_description_1 -}; - +#ifndef NEW_GC extern const struct sized_memory_description extent_list_marker_description; #endif /* not NEW_GC */ @@ -1259,19 +853,13 @@ return Qnil; } -#ifdef NEW_GC -DEFINE_NODUMP_INTERNAL_LISP_OBJECT ("extent-info", extent_info, - mark_extent_info, - extent_info_description, - struct extent_info); -#else /* not NEW_GC */ +#ifndef NEW_GC + static void finalize_extent_info (Lisp_Object obj) { struct extent_info *data = XEXTENT_INFO (obj); - data->soe = 0; - data->extents = 0; if (data->soe) { free_soe (data->soe); @@ -1284,12 +872,13 @@ } } +#endif /* not NEW_GC */ + DEFINE_NODUMP_LISP_OBJECT ("extent-info", extent_info, mark_extent_info, internal_object_printer, - finalize_extent_info, 0, 0, + IF_OLD_GC (finalize_extent_info), 0, 0, extent_info_description, struct extent_info); -#endif /* not NEW_GC */ static Lisp_Object allocate_extent_info (void) @@ -7414,9 +7003,8 @@ #ifdef MEMORY_USAGE_STATS -int -compute_buffer_extent_usage (struct buffer *UNUSED (b), - struct usage_stats *UNUSED (ustats)) +Bytecount +compute_buffer_extent_usage (struct buffer *UNUSED (b)) { /* #### not yet written */ return 0; @@ -7445,8 +7033,6 @@ INIT_LISP_OBJECT (extent_info); INIT_LISP_OBJECT (extent_auxiliary); #ifdef NEW_GC - INIT_LISP_OBJECT (gap_array_marker); - INIT_LISP_OBJECT (gap_array); INIT_LISP_OBJECT (extent_list_marker); INIT_LISP_OBJECT (extent_list); INIT_LISP_OBJECT (stack_of_extents);
--- a/src/extents.h Fri Mar 26 15:06:28 2010 +0000 +++ b/src/extents.h Mon Mar 29 00:11:03 2010 -0500 @@ -50,25 +50,6 @@ #define CONCHECK_EXTENT_INFO(x) CONCHECK_RECORD (x, extent_info) #ifdef NEW_GC -struct gap_array_marker; - -DECLARE_LISP_OBJECT (gap_array_marker, struct gap_array_marker); -#define XGAP_ARRAY_MARKER(x) \ - XRECORD (x, gap_array_marker, struct gap_array_marker) -#define wrap_gap_array_marker(p) wrap_record (p, gap_array_marker) -#define GAP_ARRAY_MARKERP(x) RECORDP (x, gap_array_marker) -#define CHECK_GAP_ARRAY_MARKER(x) CHECK_RECORD (x, gap_array_marker) -#define CONCHECK_GAP_ARRAY_MARKER(x) CONCHECK_RECORD (x, gap_array_marker) - -struct gap_array; - -DECLARE_LISP_OBJECT (gap_array, struct gap_array); -#define XGAP_ARRAY(x) XRECORD (x, gap_array, struct gap_array) -#define wrap_gap_array(p) wrap_record (p, gap_array) -#define GAP_ARRAYP(x) RECORDP (x, gap_array) -#define CHECK_GAP_ARRAY(x) CHECK_RECORD (x, gap_array) -#define CONCHECK_GAP_ARRAY(x) CONCHECK_RECORD (x, gap_array) - struct extent_list_marker; DECLARE_LISP_OBJECT (extent_list_marker, struct extent_list_marker); @@ -237,8 +218,7 @@ #endif #ifdef MEMORY_USAGE_STATS -int compute_buffer_extent_usage (struct buffer *b, - struct usage_stats *ustats); +Bytecount compute_buffer_extent_usage (struct buffer *b); #endif #endif /* INCLUDED_extents_h_ */
--- a/src/file-coding.c Fri Mar 26 15:06:28 2010 +0000 +++ b/src/file-coding.c Mon Mar 29 00:11:03 2010 -0500 @@ -377,22 +377,13 @@ 0, coding_system_empty_extra_description_1 }; -#ifdef NEW_GC DEFINE_DUMPABLE_SIZABLE_LISP_OBJECT ("coding-system", coding_system, mark_coding_system, print_coding_system, - 0, 0, 0, coding_system_description, - sizeof_coding_system, - Lisp_Coding_System); -#else /* not NEW_GC */ -DEFINE_DUMPABLE_SIZABLE_LISP_OBJECT ("coding-system", coding_system, - mark_coding_system, - print_coding_system, - finalize_coding_system, + IF_OLD_GC (finalize_coding_system), 0, 0, coding_system_description, sizeof_coding_system, Lisp_Coding_System); -#endif /* not NEW_GC */ /************************************************************************/ /* Creating coding systems */ @@ -2713,6 +2704,7 @@ Lstream_delete (XLSTREAM ((data->lstreams)[i])); } xfree (data->lstreams); + data->lstreams = 0; } }
--- a/src/gc.c Fri Mar 26 15:06:28 2010 +0000 +++ b/src/gc.c Mon Mar 29 00:11:03 2010 -0500 @@ -381,9 +381,9 @@ 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 defined (USE_KKCC) && defined (DEBUG_XEMACS) if (gc_in_progress) - kkcc_backtrace (); + kkcc_detailed_backtrace (); #endif #ifdef PDUMP if (in_pdump) @@ -436,7 +436,7 @@ case XD_OPAQUE_PTR: return sizeof (void *); #ifdef NEW_GC - case XD_LISP_OBJECT_BLOCK_PTR: + case XD_INLINE_LISP_OBJECT_BLOCK_PTR: #endif /* NEW_GC */ case XD_BLOCK_PTR: { @@ -557,8 +557,13 @@ EMACS_INT offset = lispdesc_indirect_count (desc[pos].offset, desc, obj); if (offset == max_offset) { +#if 0 + /* This can legitimately happen with gap arrays -- if there are + no elements in the array, and the gap size is 0, then both + parts of the array will be of size 0 and in the same place. */ stderr_out ("Two relocatable elements at same offset?\n"); ABORT (); +#endif } else if (offset > max_offset) { @@ -611,6 +616,7 @@ void *obj; const struct memory_description *desc; int pos; + int is_lisp; } kkcc_bt_stack_entry; static kkcc_bt_stack_entry *kkcc_bt; @@ -632,25 +638,33 @@ } } +/* Workhorse backtrace function. Not static because may potentially be + called from a debugger. */ + +void kkcc_backtrace_1 (int size, int detailed); void -kkcc_backtrace (void) +kkcc_backtrace_1 (int size, int detailed) { int i; stderr_out ("KKCC mark stack backtrace :\n"); - for (i = kkcc_bt_depth - 1; i >= 0; i--) + for (i = kkcc_bt_depth - 1; i >= kkcc_bt_depth - size && i >= 0; i--) { Lisp_Object obj = wrap_pointer_1 (kkcc_bt[i].obj); - stderr_out (" [%d]", i); - if ((XRECORD_LHEADER (obj)->type >= lrecord_type_last_built_in_type) - || (!LRECORDP (obj)) - || (!XRECORD_LHEADER_IMPLEMENTATION (obj))) + stderr_out (" [%d] ", i); + if (!kkcc_bt[i].is_lisp) + stderr_out ("non Lisp Object"); + else if (!LRECORDP (obj)) + stderr_out ("Lisp Object, non-record"); + else if (XRECORD_LHEADER (obj)->type >= lrecord_type_last_built_in_type + || (!XRECORD_LHEADER_IMPLEMENTATION (obj))) + stderr_out ("WARNING! Bad Lisp Object type %d", + XRECORD_LHEADER (obj)->type); + else + stderr_out ("%s", XRECORD_LHEADER_IMPLEMENTATION (obj)->name); + if (detailed && kkcc_bt[i].is_lisp) { - stderr_out (" non Lisp Object"); - } - else - { - stderr_out (" %s", - XRECORD_LHEADER_IMPLEMENTATION (obj)->name); + stderr_out (" "); + debug_print (obj); } stderr_out (" (addr: %p, desc: %p, ", (void *) kkcc_bt[i].obj, @@ -665,6 +679,76 @@ } } +/* Various front ends onto kkcc_backtrace_1(), meant to be called from + a debugger. + + The variants are: + + normal vs _full(): Normal displays up to the topmost 100 items on the + stack, whereas full displays all items (even if there are thousands) + + _detailed_() vs _short_(): Detailed here means print out the actual + Lisp objects on the stack using debug_print() in addition to their type, + whereas short means only show the type +*/ + +void +kkcc_detailed_backtrace (void) +{ + kkcc_backtrace_1 (100, 1); +} + +void kkcc_short_backtrace (void); +void +kkcc_short_backtrace (void) +{ + kkcc_backtrace_1 (100, 0); +} + +void kkcc_detailed_backtrace_full (void); +void +kkcc_detailed_backtrace_full (void) +{ + kkcc_backtrace_1 (kkcc_bt_depth, 1); +} + +void kkcc_short_backtrace_full (void); +void +kkcc_short_backtrace_full (void) +{ + kkcc_backtrace_1 (kkcc_bt_depth, 0); +} + +/* Short versions for ease in calling from a debugger */ + +void kbt (void); +void +kbt (void) +{ + kkcc_detailed_backtrace (); +} + +void kbts (void); +void +kbts (void) +{ + kkcc_short_backtrace (); +} + +void kbtf (void); +void +kbtf (void) +{ + kkcc_detailed_backtrace_full (); +} + +void kbtsf (void); +void +kbtsf (void) +{ + kkcc_short_backtrace_full (); +} + static void kkcc_bt_stack_realloc (void) { @@ -688,13 +772,14 @@ } static void -kkcc_bt_push (void *obj, const struct memory_description *desc, - int level, int pos) +kkcc_bt_push (void *obj, const struct memory_description *desc, + int is_lisp DECLARE_KKCC_DEBUG_ARGS) { 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[kkcc_bt_depth].is_lisp = is_lisp; kkcc_bt_depth++; if (kkcc_bt_depth >= kkcc_bt_stack_size) kkcc_bt_stack_realloc (); @@ -702,7 +787,7 @@ #else /* not DEBUG_XEMACS */ #define kkcc_bt_init() -#define kkcc_bt_push(obj, desc, level, pos) +#define kkcc_bt_push(obj, desc) #endif /* not DEBUG_XEMACS */ /* Object memory descriptions are in the lrecord_implementation structure. @@ -719,6 +804,7 @@ #ifdef DEBUG_XEMACS int level; int pos; + int is_lisp; #endif } kkcc_gc_stack_entry; @@ -794,12 +880,8 @@ } 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 +kkcc_gc_stack_push (void *data, const struct memory_description *desc + DECLARE_KKCC_DEBUG_ARGS) { #ifdef NEW_GC GC_STAT_ENQUEUED; @@ -816,12 +898,44 @@ } #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 inline void +kkcc_gc_stack_push_0 (void *data, const struct memory_description *desc, + int is_lisp DECLARE_KKCC_DEBUG_ARGS) +{ + kkcc_gc_stack_push (data, desc KKCC_DEBUG_ARGS); + kkcc_gc_stack_ptr[kkcc_gc_stack_rear].is_lisp = is_lisp; +} + +static inline void +kkcc_gc_stack_push_lisp (void *data, const struct memory_description *desc + DECLARE_KKCC_DEBUG_ARGS) +{ + kkcc_gc_stack_push_0 (data, desc, 1 KKCC_DEBUG_ARGS); +} + +static inline void +kkcc_gc_stack_push_nonlisp (void *data, const struct memory_description *desc + DECLARE_KKCC_DEBUG_ARGS) +{ + kkcc_gc_stack_push_0 (data, desc, 0 KKCC_DEBUG_ARGS); +} + +#else /* not DEBUG_XEMACS */ + +static inline void +kkcc_gc_stack_push_lisp (void *data, const struct memory_description *desc) +{ + kkcc_gc_stack_push (data, desc); +} + +static inline void +kkcc_gc_stack_push_nonlisp (void *data, const struct memory_description *desc) +{ + kkcc_gc_stack_push (data, desc); +} + +#endif /* (not) DEBUG_XEMACS */ static kkcc_gc_stack_entry * kkcc_gc_stack_pop (void) @@ -845,11 +959,7 @@ } 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 +kkcc_gc_stack_push_lisp_object (Lisp_Object obj DECLARE_KKCC_DEBUG_ARGS) { if (XTYPE (obj) == Lisp_Type_Record) { @@ -864,26 +974,15 @@ #else /* not NEW_GC */ MARK_RECORD_HEADER (lheader); #endif /* not NEW_GC */ - kkcc_gc_stack_push ((void *) lheader, desc, level, pos); + kkcc_gc_stack_push_lisp ((void *) lheader, desc KKCC_DEBUG_ARGS); } } } #ifdef NEW_GC -#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 void -#ifdef DEBUG_XEMACS -kkcc_gc_stack_repush_dirty_object_1 (Lisp_Object obj, int level, int pos) -#else -kkcc_gc_stack_repush_dirty_object_1 (Lisp_Object obj) -#endif +kkcc_gc_stack_repush_dirty_object (Lisp_Object obj DECLARE_KKCC_DEBUG_ARGS) { if (XTYPE (obj) == Lisp_Type_Record) { @@ -893,7 +992,7 @@ GC_CHECK_LHEADER_INVARIANTS (lheader); desc = RECORD_DESCRIPTION (lheader); MARK_GREY (lheader); - kkcc_gc_stack_push ((void*) lheader, desc, level, pos); + kkcc_gc_stack_push_lisp ((void*) lheader, desc KKCC_DEBUG_ARGS); } } #endif /* NEW_GC */ @@ -909,48 +1008,23 @@ } \ } while (0) #else -#define KKCC_DO_CHECK_FREE(obj, allow_free) +#define KKCC_DO_CHECK_FREE(obj, allow_free) DO_NOTHING #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 +static inline void +mark_object_maybe_checking_free (Lisp_Object obj, int allow_free + DECLARE_KKCC_DEBUG_ARGS) { KKCC_DO_CHECK_FREE (obj, allow_free); - kkcc_gc_stack_push_lisp_object (obj, level, pos); + kkcc_gc_stack_push_lisp_object (obj KKCC_DEBUG_ARGS); } -#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, +mark_struct_contents (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 count DECLARE_KKCC_DEBUG_ARGS) { int i; Bytecount elsize; @@ -958,33 +1032,19 @@ for (i = 0; i < count; i++) { - kkcc_gc_stack_push (((char *) data) + elsize * i, sdesc->description, - level, pos); + kkcc_gc_stack_push_nonlisp (((char *) data) + elsize * i, + sdesc->description + KKCC_DEBUG_ARGS); } } -#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 - - #ifdef NEW_GC /* This function loops all elements of a struct pointer and calls mark_with_description with each element. */ static void -#ifdef DEBUG_XEMACS -mark_lisp_object_block_contents_1 (const void *data, - const struct sized_memory_description *sdesc, - int count, int level, int pos) -#else -mark_lisp_object_block_contents_1 (const void *data, - const struct sized_memory_description *sdesc, - int count) -#endif +mark_lisp_object_block_contents (const void *data, + const struct sized_memory_description *sdesc, + int count DECLARE_KKCC_DEBUG_ARGS) { int i; Bytecount elsize; @@ -1002,19 +1062,12 @@ if (! MARKED_RECORD_HEADER_P (lheader)) { MARK_GREY (lheader); - kkcc_gc_stack_push ((void *) lheader, desc, level, pos); + kkcc_gc_stack_push_lisp ((void *) lheader, desc KKCC_DEBUG_ARGS); } } } } -#ifdef DEBUG_XEMACS -#define mark_lisp_object_block_contents(data, sdesc, count, level, pos) \ - mark_lisp_object_block_contents_1 (data, sdesc, count, level, pos) -#else -#define mark_lisp_object_block_contents(data, sdesc, count, level, pos) \ - mark_lisp_object_block_contents_1 (data, sdesc, count) -#endif #endif /* not NEW_GC */ /* This function implements the KKCC mark algorithm. @@ -1041,8 +1094,11 @@ desc = stack_entry->desc; #ifdef DEBUG_XEMACS level = stack_entry->level + 1; + kkcc_bt_push (data, desc, stack_entry->is_lisp, stack_entry->level, + stack_entry->pos); +#else + kkcc_bt_push (data, desc); #endif - kkcc_bt_push (data, desc, stack_entry->level, stack_entry->pos); #ifdef NEW_GC /* Mark black if object is currently grey. This first checks, @@ -1093,11 +1149,12 @@ if (EQ (*stored_obj, Qnull_pointer)) break; #ifdef NEW_GC - mark_object_maybe_checking_free (*stored_obj, 0, level, pos); + mark_object_maybe_checking_free (*stored_obj, 0 + KKCC_DEBUG_ARGS); #else /* not NEW_GC */ mark_object_maybe_checking_free - (*stored_obj, (desc1->flags) & XD_FLAG_FREE_LISP_OBJECT, - level, pos); + (*stored_obj, (desc1->flags) & XD_FLAG_FREE_LISP_OBJECT + KKCC_DEBUG_ARGS); #endif /* not NEW_GC */ break; } @@ -1116,17 +1173,17 @@ break; #ifdef NEW_GC mark_object_maybe_checking_free - (*stored_obj, 0, level, pos); + (*stored_obj, 0 KKCC_DEBUG_ARGS); #else /* not NEW_GC */ mark_object_maybe_checking_free - (*stored_obj, (desc1->flags) & XD_FLAG_FREE_LISP_OBJECT, - level, pos); + (*stored_obj, (desc1->flags) & XD_FLAG_FREE_LISP_OBJECT + KKCC_DEBUG_ARGS); #endif /* not NEW_GC */ } break; } #ifdef NEW_GC - case XD_LISP_OBJECT_BLOCK_PTR: + case XD_INLINE_LISP_OBJECT_BLOCK_PTR: { EMACS_INT count = lispdesc_indirect_count (desc1->data1, desc, data); @@ -1135,7 +1192,7 @@ const char *dobj = * (const char **) rdata; if (dobj) mark_lisp_object_block_contents - (dobj, sdesc, count, level, pos); + (dobj, sdesc, count KKCC_DEBUG_ARGS); break; } #endif /* NEW_GC */ @@ -1147,7 +1204,7 @@ lispdesc_indirect_description (data, desc1->data2.descr); const char *dobj = * (const char **) rdata; if (dobj) - mark_struct_contents (dobj, sdesc, count, level, pos); + mark_struct_contents (dobj, sdesc, count KKCC_DEBUG_ARGS); break; } case XD_BLOCK_ARRAY: @@ -1157,7 +1214,7 @@ const struct sized_memory_description *sdesc = lispdesc_indirect_description (data, desc1->data2.descr); - mark_struct_contents (rdata, sdesc, count, level, pos); + mark_struct_contents (rdata, sdesc, count KKCC_DEBUG_ARGS); break; } case XD_UNION: @@ -1169,7 +1226,7 @@ default: stderr_out ("Unsupported description type : %d\n", desc1->type); - kkcc_backtrace (); + kkcc_detailed_backtrace (); ABORT (); } } @@ -1392,7 +1449,7 @@ } /* Keep objects alive that need to be finalized by marking Vfinalizers_to_run transitively. */ - kkcc_gc_stack_push_lisp_object (Vfinalizers_to_run, 0, -1); + kkcc_gc_stack_push_lisp_object_0 (Vfinalizers_to_run); kkcc_marking (0); } @@ -1614,7 +1671,7 @@ /* Mark all the special slots that serve as the roots of accessibility. */ #ifdef USE_KKCC -# define mark_object(obj) kkcc_gc_stack_push_lisp_object (obj, 0, -1) +# define mark_object(obj) kkcc_gc_stack_push_lisp_object_0 (obj) #endif /* USE_KKCC */ { /* staticpro() */
--- a/src/gc.h Fri Mar 26 15:06:28 2010 +0000 +++ b/src/gc.h Mon Mar 29 00:11:03 2010 -0500 @@ -1,5 +1,6 @@ /* New incremental garbage collector for XEmacs. Copyright (C) 2005 Marcus Crestani. + Copyright (C) 2010 Ben Wing. This file is part of XEmacs. @@ -106,31 +107,42 @@ void recompute_need_to_garbage_collect (void); +#ifdef DEBUG_XEMACS +#define KKCC_DEBUG_ARGS , level, pos +#define DECLARE_KKCC_DEBUG_ARGS , int level, int pos +#else +#define KKCC_DEBUG_ARGS +#define DECLARE_KKCC_DEBUG_ARGS +#endif + /* KKCC mark algorithm. */ +void kkcc_gc_stack_push_lisp_object (Lisp_Object obj DECLARE_KKCC_DEBUG_ARGS); +void kkcc_gc_stack_repush_dirty_object (Lisp_Object obj + DECLARE_KKCC_DEBUG_ARGS); + #ifdef DEBUG_XEMACS -void kkcc_gc_stack_push_lisp_object_1 (Lisp_Object obj, int level, int pos); -#define kkcc_gc_stack_push_lisp_object(obj, level, pos) \ - kkcc_gc_stack_push_lisp_object_1 (obj, level, pos) -void kkcc_gc_stack_repush_dirty_object_1 (Lisp_Object obj, int level, int pos); -#define kkcc_gc_stack_repush_dirty_object(obj) \ - kkcc_gc_stack_repush_dirty_object_1 (obj, 0, -2) -void kkcc_backtrace (void); +#define kkcc_gc_stack_push_lisp_object_0(obj) \ + kkcc_gc_stack_push_lisp_object (obj, 0, -1) +void kkcc_backtrace_1 (int size, int detailed); +void kkcc_short_backtrace (void); +void kkcc_detailed_backtrace (void); +void kkcc_short_backtrace_full (void); +void kkcc_detailed_backtrace_full (void); #else -void kkcc_gc_stack_push_lisp_object_1 (Lisp_Object obj); -#define kkcc_gc_stack_push_lisp_object(obj, level, pos) \ - kkcc_gc_stack_push_lisp_object_1 (obj) -void kkcc_gc_stack_repush_dirty_object_1 (Lisp_Object obj); -#define kkcc_gc_stack_repush_dirty_object(obj) \ - kkcc_gc_stack_repush_dirty_object_1 (obj) -#define kkcc_backtrace() +#define kkcc_gc_stack_push_lisp_object_0(obj) \ + kkcc_gc_stack_push_lisp_object (obj) +#define kkcc_detailed_backtrace() #endif #ifdef NEW_GC /* Repush objects that are caught by the write barrier. */ -#define gc_write_barrier(obj) kkcc_gc_stack_repush_dirty_object (obj); - +#ifdef DEBUG_XEMACS +#define gc_write_barrier(obj) kkcc_gc_stack_repush_dirty_object (obj, 0, -2) +#else +#define gc_write_barrier(obj) kkcc_gc_stack_repush_dirty_object (obj) +#endif /* GC functions: */
--- a/src/glyphs-eimage.c Fri Mar 26 15:06:28 2010 +0000 +++ b/src/glyphs-eimage.c Mon Mar 29 00:11:03 2010 -0500 @@ -2,7 +2,7 @@ Copyright (C) 1993, 1994, 1998 Free Software Foundation, Inc. Copyright (C) 1995 Board of Trustees, University of Illinois. Copyright (C) 1995 Tinker Systems - Copyright (C) 1995, 1996, 2001, 2002, 2004, 2005 Ben Wing + Copyright (C) 1995, 1996, 2001, 2002, 2004, 2005, 2010 Ben Wing Copyright (C) 1995 Sun Microsystems This file is part of XEmacs. @@ -177,10 +177,16 @@ jpeg_destroy_decompress (data->cinfo_ptr); if (data->instream) - retry_fclose (data->instream); + { + retry_fclose (data->instream); + data->instream = 0; + } if (data->eimage) - xfree (data->eimage); + { + xfree (data->eimage); + data->eimage = 0; + } return Qnil; } @@ -577,10 +583,14 @@ if (data->giffile) { DGifCloseFile (data->giffile); - FreeSavedImages(data->giffile); + FreeSavedImages (data->giffile); + data->giffile = 0; } if (data->eimage) - xfree (data->eimage); + { + xfree (data->eimage); + data->eimage = 0; + } return Qnil; } @@ -878,10 +888,16 @@ } if (data->instream) - retry_fclose (data->instream); + { + retry_fclose (data->instream); + data->instream = 0; + } if (data->eimage) - xfree (data->eimage); + { + xfree (data->eimage); + data->eimage = 0; + } return Qnil; } @@ -1134,10 +1150,14 @@ free_opaque_ptr (unwind_obj); if (data->tiff) { - TIFFClose(data->tiff); + TIFFClose (data->tiff); + data->tiff = 0; } if (data->eimage) - xfree (data->eimage); + { + xfree (data->eimage); + data->eimage = 0; + } return Qnil; }
--- a/src/imgproc.c Fri Mar 26 15:06:28 2010 +0000 +++ b/src/imgproc.c Mon Mar 29 00:11:03 2010 -0500 @@ -27,6 +27,7 @@ Copyright (c) 1988-1997 Sam Leffler Copyright (c) 1991-1997 Silicon Graphics, Inc. + Copyright (C) 2010 Ben Wing. Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided @@ -551,8 +552,12 @@ /* 5c: done with ColorCells */ for (i = 0; i < C_LEN*C_LEN*C_LEN; i++) if (qt->ColorCells[i]) - xfree (qt->ColorCells[i]); + { + xfree (qt->ColorCells[i]); + qt->ColorCells[i] = 0; + } xfree (qt->ColorCells); + qt->ColorCells = 0; if (res) {
--- a/src/insdel.c Fri Mar 26 15:06:28 2010 +0000 +++ b/src/insdel.c Mon Mar 29 00:11:03 2010 -0500 @@ -1838,8 +1838,10 @@ { BUFFER_FREE (b->text->beg); xfree (b->text->changes); + b->text->changes = 0; } xfree (b->changes); + b->changes = 0; #ifdef REGION_CACHE_NEEDS_WORK if (b->newline_cache)
--- a/src/lisp.h Fri Mar 26 15:06:28 2010 +0000 +++ b/src/lisp.h Mon Mar 29 00:11:03 2010 -0500 @@ -1619,6 +1619,18 @@ Bytecount gap_overhead; }; +/* Generic version of usage stats structure including extra non-Lisp and + Lisp storage associated with the object, but not including the memory + used to hold the object itself. Up to 32 statistics are allowed, + in addition to the statistics in `U', which store another slice onto the + ancillary non-Lisp storage. + + Normally, each object creates its own version of this structure, e.g. + `struct window_stats', which parallels the structure in beginning with + a `struct usage_stats' and followed by Bytecount fields, so that a + pointer to that structure can be cast to a pointer of this structure + and sensible results gotten. */ + struct generic_usage_stats { struct usage_stats u; @@ -1732,583 +1744,10 @@ } /************************************************************************/ -/** Definitions of dynamic arrays (dynarrs) and other allocators **/ +/** Definitions of dynarrs and other allocators **/ /************************************************************************/ -BEGIN_C_DECLS - -/************* Dynarr declaration *************/ - -#ifdef NEW_GC -#define DECLARE_DYNARR_LISP_IMP() \ - const struct lrecord_implementation *lisp_imp; -#else -#define DECLARE_DYNARR_LISP_IMP() -#endif - -#ifdef ERROR_CHECK_DYNARR -#define DECLARE_DYNARR_LOCKED() \ - int locked; -#else -#define DECLARE_DYNARR_LOCKED() -#endif - -#define Dynarr_declare(type) \ - struct lrecord_header header; \ - type *base; \ - DECLARE_DYNARR_LISP_IMP () \ - DECLARE_DYNARR_LOCKED () \ - int elsize_; \ - int len_; \ - int largest_; \ - int max_ - -typedef struct dynarr -{ - Dynarr_declare (void); -} Dynarr; - -#define XD_DYNARR_DESC(base_type, sub_desc) \ - { XD_BLOCK_PTR, offsetof (base_type, base), \ - XD_INDIRECT(1, 0), {sub_desc} }, \ - { XD_INT, offsetof (base_type, len_) }, \ - { XD_INT_RESET, offsetof (base_type, largest_), XD_INDIRECT(1, 0) }, \ - { XD_INT_RESET, offsetof (base_type, max_), XD_INDIRECT(1, 0) } - -#ifdef NEW_GC -#define XD_LISP_DYNARR_DESC(base_type, sub_desc) \ - { XD_LISP_OBJECT_BLOCK_PTR, offsetof (base_type, base), \ - XD_INDIRECT(1, 0), {sub_desc} }, \ - { XD_INT, offsetof (base_type, len_) }, \ - { XD_INT_RESET, offsetof (base_type, largest_), XD_INDIRECT(1, 0) }, \ - { XD_INT_RESET, offsetof (base_type, max_), XD_INDIRECT(1, 0) } -#endif /* NEW_GC */ - -/************* Dynarr verification *************/ - -/* Dynarr locking and verification. - - [I] VERIFICATION - - Verification routines simply return their basic argument, possibly - casted, but in the process perform some verification on it, aborting if - the verification fails. The verification routines take FILE and LINE - parameters, and use them to output the file and line of the caller - when an abort occurs, rather than the file and line of the inline - function, which is less than useful. - - There are three basic types of verification routines: - - (1) Verify the dynarr itself. This verifies the basic invariant - involving the length/size values: - - 0 <= Dynarr_length(d) <= Dynarr_largest(d) <= Dynarr_max(d) - - (2) Verify the dynarr itself prior to modifying it. This performs - the same verification as previously, but also checks that the - dynarr is not locked (see below). - - (3) Verify a dynarr position. Unfortunately we have to have - different verification routines depending on which kind of operation - is being performed: - - (a) For Dynarr_at(), we check that the POS is bounded by Dynarr_largest(), - i.e. 0 <= POS < Dynarr_largest(). - (b) For Dynarr_atp_allow_end(), we also have to allow - POS == Dynarr_largest(). - (c) For Dynarr_atp(), we behave largely like Dynarr_at() but make a - special exception when POS == 0 and Dynarr_largest() == 0 -- see - comment below. - (d) Some other routines contain the POS verification within their code, - and make the check 0 <= POS < Dynarr_length() or - 0 <= POS <= Dynarr_length(). - - #### It is not well worked-out whether and in what circumstances it's - allowed to use a position that is between Dynarr_length() and - Dynarr_largest(). The ideal solution is to never allow this, and require - instead that code first change the length before accessing higher - positions. That would require looking through all the code that accesses - dynarrs and fixing it appropriately (especially redisplay code, and - especially redisplay code in the vicinity of a reference to - Dynarr_largest(), since such code usually checks explicitly to see whether - there is extra stuff between Dynarr_length() and Dynarr_largest().) - - [II] LOCKING - - The idea behind dynarr locking is simple: Locking a dynarr prevents - any modification from occurring, or rather, leads to an abort upon - any attempt to modify a dynarr. - - Dynarr locking was originally added to catch some sporadic and hard-to- - debug crashes in the redisplay code where dynarrs appeared to be getting - corrupted in an unexpected fashion. The solution was to lock the - dynarrs that were getting corrupted (in this case, the display-line - dynarrs) around calls to routines that weren't supposed to be changing - these dynarrs but might somehow be calling code that modified them. - This eventually revealed that there was a reentrancy problem with - redisplay that involved the QUIT mechanism and the processing done in - order to determine whether C-g had been pressed -- this processing - involves retrieving, processing and queueing pending events to see - whether any of them result in a C-g keypress. However, at least under - MS Windows this can result in redisplay being called reentrantly. - For more info:-- - - (Info-goto-node "(internals)Critical Redisplay Sections") - -*/ - -#ifdef ERROR_CHECK_DYNARR -DECLARE_INLINE_HEADER ( -int -Dynarr_verify_pos_at (void *d, Elemcount pos, const Ascbyte *file, int line) -) -{ - Dynarr *dy = (Dynarr *) d; - /* We use `largest', not `len', because the redisplay code often - accesses stuff between len and largest. */ - assert_at_line (pos >= 0 && pos < dy->largest_, file, line); - return pos; -} - -DECLARE_INLINE_HEADER ( -int -Dynarr_verify_pos_atp (void *d, Elemcount pos, const Ascbyte *file, int line) -) -{ - Dynarr *dy = (Dynarr *) d; - /* We use `largest', not `len', because the redisplay code often - accesses stuff between len and largest. */ - /* [[ Code will often do something like ... - - val = make_bit_vector_from_byte_vector (Dynarr_atp (dyn, 0), - Dynarr_length (dyn)); - - which works fine when the Dynarr_length is non-zero, but when zero, - the result of Dynarr_atp() not only points past the end of the - allocated array, but the array may not have ever been allocated and - hence the return value is NULL. But the length of 0 causes the - pointer to never get checked. These can occur throughout the code - so we put in a special check. --ben ]] - - Update: The common idiom `Dynarr_atp (dyn, 0)' has been changed to - `Dynarr_begin (dyn)'. Possibly this special check at POS 0 can be - done only for Dynarr_begin() not for general Dynarr_atp(). --ben */ - if (pos == 0 && dy->len_ == 0) - return pos; - /* #### It's vaguely possible that some code could legitimately want to - retrieve a pointer to the position just past the end of dynarr memory. - This could happen with Dynarr_atp() but not Dynarr_at(). If so, it - will trigger this assert(). In such cases, it should be obvious that - the code wants to do this; rather than relaxing the assert, we should - probably create a new macro Dynarr_atp_allow_end() which is like - Dynarr_atp() but which allows for pointing at invalid addresses -- we - really want to check for cases of accessing just past the end of - memory, which is a likely off-by-one problem to occur and will usually - not trigger a protection fault (instead, you'll just get random - behavior, possibly overwriting other memory, which is bad). --ben */ - assert_at_line (pos >= 0 && pos < dy->largest_, file, line); - return pos; -} - -DECLARE_INLINE_HEADER ( -int -Dynarr_verify_pos_atp_allow_end (void *d, Elemcount pos, const Ascbyte *file, - int line) -) -{ - Dynarr *dy = (Dynarr *) d; - /* We use `largest', not `len', because the redisplay code often - accesses stuff between len and largest. - We also allow referencing the very end, past the end of allocated - legitimately space. See comments in Dynarr_verify_pos_atp.()*/ - assert_at_line (pos >= 0 && pos <= dy->largest_, file, line); - return pos; -} - -#else -#define Dynarr_verify_pos_at(d, pos, file, line) (pos) -#define Dynarr_verify_pos_atp(d, pos, file, line) (pos) -#define Dynarr_verify_pos_atp_allow_end(d, pos, file, line) (pos) -#endif /* ERROR_CHECK_DYNARR */ - -#ifdef ERROR_CHECK_DYNARR -DECLARE_INLINE_HEADER ( -Dynarr * -Dynarr_verify_1 (void *d, const Ascbyte *file, int line) -) -{ - Dynarr *dy = (Dynarr *) d; - assert_at_line (dy->len_ >= 0 && dy->len_ <= dy->largest_ && - dy->largest_ <= dy->max_, file, line); - return dy; -} - -DECLARE_INLINE_HEADER ( -Dynarr * -Dynarr_verify_mod_1 (void *d, const Ascbyte *file, int line) -) -{ - Dynarr *dy = (Dynarr *) d; - assert_at_line (!dy->locked, file, line); - return Dynarr_verify_1 (d, file, line); -} - -#define Dynarr_verify(d) Dynarr_verify_1 (d, __FILE__, __LINE__) -#define Dynarr_verify_mod(d) Dynarr_verify_mod_1 (d, __FILE__, __LINE__) - -DECLARE_INLINE_HEADER ( -void -Dynarr_lock (void *d) -) -{ - Dynarr *dy = Dynarr_verify_mod (d); - dy->locked = 1; -} - -DECLARE_INLINE_HEADER ( -void -Dynarr_unlock (void *d) -) -{ - Dynarr *dy = Dynarr_verify (d); - assert (dy->locked); - dy->locked = 0; -} - -#else /* not ERROR_CHECK_DYNARR */ - -#define Dynarr_verify(d) ((Dynarr *) d) -#define Dynarr_verify_mod(d) ((Dynarr *) d) -#define Dynarr_lock(d) DO_NOTHING -#define Dynarr_unlock(d) DO_NOTHING - -#endif /* ERROR_CHECK_DYNARR */ - -/************* Dynarr creation *************/ - -MODULE_API void *Dynarr_newf (Bytecount elsize); -MODULE_API void Dynarr_free (void *d); - -#ifdef NEW_GC -MODULE_API void *Dynarr_lisp_newf (Bytecount elsize, - const struct lrecord_implementation - *dynarr_imp, - const struct lrecord_implementation *imp); - -#define Dynarr_lisp_new(type, dynarr_imp, imp) \ - ((type##_dynarr *) Dynarr_lisp_newf (sizeof (type), dynarr_imp, imp)) -#define Dynarr_lisp_new2(dynarr_type, type, dynarr_imp, imp) \ - ((dynarr_type *) Dynarr_lisp_newf (sizeof (type)), dynarr_imp, imp) -#endif /* NEW_GC */ -#define Dynarr_new(type) ((type##_dynarr *) Dynarr_newf (sizeof (type))) -#define Dynarr_new2(dynarr_type, type) \ - ((dynarr_type *) Dynarr_newf (sizeof (type))) - -/************* Dynarr access *************/ - -#ifdef ERROR_CHECK_DYNARR -#define Dynarr_at(d, pos) \ - ((d)->base[Dynarr_verify_pos_at (d, pos, __FILE__, __LINE__)]) -#define Dynarr_atp_allow_end(d, pos) \ - (&((d)->base[Dynarr_verify_pos_atp_allow_end (d, pos, __FILE__, __LINE__)])) -#define Dynarr_atp(d, pos) \ - (&((d)->base[Dynarr_verify_pos_atp (d, pos, __FILE__, __LINE__)])) -#else -#define Dynarr_at(d, pos) ((d)->base[pos]) -#define Dynarr_atp(d, pos) (&Dynarr_at (d, pos)) -#define Dynarr_atp_allow_end(d, pos) Dynarr_atp (d, pos) -#endif - -/* Old #define Dynarr_atp(d, pos) (&Dynarr_at (d, pos)) */ -#define Dynarr_begin(d) Dynarr_atp (d, 0) -#define Dynarr_lastp(d) Dynarr_atp (d, Dynarr_length (d) - 1) -#define Dynarr_past_lastp(d) Dynarr_atp_allow_end (d, Dynarr_length (d)) - - -/************* Dynarr length/size retrieval and setting *************/ - -/* Retrieve the length of a dynarr. The `+ 0' is to ensure that this cannot - be used as an lvalue. */ -#define Dynarr_length(d) (Dynarr_verify (d)->len_ + 0) -/* Retrieve the largest ever length seen of a dynarr. The `+ 0' is to - ensure that this cannot be used as an lvalue. */ -#define Dynarr_largest(d) (Dynarr_verify (d)->largest_ + 0) -/* Retrieve the number of elements that fit in the currently allocated - space. The `+ 0' is to ensure that this cannot be used as an lvalue. */ -#define Dynarr_max(d) (Dynarr_verify (d)->max_ + 0) -/* Return the size in bytes of an element in a dynarr. */ -#define Dynarr_elsize(d) (Dynarr_verify (d)->elsize_ + 0) -/* Retrieve the advertised memory usage of a dynarr, i.e. the number of - bytes occupied by the elements in the dynarr, not counting any overhead. */ -#define Dynarr_sizeof(d) (Dynarr_length (d) * Dynarr_elsize (d)) - -/* Actually set the length of a dynarr. This is a low-level routine that - should not be directly used; use Dynarr_set_length() or - Dynarr_set_lengthr() instead. */ -DECLARE_INLINE_HEADER ( -void -Dynarr_set_length_1 (void *d, Elemcount len) -) -{ - Dynarr *dy = Dynarr_verify_mod (d); - dynarr_checking_assert (len >= 0 && len <= Dynarr_max (dy)); - /* Use the raw field references here otherwise we get a crash because - we've set the length but not yet fixed up the largest value. */ - dy->len_ = len; - if (dy->len_ > dy->largest_) - dy->largest_ = dy->len_; - (void) Dynarr_verify_mod (d); -} - -/* "Restricted set-length": Set the length of dynarr D to LEN, - which must be in the range [0, Dynarr_largest(d)]. */ - -DECLARE_INLINE_HEADER ( -void -Dynarr_set_lengthr (void *d, Elemcount len) -) -{ - Dynarr *dy = Dynarr_verify_mod (d); - dynarr_checking_assert (len >= 0 && len <= Dynarr_largest (dy)); - Dynarr_set_length_1 (dy, len); -} - -/* "Restricted increment": Increment the length of dynarr D by 1; the resulting - length must be in the range [0, Dynarr_largest(d)]. */ - -#define Dynarr_incrementr(d) Dynarr_set_lengthr (d, Dynarr_length (d) + 1) - - -MODULE_API void Dynarr_resize (void *d, Elemcount size); - -DECLARE_INLINE_HEADER ( -void -Dynarr_resize_to_fit (void *d, Elemcount size) -) -{ - Dynarr *dy = Dynarr_verify_mod (d); - if (size > Dynarr_max (dy)) - Dynarr_resize (dy, size); -} - -#define Dynarr_resize_to_add(d, numels) \ - Dynarr_resize_to_fit (d, Dynarr_length (d) + numels) - -/* This is an optimization. This is like Dynarr_set_length() but the length - is guaranteed to be at least as big as the existing length. */ - -DECLARE_INLINE_HEADER ( -void -Dynarr_increase_length (void *d, Elemcount len) -) -{ - Dynarr *dy = Dynarr_verify_mod (d); - dynarr_checking_assert (len >= Dynarr_length (dy)); - Dynarr_resize_to_fit (dy, len); - Dynarr_set_length_1 (dy, len); -} - -/* Set the length of dynarr D to LEN. If the length increases, resize as - necessary to fit. (NOTE: This will leave uninitialized memory. If you - aren't planning on immediately overwriting the memory, use - Dynarr_set_length_and_zero() to zero out all the memory that would - otherwise be uninitialized.) */ - -DECLARE_INLINE_HEADER ( -void -Dynarr_set_length (void *d, Elemcount len) -) -{ - Dynarr *dy = Dynarr_verify_mod (d); - Elemcount old_len = Dynarr_length (dy); - if (old_len >= len) - Dynarr_set_lengthr (dy, len); - else - Dynarr_increase_length (d, len); -} - -#define Dynarr_increment(d) Dynarr_increase_length (d, Dynarr_length (d) + 1) - -/* Zero LEN contiguous elements starting at POS. */ - -DECLARE_INLINE_HEADER ( -void -Dynarr_zero_many (void *d, Elemcount pos, Elemcount len) -) -{ - Dynarr *dy = Dynarr_verify_mod (d); - memset ((Rawbyte *) dy->base + pos*Dynarr_elsize (dy), 0, - len*Dynarr_elsize (dy)); -} - -/* This is an optimization. This is like Dynarr_set_length_and_zero() but - the length is guaranteed to be at least as big as the existing - length. */ - -DECLARE_INLINE_HEADER ( -void -Dynarr_increase_length_and_zero (void *d, Elemcount len) -) -{ - Dynarr *dy = Dynarr_verify_mod (d); - Elemcount old_len = Dynarr_length (dy); - Dynarr_increase_length (dy, len); - Dynarr_zero_many (dy, old_len, len - old_len); -} - -/* Set the length of dynarr D to LEN. If the length increases, resize as - necessary to fit and zero out all the elements between the old and new - lengths. */ - -DECLARE_INLINE_HEADER ( -void -Dynarr_set_length_and_zero (void *d, Elemcount len) -) -{ - Dynarr *dy = Dynarr_verify_mod (d); - Elemcount old_len = Dynarr_length (dy); - if (old_len >= len) - Dynarr_set_lengthr (dy, len); - else - Dynarr_increase_length_and_zero (d, len); -} - -/* Reset the dynarr's length to 0. */ -#define Dynarr_reset(d) Dynarr_set_lengthr (d, 0) - -#ifdef MEMORY_USAGE_STATS -struct usage_stats; -Bytecount Dynarr_memory_usage (void *d, struct usage_stats *stats); -#endif - -/************* Adding/deleting elements to/from a dynarr *************/ - -/* Set the Lisp implementation of the element at POS in dynarr D. Only - does this if the dynarr holds Lisp objects of a particular type (the - objects themselves, not pointers to them), and only under NEW_GC. */ - -#ifdef NEW_GC -#define DYNARR_SET_LISP_IMP(d, pos) \ -do { \ - if ((d)->lisp_imp) \ - set_lheader_implementation \ - ((struct lrecord_header *)&(((d)->base)[pos]), (d)->lisp_imp); \ -} while (0) -#else -#define DYNARR_SET_LISP_IMP(d, pos) DO_NOTHING -#endif /* (not) NEW_GC */ - -/* Add Element EL to the end of dynarr D. */ - -#define Dynarr_add(d, el) \ -do { \ - Elemcount _da_pos = Dynarr_length (d); \ - (void) Dynarr_verify_mod (d); \ - Dynarr_increment (d); \ - ((d)->base)[_da_pos] = (el); \ - DYNARR_SET_LISP_IMP (d, _da_pos); \ -} while (0) - -/* Set EL as the element at position POS in dynarr D. - Expand the dynarr as necessary so that its length is enough to include - position POS within it, and zero out any new elements created as a - result of expansion, other than the one at POS. */ - -#define Dynarr_set(d, pos, el) \ -do { \ - Elemcount _ds_pos = (pos); \ - (void) Dynarr_verify_mod (d); \ - if (Dynarr_length (d) < _ds_pos + 1) \ - Dynarr_increase_length_and_zero (d, _ds_pos + 1); \ - ((d)->base)[_ds_pos] = (el); \ - DYNARR_SET_LISP_IMP (d, _ds_pos); \ -} while (0) - -/* Add LEN contiguous elements, stored at BASE, to dynarr D. If BASE is - NULL, reserve space but don't store anything. */ - -DECLARE_INLINE_HEADER ( -void -Dynarr_add_many (void *d, const void *base, Elemcount len) -) -{ - /* This duplicates Dynarr_insert_many to some extent; but since it is - called so often, it seemed useful to remove the unnecessary stuff - from that function and to make it inline */ - Dynarr *dy = Dynarr_verify_mod (d); - Elemcount pos = Dynarr_length (dy); - Dynarr_increase_length (dy, Dynarr_length (dy) + len); - if (base) - memcpy ((Rawbyte *) dy->base + pos*Dynarr_elsize (dy), base, - len*Dynarr_elsize (dy)); -} - -/* Insert LEN elements, currently pointed to by BASE, into dynarr D - starting at position POS. */ - -MODULE_API void Dynarr_insert_many (void *d, const void *base, Elemcount len, - Elemcount pos); - -/* Prepend LEN elements, currently pointed to by BASE, to the beginning. */ - -#define Dynarr_prepend_many(d, base, len) Dynarr_insert_many (d, base, len, 0) - -/* Add literal string S to dynarr D, which should hold chars or unsigned - chars. The final zero byte is not stored. */ - -#define Dynarr_add_literal_string(d, s) Dynarr_add_many (d, s, sizeof (s) - 1) - -/* Convert Lisp string S to an external encoding according to CODESYS and - add to dynarr D, which should hold chars or unsigned chars. No final - zero byte is appended. */ - -/* #### This should be an inline function but LISP_STRING_TO_SIZED_EXTERNAL - isn't declared yet. */ - -#define Dynarr_add_ext_lisp_string(d, s, codesys) \ -do { \ - Lisp_Object dyna_ls_s = (s); \ - Lisp_Object dyna_ls_cs = (codesys); \ - Extbyte *dyna_ls_eb; \ - Bytecount dyna_ls_bc; \ - \ - LISP_STRING_TO_SIZED_EXTERNAL (dyna_ls_s, dyna_ls_eb, \ - dyna_ls_bc, dyna_ls_cs); \ - Dynarr_add_many (d, dyna_ls_eb, dyna_ls_bc); \ -} while (0) - -/* Delete LEN elements starting at position POS. */ - -MODULE_API void Dynarr_delete_many (void *d, Elemcount pos, Elemcount len); - -/* Pop off (i.e. delete) the last element from the dynarr and return it */ - -#define Dynarr_pop(d) \ - (dynarr_checking_assert (Dynarr_length (d) > 0), \ - Dynarr_verify_mod (d)->len_--, \ - Dynarr_at (d, Dynarr_length (d))) - -/* Delete the item at POS */ - -#define Dynarr_delete(d, pos) Dynarr_delete_many (d, pos, 1) - -/* Delete the item located at memory address P, which must be a `type *' - pointer, where `type' is the type of the elements of the dynarr. */ -#define Dynarr_delete_by_pointer(d, p) \ - Dynarr_delete_many (d, (p) - ((d)->base), 1) - -/* Delete all elements that are numerically equal to EL. */ - -#define Dynarr_delete_object(d, el) \ -do \ -{ \ - REGISTER int i; \ - for (i = Dynarr_length (d) - 1; i >= 0; i--) \ - { \ - if (el == Dynarr_at (d, i)) \ - Dynarr_delete_many (d, i, 1); \ - } \ -} while (0) +#include "array.h" /************* Dynarr typedefs *************/ @@ -2436,12 +1875,6 @@ } Lisp_Object_ptr_dynarr; -/************* Stack-like malloc/free: Another allocator *************/ - -void *stack_like_malloc (Bytecount size); -void stack_like_free (void *val); - - /************************************************************************/ /** Definitions of other basic Lisp objects **/ /************************************************************************/ @@ -4812,21 +4245,6 @@ void free_marker (Lisp_Object); int object_dead_p (Lisp_Object); void mark_object (Lisp_Object obj); -#ifndef NEW_GC -#ifdef USE_KKCC -#ifdef DEBUG_XEMACS -void kkcc_gc_stack_push_lisp_object_1 (Lisp_Object obj, int level, int pos); -#define kkcc_gc_stack_push_lisp_object(obj, level, pos) \ - kkcc_gc_stack_push_lisp_object_1 (obj, level, pos) -void kkcc_backtrace (void); -#else -void kkcc_gc_stack_push_lisp_object_1 (Lisp_Object obj); -#define kkcc_gc_stack_push_lisp_object(obj, level, pos) \ - kkcc_gc_stack_push_lisp_object_1 (obj) -#define kkcc_backtrace() -#endif -#endif /* USE_KKCC */ -#endif /* not NEW_GC */ int marked_p (Lisp_Object obj); extern int funcall_allocation_flag; extern int need_to_garbage_collect; @@ -5928,7 +5346,7 @@ Lisp_Object noseeum_copy_marker (Lisp_Object, Lisp_Object); Lisp_Object set_marker_restricted (Lisp_Object, Lisp_Object, Lisp_Object); #ifdef MEMORY_USAGE_STATS -Bytecount compute_buffer_marker_usage (struct buffer *, struct usage_stats *); +Bytecount compute_buffer_marker_usage (struct buffer *b); #endif void init_buffer_markers (struct buffer *b); void uninit_buffer_markers (struct buffer *b);
--- a/src/lrecord.h Fri Mar 26 15:06:28 2010 +0000 +++ b/src/lrecord.h Mon Mar 29 00:11:03 2010 -0500 @@ -187,6 +187,8 @@ #define NORMAL_LISP_OBJECT_HEADER struct lrecord_header #define FROB_BLOCK_LISP_OBJECT_HEADER struct lrecord_header #define LISP_OBJECT_FROB_BLOCK_P(obj) 0 +#define IF_NEW_GC(x) x +#define IF_OLD_GC(x) 0 #else /* not NEW_GC */ #define ALLOC_NORMAL_LISP_OBJECT(type) alloc_automanaged_lcrecord (&lrecord_##type) #define ALLOC_SIZED_LISP_OBJECT(size, type) \ @@ -194,6 +196,8 @@ #define NORMAL_LISP_OBJECT_HEADER struct old_lcrecord_header #define FROB_BLOCK_LISP_OBJECT_HEADER struct lrecord_header #define LISP_OBJECT_FROB_BLOCK_P(obj) (XRECORD_LHEADER_IMPLEMENTATION(obj)->frob_block_p) +#define IF_NEW_GC(x) 0 +#define IF_OLD_GC(x) x #endif /* not NEW_GC */ #define LISP_OBJECT_UID(obj) (XRECORD_LHEADER (obj)->uid) @@ -310,7 +314,9 @@ /* Symbol value magic types come first to make SYMBOL_VALUE_MAGIC_P fast. #### This should be replaced by a symbol_value_magic_p flag in the Lisp_Symbol lrecord_header. */ - lrecord_type_symbol_value_forward, /* 0 */ + /* Don't assign any type to 0, so in case we come across zeroed memory + it will be more obvious when printed */ + lrecord_type_symbol_value_forward = 1, lrecord_type_symbol_value_varalias, lrecord_type_symbol_value_lisp_magic, lrecord_type_symbol_value_buffer_local, @@ -508,8 +514,8 @@ /**********************************************************************/ /* Remaining stuff is not assignable statically using - DEFINE_*_LISP_OBJECT, but must be assigned with OBJECT_HAS_METHOD - or the like. */ + DEFINE_*_LISP_OBJECT, but must be assigned with OBJECT_HAS_METHOD, + OBJECT_HAS_PROPERTY or the like. */ /* These functions allow any object type to have builtin property lists that can be manipulated from the lisp level with @@ -536,34 +542,73 @@ #ifdef MEMORY_USAGE_STATS /* Return memory-usage information about the object in question, stored - into STATS. */ - void (*memory_usage) (Lisp_Object obj, struct generic_usage_stats *stats); + into STATS. - /* Number of additional type-specific statistics related to memory usage. - Automatically calculated (see compute_memusage_stats_length()) based - on the value placed in `memusage_stats_list'. */ - Elemcount num_extra_memusage_stats; + Two types of information are stored: storage (including overhead) for + ancillary non-Lisp structures attached to the object, and storage + (including overhead) for ancillary Lisp objects attached to the + object. The third type of memory-usage information (storage for the + object itself) is not noted here, because it's computed automatically + by the calling function. Also, the computed storage for ancillary + Lisp objects is the sum of all three source of memory associated with + the Lisp object: the object itself, ancillary non-Lisp structures and + ancillary Lisp objects. Note also that the `struct usage_stats u' at + the beginning of the STATS structure is for ancillary non-Lisp usage + *ONLY*; do not store any memory into it related to ancillary Lisp + objects. - /* Number of additional type-specific statistics related to - non-Lisp-Object memory usage for this object. Automatically - calculated (see compute_memusage_stats_length()) based on the value - placed in `memusage_stats_list'. */ - Elemcount num_extra_nonlisp_memusage_stats; + Note that it may be subjective which Lisp objects are considered + "attached" to the object. Some guidelines: + + -- Lisp objects which are "internal" to the main object and not + accessible except through the main object should be included + -- Objects linked by a weak reference should *NOT* be included + */ + void (*memory_usage) (Lisp_Object obj, struct generic_usage_stats *stats); /* List of tags to be given to the extra statistics, one per statistic. Qnil or Qt can be present to separate off different slices. Qnil - separates different slices within the same type of statistics. - Qt separates slices corresponding to different types of statistics. + separates different slices within the same group of statistics. + These represent different ways of partitioning the same memory space. + Qt separates different groups; these represent different spaces of + memory. + If Qt is not present, all slices describe extra non-Lisp-Object memory - associated with a Lisp object. If Qt is present, slices after Qt - describe non-Lisp-Object memory and slices before Qt describe - Lisp-Object memory logically associated with the object. For example, - if the object is a table, then Lisp-Object memory might be the entries - in the table. This info is only advisory since it will duplicate - memory described elsewhere and since it may not be possible to be - completely accurate if the same object occurs multiple times in the - table. */ + associated with a Lisp object. If Qt is present, slices before Qt + describe non-Lisp-Object memory, as before, and slices after Qt + describe ancillary Lisp-Object memory logically associated with the + object. For example, if the object is a table, then ancillary + Lisp-Object memory might be the entries in the table. This info is + only advisory since it will duplicate memory described elsewhere and + since it may not be possible to be completely accurate, e.g. it may + not be clear what to count in "ancillary objects", and the value may + be too high if the same object occurs multiple times in the table. */ Lisp_Object memusage_stats_list; + + /* --------------------------------------------------------------------- */ + + /* The following are automatically computed based on the value in + `memusage_stats_list' (see compute_memusage_stats_length()). */ + + /* Total number of additional type-specific statistics related to memory + usage. */ + Elemcount num_extra_memusage_stats; + + /* Number of additional type-specific statistics belonging to the first + slice of the group describing non-Lisp-Object memory usage for this + object. These stats occur starting at offset 0. */ + Elemcount num_extra_nonlisp_memusage_stats; + + /* The offset into the extra statistics at which the Lisp-Object + memory-usage statistics begin. */ + Elemcount offset_lisp_ancillary_memusage_stats; + + /* Number of additional type-specific statistics belonging to the first + slice of the group describing Lisp-Object memory usage for this + object. These stats occur starting at offset + `offset_lisp_ancillary_memusage_stats'. */ + Elemcount num_extra_lisp_ancillary_memusage_stats; + #endif /* MEMORY_USAGE_STATS */ }; @@ -974,17 +1019,28 @@ XD_LISP_OBJECT - A Lisp object. This is also the type to use for pointers to other lrecords + A Lisp_Object. This is also the type to use for pointers to other lrecords (e.g. struct frame *). XD_LISP_OBJECT_ARRAY - An array of Lisp objects or (equivalently) pointers to lrecords. + An array of Lisp_Objects or (equivalently) pointers to lrecords. The parameter (i.e. third element) is the count. This would be declared as Lisp_Object foo[666]. For something declared as Lisp_Object *foo, use XD_BLOCK_PTR, whose description parameter is a sized_memory_description consisting of only XD_LISP_OBJECT and XD_END. + XD_INLINE_LISP_OBJECT_BLOCK_PTR + + An pointer to a contiguous block of inline Lisp objects -- i.e., the Lisp + object itself rather than a Lisp_Object pointer is stored in the block. + This is used only under NEW_GC and is useful for increased efficiency when + an array of the same kind of object is needed. Examples of the use of this + type are Lisp dynarrs, where the array elements are inline Lisp objects + rather than non-Lisp structures, as is normally the case; and hash tables, + where the key/value pairs are encapsulated as hash-table-entry objects and + an array of inline hash-table-entry objects is stored. + XD_LO_LINK Weak link in a linked list of objects of the same type. This is a @@ -1150,7 +1206,7 @@ XD_LISP_OBJECT_ARRAY, XD_LISP_OBJECT, #ifdef NEW_GC - XD_LISP_OBJECT_BLOCK_PTR, + XD_INLINE_LISP_OBJECT_BLOCK_PTR, #endif /* NEW_GC */ XD_LO_LINK, XD_OPAQUE_PTR, @@ -1200,10 +1256,9 @@ lcrecord-lists, where the objects have had their type changed to lrecord_type_free and also have had their free bit set, but we mark them as normal. */ - XD_FLAG_FREE_LISP_OBJECT = 8 + XD_FLAG_FREE_LISP_OBJECT = 8, #endif /* not NEW_GC */ #if 0 - , /* Suggestions for other possible flags: */ /* Eliminate XD_UNION_DYNAMIC_SIZE and replace it with a flag, like this. */ @@ -1215,7 +1270,7 @@ expanded and we need to stick a pointer in the second slot (although we could still ensure that the second slot in the first entry was NULL or <0). */ - XD_FLAG_DESCRIPTION_MAP = 32 + XD_FLAG_DESCRIPTION_MAP = 32, #endif }; @@ -1258,20 +1313,20 @@ This function must put a pointer to the opaque result in *data and its size in *size. */ - void (*convert)(const void *object, void **data, Bytecount *size); + void (*convert) (const void *object, void **data, Bytecount *size); /* Post-conversion cleanup. Optional (null if not provided). When provided it will be called post-dumping to free any storage allocated for the conversion results. */ - void (*convert_free)(const void *object, void *data, Bytecount size); + void (*convert_free) (const void *object, void *data, Bytecount size); /* De-conversion. At reload time, rebuilds the object from the converted form. "object" is 0 for the PTR case, return is ignored in the DATA case. */ - void *(*deconvert)(void *object, void *data, Bytecount size); + void *(*deconvert) (void *object, void *data, Bytecount size); }; @@ -2024,6 +2079,12 @@ MODULE_API void zero_nonsized_lisp_object (Lisp_Object obj); Bytecount lisp_object_storage_size (Lisp_Object obj, struct usage_stats *ustats); +Bytecount lisp_object_memory_usage_full (Lisp_Object object, + Bytecount *storage_size, + Bytecount *extra_nonlisp_storage, + Bytecount *extra_lisp_storage, + struct generic_usage_stats *stats); +Bytecount lisp_object_memory_usage (Lisp_Object object); void free_normal_lisp_object (Lisp_Object obj);
--- a/src/marker.c Fri Mar 26 15:06:28 2010 +0000 +++ b/src/marker.c Mon Mar 29 00:11:03 2010 -0500 @@ -111,18 +111,13 @@ { unchain_marker (obj); } +#endif /* NEW_GC */ DEFINE_DUMPABLE_FROB_BLOCK_LISP_OBJECT ("marker", marker, mark_marker, print_marker, - finalize_marker, + IF_NEW_GC (finalize_marker), marker_equal, marker_hash, marker_description, Lisp_Marker); -#else /* not NEW_GC */ -DEFINE_DUMPABLE_FROB_BLOCK_LISP_OBJECT ("marker", marker, - mark_marker, print_marker, 0, - marker_equal, marker_hash, - marker_description, Lisp_Marker); -#endif /* not NEW_GC */ /* Operations on markers. */ @@ -498,13 +493,13 @@ #ifdef MEMORY_USAGE_STATS Bytecount -compute_buffer_marker_usage (struct buffer *b, struct usage_stats *ustats) +compute_buffer_marker_usage (struct buffer *b) { Lisp_Marker *m; Bytecount total = 0; for (m = BUF_MARKERS (b); m; m = m->next) - total += lisp_object_storage_size (wrap_marker (m), ustats); + total += lisp_object_memory_usage (wrap_marker (m)); return total; }
--- a/src/mc-alloc.c Fri Mar 26 15:06:28 2010 +0000 +++ b/src/mc-alloc.c Mon Mar 29 00:11:03 2010 -0500 @@ -962,7 +962,6 @@ } -#ifdef MEMORY_USAGE_STATS Bytecount mc_alloced_storage_size (Bytecount claimed_size, struct usage_stats *stats) { @@ -979,7 +978,6 @@ return used_size; } -#endif /* not MEMORY_USAGE_STATS */
--- a/src/mc-alloc.h Fri Mar 26 15:06:28 2010 +0000 +++ b/src/mc-alloc.h Mon Mar 29 00:11:03 2010 -0500 @@ -1,5 +1,6 @@ /* New allocator for XEmacs. Copyright (C) 2005 Marcus Crestani. + Copyright (C) 2010 Ben Wing. This file is part of XEmacs. @@ -122,12 +123,10 @@ /* Functions and macros related with allocation statistics: */ -#ifdef MEMORY_USAGE_STATS /* Returns the real size, including overhead, which is actually alloced for an object with given claimed_size. */ Bytecount mc_alloced_storage_size (Bytecount claimed_size, struct usage_stats *stats); -#endif /* MEMORY_USAGE_STATS */ /* Incremental Garbage Collector / Write Barrier Support: */
--- a/src/mule-coding.c Fri Mar 26 15:06:28 2010 +0000 +++ b/src/mule-coding.c Mon Mar 29 00:11:03 2010 -0500 @@ -2839,14 +2839,15 @@ return 1; } +#ifdef ENABLE_COMPOSITE_CHARS +#define USED_IF_COMPOSITE_CHARS(x) x +#else +#define USED_IF_COMPOSITE_CHARS(x) UNUSED (x) +#endif + static void -iso2022_finalize_coding_stream ( -#ifdef ENABLE_COMPOSITE_CHARS - struct coding_stream *str -#else - struct coding_stream *UNUSED (str) -#endif - ) +iso2022_finalize_coding_stream (struct coding_stream * + USED_IF_COMPOSITE_CHARS (str)) { #ifdef ENABLE_COMPOSITE_CHARS struct iso2022_coding_stream *data = @@ -3247,7 +3248,10 @@ { struct iso2022_detector *data = DETECTION_STATE_DATA (st, iso2022); if (data->iso) - xfree (data->iso); + { + xfree (data->iso); + data->iso = 0; + } }
--- a/src/number.c Fri Mar 26 15:06:28 2010 +0000 +++ b/src/number.c Mon Mar 29 00:11:03 2010 -0500 @@ -70,9 +70,6 @@ zero after finalizing. */ bignum_fini (num->data); } -#define BIGNUM_FINALIZE bignum_finalize -#else -#define BIGNUM_FINALIZE 0 #endif static int @@ -125,10 +122,9 @@ }; DEFINE_DUMPABLE_FROB_BLOCK_LISP_OBJECT ("bignum", bignum, 0, bignum_print, - BIGNUM_FINALIZE, bignum_equal, - bignum_hash, bignum_description, - Lisp_Bignum); - + IF_NEW_GC (bignum_finalize), + bignum_equal, bignum_hash, + bignum_description, Lisp_Bignum); #endif /* HAVE_BIGNUM */ Lisp_Object Qbignump; @@ -164,10 +160,7 @@ zero after finalizing. */ ratio_fini (num->data); } -#define RATIO_FINALIZE ratio_finalize -#else -#define RATIO_FINALIZE 0 -#endif +#endif /* not NEW_GC */ static int ratio_equal (Lisp_Object obj1, Lisp_Object obj2, int UNUSED (depth), @@ -188,7 +181,8 @@ }; DEFINE_NODUMP_FROB_BLOCK_LISP_OBJECT ("ratio", ratio, 0, ratio_print, - RATIO_FINALIZE, ratio_equal, ratio_hash, + IF_NEW_GC (ratio_finalize), + ratio_equal, ratio_hash, ratio_description, Lisp_Ratio); #endif /* HAVE_RATIO */ @@ -270,10 +264,7 @@ zero after finalizing. */ bigfloat_fini (num->bf); } -#define BIGFLOAT_FINALIZE bigfloat_finalize -#else -#define BIGFLOAT_FINALIZE 0 -#endif +#endif /* not NEW_GC */ static int bigfloat_equal (Lisp_Object obj1, Lisp_Object obj2, int UNUSED (depth), @@ -294,7 +285,8 @@ }; DEFINE_DUMPABLE_FROB_BLOCK_LISP_OBJECT ("bigfloat", bigfloat, 0, - bigfloat_print, BIGFLOAT_FINALIZE, + bigfloat_print, + IF_NEW_GC (bigfloat_finalize), bigfloat_equal, bigfloat_hash, bigfloat_description, Lisp_Bigfloat);
--- a/src/objects-tty.c Fri Mar 26 15:06:28 2010 +0000 +++ b/src/objects-tty.c Mon Mar 29 00:11:03 2010 -0500 @@ -219,7 +219,10 @@ { #ifndef NEW_GC if (c->data) - xfree (c->data); + { + xfree (c->data); + c->data = 0; + } #endif /* not NEW_GC */ } @@ -314,7 +317,10 @@ { #ifndef NEW_GC if (f->data) - xfree (f->data); + { + xfree (f->data); + f->data = 0; + } #endif /* not NEW_GC */ }
--- a/src/process.c Fri Mar 26 15:06:28 2010 +0000 +++ b/src/process.c Mon Mar 29 00:11:03 2010 -0500 @@ -189,6 +189,7 @@ { MAYBE_PROCMETH (finalize_process_data, (p)); xfree (p->process_data); + p->process_data = 0; } }
--- a/src/profile.c Fri Mar 26 15:06:28 2010 +0000 +++ b/src/profile.c Mon Mar 29 00:11:03 2010 -0500 @@ -1,5 +1,5 @@ /* Why the hell is XEmacs so fucking slow? - Copyright (C) 1996, 2002, 2003, 2004 Ben Wing. + Copyright (C) 1996, 2002, 2003, 2004, 2010 Ben Wing. Copyright (C) 1998 Free Software Foundation, Inc. This file is part of XEmacs. @@ -25,6 +25,7 @@ #include "backtrace.h" #include "bytecode.h" #include "elhash.h" +#include "gc.h" #include "hash.h" #include "profile.h" @@ -609,7 +610,7 @@ void *UNUSED (void_closure)) { #ifdef USE_KKCC - kkcc_gc_stack_push_lisp_object (GET_LISP_FROM_VOID (void_key), 0, -1); + kkcc_gc_stack_push_lisp_object_0 (GET_LISP_FROM_VOID (void_key)); #else /* NOT USE_KKCC */ mark_object (GET_LISP_FROM_VOID (void_key)); #endif /* NOT USE_KKCC */
--- a/src/rangetab.c Fri Mar 26 15:06:28 2010 +0000 +++ b/src/rangetab.c Mon Mar 29 00:11:03 2010 -0500 @@ -90,8 +90,8 @@ Lisp_Range_Table *rt = XRANGE_TABLE (obj); int i; - for (i = 0; i < Dynarr_length (rt->entries); i++) - mark_object (Dynarr_at (rt->entries, i).val); + for (i = 0; i < gap_array_length (rt->entries); i++) + mark_object (rangetab_gap_array_at (rt->entries, i).val); return Qnil; } @@ -108,9 +108,9 @@ 1, range_table_type_to_symbol (rt->type)); else write_ascstring (printcharfun, "#<range-table "); - for (i = 0; i < Dynarr_length (rt->entries); i++) + for (i = 0; i < gap_array_length (rt->entries); i++) { - struct range_table_entry *rte = Dynarr_atp (rt->entries, i); + struct range_table_entry rte = rangetab_gap_array_at (rt->entries, i); int so, ec; if (i > 0) write_ascstring (printcharfun, " "); @@ -124,11 +124,11 @@ } write_fmt_string (printcharfun, "%c%ld %ld%c ", print_readably ? '(' : so ? '(' : '[', - (long) (rte->first - so), - (long) (rte->last - ec), + (long) (rte.first - so), + (long) (rte.last - ec), print_readably ? ')' : ec ? ']' : ')' ); - print_internal (rte->val, printcharfun, 1); + print_internal (rte.val, printcharfun, 1); } if (print_readably) write_ascstring (printcharfun, "))"); @@ -143,13 +143,15 @@ Lisp_Range_Table *rt2 = XRANGE_TABLE (obj2); int i; - if (Dynarr_length (rt1->entries) != Dynarr_length (rt2->entries)) + if (gap_array_length (rt1->entries) != gap_array_length (rt2->entries)) return 0; - for (i = 0; i < Dynarr_length (rt1->entries); i++) + for (i = 0; i < gap_array_length (rt1->entries); i++) { - struct range_table_entry *rte1 = Dynarr_atp (rt1->entries, i); - struct range_table_entry *rte2 = Dynarr_atp (rt2->entries, i); + struct range_table_entry *rte1 = + rangetab_gap_array_atp (rt1->entries, i); + struct range_table_entry *rte2 = + rangetab_gap_array_atp (rt2->entries, i); if (rte1->first != rte2->first || rte1->last != rte2->last @@ -171,7 +173,7 @@ { Lisp_Range_Table *rt = XRANGE_TABLE (obj); int i; - int size = Dynarr_length (rt->entries); + int size = gap_array_length (rt->entries); Hashcode hash = size; /* approach based on internal_array_hash(). */ @@ -179,8 +181,8 @@ { for (i = 0; i < size; i++) hash = HASH2 (hash, - range_table_entry_hash (Dynarr_atp (rt->entries, i), - depth)); + range_table_entry_hash + (rangetab_gap_array_atp (rt->entries, i), depth)); return hash; } @@ -188,12 +190,31 @@ A slightly better approach would be to offset by some noise factor from the points chosen below. */ for (i = 0; i < 5; i++) - hash = HASH2 (hash, range_table_entry_hash (Dynarr_atp (rt->entries, - i*size/5), - depth)); + hash = HASH2 (hash, + range_table_entry_hash + (rangetab_gap_array_atp (rt->entries, i*size/5), depth)); return hash; } +#ifndef NEW_GC + +/* #### This leaks memory under NEW_GC. To fix this, convert to Lisp object + gap array. */ + +static void +finalize_range_table (Lisp_Object obj) +{ + Lisp_Range_Table *rt = XRANGE_TABLE (obj); + if (rt->entries) + { + if (!DUMPEDP (rt->entries)) + free_gap_array (rt->entries); + rt->entries = 0; + } +} + +#endif /* not NEW_GC */ + static const struct memory_description rte_description_1[] = { { XD_LISP_OBJECT, offsetof (range_table_entry, val) }, { XD_END } @@ -204,24 +225,24 @@ rte_description_1 }; -static const struct memory_description rted_description_1[] = { - XD_DYNARR_DESC (range_table_entry_dynarr, &rte_description), +static const struct memory_description rtega_description_1[] = { + XD_GAP_ARRAY_DESC (&rte_description), { XD_END } }; -static const struct sized_memory_description rted_description = { - sizeof (range_table_entry_dynarr), - rted_description_1 +static const struct sized_memory_description rtega_description = { + 0, rtega_description_1 }; static const struct memory_description range_table_description[] = { { XD_BLOCK_PTR, offsetof (Lisp_Range_Table, entries), 1, - { &rted_description } }, + { &rtega_description } }, { XD_END } }; DEFINE_DUMPABLE_LISP_OBJECT ("range-table", range_table, - mark_range_table, print_range_table, 0, + mark_range_table, print_range_table, + IF_OLD_GC (finalize_range_table), range_table_equal, range_table_hash, range_table_description, Lisp_Range_Table); @@ -237,12 +258,12 @@ { int i; - for (i = 0; i < Dynarr_length (rt->entries); i++) + for (i = 0; i < gap_array_length (rt->entries); i++) { - struct range_table_entry *rte = Dynarr_atp (rt->entries, i); + struct range_table_entry *rte = rangetab_gap_array_atp (rt->entries, i); assert (rte->last >= rte->first); if (i > 0) - assert (Dynarr_at (rt->entries, i - 1).last <= rte->first); + assert (rangetab_gap_array_at (rt->entries, i - 1).last <= rte->first); } } @@ -252,14 +273,18 @@ #endif -/* Look up in a range table without the Dynarr wrapper. - Used also by the unified range table format. */ +/* Locate the range table entry corresponding to the value POS, and return + it. If found, FOUNDP is set to 1 and the return value specifies an entry + that encloses POS. Otherwise, FOUNDP is set to 0 and the return value + specifies where an entry that encloses POS would be inserted. */ -static Lisp_Object -get_range_table (EMACS_INT pos, int nentries, struct range_table_entry *tab, - Lisp_Object default_) +static Elemcount +get_range_table_pos (Elemcount pos, Elemcount nentries, + struct range_table_entry *tab, + Elemcount gappos, Elemcount gapsize, + int *foundp) { - int left = 0, right = nentries; + Elemcount left = 0, right = nentries; /* binary search for the entry. Based on similar code in extent_list_locate(). */ @@ -267,14 +292,41 @@ { /* RIGHT might not point to a valid entry (i.e. it's at the end of the list), so NEWPOS must round down. */ - int newpos = (left + right) >> 1; - struct range_table_entry *entry = tab + newpos; + Elemcount newpos = (left + right) >> 1; + struct range_table_entry *entry = + tab + GAP_ARRAY_ARRAY_TO_MEMORY_POS_1 (newpos, gappos, gapsize); if (pos >= entry->last) left = newpos + 1; else if (pos < entry->first) right = newpos; else - return entry->val; + { + *foundp = 1; + return newpos; + } + } + + *foundp = 0; + return left; +} + +/* Look up in a range table without the gap array wrapper. + Used also by the unified range table format. */ + +static Lisp_Object +get_range_table (Elemcount pos, Elemcount nentries, + struct range_table_entry *tab, + Elemcount gappos, Elemcount gapsize, + Lisp_Object default_) +{ + int foundp; + Elemcount entrypos = get_range_table_pos (pos, nentries, tab, gappos, + gapsize, &foundp); + if (foundp) + { + struct range_table_entry *entry = + tab + GAP_ARRAY_ARRAY_TO_MEMORY_POS_1 (entrypos, gappos, gapsize); + return entry->val; } return default_; @@ -333,7 +385,7 @@ { Lisp_Object obj = ALLOC_NORMAL_LISP_OBJECT (range_table); Lisp_Range_Table *rt = XRANGE_TABLE (obj); - rt->entries = Dynarr_new (range_table_entry); + rt->entries = make_gap_array (sizeof (struct range_table_entry), 0); rt->type = range_table_symbol_to_type (type); return obj; } @@ -347,17 +399,20 @@ { Lisp_Range_Table *rt, *rtnew; Lisp_Object obj; + Elemcount i; CHECK_RANGE_TABLE (range_table); rt = XRANGE_TABLE (range_table); obj = ALLOC_NORMAL_LISP_OBJECT (range_table); rtnew = XRANGE_TABLE (obj); - rtnew->entries = Dynarr_new (range_table_entry); + rtnew->entries = make_gap_array (sizeof (struct range_table_entry), 0); rtnew->type = rt->type; - Dynarr_add_many (rtnew->entries, Dynarr_begin (rt->entries), - Dynarr_length (rt->entries)); + for (i = 0; i < gap_array_length (rt->entries); i++) + rtnew->entries = + gap_array_insert_els (rtnew->entries, i, + rangetab_gap_array_atp (rt->entries, i), 1); return obj; } @@ -374,8 +429,12 @@ CHECK_INT_COERCE_CHAR (pos); - return get_range_table (XINT (pos), Dynarr_length (rt->entries), - Dynarr_begin (rt->entries), default_); + return get_range_table (XINT (pos), gap_array_length (rt->entries), + gap_array_begin (rt->entries, + struct range_table_entry), + gap_array_gappos (rt->entries), + gap_array_gapsize (rt->entries), + default_); } static void @@ -415,6 +474,7 @@ int i; int insert_me_here = -1; Lisp_Range_Table *rt = XRANGE_TABLE (table); + int foundp; external_to_internal_adjust_ends (rt->type, &first, &last); if (first == last) @@ -424,15 +484,59 @@ open. #### Should we signal an error? */ return; + if (DUMPEDP (rt->entries)) + rt->entries = gap_array_clone (rt->entries); + + i = get_range_table_pos (first, gap_array_length (rt->entries), + gap_array_begin (rt->entries, + struct range_table_entry), + gap_array_gappos (rt->entries), + gap_array_gapsize (rt->entries), &foundp); + +#ifdef ERROR_CHECK_TYPES + if (foundp) + { + if (i < gap_array_length (rt->entries)) + { + struct range_table_entry *entry = + rangetab_gap_array_atp (rt->entries, i); + assert (first >= entry->first && first < entry->last); + } + } + else + { + if (i < gap_array_length (rt->entries)) + { + struct range_table_entry *entry = + rangetab_gap_array_atp (rt->entries, i); + assert (first < entry->first); + } + if (i > 0) + { + struct range_table_entry *entry = + rangetab_gap_array_atp (rt->entries, i - 1); + assert (first >= entry->last); + } + } +#endif /* ERROR_CHECK_TYPES */ + + /* If the beginning of the new range isn't within any existing range, + it might still be just grazing the end of an end-open range (remember, + internally all ranges are start-close end-open); so back up one + so we consider this range. */ + if (!foundp && i > 0) + i--; + /* Now insert in the proper place. This gets tricky because we may be overlapping one or more existing ranges and need to fix them up. */ /* First delete all sections of any existing ranges that overlap the new range. */ - for (i = 0; i < Dynarr_length (rt->entries); i++) + for (; i < gap_array_length (rt->entries); i++) { - struct range_table_entry *entry = Dynarr_atp (rt->entries, i); + struct range_table_entry *entry = + rangetab_gap_array_atp (rt->entries, i); /* We insert before the first range that begins at or after the new range. */ if (entry->first >= first && insert_me_here < 0) @@ -476,7 +580,8 @@ insert_me_too.last = entry->last; insert_me_too.val = entry->val; entry->last = first; - Dynarr_insert_many (rt->entries, &insert_me_too, 1, i + 1); + rt->entries = + gap_array_insert_els (rt->entries, i + 1, &insert_me_too, 1); } else if (entry->last >= last) { @@ -497,7 +602,7 @@ else { /* existing is entirely within new. */ - Dynarr_delete_many (rt->entries, i, 1); + gap_array_delete_els (rt->entries, i, 1); i--; /* back up since everything shifted one to the left. */ } } @@ -518,7 +623,8 @@ insert_me.last = last; insert_me.val = val; - Dynarr_insert_many (rt->entries, &insert_me, 1, insert_me_here); + rt->entries = + gap_array_insert_els (rt->entries, insert_me_here, &insert_me, 1); } /* Now see if we can combine this entry with adjacent ones just @@ -526,12 +632,12 @@ if (insert_me_here > 0) { - struct range_table_entry *entry = Dynarr_atp (rt->entries, - insert_me_here - 1); + struct range_table_entry *entry = + rangetab_gap_array_atp (rt->entries, insert_me_here - 1); if (EQ (val, entry->val) && entry->last == first) { entry->last = last; - Dynarr_delete_many (rt->entries, insert_me_here, 1); + gap_array_delete_els (rt->entries, insert_me_here, 1); insert_me_here--; /* We have morphed into a larger range. Update our records in case we also combine with the one after. */ @@ -539,14 +645,14 @@ } } - if (insert_me_here < Dynarr_length (rt->entries) - 1) + if (insert_me_here < gap_array_length (rt->entries) - 1) { - struct range_table_entry *entry = Dynarr_atp (rt->entries, - insert_me_here + 1); + struct range_table_entry *entry = + rangetab_gap_array_atp (rt->entries, insert_me_here + 1); if (EQ (val, entry->val) && entry->first == last) { entry->first = first; - Dynarr_delete_many (rt->entries, insert_me_here, 1); + gap_array_delete_els (rt->entries, insert_me_here, 1); } } } @@ -585,7 +691,7 @@ (range_table)) { CHECK_RANGE_TABLE (range_table); - Dynarr_reset (XRANGE_TABLE (range_table)->entries); + gap_array_delete_all_els (XRANGE_TABLE (range_table)->entries); return Qnil; } @@ -611,17 +717,18 @@ /* Do not "optimize" by pulling out the length computation below! FUNCTION may have changed the table. */ - for (i = 0; i < Dynarr_length (rt->entries); i++) + for (i = 0; i < gap_array_length (rt->entries); i++) { - struct range_table_entry *entry = Dynarr_atp (rt->entries, i); + struct range_table_entry entry = + rangetab_gap_array_at (rt->entries, i); EMACS_INT first, last; Lisp_Object args[4]; int oldlen; again: - first = entry->first; - last = entry->last; - oldlen = Dynarr_length (rt->entries); + first = entry.first; + last = entry.last; + oldlen = gap_array_length (rt->entries); args[0] = function; /* Fix up the numbers in accordance with the open/closedness of the table. */ @@ -631,12 +738,12 @@ args[1] = make_int (premier); args[2] = make_int (dernier); } - args[3] = entry->val; + args[3] = entry.val; Ffuncall (countof (args), args); /* Has FUNCTION removed the entry? */ - if (oldlen > Dynarr_length (rt->entries) - && i < Dynarr_length (rt->entries) - && (first != entry->first || last != entry->last)) + if (oldlen > gap_array_length (rt->entries) + && i < gap_array_length (rt->entries) + && (first != entry.first || last != entry.last)) goto again; } @@ -778,7 +885,7 @@ unified_range_table_bytes_needed (Lisp_Object rangetab) { return (sizeof (struct range_table_entry) * - (Dynarr_length (XRANGE_TABLE (rangetab)->entries) - 1) + + (gap_array_length (XRANGE_TABLE (rangetab)->entries) - 1) + sizeof (struct unified_range_table) + /* ALIGNOF a struct may be too big. */ /* We have four bytes for the size numbers, and an extra @@ -798,9 +905,10 @@ char * and adding sizeof(int), because that will lead to mis-aligned data on the Alpha machines. */ struct unified_range_table *un; - range_table_entry_dynarr *rted = XRANGE_TABLE (rangetab)->entries; + Gap_Array *rtega = XRANGE_TABLE (rangetab)->entries; int total_needed = unified_range_table_bytes_needed (rangetab); void *new_dest = ALIGN_PTR ((char *) dest + 4, EMACS_INT); + Elemcount i; * (char *) dest = (char) ((char *) new_dest - (char *) dest); * ((unsigned char *) dest + 1) = total_needed & 0xFF; @@ -809,10 +917,10 @@ total_needed >>= 8; * ((unsigned char *) dest + 3) = total_needed & 0xFF; un = (struct unified_range_table *) new_dest; - un->nentries = Dynarr_length (rted); + un->nentries = gap_array_length (rtega); un->type = XRANGE_TABLE (rangetab)->type; - memcpy (&un->first, Dynarr_begin (rted), - sizeof (struct range_table_entry) * Dynarr_length (rted)); + for (i = 0; i < gap_array_length (rtega); i++) + (&un->first)[i] = rangetab_gap_array_at (rtega, i); } /* Return number of bytes actually used by a unified range table. */ @@ -855,7 +963,7 @@ new_dest = (char *) unrangetab + * (char *) unrangetab; un = (struct unified_range_table *) new_dest; - return get_range_table (pos, un->nentries, &un->first, default_); + return get_range_table (pos, un->nentries, &un->first, 0, 0, default_); } /* Return number of entries in a unified range table. */
--- a/src/rangetab.h Fri Mar 26 15:06:28 2010 +0000 +++ b/src/rangetab.h Mon Mar 29 00:11:03 2010 -0500 @@ -1,6 +1,6 @@ /* XEmacs routines to deal with range tables. Copyright (C) 1995 Sun Microsystems, Inc. - Copyright (C) 1995, 2004 Ben Wing. + Copyright (C) 1995, 2004, 2010 Ben Wing. This file is part of XEmacs. @@ -29,6 +29,9 @@ typedef struct range_table_entry range_table_entry; struct range_table_entry { +#ifdef NEW_GC + NORMAL_LISP_OBJECT_HEADER header; +#endif /* NEW_GC */ EMACS_INT first; EMACS_INT last; Lisp_Object val; @@ -50,7 +53,7 @@ struct Lisp_Range_Table { NORMAL_LISP_OBJECT_HEADER header; - range_table_entry_dynarr *entries; + Gap_Array *entries; enum range_table_type type; }; typedef struct Lisp_Range_Table Lisp_Range_Table; @@ -61,4 +64,8 @@ #define RANGE_TABLEP(x) RECORDP (x, range_table) #define CHECK_RANGE_TABLE(x) CHECK_RECORD (x, range_table) +#define rangetab_gap_array_at(ga, pos) \ + gap_array_at (ga, pos, struct range_table_entry) +#define rangetab_gap_array_atp(ga, pos) \ + gap_array_atp (ga, pos, struct range_table_entry) #endif /* INCLUDED_rangetab_h_ */
--- a/src/redisplay.c Fri Mar 26 15:06:28 2010 +0000 +++ b/src/redisplay.c Mon Mar 29 00:11:03 2010 -0500 @@ -1686,7 +1686,10 @@ break; case PROP_STRING: if (pb->data.p_string.str) - xfree (pb->data.p_string.str); + { + xfree (pb->data.p_string.str); + pb->data.p_string.str = 0; + } /* #### bogus bogus -- this doesn't do anything! Should probably call add_ibyte_string_runes(), once that function is fixed. */
--- a/src/scrollbar-gtk.c Fri Mar 26 15:06:28 2010 +0000 +++ b/src/scrollbar-gtk.c Mon Mar 29 00:11:03 2010 -0500 @@ -3,6 +3,7 @@ Copyright (C) 1994 Amdhal Corporation. Copyright (C) 1995 Sun Microsystems, Inc. Copyright (C) 1995 Darrell Kindred <dkindred+@cmu.edu>. + Copyright (C) 2010 Ben Wing. This file is part of XEmacs. @@ -65,6 +66,7 @@ } xfree (instance->scrollbar_data); + instance->scrollbar_data = 0; } } @@ -474,23 +476,15 @@ } #ifdef MEMORY_USAGE_STATS -static int +static Bytecount gtk_compute_scrollbar_instance_usage (struct device *UNUSED (d), struct scrollbar_instance *inst, struct usage_stats *ustats) { - int total = 0; + struct gtk_scrollbar_data *data = + (struct gtk_scrollbar_data *) inst->scrollbar_data; - while (inst) - { - struct gtk_scrollbar_data *data = - (struct gtk_scrollbar_data *) inst->scrollbar_data; - - total += malloced_storage_size (data, sizeof (*data), ustats); - inst = inst->next; - } - - return total; + return malloced_storage_size (data, sizeof (*data), ustats); } #endif /* MEMORY_USAGE_STATS */
--- a/src/scrollbar-msw.c Fri Mar 26 15:06:28 2010 +0000 +++ b/src/scrollbar-msw.c Mon Mar 29 00:11:03 2010 -0500 @@ -3,7 +3,7 @@ Copyright (C) 1994 Amdahl Corporation. Copyright (C) 1995 Sun Microsystems, Inc. Copyright (C) 1995 Darrell Kindred <dkindred+@cmu.edu>. - Copyright (C) 2001, 2002 Ben Wing. + Copyright (C) 2001, 2002, 2010 Ben Wing. This file is part of XEmacs. @@ -102,6 +102,7 @@ assert (!NILP (ptr)); DestroyWindow (SCROLLBAR_MSW_HANDLE (sb)); xfree (sb->scrollbar_data); + sb->scrollbar_data = 0; } } @@ -423,23 +424,15 @@ #ifdef MEMORY_USAGE_STATS -static int +static Bytecount mswindows_compute_scrollbar_instance_usage (struct device *UNUSED (d), struct scrollbar_instance *inst, struct usage_stats *ustats) { - int total = 0; + struct mswindows_scrollbar_data *data = + (struct mswindows_scrollbar_data *) inst->scrollbar_data; - while (inst) - { - struct mswindows_scrollbar_data *data = - (struct mswindows_scrollbar_data *) inst->scrollbar_data; - - total += malloced_storage_size (data, sizeof (*data), ustats); - inst = inst->next; - } - - return total; + return malloced_storage_size (data, sizeof (*data), ustats); } #endif /* MEMORY_USAGE_STATS */
--- a/src/scrollbar-x.c Fri Mar 26 15:06:28 2010 +0000 +++ b/src/scrollbar-x.c Mon Mar 29 00:11:03 2010 -0500 @@ -76,7 +76,10 @@ if (instance->scrollbar_data) { if (SCROLLBAR_X_NAME (instance)) - xfree (SCROLLBAR_X_NAME (instance)); + { + xfree (SCROLLBAR_X_NAME (instance)); + SCROLLBAR_X_NAME (instance) = 0; + } if (SCROLLBAR_X_WIDGET (instance)) { @@ -87,6 +90,7 @@ } xfree (instance->scrollbar_data); + instance->scrollbar_data = 0; } } @@ -694,23 +698,18 @@ #ifdef MEMORY_USAGE_STATS -static int +static Bytecount x_compute_scrollbar_instance_usage (struct device *UNUSED (d), struct scrollbar_instance *inst, struct usage_stats *ustats) { - int total = 0; + Bytecount total = 0; + struct x_scrollbar_data *data = + (struct x_scrollbar_data *) inst->scrollbar_data; - while (inst) - { - struct x_scrollbar_data *data = - (struct x_scrollbar_data *) inst->scrollbar_data; - - total += malloced_storage_size (data, sizeof (*data), ustats); - total += malloced_storage_size (data->name, 1 + strlen (data->name), - ustats); - inst = inst->next; - } + total += malloced_storage_size (data, sizeof (*data), ustats); + total += malloced_storage_size (data->name, 1 + strlen (data->name), + ustats); return total; }
--- a/src/scrollbar.c Fri Mar 26 15:06:28 2010 +0000 +++ b/src/scrollbar.c Mon Mar 29 00:11:03 2010 -0500 @@ -257,26 +257,43 @@ #ifdef MEMORY_USAGE_STATS -int -compute_scrollbar_instance_usage (struct device *d, - struct scrollbar_instance *inst, - struct usage_stats *ustats) +struct scrollbar_instance_stats { - int total = 0; + struct usage_stats u; + Bytecount device_data; +}; - if (HAS_DEVMETH_P(d, compute_scrollbar_instance_usage)) - total += DEVMETH (d, compute_scrollbar_instance_usage, (d, inst, ustats)); +Bytecount +compute_all_scrollbar_instance_usage (struct scrollbar_instance *inst) +{ + Bytecount total = 0; while (inst) { - total += lisp_object_storage_size (wrap_scrollbar_instance (inst), - ustats); + total += lisp_object_memory_usage (wrap_scrollbar_instance (inst)); inst = inst->next; } return total; } +static void +scrollbar_instance_memory_usage (Lisp_Object scrollbar_instance, + struct generic_usage_stats *gustats) +{ + struct scrollbar_instance_stats *stats = + (struct scrollbar_instance_stats *) gustats; + struct scrollbar_instance *inst = XSCROLLBAR_INSTANCE (scrollbar_instance); + struct device *d = FRAME_XDEVICE (inst->mirror->frame); + Bytecount total = 0; + + if (HAS_DEVMETH_P (d, compute_scrollbar_instance_usage)) + total += DEVMETH (d, compute_scrollbar_instance_usage, (d, inst, + &gustats->u)); + + stats->device_data = total; +} + #endif /* MEMORY_USAGE_STATS */ void @@ -924,6 +941,13 @@ /************************************************************************/ void +scrollbar_objects_create (void) +{ +#ifdef MEMORY_USAGE_STATS + OBJECT_HAS_METHOD (scrollbar_instance, memory_usage); +#endif +} +void syms_of_scrollbar (void) { INIT_LISP_OBJECT (scrollbar_instance); @@ -962,6 +986,12 @@ void vars_of_scrollbar (void) { +#ifdef MEMORY_USAGE_STATS + OBJECT_HAS_PROPERTY + (scrollbar_instance, memusage_stats_list, + list1 (intern ("device-data"))); +#endif /* MEMORY_USAGE_STATS */ + DEFVAR_LISP ("scrollbar-pointer-glyph", &Vscrollbar_pointer_glyph /* *The shape of the mouse-pointer when over a scrollbar. This is a glyph; use `set-glyph-image' to change it.
--- a/src/scrollbar.h Fri Mar 26 15:06:28 2010 +0000 +++ b/src/scrollbar.h Mon Mar 29 00:11:03 2010 -0500 @@ -1,5 +1,6 @@ /* Define scrollbar instance. Copyright (C) 1994, 1995 Board of Trustees, University of Illinois. + Copyright (C) 2010 Ben Wing. This file is part of XEmacs. @@ -65,9 +66,8 @@ struct window_mirror *mirror, int active, int horiz_only); #ifdef MEMORY_USAGE_STATS -int compute_scrollbar_instance_usage (struct device *d, - struct scrollbar_instance *inst, - struct usage_stats *ustats); +Bytecount compute_all_scrollbar_instance_usage (struct scrollbar_instance * + inst); #endif extern Lisp_Object Vscrollbar_width, Vscrollbar_height;
--- a/src/select-x.c Fri Mar 26 15:06:28 2010 +0000 +++ b/src/select-x.c Mon Mar 29 00:11:03 2010 -0500 @@ -1,6 +1,6 @@ /* X Selection processing for XEmacs Copyright (C) 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc. - Copyright (C) 2001, 2002 Ben Wing. + Copyright (C) 2001, 2002, 2010 Ben Wing. This file is part of XEmacs. @@ -691,10 +691,8 @@ event->type = 0; /* Data need not have been allocated; cf. select-convert-to-delete in lisp/select.el . */ - if ((Rawbyte *)0 != data) - { + if (data) xfree (data); - } } unbind_to (count);
--- a/src/specifier.c Fri Mar 26 15:06:28 2010 +0000 +++ b/src/specifier.c Mon Mar 29 00:11:03 2010 -0500 @@ -442,22 +442,13 @@ 0, specifier_empty_extra_description_1 }; -#ifdef NEW_GC DEFINE_DUMPABLE_SIZABLE_LISP_OBJECT ("specifier", specifier, mark_specifier, print_specifier, - 0, specifier_equal, specifier_hash, - specifier_description, - sizeof_specifier, - Lisp_Specifier); -#else /* not NEW_GC */ -DEFINE_DUMPABLE_SIZABLE_LISP_OBJECT ("specifier", specifier, - mark_specifier, print_specifier, - finalize_specifier, + IF_OLD_GC (finalize_specifier), specifier_equal, specifier_hash, specifier_description, sizeof_specifier, Lisp_Specifier); -#endif /* not NEW_GC */ /************************************************************************/ /* Creating specifiers */
--- a/src/symsinit.h Fri Mar 26 15:06:28 2010 +0000 +++ b/src/symsinit.h Mon Mar 29 00:11:03 2010 -0500 @@ -72,6 +72,7 @@ void syms_of_abbrev (void); void syms_of_alloc (void); +void syms_of_array (void); void syms_of_balloon_x (void); void syms_of_buffer (void); void syms_of_bytecode (void); @@ -208,6 +209,7 @@ Dump time and post-pdump-load-time. */ void buffer_objects_create (void); +void casetab_objects_create (void); void extent_objects_create (void); void face_objects_create (void); void frame_objects_create (void); @@ -215,6 +217,7 @@ void hash_table_objects_create (void); void lstream_objects_create (void); void mule_charset_objects_create (void); +void scrollbar_objects_create (void); void ui_gtk_objects_create (void); void window_objects_create (void); @@ -353,6 +356,7 @@ void reinit_vars_of_bytecode (void); void vars_of_callint (void); EXTERN_C void vars_of_canna_api (void); +void vars_of_casetab (void); void vars_of_chartab (void); void vars_of_cmdloop (void); void vars_of_cmds (void);
--- a/src/syntax.c Fri Mar 26 15:06:28 2010 +0000 +++ b/src/syntax.c Mon Mar 29 00:11:03 2010 -0500 @@ -1,7 +1,7 @@ /* XEmacs routines to deal with syntax tables; also word and list parsing. Copyright (C) 1985-1994 Free Software Foundation, Inc. Copyright (C) 1995 Sun Microsystems, Inc. - Copyright (C) 2001, 2002, 2003 Ben Wing. + Copyright (C) 2001, 2002, 2003, 2010 Ben Wing. This file is part of XEmacs. @@ -542,8 +542,11 @@ uninit_buffer_syntax_cache (struct buffer *UNUSED_IF_NEW_GC (buf)) { #ifndef NEW_GC - xfree (buf->syntax_cache); - buf->syntax_cache = 0; + if (buf->syntax_cache) + { + xfree (buf->syntax_cache); + buf->syntax_cache = 0; + } #endif /* not NEW_GC */ }
--- a/src/text.h Fri Mar 26 15:06:28 2010 +0000 +++ b/src/text.h Mon Mar 29 00:11:03 2010 -0500 @@ -2060,9 +2060,15 @@ if ((ei)->mallocp_) \ { \ if ((ei)->data_) \ - xfree ((ei)->data_); \ + { \ + xfree ((ei)->data_); \ + (ei)->data_ = 0; \ + } \ if ((ei)->extdata_) \ - xfree ((ei)->extdata_); \ + { \ + xfree ((ei)->extdata_); \ + (ei)->extdata_ = 0; \ + } \ eiinit_malloc (ei); \ } \ else \
--- a/src/window.c Fri Mar 26 15:06:28 2010 +0000 +++ b/src/window.c Mon Mar 29 00:11:03 2010 -0500 @@ -55,7 +55,7 @@ Lisp_Object Qdisplay_buffer; #ifdef MEMORY_USAGE_STATS -Lisp_Object Qface_cache, Qglyph_cache, Qline_start_cache, Qother_redisplay; +Lisp_Object Qface_cache, Qglyph_cache, Qline_start_cache, Qredisplay_structs; #ifdef HAVE_SCROLLBARS Lisp_Object Qscrollbar_instances; #endif @@ -627,7 +627,7 @@ find_window_mirror_internal (Lisp_Object win, struct window_mirror *rmir, struct window *w) { - for (; !NILP (win); win = XWINDOW (win)->next, rmir = rmir->next) + for (; !NILP (win) && rmir; win = XWINDOW (win)->next, rmir = rmir->next) { if (w == XWINDOW (win)) return rmir; @@ -710,6 +710,18 @@ XWINDOW_MIRROR (f->root_mirror), w); } +/* Given a real window, return its mirror structure, if it exists. + Don't do any updating. */ +static struct window_mirror * +find_window_mirror_maybe (struct window *w) +{ + struct frame *f = XFRAME (w->frame); + if (!WINDOW_MIRRORP (f->root_mirror)) + return 0; + return find_window_mirror_internal (f->root_window, + XWINDOW_MIRROR (f->root_mirror), w); +} + /***************************************************************************** find_window_by_pixel_pos @@ -752,8 +764,6 @@ { struct window_mirror *t; - if (XFRAME (w->frame)->mirror_dirty) - update_frame_window_mirror (XFRAME (w->frame)); t = find_window_mirror (w); assert (t); @@ -775,8 +785,6 @@ { struct window_mirror *t; - if (XFRAME (w->frame)->mirror_dirty) - update_frame_window_mirror (XFRAME (w->frame)); t = find_window_mirror (w); assert (t); @@ -788,8 +796,6 @@ { struct window_mirror *t; - if (XFRAME (w->frame)->mirror_dirty) - update_frame_window_mirror (XFRAME (w->frame)); t = find_window_mirror (w); assert (t); @@ -5156,52 +5162,93 @@ #ifdef MEMORY_USAGE_STATS +struct window_mirror_stats +{ + struct usage_stats u; + /* Ancilliary non-lisp */ + Bytecount redisplay_structs; +#ifdef HAVE_SCROLLBARS + /* Ancilliary Lisp */ + Bytecount scrollbar; +#endif +}; + struct window_stats { struct usage_stats u; + /* Ancillary non-Lisp */ + Bytecount line_start; + /* The next two: ancillary non-Lisp under old-GC, ancillary Lisp under + NEW_GC */ Bytecount face; Bytecount glyph; - Bytecount line_start; - Bytecount other_redisplay; + /* The next two are copied out of the window mirror, which is an ancillary + Lisp structure; the first is non-Lisp, the second Lisp, but from our + perspective, they are both counted as Lisp */ + Bytecount redisplay_structs; #ifdef HAVE_SCROLLBARS Bytecount scrollbar; #endif + /* Remaining memory associated with window mirror (ancillary Lisp) */ + Bytecount window_mirror; }; static void compute_window_mirror_usage (struct window_mirror *mir, - struct window_stats *stats, - struct usage_stats *ustats) -{ - if (!mir) - return; + struct window_mirror_stats *stats) +{ + stats->redisplay_structs = + compute_display_line_dynarr_usage (mir->current_display_lines, &stats->u) + + + compute_display_line_dynarr_usage (mir->desired_display_lines, &stats->u); #ifdef HAVE_SCROLLBARS - { - struct device *d = XDEVICE (FRAME_DEVICE (mir->frame)); - - stats->scrollbar += - compute_scrollbar_instance_usage (d, mir->scrollbar_vertical_instance, - ustats); - stats->scrollbar += - compute_scrollbar_instance_usage (d, mir->scrollbar_horizontal_instance, - ustats); - } + stats->scrollbar = + compute_all_scrollbar_instance_usage (mir->scrollbar_vertical_instance) + + compute_all_scrollbar_instance_usage (mir->scrollbar_horizontal_instance); #endif /* HAVE_SCROLLBARS */ - stats->other_redisplay += - compute_display_line_dynarr_usage (mir->current_display_lines, ustats); - stats->other_redisplay += - compute_display_line_dynarr_usage (mir->desired_display_lines, ustats); +} + + +static void +window_mirror_memory_usage (Lisp_Object window_mirror, + struct generic_usage_stats *gustats) +{ + struct window_mirror_stats *stats = (struct window_mirror_stats *) gustats; + + compute_window_mirror_usage (XWINDOW_MIRROR (window_mirror), stats); } static void compute_window_usage (struct window *w, struct window_stats *stats, struct usage_stats *ustats) { - stats->face += compute_face_cachel_usage (w->face_cachels, ustats); - stats->glyph += compute_glyph_cachel_usage (w->glyph_cachels, ustats); - stats->line_start += + stats->line_start = compute_line_start_cache_dynarr_usage (w->line_start_cache, ustats); - compute_window_mirror_usage (find_window_mirror (w), stats, ustats); + stats->face = compute_face_cachel_usage (w->face_cachels, + IF_OLD_GC (ustats)); + stats->glyph = compute_glyph_cachel_usage (w->glyph_cachels, + IF_OLD_GC (ustats)); + { + struct window_mirror *wm; + + wm = find_window_mirror_maybe (w); + if (wm) + { + struct generic_usage_stats gustats; + struct window_mirror_stats *wmstats; + Bytecount total; + total = lisp_object_memory_usage_full (wrap_window_mirror (wm), + NULL, NULL, NULL, &gustats); + wmstats = (struct window_mirror_stats *) &gustats; + stats->redisplay_structs = wmstats->redisplay_structs; + total -= stats->redisplay_structs; +#ifdef HAVE_SCROLLBARS + stats->scrollbar = wmstats->scrollbar; + total -= stats->scrollbar; +#endif + stats->window_mirror = total; + } + } } static void @@ -5396,6 +5443,7 @@ { #ifdef MEMORY_USAGE_STATS OBJECT_HAS_METHOD (window, memory_usage); + OBJECT_HAS_METHOD (window_mirror, memory_usage); #endif } @@ -5422,7 +5470,7 @@ #ifdef HAVE_SCROLLBARS DEFSYMBOL (Qscrollbar_instances); #endif - DEFSYMBOL (Qother_redisplay); + DEFSYMBOL (Qredisplay_structs); #endif DEFSYMBOL (Qtruncate_partial_width_windows); @@ -5516,20 +5564,31 @@ vars_of_window (void) { #ifdef MEMORY_USAGE_STATS + Lisp_Object l; + + l = listu (Qline_start_cache, +#ifdef NEW_GC + Qt, +#endif + Qface_cache, Qglyph_cache, +#ifndef NEW_GC + Qt, +#endif + Qredisplay_structs, #ifdef HAVE_SCROLLBARS - OBJECT_HAS_PROPERTY - (window, memusage_stats_list, - listu (Qface_cache, Qglyph_cache, - Qline_start_cache, Qother_redisplay, - Qscrollbar_instances, - Qunbound)); -#else - OBJECT_HAS_PROPERTY - (window, memusage_stats_list, - listu (Qface_cache, Qglyph_cache, - Qline_start_cache, Qother_redisplay, - Qunbound)); + Qscrollbar_instances, #endif + intern ("window-mirror"), + Qunbound); + + OBJECT_HAS_PROPERTY (window, memusage_stats_list, l); + + l = listu (Qredisplay_structs, +#ifdef HAVE_SCROLLBARS + Qt, Qscrollbar_instances, +#endif + Qunbound); + OBJECT_HAS_PROPERTY (window_mirror, memusage_stats_list, l); #endif /* MEMORY_USAGE_STATS */ DEFVAR_BOOL ("scroll-on-clipped-lines", &scroll_on_clipped_lines /*