changeset 5159:cb303ff63e76

merge
author Ben Wing <ben@xemacs.org>
date Fri, 19 Mar 2010 17:02:11 -0500
parents 9e0b43d3095c (diff) 45753d9a0dc4 (current diff)
children ab9ee10a53e4
files ChangeLog src/ChangeLog src/alloc.c
diffstat 44 files changed, 1442 insertions(+), 556 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES-beta	Thu Mar 18 23:12:41 2010 -0500
+++ b/CHANGES-beta	Fri Mar 19 17:02:11 2010 -0500
@@ -1,3 +1,133 @@
+to XEmacs 21.5.30 "harblegarble"
+
+by Ben Wing:
+
+debugging:
+
+-- make objects consistently print a UID, with a separate number space per
+   object type
+-- add variable `debug-soe' for debugging stack-of-extents code in extents.c
+-- correctly note pdumped objects in memory-usage stats returned by
+   `garbage-collect' and `object-memory-usage-stats'.
+-- make VDB debugging functions (e.g. `test-segfault', which causes an
+   immediate crash!) conditional on `--with-debug'
+-- rename `debug-xemacs-searches' -> `debug-searches'
+-- Turn on "compiled-function annotation hack" so that compiled-function
+   objects print the function they are assigned to
+-- Resurrect byte-metering code when --with-debug; enable with variables
+   `byte-code-meter', `byte-metering-on'
+-- Add more checks for invalid byte code; when a byte-code-related crash
+   occurs, output the last 100 instructions processed
+
+documentation:
+
+-- fix to `previous/next-single[-char]-property-change'
+
+Lisp API:
+
+-- `set-frame-displayable-pixel-height' and friends had bugs in them, esp.
+   on MS Windows, where they didn't work; fixed
+-- `frame-pixel-height', `set-frame-pixel-height' and friends will now
+   use updated values for frame size (as of next redisplay) when the frame
+   was previously resized but a redisplay has not yet happened
+-- When `set-case-table' called with a length-256 vector, don't overwrite
+   existing case table; instead, populate a new table
+-- Fix internal case comparisons to use the "canonical case mapping" so that
+   they always work even in the presence of complex case mappings (other
+   than just upper -> lower and lower -> upper)
+-- In `scan-lists' and friends, when an error occurs, return a `scan-error'
+   along with two arguments specifying the range in which the error occurred,
+   for GNU compatibility
+
+Internals:
+
+-- reduce lcrecord header size from 3 words to 2
+-- major change to the way Lisp objects are defined and declared; introduce
+   a cleaner surface-layer API that eliminates references to "lrecords" and
+   "lcrecords", and uses "frob-block object" in place of "basic object"/
+   "simple object"/etc.
+-- new disksave method for Lisp objects, separated out from the finalize method
+-- Lisp objects now must specify a print method; use either
+   internal_object_printer() or external_object_printer() as a default
+-- equal method for Lisp objects has new `foldcase' param, to implement
+   case-folding comparison ala `equalp'
+-- various changes to frame-geometry macros in frame-impl.h, gutter.h, etc.,
+   and frame-sizing code in frame.c
+-- Major rewrite, updated documentation to dynarr functions and macros
+-- Major updates to internals manual and long comments in C files:
+   frame geometry, specifier authors, MS-Windows compilation flags, xlike
+   mechanism, ...
+-- Rename LISP_TO_VOID -> STORE_LISP_IN_VOID,
+   VOID_TO_LISP -> GET_LISP_FROM_VOID; add STORE_VOID_IN_LISP,
+   GET_VOID_FROM_LISP
+-- Convert various source files to UTF-8
+-- File renames:
+   select-common.h -> select-xlike-inc.c
+   xgccache.{ch} -> gccache-x.{ch}
+   toolbar-common.{ch} -> toolbar-xlike.{ch}
+-- New files:
+   bytecode-ops.h
+   sysgtk.h, sysgdkx.h
+   keymap-buttons.h, keymap-slots.h
+-- Deleted files:
+   event-gtk.h
+-- Major reworking of DFC macros e.g. EXTERNAL_TO_C_STRING renamed to
+   EXTERNAL_TO_ITEXT; make them return their values when possible rather
+   than storing into a named variable
+-- Eliminate unused second argument to xfree()
+-- separate HAVE_XFT into HAVE_XFT and USE_XFT, to facilitate compiling
+   simultaneously with X and GTK
+-- Move `equalp' to C
+
+Testing:
+
+-- Move test-harness.el to Lisp directory
+
+Building:
+
+-- Fix `--quick-build' so full rebuilds don't happen when changes are made
+   to files like lisp.h, config.h that are included by all C files
+-- Fix C++ build on Cygwin when configured with --have-database
+
+User-Visible Bug Fixes:
+
+-- `escape-quoted' was failing to add escape quoting to Control-1 characters;
+   many potential byte-code-related crashes may have resulted from the old
+   behavior
+-- Fix a redisplay bug where args to default_face_height_and_width() were
+   in wrong order
+-- "speedy insert" code (to make `revert-buffer' preserve extents, markers,
+   etc. in unmodified sections of a reverted file) was broken with binary
+   files
+-- File-locking code now names lock files .#FN# instead of .#FN, to avoid
+   problems with programs that e.g. try to process all .c or .h files
+-- Fix a crash in frame creation due to lack of call to reset_glyph_cachels()
+-- Fix long-standing bug: searching for Control-1 chars didn't work
+-- Turn on `load-ignore-out-of-date-elc-files' by default
+
+
+
+by Didier Verna:
+
+Lisp API:
+
+-- new `background-placement' property of faces; with a value of `absolute',
+   the background pixmap is drawn relative to the root window, allowing
+   seamless integration with the desktop background
+
+by Jerry James:
+
+Lisp API:
+
+-- signal an error instead of crashing when encountering a ratio like 1/0
+
+Internals:
+
+-- locate and add copyright notices to various files in preparation for
+   move to GPL v3
+
+
+
 to XEmacs 21.5.29 "garbanzo"
 
 Major Features and Backward Incompatible Changes
--- a/ChangeLog	Thu Mar 18 23:12:41 2010 -0500
+++ b/ChangeLog	Fri Mar 19 17:02:11 2010 -0500
@@ -1,3 +1,8 @@
+2010-03-18  Ben Wing  <ben@xemacs.org>
+
+	* CHANGES-beta:
+	Partially updated with last couple of months worth of changes.
+
 2010-03-18  Mike Sperber  <mike@xemacs.org>
 
 	* INSTALL: Reflect change from `lib' to `share'; also, document
--- a/lisp/ChangeLog	Thu Mar 18 23:12:41 2010 -0500
+++ b/lisp/ChangeLog	Fri Mar 19 17:02:11 2010 -0500
@@ -1,3 +1,14 @@
+2010-03-19  Ben Wing  <ben@xemacs.org>
+
+	* diagnose.el (show-object-memory-usage-stats):
+	Rewrite to take into account non-lisp-storage statistics
+	returned by garbage-collect-1 and friends.
+
+2010-03-18  Ben Wing  <ben@xemacs.org>
+
+	* diagnose.el (show-memory-usage):
+	Rewrite to take into account API changes in memory-usage functions.
+
 2010-03-15  Ben Wing  <ben@xemacs.org>
 
 	* mule/mule-cmds.el:
--- a/lisp/diagnose.el	Thu Mar 18 23:12:41 2010 -0500
+++ b/lisp/diagnose.el	Fri Mar 19 17:02:11 2010 -0500
@@ -35,16 +35,25 @@
   "Show statistics about memory usage of various sorts in XEmacs."
   (interactive)
   (garbage-collect)
-  (flet ((show-foo-stats (objtypename objlist memfun)
+  (flet ((show-foo-stats (objtypename cleanfun objlist)
 	   (let* ((hash (make-hash-table))
 		  (first t)
 		  types fmt
 		  (objnamelen 25)
 		  (linelen objnamelen)
 		  (totaltotal 0))
-	     (dolist (obj objlist)
+	     (loop for obj in objlist do
 	       (let ((total 0)
-		     (stats (funcall memfun obj)))
+		     (stats (object-memory-usage obj)))
+		 ;; Pop off the slice describing the object itself's
+		 ;; memory
+		 (while (and stats (not (eq t (pop stats)))))
+		 ;; Pop off the slice describing the associated
+		 ;; non-Lisp-Object memory from the allocation
+		 ;; perspective, so we can get to the slice describing
+		 ;; the  memory grouped by type
+		 (while (and stats (pop stats)))
+
 		 (loop for (type . num) in stats while type do
 		   (puthash type (+ num (or (gethash type hash) 0)) hash)
 		   (incf total num)
@@ -68,7 +77,7 @@
 				 (append types (list 'total))))
 		   (princ (make-string linelen ?-))
 		   (princ "\n"))
-		 (let ((objname (format "%s" obj)))
+		 (let ((objname (format "%s" (funcall cleanfun obj))))
 		   (princ (apply 'format fmt (substring objname 0
 							(min (length objname)
 							     (1- objnamelen)))
@@ -94,8 +103,8 @@
 	  (when-fboundp 'charset-list
 	    (setq begin (point))
 	    (incf grandtotal
-		  (show-foo-stats 'charset (charset-list)
-				  #'charset-memory-usage))
+		  (show-foo-stats 'charset 'charset-name
+				  (mapcar 'get-charset (charset-list))))
 	    (when-fboundp 'sort-numeric-fields
 	      (sort-numeric-fields -1
 				   (save-excursion
@@ -108,7 +117,7 @@
 	    (princ "\n"))
 	  (setq begin (point))
 	  (incf grandtotal
-		(show-foo-stats 'buffer (buffer-list) #'buffer-memory-usage))
+		(show-foo-stats 'buffer 'buffer-name (buffer-list)))
 	  (when-fboundp 'sort-numeric-fields
 	    (sort-numeric-fields -1
 				 (save-excursion
@@ -121,10 +130,11 @@
 	  (princ "\n")
 	  (setq begin (point))
 	  (incf grandtotal
-		(show-foo-stats 'window (mapcan #'(lambda (fr)
-						    (window-list fr t))
-						(frame-list))
-				#'window-memory-usage))
+		(show-foo-stats 'window #'(lambda (x)
+					    (buffer-name (window-buffer x)))
+				(mapcan #'(lambda (fr)
+					    (window-list fr t))
+					(frame-list))))
           (when-fboundp #'sort-numeric-fields
             (sort-numeric-fields -1
                                  (save-excursion
@@ -176,26 +186,40 @@
   (garbage-collect)
   (let ((buffer "*object memory usage statistics*")
 	(plist (object-memory-usage-stats))
-	(fmt "%-30s%10s%10s\n")
+	(fmt "%-30s%10s%10s%18s\n")
 	(grandtotal 0)
 	begin)
   (flet ((show-stats (match-string)
-	(princ (format fmt "object" "count" "storage"))
-	(princ (make-string 50 ?-))
+	(princ (format fmt "object" "count" "storage" "non-Lisp storage"))
+	(princ (make-string 68 ?-))
 	(princ "\n")
 	(let ((total-use 0)
+	      (total-non-lisp-use 0)
 	      (total-use-overhead 0)
 	      (total-count 0))
 	  (map-plist 
 	   #'(lambda (stat num)
-	       (when (string-match match-string
-				   (symbol-name stat))
+	       (when (and (string-match match-string
+					(symbol-name stat))
+			  (let ((match (match-string
+					1 (symbol-name stat))))
+			    (or (< (length match) 9)
+				(not (equal (substring match -9)
+					    "-non-lisp")))))
 		 (let ((storage-use num)
 		       (storage-use-overhead 
 			(plist-get 
 			 plist 
 			 (intern (concat (match-string 1 (symbol-name stat))
 					 "-storage-including-overhead"))))
+		       (non-lisp-storage
+			(or (plist-get
+			     plist
+			     (intern (concat (match-string 1
+							   (symbol-name stat))
+					     "-non-lisp-storage")))
+			    0))
+
 		       (storage-count 
 			(or (loop for str in '("s-used" "es-used" "-used")
 			      for val = (plist-get
@@ -218,19 +242,21 @@
 		   (incf total-use-overhead (if storage-use-overhead 
 						storage-use-overhead 
 					      storage-use))
+		   (incf total-non-lisp-use non-lisp-storage)
 		   (incf total-count (or storage-count 0))
 		   (and (> storage-use 0)
 			(princ (format fmt
 				       (match-string 1 (symbol-name stat)) 
 				       (or storage-count "unknown")
-				       storage-use))))))
+				       storage-use
+				       non-lisp-storage))))))
 	   plist)
 	  (princ "\n")
 	  (princ (format fmt "total" 
-			 total-count total-use-overhead))
+			 total-count total-use-overhead total-non-lisp-use))
 	  (incf grandtotal total-use-overhead)
           (when-fboundp #'sort-numeric-fields
-            (sort-numeric-fields -1
+            (sort-numeric-fields -2
                                  (save-excursion
                                    (goto-char begin)
                                    (forward-line 3)
@@ -242,7 +268,7 @@
       (save-excursion
 	(set-buffer buffer)
 	(setq begin (point))
-	(princ "Allocated with lisp allocator:\n")
+	(princ "Allocated with lisp allocator or related:\n")
 	(show-stats "\\(.*\\)-storage$")
 	(princ (format "\n\ngrand total: %s\n" grandtotal)))
       grandtotal))))
--- a/src/ChangeLog	Thu Mar 18 23:12:41 2010 -0500
+++ b/src/ChangeLog	Fri Mar 19 17:02:11 2010 -0500
@@ -1,3 +1,264 @@
+2010-03-19  Ben Wing  <ben@xemacs.org>
+
+	* alloc.c:
+	* alloc.c (struct):
+	* alloc.c (tick_lrecord_stats):
+	* alloc.c (gc_sweep_1):
+	* alloc.c (finish_object_memory_usage_stats):
+	* alloc.c (object_memory_usage_stats):
+	* alloc.c (compute_memusage_stats_length):
+	Call new memory-usage mechanism at sweep time to compute extra
+	memory utilization for all objects.  Add up the values element-by-
+	element to get an aggregrate set of statistics, where each is the
+	sum of the values of a single statistic across different objects
+	of the same type.  At end of sweep time, call
+	finish_object_memory_usage_stats() to add up all the aggreggrate
+	stats that are related to non-Lisp memory storage to compute
+	a single value, and add it to the list of values returned by
+	`garbage-collect' and `object-memory-usage-stats'.
+	
+	* buffer.c (compute_buffer_text_usage):
+	Don't crash on buffers without text (killed buffers?) and don't
+	double-count indirect buffers.
+	
+	* elhash.c:
+	* elhash.c (hash_table_objects_create):
+	* elhash.c (vars_of_elhash):
+	* symsinit.h:
+	Add memory-usage method to count the size of `hentries'.
+	
+	* emacs.c (main_1):
+	Call new functions in elhash.c, frame.c at init.
+	
+	* frame.c:
+	* frame.c (compute_frame_usage):
+	* frame.c (frame_memory_usage):
+	* frame.c (frame_objects_create):
+	* symsinit.h:
+	Add memory-usage method to count gutter display structures,
+	subwindow exposures.
+	
+	* gc.c (gc_finish):
+	* lisp.h:
+	Declare finish_object_memory_usage_stats(), call it in gc_finish().
+	
+	* lrecord.h (struct lrecord_implementation):
+	* lrecord.h (INIT_MEMORY_USAGE_STATS):
+	New value in implementation struct to track number of non-Lisp-memory
+	statistics.  Computed in alloc.c.
+	
+
+2010-03-18  Ben Wing  <ben@xemacs.org>
+
+	* alloc.c:
+	* alloc.c (disksave_object_finalization_1):
+	* alloc.c (lisp_object_storage_size):
+	* alloc.c (listu):
+	* alloc.c (listn):
+	* alloc.c (Fobject_memory_usage_stats):
+	* alloc.c (compute_memusage_stats_length):
+	* alloc.c (Fobject_memory_usage):
+	* alloc.c (Ftotal_object_memory_usage):
+	* alloc.c (malloced_storage_size):
+	* alloc.c (common_init_alloc_early):
+	* alloc.c (reinit_alloc_objects_early):
+	* alloc.c (reinit_alloc_early):
+	* alloc.c (init_alloc_once_early):
+	* alloc.c (syms_of_alloc):
+	* alloc.c (reinit_vars_of_alloc):
+	* buffer.c:
+	* buffer.c (struct buffer_stats):
+	* buffer.c (compute_buffer_text_usage):
+	* buffer.c (compute_buffer_usage):
+	* buffer.c (buffer_memory_usage):
+	* buffer.c (buffer_objects_create):
+	* buffer.c (syms_of_buffer):
+	* buffer.c (vars_of_buffer):
+	* console-impl.h (struct console_methods):
+	* dynarr.c (Dynarr_memory_usage):
+	* emacs.c (main_1):
+	* events.c (clear_event_resource):
+	* extents.c:
+	* extents.c (compute_buffer_extent_usage):
+	* extents.c (extent_objects_create):
+	* extents.h:
+	* faces.c:
+	* faces.c (compute_face_cachel_usage):
+	* faces.c (face_objects_create):
+	* faces.h:
+	* general-slots.h:
+	* glyphs.c:
+	* glyphs.c (compute_glyph_cachel_usage):
+	* glyphs.c (glyph_objects_create):
+	* glyphs.h:
+	* lisp.h:
+	* lisp.h (struct usage_stats):
+	* lrecord.h:
+	* lrecord.h (enum lrecord_type):
+	* lrecord.h (struct lrecord_implementation):
+	* lrecord.h (MC_ALLOC_CALL_FINALIZER_FOR_DISKSAVE):
+	* lrecord.h (DEFINE_DUMPABLE_LISP_OBJECT):
+	* lrecord.h (DEFINE_DUMPABLE_SIZABLE_LISP_OBJECT):
+	* lrecord.h (DEFINE_DUMPABLE_FROB_BLOCK_LISP_OBJECT):
+	* lrecord.h (DEFINE_DUMPABLE_FROB_BLOCK_SIZABLE_LISP_OBJECT):
+	* lrecord.h (DEFINE_DUMPABLE_INTERNAL_LISP_OBJECT):
+	* lrecord.h (DEFINE_DUMPABLE_SIZABLE_INTERNAL_LISP_OBJECT):
+	* lrecord.h (DEFINE_NODUMP_LISP_OBJECT):
+	* lrecord.h (DEFINE_NODUMP_SIZABLE_LISP_OBJECT):
+	* lrecord.h (DEFINE_NODUMP_FROB_BLOCK_LISP_OBJECT):
+	* lrecord.h (DEFINE_NODUMP_FROB_BLOCK_SIZABLE_LISP_OBJECT):
+	* lrecord.h (DEFINE_NODUMP_INTERNAL_LISP_OBJECT):
+	* lrecord.h (DEFINE_NODUMP_SIZABLE_INTERNAL_LISP_OBJECT):
+	* lrecord.h (MAKE_LISP_OBJECT):
+	* lrecord.h (DEFINE_DUMPABLE_MODULE_LISP_OBJECT):
+	* lrecord.h (DEFINE_DUMPABLE_MODULE_SIZABLE_LISP_OBJECT):
+	* lrecord.h (DEFINE_NODUMP_MODULE_LISP_OBJECT):
+	* lrecord.h (DEFINE_NODUMP_MODULE_SIZABLE_LISP_OBJECT):
+	* lrecord.h (MAKE_MODULE_LISP_OBJECT):
+	* lrecord.h (INIT_LISP_OBJECT):
+	* lrecord.h (INIT_MODULE_LISP_OBJECT):
+	* lrecord.h (UNDEF_LISP_OBJECT):
+	* lrecord.h (UNDEF_MODULE_LISP_OBJECT):
+	* lrecord.h (DECLARE_LISP_OBJECT):
+	* lrecord.h (DECLARE_MODULE_API_LISP_OBJECT):
+	* lrecord.h (DECLARE_MODULE_LISP_OBJECT):
+	* lstream.c:
+	* lstream.c (syms_of_lstream):
+	* lstream.c (vars_of_lstream):
+	* marker.c:
+	* marker.c (compute_buffer_marker_usage):
+	* mc-alloc.c (mc_alloced_storage_size):
+	* mc-alloc.h:
+	* mule-charset.c:
+	* mule-charset.c (struct charset_stats):
+	* mule-charset.c (compute_charset_usage):
+	* mule-charset.c (charset_memory_usage):
+	* mule-charset.c (mule_charset_objects_create):
+	* mule-charset.c (syms_of_mule_charset):
+	* mule-charset.c (vars_of_mule_charset):
+	* redisplay.c:
+	* redisplay.c (compute_rune_dynarr_usage):
+	* redisplay.c (compute_display_block_dynarr_usage):
+	* redisplay.c (compute_glyph_block_dynarr_usage):
+	* redisplay.c (compute_display_line_dynarr_usage):
+	* redisplay.c (compute_line_start_cache_dynarr_usage):
+	* redisplay.h:
+	* scrollbar-gtk.c (gtk_compute_scrollbar_instance_usage):
+	* scrollbar-msw.c (mswindows_compute_scrollbar_instance_usage):
+	* scrollbar-x.c (x_compute_scrollbar_instance_usage):
+	* scrollbar.c (compute_scrollbar_instance_usage):
+	* scrollbar.h:
+	* symbols.c:
+	* symbols.c (reinit_symbol_objects_early):
+	* symbols.c (init_symbols_once_early):
+	* symbols.c (reinit_symbols_early):
+	* symbols.c (defsymbol_massage_name_1):
+	* symsinit.h:
+	* ui-gtk.c:
+	* ui-gtk.c (emacs_gtk_object_getprop):
+	* ui-gtk.c (emacs_gtk_object_putprop):
+	* ui-gtk.c (ui_gtk_objects_create):
+	* unicode.c (compute_from_unicode_table_size_1):
+	* unicode.c (compute_to_unicode_table_size_1):
+	* unicode.c (compute_from_unicode_table_size):
+	* unicode.c (compute_to_unicode_table_size):
+	* window.c:
+	* window.c (struct window_stats):
+	* window.c (compute_window_mirror_usage):
+	* window.c (compute_window_usage):
+	* window.c (window_memory_usage):
+	* window.c (window_objects_create):
+	* window.c (syms_of_window):
+	* window.c (vars_of_window):
+	* window.h:
+	Redo memory-usage mechanism, make it general; add way of dynamically
+	initializing Lisp object types -- OBJECT_HAS_METHOD(), similar to
+	CONSOLE_HAS_METHOD().
+
+	(1) Create OBJECT_HAS_METHOD(), OBJECT_HAS_PROPERTY() etc. for
+	specifying that a Lisp object type has a particular method or
+	property.  Call such methods with OBJECT_METH, MAYBE_OBJECT_METH,
+	OBJECT_METH_OR_GIVEN; retrieve properties with OBJECT_PROPERTY.
+	Methods that formerly required a DEFINE_*GENERAL_LISP_OBJECT() to
+	specify them (getprop, putprop, remprop, plist, disksave) now
+	instead use the dynamic-method mechanism.  The main benefit of
+	this is that new methods or properties can be added without
+	requiring that the declaration statements of all existing methods
+	be modified.  We have to make the `struct lrecord_implementation'
+	non-const, but I don't think this should have any effect on speed --
+	the only possible method that's really speed-critical is the
+	mark method, and we already extract those out into a separate
+	(non-const) array for increased cache locality.
+
+	Object methods need to be reinitialized after pdump, so we put
+	them in separate functions such as face_objects_create(),
+	extent_objects_create() and call them appropriately from emacs.c
+	The only current object property (`memusage_stats_list') that
+	objects can specify is a Lisp object and gets staticpro()ed so it
+	only needs to be set during dump time, but because it references
+	symbols that might not exist in a syms_of_() function, we
+	initialize it in vars_of_().  There is also an object property
+	(`num_extra_memusage_stats') that is automatically initialized based
+	on `memusage_stats_list'; we do that in reinit_vars_of_alloc(),
+	which is called after all vars_of_() functions are called.
+
+	`disksaver' method was renamed `disksave' to correspond with the
+	name normally given to the function (e.g. disksave_lstream()).
+
+	(2) Generalize the memory-usage mechanism in `buffer-memory-usage',
+	`window-memory-usage', `charset-memory-usage' into an object-type-
+	specific mechanism called by a single function
+	`object-memory-usage'.  (Former function `object-memory-usage'
+	renamed to `total-object-memory-usage').  Generalize the mechanism
+	of different "slices" so that we can have different "classes" of
+	memory described and different "slices" onto each class; `t'
+	separates classes, `nil' separates slices.  Currently we have
+	three classes defined: the memory of an object itself,
+	non-Lisp-object memory associated with the object (e.g. arrays or
+	dynarrs stored as fields in the object), and Lisp-object memory
+	associated with the object (other internal Lisp objects stored in
+	the object).  This isn't completely finished yet and we might need
+	to further separate the "other internal Lisp objects" class into
+	two classes.
+
+	The memory-usage mechanism uses a `struct usage_stats' (renamed
+	from `struct overhead_stats') to describe a malloc-view onto a set
+	of allocated memory (listing how much was requested and various
+	types of overhead) and a more general `struct generic_usage_stats'
+	(with a `struct usage_stats' in it) to hold all statistics about
+	object memory.  `struct generic_usage_stats' contains an array of
+	32 Bytecounts, which are statistics of unspecified semantics.  The
+	intention is that individual types declare a corresponding struct
+	(e.g. `struct window_stats') with the same structure but with
+	specific fields in place of the array, corresponding to specific
+	statistics.  The number of such statistics is an object property
+	computed from the list of tags (Lisp symbols describing the
+	statistics) stored in `memusage_stats_list'.  The idea here is to
+	allow particular object types to customize the number and
+	semantics of the statistics where completely avoiding consing.
+	This doesn't matter so much yet, but the intention is to have the
+	memory usage of all objects computed at the end of GC, at the same
+	time as other statistics are currently computed.  The values for
+	all statistics for a single type would be added up to compute
+	aggregate values for all objects of a specific type.  To make this
+	efficient, we can't allow any memory allocation at all.
+
+	(3) Create some additional functions for creating lists that
+	specify the elements directly as args rather than indirectly through
+	an array: listn() (number of args given), listu() (list terminated
+	by Qunbound).
+
+	(4) Delete a bit of remaining unused C window_config stuff, also
+	unused lrecord_type_popup_data.
+	
+	
+2010-03-18  Ben Wing  <ben@xemacs.org>
+
+	* tests.c:
+	* tests.c (Ftest_data_format_conversion):
+	Need to GCPRO newly created objects or we'll eventually get
+	a crash due to occurrence of call2().
+
 2010-03-16  Ben Wing  <ben@xemacs.org>
 
 	* alloc.c (make_lcrecord_list):
@@ -149,18 +410,6 @@
 	(7) Delete some custom print methods that were identical to
 	external_object_printer().
 
-2010-03-15  Ben Wing  <ben@xemacs.org>
-
-	* extents.c:
-	* extents.c (soe_dump):
-	* extents.c (soe_insert):
-	* extents.c (soe_delete):
-	* extents.c (soe_move):
-	* extents.c (extent_fragment_update):
-	* extents.c (print_extent_1):
-	* extents.c (print_extent):
-	* extents.c (vars_of_extents):
-
 2010-03-12  Ben Wing  <ben@xemacs.org>
 
 	* lisp.h:
--- a/src/alloc.c	Thu Mar 18 23:12:41 2010 -0500
+++ b/src/alloc.c	Fri Mar 19 17:02:11 2010 -0500
@@ -105,7 +105,7 @@
 /* All the built-in lisp object types are enumerated in `enum lrecord_type'.
    Additional ones may be defined by a module (none yet).  We leave some
    room in `lrecord_implementations_table' for such new lisp object types. */
-const struct lrecord_implementation *lrecord_implementations_table[(int)lrecord_type_last_built_in_type + MODULE_DEFINABLE_TYPE_COUNT];
+struct lrecord_implementation *lrecord_implementations_table[(int)lrecord_type_last_built_in_type + MODULE_DEFINABLE_TYPE_COUNT];
 int lrecord_type_count = lrecord_type_last_built_in_type;
 
 /* This is just for use by the printer, to allow things to print uniquely.
@@ -127,6 +127,12 @@
 
 #endif
 
+#ifdef MEMORY_USAGE_STATS
+Lisp_Object Qobject_actually_requested, Qobject_malloc_overhead;
+Lisp_Object Qother_memory_actually_requested, Qother_memory_malloc_overhead;
+Lisp_Object Qother_memory_dynarr_overhead, Qother_memory_gap_overhead;
+#endif /* MEMORY_USAGE_STATS */
+
 /* Very cheesy ways of figuring out how much memory is being used for
    data. #### Need better (system-dependent) ways. */
 void *minimum_address_seen;
@@ -760,8 +766,8 @@
 	  debug_print (wrap_pointer_1 (header));
 	}
 #endif
-      if (imp->disksaver && !objh->free)
-	(imp->disksaver) (wrap_pointer_1 (header));
+      if (imp->disksave && !objh->free)
+	(imp->disksave) (wrap_pointer_1 (header));
     }
 #endif /* not NEW_GC */
 }
@@ -842,7 +848,7 @@
 #ifdef MEMORY_USAGE_STATS
 
 Bytecount
-lisp_object_storage_size (Lisp_Object obj, struct overhead_stats *ovstats)
+lisp_object_storage_size (Lisp_Object obj, struct usage_stats *ustats)
 {
 #ifndef NEW_GC
   const struct lrecord_implementation *imp =
@@ -851,20 +857,20 @@
   Bytecount size = lisp_object_size (obj);
 
 #ifdef NEW_GC
-  return mc_alloced_storage_size (size, ovstats);
+  return mc_alloced_storage_size (size, ustats);
 #else
   if (imp->frob_block_p)
     {
       Bytecount overhead = fixed_type_block_overhead (size);
-      if (ovstats)
+      if (ustats)
 	{
-	  ovstats->was_requested += size;
-	  ovstats->malloc_overhead += overhead;
+	  ustats->was_requested += size;
+	  ustats->malloc_overhead += overhead;
 	}
       return size + overhead;
     }
   else
-    return malloced_storage_size (XPNTR (obj), size, ovstats);
+    return malloced_storage_size (XPNTR (obj), size, ustats);
 #endif
 }
 
@@ -1480,6 +1486,46 @@
   return Fcons (obj0, Fcons (obj1, Fcons (obj2, Fcons (obj3, Fcons (obj4, Fcons (obj5, Qnil))))));
 }
 
+/* Return a list of arbitrary length, terminated by Qunbound. */
+
+Lisp_Object
+listu (Lisp_Object first, ...)
+{
+  Lisp_Object obj = Qnil;
+  Lisp_Object val;
+  va_list va;
+
+  va_start (va, first);
+  val = first;
+  while (!UNBOUNDP (val))
+    {
+      obj = Fcons (val, obj);
+      val = va_arg (va, Lisp_Object);
+    }
+  va_end (va);
+  return Fnreverse (obj);
+}
+
+/* Return a list of arbitrary length, with length specified and remaining
+   args making up the list. */
+
+Lisp_Object
+listn (int num_args, ...)
+{
+  int i;
+  Lisp_Object obj = Qnil;
+  va_list va;
+
+  va_start (va, num_args);
+  for (i = 0; i < num_args; i++)
+    obj = Fcons (va_arg (va, Lisp_Object), obj);
+  va_end (va);
+  return Fnreverse (obj);
+}
+
+/* Return a list of arbitrary length, with length specified and an array
+   of elements. */
+
 DEFUN ("make-list", Fmake_list, 2, 2, 0, /*
 Return a new list of length LENGTH, with each element being OBJECT.
 */
@@ -2434,16 +2480,11 @@
    standard way to do finalization when using
    SWEEP_FIXED_TYPE_BLOCK(). */
 
-DEFINE_DUMPABLE_FROB_BLOCK_GENERAL_LISP_OBJECT ("string", string,
-						mark_string, print_string,
-						0, string_equal, 0,
-						string_description,
-						string_getprop,
-						string_putprop,
-						string_remprop,
-						string_plist,
-						0 /* no disksaver */,
-						Lisp_String);
+DEFINE_DUMPABLE_FROB_BLOCK_LISP_OBJECT ("string", string,
+					mark_string, print_string,
+					0, string_equal, 0,
+					string_description,
+					Lisp_String);
 #endif /* not NEW_GC */
 
 #ifdef NEW_GC
@@ -2484,17 +2525,9 @@
 #endif /* not NEW_GC */
 
 #ifdef NEW_GC
-DEFINE_DUMPABLE_GENERAL_LISP_OBJECT ("string", string,
-				     mark_string, print_string,
-				     0,
-				     string_equal, 0,
-				     string_description,
-				     string_getprop,
-				     string_putprop,
-				     string_remprop,
-				     string_plist,
-				     0 /* no disksaver */,
-				     Lisp_String);
+DEFINE_DUMPABLE_LISP_OBJECT ("string", string, mark_string, print_string,
+			     0, string_equal, 0,
+			     string_description, Lisp_String);
 
 
 static const struct memory_description string_direct_data_description[] = {
@@ -3590,6 +3623,10 @@
   int bytes_freed;
   int instances_on_free_list;
   int bytes_on_free_list;
+#ifdef MEMORY_USAGE_STATS
+  Bytecount nonlisp_bytes_in_use;
+  struct generic_usage_stats stats;
+#endif
 } lrecord_stats [countof (lrecord_implementations_table)];
 
 void
@@ -3604,6 +3641,22 @@
     case ALLOC_IN_USE:
       lrecord_stats[type_index].instances_in_use++;
       lrecord_stats[type_index].bytes_in_use += sz;
+#ifdef MEMORY_USAGE_STATS
+      {
+	struct generic_usage_stats stats;
+	Lisp_Object obj = wrap_pointer_1 (h);
+	if (HAS_OBJECT_METH_P (obj, memory_usage))
+	  {
+	    int i;
+	    int total_stats = OBJECT_PROPERTY (obj, num_extra_memusage_stats);
+	    xzero (stats);
+	    OBJECT_METH (obj, memory_usage, (obj, &stats));
+	    for (i = 0; i < total_stats; i++)
+	      lrecord_stats[type_index].stats.othervals[i] +=
+		stats.othervals[i];
+	  }
+      }
+#endif
       break;
     case ALLOC_FREE:
       lrecord_stats[type_index].instances_freed++;
@@ -4483,9 +4536,7 @@
   sweep_eval_data ();
   sweep_misc_user_data ();
 #endif /* EVENT_DATA_AS_OBJECTS */
-#endif /* not NEW_GC */
-
-#ifndef NEW_GC
+
 #ifdef PDUMP
   pdump_objects_unmark ();
 #endif
@@ -4625,6 +4676,25 @@
   strcat (buf, suffix);
 }
 
+void
+finish_object_memory_usage_stats (void)
+{
+#ifdef MEMORY_USAGE_STATS
+  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 /* MEMORY_USAGE_STATS */
+}
+
 static Lisp_Object
 object_memory_usage_stats (int set_total_gc_usage)
 {
@@ -4633,7 +4703,6 @@
   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)
@@ -4708,6 +4777,13 @@
           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;
+	  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;
+	    }
 	  pluralize_and_append (buf, name, "-freed");
           if (lrecord_stats[i].instances_freed != 0)
             pl = gc_plist_hack (buf, lrecord_stats[i].instances_freed, pl);
@@ -4747,7 +4823,7 @@
   return pl;
 }
 
-DEFUN("object-memory-usage-stats", Fobject_memory_usage_stats, 0, 0 ,"", /*
+DEFUN ("object-memory-usage-stats", Fobject_memory_usage_stats, 0, 0, 0, /*
 Return statistics about memory usage of Lisp objects.
 */
        ())
@@ -4757,6 +4833,137 @@
 
 #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 */
+
 /* Debugging aids.  */
 
 DEFUN ("garbage-collect", Fgarbage_collect, 0, 0, "", /*
@@ -4857,7 +5064,7 @@
 }
 
 #ifdef ALLOC_TYPE_STATS
-DEFUN ("object-memory-usage", Fobject_memory_usage, 0, 0, 0, /*
+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'.
@@ -4949,7 +5156,7 @@
 
 Bytecount
 malloced_storage_size (void * UNUSED (ptr), Bytecount claimed_size,
-		       struct overhead_stats *stats)
+		       struct usage_stats *stats)
 {
   Bytecount orig_claimed_size = claimed_size;
 
@@ -5055,6 +5262,7 @@
 #ifndef NEW_GC
   init_string_chars_alloc ();
   init_string_alloc ();
+  /* #### Is it intentional that this is called twice? --ben */
   init_string_chars_alloc ();
   init_cons_alloc ();
   init_symbol_alloc ();
@@ -5163,6 +5371,15 @@
 #endif /* defined (__cplusplus) && defined (ERROR_CHECK_GC) */
 }
 
+static void
+reinit_alloc_objects_early (void)
+{
+  OBJECT_HAS_METHOD (string, getprop);
+  OBJECT_HAS_METHOD (string, putprop);
+  OBJECT_HAS_METHOD (string, remprop);
+  OBJECT_HAS_METHOD (string, plist);
+}
+
 void
 reinit_alloc_early (void)
 {
@@ -5170,6 +5387,7 @@
 #ifndef NEW_GC
   init_lcrecord_lists ();
 #endif /* not NEW_GC */
+  reinit_alloc_objects_early ();
 }
 
 void
@@ -5185,18 +5403,6 @@
 
   dump_add_opaque (lrecord_uid_counter, sizeof (lrecord_uid_counter));
 
-  INIT_LISP_OBJECT (cons);
-  INIT_LISP_OBJECT (vector);
-  INIT_LISP_OBJECT (string);
-#ifdef NEW_GC
-  INIT_LISP_OBJECT (string_indirect_data);
-  INIT_LISP_OBJECT (string_direct_data);
-#endif /* NEW_GC */
-#ifndef NEW_GC
-  INIT_LISP_OBJECT (lcrecord_list);
-  INIT_LISP_OBJECT (free);
-#endif /* not NEW_GC */
-
   staticpros = Dynarr_new2 (Lisp_Object_ptr_dynarr, Lisp_Object *);
   Dynarr_resize (staticpros, 1410); /* merely a small optimization */
   dump_add_root_block_ptr (&staticpros, &staticpros_description);
@@ -5220,6 +5426,21 @@
 #else /* not NEW_GC */
   init_lcrecord_lists ();
 #endif /* not NEW_GC */
+
+  INIT_LISP_OBJECT (cons);
+  INIT_LISP_OBJECT (vector);
+  INIT_LISP_OBJECT (string);
+
+#ifdef NEW_GC
+  INIT_LISP_OBJECT (string_indirect_data);
+  INIT_LISP_OBJECT (string_direct_data);
+#endif /* NEW_GC */
+#ifndef NEW_GC
+  INIT_LISP_OBJECT (lcrecord_list);
+  INIT_LISP_OBJECT (free);
+#endif /* not NEW_GC */
+
+  reinit_alloc_objects_early ();
 }
 
 void
@@ -5227,6 +5448,15 @@
 {
   DEFSYMBOL (Qgarbage_collecting);
 
+#ifdef MEMORY_USAGE_STATS
+  DEFSYMBOL (Qobject_actually_requested);
+  DEFSYMBOL (Qobject_malloc_overhead);
+  DEFSYMBOL (Qother_memory_actually_requested);
+  DEFSYMBOL (Qother_memory_malloc_overhead);
+  DEFSYMBOL (Qother_memory_dynarr_overhead);
+  DEFSYMBOL (Qother_memory_gap_overhead);
+#endif /* MEMORY_USAGE_STATS */
+
   DEFSUBR (Fcons);
   DEFSUBR (Flist);
   DEFSUBR (Fvector);
@@ -5242,8 +5472,11 @@
   DEFSUBR (Fpurecopy);
 #ifdef ALLOC_TYPE_STATS
   DEFSUBR (Fobject_memory_usage_stats);
+  DEFSUBR (Ftotal_object_memory_usage);
+#endif /* ALLOC_TYPE_STATS */
+#ifdef MEMORY_USAGE_STATS
   DEFSUBR (Fobject_memory_usage);
-#endif /* ALLOC_TYPE_STATS */
+#endif /* MEMORY_USAGE_STATS */
   DEFSUBR (Fgarbage_collect);
 #if 0
   DEFSUBR (Fmemory_limit);
@@ -5257,6 +5490,14 @@
 }
 
 void
+reinit_vars_of_alloc (void)
+{
+#ifdef MEMORY_USAGE_STATS
+  compute_memusage_stats_length ();
+#endif /* MEMORY_USAGE_STATS */
+}
+
+void
 vars_of_alloc (void)
 {
 #ifdef DEBUG_XEMACS
--- a/src/buffer.c	Thu Mar 18 23:12:41 2010 -0500
+++ b/src/buffer.c	Fri Mar 19 17:02:11 2010 -0500
@@ -1752,76 +1752,51 @@
 
 struct buffer_stats
 {
-  int text;
-  int markers;
-  int extents;
-  int other;
+  struct usage_stats u;
+  Bytecount text;
+  Bytecount markers;
+  Bytecount extents;
 };
 
 static Bytecount
-compute_buffer_text_usage (struct buffer *b, struct overhead_stats *ovstats)
+compute_buffer_text_usage (struct buffer *b, struct usage_stats *ustats)
 {
-  int was_requested = b->text->z - 1;
-  Bytecount gap = b->text->gap_size + b->text->end_gap_size;
-  Bytecount malloc_use = malloced_storage_size (b->text->beg, was_requested + gap, 0);
-
-  ovstats->gap_overhead    += gap;
-  ovstats->was_requested   += was_requested;
-  ovstats->malloc_overhead += malloc_use - (was_requested + gap);
+  Bytecount was_requested, gap, malloc_use;
+
+  /* Killed buffer? */
+  if (!b->text)
+    return 0;
+
+  /* Indirect buffer shares its text with someone else, so don't double-
+     count the text */
+  if (b->base_buffer)
+    return 0;
+
+  was_requested = b->text->z - 1;
+  gap = b->text->gap_size + b->text->end_gap_size;
+  malloc_use = malloced_storage_size (b->text->beg, was_requested + gap, 0);
+
+  ustats->gap_overhead    += gap;
+  ustats->was_requested   += was_requested;
+  ustats->malloc_overhead += malloc_use - (was_requested + gap);
   return malloc_use;
 }
 
 static void
 compute_buffer_usage (struct buffer *b, struct buffer_stats *stats,
-		      struct overhead_stats *ovstats)
+		      struct usage_stats *ustats)
 {
-  xzero (*stats);
-  stats->other   += lisp_object_storage_size (wrap_buffer (b), ovstats);
-  stats->text    += compute_buffer_text_usage   (b, ovstats);
-  stats->markers += compute_buffer_marker_usage (b, ovstats);
-  stats->extents += compute_buffer_extent_usage (b, ovstats);
+  stats->text    += compute_buffer_text_usage   (b, ustats);
+  stats->markers += compute_buffer_marker_usage (b, ustats);
+  stats->extents += compute_buffer_extent_usage (b, ustats);
 }
 
-DEFUN ("buffer-memory-usage", Fbuffer_memory_usage, 1, 1, 0, /*
-Return stats about the memory usage of buffer BUFFER.
-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 buffer (separate from the memory logically associated with a
-buffer or frame), 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) and because there is other stuff that might logically
-be associated with a window, buffer, or frame (e.g. window configurations,
-glyphs) but should not obviously be included in the usage counts.
-
-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.
-*/
-       (buffer))
+static void
+buffer_memory_usage (Lisp_Object buffer, struct generic_usage_stats *gustats)
 {
-  struct buffer_stats stats;
-  struct overhead_stats ovstats;
-  Lisp_Object val = Qnil;
-
-  CHECK_BUFFER (buffer); /* dead buffers should be allowed, no? */
-  xzero (ovstats);
-  compute_buffer_usage (XBUFFER (buffer), &stats, &ovstats);
-
-  val = acons (Qtext,    make_int (stats.text),    val);
-  val = acons (Qmarkers, make_int (stats.markers), val);
-  val = acons (Qextents, make_int (stats.extents), val);
-  val = acons (Qother,   make_int (stats.other),   val);
-  val = Fcons (Qnil, val);
-  val = acons (Qactually_requested, make_int (ovstats.was_requested),   val);
-  val = acons (Qmalloc_overhead,    make_int (ovstats.malloc_overhead), val);
-  val = acons (Qgap_overhead,       make_int (ovstats.gap_overhead),    val);
-  val = acons (Qdynarr_overhead,    make_int (ovstats.dynarr_overhead), val);
-
-  return Fnreverse (val);
+  struct buffer_stats *stats = (struct buffer_stats *) gustats;
+
+  compute_buffer_usage (XBUFFER (buffer), stats, &stats->u);
 }
 
 #endif /* MEMORY_USAGE_STATS */
@@ -1905,6 +1880,14 @@
 
 
 void
+buffer_objects_create (void)
+{
+#ifdef MEMORY_USAGE_STATS
+  OBJECT_HAS_METHOD (buffer, memory_usage);
+#endif
+}
+
+void
 syms_of_buffer (void)
 {
   INIT_LISP_OBJECT (buffer);
@@ -1969,9 +1952,6 @@
   DEFSUBR (Fbarf_if_buffer_read_only);
   DEFSUBR (Fbury_buffer);
   DEFSUBR (Fkill_all_local_variables);
-#ifdef MEMORY_USAGE_STATS
-  DEFSUBR (Fbuffer_memory_usage);
-#endif
 #if defined (DEBUG_XEMACS) && defined (MULE)
   DEFSUBR (Fbuffer_char_byte_converion_info);
   DEFSUBR (Fstring_char_byte_converion_info);
@@ -1994,6 +1974,11 @@
 vars_of_buffer (void)
 {
   /* This function can GC */
+#ifdef MEMORY_USAGE_STATS
+  OBJECT_HAS_PROPERTY
+    (buffer, memusage_stats_list, list3 (Qtext, Qmarkers, Qextents));
+#endif /* MEMORY_USAGE_STATS */
+
   staticpro (&QSFundamental);
   staticpro (&QSscratch);
 
--- a/src/console-impl.h	Thu Mar 18 23:12:41 2010 -0500
+++ b/src/console-impl.h	Fri Mar 19 17:02:11 2010 -0500
@@ -292,7 +292,7 @@
 #ifdef MEMORY_USAGE_STATS
   int (*compute_scrollbar_instance_usage_method) (struct device *,
 						  struct scrollbar_instance *,
-						  struct overhead_stats *);
+						  struct usage_stats *);
 #endif
   /* Paint the window's deadbox, a rectangle between window
      borders and two short edges of both scrollbars. */
--- a/src/dynarr.c	Thu Mar 18 23:12:41 2010 -0500
+++ b/src/dynarr.c	Fri Mar 19 17:02:11 2010 -0500
@@ -422,7 +422,7 @@
    See the comment above the definition of this structure. */
 
 Bytecount
-Dynarr_memory_usage (void *d, struct overhead_stats *stats)
+Dynarr_memory_usage (void *d, struct usage_stats *stats)
 {
   Bytecount total = 0;
   Dynarr *dy = (Dynarr *) d;
--- a/src/elhash.c	Thu Mar 18 23:12:41 2010 -0500
+++ b/src/elhash.c	Fri Mar 19 17:02:11 2010 -0500
@@ -280,6 +280,28 @@
   return XHASH_TABLE (hash_table)->count;
 }
 
+#ifdef MEMORY_USAGE_STATS
+
+struct hash_table_stats
+{
+  struct usage_stats u;
+  Bytecount hentries;
+};
+
+static void
+hash_table_memory_usage (Lisp_Object hashtab,
+			 struct generic_usage_stats *gustats)
+{
+  Lisp_Hash_Table *ht = XHASH_TABLE (hashtab);
+  struct hash_table_stats *stats = (struct hash_table_stats *) gustats;
+  stats->hentries +=
+    malloced_storage_size (ht->hentries,
+			   sizeof (htentry) * (ht->size + 1),
+			   &stats->u);
+}
+
+#endif /* MEMORY_USAGE_STATS */
+
 
 /* Printing hash tables.
 
@@ -1805,6 +1827,14 @@
 /************************************************************************/
 
 void
+hash_table_objects_create (void)
+{
+#ifdef MEMORY_USAGE_STATS
+  OBJECT_HAS_METHOD (hash_table, memory_usage);
+#endif
+}
+
+void
 syms_of_elhash (void)
 {
   DEFSUBR (Fhash_table_p);
@@ -1854,6 +1884,15 @@
 }
 
 void
+vars_of_elhash (void)
+{
+#ifdef MEMORY_USAGE_STATS
+  OBJECT_HAS_PROPERTY
+    (hash_table, memusage_stats_list, list1 (intern ("hash-entries")));
+#endif /* MEMORY_USAGE_STATS */
+}
+
+void
 init_elhash_once_early (void)
 {
   INIT_LISP_OBJECT (hash_table);
--- a/src/emacs.c	Thu Mar 18 23:12:41 2010 -0500
+++ b/src/emacs.c	Fri Mar 19 17:02:11 2010 -0500
@@ -1464,7 +1464,26 @@
 
       /* Make sure that eistrings can be created. */
       init_eistring_once_early ();
-
+    }
+#ifdef PDUMP
+  else if (!restart)	      /* after successful pdump_load()
+				 (note, we are inside ifdef PDUMP) */
+    {
+      reinit_alloc_early ();
+      reinit_gc_early ();
+      reinit_symbols_early ();
+#ifndef NEW_GC
+      reinit_opaque_early ();
+#endif /* not NEW_GC */
+      reinit_eistring_early ();
+#ifdef WITH_NUMBER_TYPES
+      reinit_vars_of_number ();
+#endif
+    }
+#endif /* PDUMP */
+
+  if (!initialized)
+    {
       /* Now declare all the symbols and define all the Lisp primitives.
 
 	 The *only* thing that the syms_of_*() functions are allowed to do
@@ -1549,6 +1568,7 @@
       syms_of_intl ();
       syms_of_keymap ();
       syms_of_lread ();
+      syms_of_lstream ();
       syms_of_macros ();
       syms_of_marker ();
       syms_of_md5 ();
@@ -1732,7 +1752,30 @@
 #if defined (HAVE_POSTGRESQL) && !defined (HAVE_SHLIB)
       syms_of_postgresql ();
 #endif
-
+    }
+
+  if (!initialized
+#ifdef PDUMP
+      || !restart
+#endif
+      )
+    {
+      buffer_objects_create ();
+      extent_objects_create ();
+      face_objects_create ();
+      frame_objects_create ();
+      glyph_objects_create ();
+      hash_table_objects_create ();
+      lstream_objects_create ();
+      mule_charset_objects_create ();
+#ifdef HAVE_GTK
+      ui_gtk_objects_create ();
+#endif
+      window_objects_create ();
+    }
+
+  if (!initialized)
+    {
       /* Now create the subtypes for the types that have them.
 	 We do this before the vars_*() because more symbols
 	 may get initialized here. */
@@ -1896,17 +1939,6 @@
   else if (!restart)	      /* after successful pdump_load()
 				 (note, we are inside ifdef PDUMP) */
     {
-      reinit_alloc_early ();
-      reinit_gc_early ();
-      reinit_symbols_early ();
-#ifndef NEW_GC
-      reinit_opaque_early ();
-#endif /* not NEW_GC */
-      reinit_eistring_early ();
-#ifdef WITH_NUMBER_TYPES
-      reinit_vars_of_number ();
-#endif
-
       reinit_console_type_create_stream ();
 #ifdef HAVE_TTY
       reinit_console_type_create_tty ();
@@ -2078,6 +2110,7 @@
       vars_of_dragdrop ();
 #endif
       vars_of_editfns ();
+      vars_of_elhash ();
       vars_of_emacs ();
       vars_of_eval ();
 
@@ -2305,6 +2338,7 @@
     {
       /* Now do additional vars_of_*() initialization that happens both
 	 at dump time and after pdump load. */
+      reinit_vars_of_alloc ();
       reinit_vars_of_buffer ();
       reinit_vars_of_bytecode ();
       reinit_vars_of_console ();
--- a/src/events.c	Thu Mar 18 23:12:41 2010 -0500
+++ b/src/events.c	Fri Mar 19 17:02:11 2010 -0500
@@ -62,7 +62,7 @@
 /*                       definition of event object                     */
 /************************************************************************/
 
-/* #### Ad-hoc hack.  Should be part of DEFINE_*_GENERAL_LISP_OBJECT. */
+/* #### Ad-hoc hack.  Should be an object method. */
 void
 clear_event_resource (void)
 {
--- a/src/extents.c	Thu Mar 18 23:12:41 2010 -0500
+++ b/src/extents.c	Fri Mar 19 17:02:11 2010 -0500
@@ -3462,20 +3462,17 @@
   return Fextent_properties (obj);
 }
 
-DEFINE_DUMPABLE_FROB_BLOCK_GENERAL_LISP_OBJECT ("extent", extent,
-						mark_extent,
-						print_extent,
-						/* NOTE: If you declare a
-						   finalization method here,
-						   it will NOT be called.
-						   Shaft city. */
-						0,
-						extent_equal, extent_hash,
-						extent_description,
-						extent_getprop, extent_putprop,
-						extent_remprop, extent_plist,
-						0 /* no disksaver */,
-						struct extent);
+DEFINE_DUMPABLE_FROB_BLOCK_LISP_OBJECT ("extent", extent,
+					mark_extent,
+					print_extent,
+					/* NOTE: If you declare a
+					   finalization method here,
+					   it will NOT be called.
+					   Shaft city. */
+					0,
+					extent_equal, extent_hash,
+					extent_description,
+					struct extent);
 
 /************************************************************************/
 /*			basic extent accessors				*/
@@ -7419,7 +7416,7 @@
 
 int
 compute_buffer_extent_usage (struct buffer *UNUSED (b),
-			     struct overhead_stats *UNUSED (ovstats))
+			     struct usage_stats *UNUSED (ustats))
 {
   /* #### not yet written */
   return 0;
@@ -7433,6 +7430,15 @@
 /************************************************************************/
 
 void
+extent_objects_create (void)
+{
+  OBJECT_HAS_METHOD (extent, getprop);
+  OBJECT_HAS_METHOD (extent, putprop);
+  OBJECT_HAS_METHOD (extent, remprop);
+  OBJECT_HAS_METHOD (extent, plist);
+}
+
+void
 syms_of_extents (void)
 {
   INIT_LISP_OBJECT (extent);
--- a/src/extents.h	Thu Mar 18 23:12:41 2010 -0500
+++ b/src/extents.h	Fri Mar 19 17:02:11 2010 -0500
@@ -238,7 +238,7 @@
 
 #ifdef MEMORY_USAGE_STATS
 int compute_buffer_extent_usage (struct buffer *b,
-				 struct overhead_stats *ovstats);
+				 struct usage_stats *ustats);
 #endif
 
 #endif /* INCLUDED_extents_h_ */
--- a/src/faces.c	Thu Mar 18 23:12:41 2010 -0500
+++ b/src/faces.c	Fri Mar 19 17:02:11 2010 -0500
@@ -314,13 +314,10 @@
   { XD_END }
 };
 
-DEFINE_DUMPABLE_GENERAL_LISP_OBJECT ("face", face,
-				     mark_face, print_face, 0, face_equal,
-				     face_hash, face_description,
-				     face_getprop,
-				     face_putprop, face_remprop,
-				     face_plist, 0 /* no disksaver */,
-				     Lisp_Face);
+DEFINE_DUMPABLE_LISP_OBJECT ("face", face,
+			     mark_face, print_face, 0, face_equal,
+			     face_hash, face_description,
+			     Lisp_Face);
 
 /************************************************************************/
 /*                             face read syntax                         */
@@ -1652,7 +1649,7 @@
 
 int
 compute_face_cachel_usage (face_cachel_dynarr *face_cachels,
-			   struct overhead_stats *ovstats)
+			   struct usage_stats *ustats)
 {
   int total = 0;
 
@@ -1660,12 +1657,12 @@
     {
       int i;
 
-      total += Dynarr_memory_usage (face_cachels, ovstats);
+      total += Dynarr_memory_usage (face_cachels, ustats);
       for (i = 0; i < Dynarr_length (face_cachels); i++)
 	{
 	  int_dynarr *merged = Dynarr_at (face_cachels, i).merged_faces;
 	  if (merged)
-	    total += Dynarr_memory_usage (merged, ovstats);
+	    total += Dynarr_memory_usage (merged, ustats);
 	}
     }
 
@@ -2112,6 +2109,15 @@
 
 
 void
+face_objects_create (void)
+{
+  OBJECT_HAS_METHOD (face, getprop);
+  OBJECT_HAS_METHOD (face, putprop);
+  OBJECT_HAS_METHOD (face, remprop);
+  OBJECT_HAS_METHOD (face, plist);
+}
+
+void
 syms_of_faces (void)
 {
   INIT_LISP_OBJECT (face);
--- a/src/faces.h	Thu Mar 18 23:12:41 2010 -0500
+++ b/src/faces.h	Fri Mar 19 17:02:11 2010 -0500
@@ -281,7 +281,7 @@
 
 #ifdef MEMORY_USAGE_STATS
 int compute_face_cachel_usage (face_cachel_dynarr *face_cachels,
-			       struct overhead_stats *ovstats);
+			       struct usage_stats *ustats);
 #endif /* MEMORY_USAGE_STATS */
 
 EXFUN (Fface_name, 1);
--- a/src/frame.c	Thu Mar 18 23:12:41 2010 -0500
+++ b/src/frame.c	Fri Mar 19 17:02:11 2010 -0500
@@ -4064,6 +4064,53 @@
 }
 
 
+#ifdef MEMORY_USAGE_STATS
+
+struct frame_stats
+{
+  struct usage_stats u;
+  Bytecount gutter;
+  Bytecount expose_ignore;
+  Bytecount other;
+};
+
+static void
+compute_frame_usage (struct frame *f, struct frame_stats *stats,
+		     struct usage_stats *ustats)
+{
+  enum edge_pos edge;
+  EDGE_POS_LOOP (edge)
+    {
+      stats->gutter +=
+	compute_display_line_dynarr_usage (f->current_display_lines[edge],
+					   ustats);
+      stats->gutter +=
+	compute_display_line_dynarr_usage (f->desired_display_lines[edge],
+					   ustats);
+    }
+  {
+    struct expose_ignore *e;
+
+    for (e = f->subwindow_exposures; e; e = e->next)
+      stats->expose_ignore += malloced_storage_size (e, sizeof (*e), ustats);
+  }
+
+#if 0
+  stats->other += FRAMEMETH (f, frame_memory_usage, (f, ustats));
+#endif
+}
+
+static void
+frame_memory_usage (Lisp_Object frame, struct generic_usage_stats *gustats)
+{
+  struct frame_stats *stats = (struct frame_stats *) gustats;
+
+  compute_frame_usage (XFRAME (frame), stats, &stats->u);
+}
+
+#endif /* MEMORY_USAGE_STATS */
+
+
 /***************************************************************************/
 /*									   */
 /*                              initialization                             */
@@ -4071,6 +4118,14 @@
 /***************************************************************************/
 
 void
+frame_objects_create (void)
+{
+#ifdef MEMORY_USAGE_STATS
+  OBJECT_HAS_METHOD (frame, memory_usage);
+#endif
+}
+
+void
 init_frame (void)
 {
 #ifndef PDUMP
@@ -4216,6 +4271,12 @@
 void
 vars_of_frame (void)
 {
+#ifdef MEMORY_USAGE_STATS
+  OBJECT_HAS_PROPERTY
+    (frame, memusage_stats_list, list3 (Qgutter, intern ("expose-ignore"),
+					Qother));
+#endif /* MEMORY_USAGE_STATS */
+
   /* */
   Vframe_being_created = Qnil;
   staticpro (&Vframe_being_created);
--- a/src/gc.c	Thu Mar 18 23:12:41 2010 -0500
+++ b/src/gc.c	Fri Mar 19 17:02:11 2010 -0500
@@ -1774,6 +1774,7 @@
 #ifdef NEW_GC
   GC_SET_PHASE (FINISH_GC);
 #endif /* NEW_GC */
+  finish_object_memory_usage_stats ();
   consing_since_gc = 0;
 #ifndef DEBUG_XEMACS
   /* Allow you to set it really fucking low if you really want ... */
--- a/src/general-slots.h	Thu Mar 18 23:12:41 2010 -0500
+++ b/src/general-slots.h	Fri Mar 19 17:02:11 2010 -0500
@@ -1,6 +1,6 @@
 /* Commonly-used symbols -- include file
    Copyright (C) 1995 Sun Microsystems.
-   Copyright (C) 1995, 1996, 2000, 2001, 2002, 2003 Ben Wing.
+   Copyright (C) 1995, 1996, 2000, 2001, 2002, 2003, 2010 Ben Wing.
 
 This file is part of XEmacs.
 
@@ -46,7 +46,6 @@
 SYMBOL (Qabort);
 SYMBOL_KEYWORD (Q_accelerator);
 SYMBOL_KEYWORD (Q_active);
-SYMBOL (Qactually_requested);
 SYMBOL (Qafter);
 SYMBOL (Qall);
 SYMBOL_KEYWORD (Q_allow_other_keys);
@@ -115,7 +114,6 @@
 SYMBOL (Qdoc_string);
 SYMBOL (Qdocumentation);
 SYMBOL (Qduplex);
-SYMBOL (Qdynarr_overhead);
 SYMBOL (Qemergency);
 SYMBOL (Qempty);
 SYMBOL (Qencode_as_utf_8);
@@ -143,7 +141,6 @@
 SYMBOL (Qfull_assoc);
 SYMBOL (Qfuncall);
 SYMBOL (Qfunction);
-SYMBOL (Qgap_overhead);
 SYMBOL (Qgarbage_collection);
 SYMBOL (Qgeneric);
 SYMBOL (Qgeometry);
@@ -193,7 +190,6 @@
 SYMBOL (Qlocale);
 SYMBOL (Qlow);
 SYMBOL (Qmagic);
-SYMBOL (Qmalloc_overhead);
 SYMBOL_KEYWORD (Q_margin_width);
 SYMBOL (Qmarkers);
 SYMBOL (Qmax);
--- a/src/glyphs.c	Thu Mar 18 23:12:41 2010 -0500
+++ b/src/glyphs.c	Fri Mar 19 17:02:11 2010 -0500
@@ -3818,14 +3818,11 @@
   { XD_END }
 };
 
-DEFINE_DUMPABLE_GENERAL_LISP_OBJECT ("glyph", glyph,
-				     mark_glyph, print_glyph, 0,
-				     glyph_equal, glyph_hash,
-				     glyph_description,
-				     glyph_getprop, glyph_putprop,
-				     glyph_remprop, glyph_plist,
-				     0 /* no disksaver */,
-				     Lisp_Glyph);
+DEFINE_DUMPABLE_LISP_OBJECT ("glyph", glyph,
+			     mark_glyph, print_glyph, 0,
+			     glyph_equal, glyph_hash,
+			     glyph_description,
+			     Lisp_Glyph);
 
 Lisp_Object
 allocate_glyph (enum glyph_type type,
@@ -4477,12 +4474,12 @@
 
 int
 compute_glyph_cachel_usage (glyph_cachel_dynarr *glyph_cachels,
-			    struct overhead_stats *ovstats)
+			    struct usage_stats *ustats)
 {
   int total = 0;
 
   if (glyph_cachels)
-    total += Dynarr_memory_usage (glyph_cachels, ovstats);
+    total += Dynarr_memory_usage (glyph_cachels, ustats);
 
   return total;
 }
@@ -5187,6 +5184,15 @@
  *****************************************************************************/
 
 void
+glyph_objects_create (void)
+{
+  OBJECT_HAS_METHOD (glyph, getprop);
+  OBJECT_HAS_METHOD (glyph, putprop);
+  OBJECT_HAS_METHOD (glyph, remprop);
+  OBJECT_HAS_METHOD (glyph, plist);
+}
+
+void
 syms_of_glyphs (void)
 {
   INIT_LISP_OBJECT (glyph);
--- a/src/glyphs.h	Thu Mar 18 23:12:41 2010 -0500
+++ b/src/glyphs.h	Fri Mar 19 17:02:11 2010 -0500
@@ -1165,7 +1165,7 @@
 
 #ifdef MEMORY_USAGE_STATS
 int compute_glyph_cachel_usage (glyph_cachel_dynarr *glyph_cachels,
-				struct overhead_stats *ovstats);
+				struct usage_stats *ustats);
 #endif /* MEMORY_USAGE_STATS */
 
 /************************************************************************/
--- a/src/lisp.h	Thu Mar 18 23:12:41 2010 -0500
+++ b/src/lisp.h	Fri Mar 19 17:02:11 2010 -0500
@@ -1613,12 +1613,18 @@
    the fields to 0, and add any existing values to whatever was there
    before; this way, you can get a cumulative effect. */
 
-struct overhead_stats
+struct usage_stats
 {
-  int was_requested;
-  int malloc_overhead;
-  int dynarr_overhead;
-  int gap_overhead;
+  Bytecount was_requested;
+  Bytecount malloc_overhead;
+  Bytecount dynarr_overhead;
+  Bytecount gap_overhead;
+};
+
+struct generic_usage_stats
+{
+  struct usage_stats u;
+  Bytecount othervals[32];
 };
 
 #endif /* MEMORY_USAGE_STATS */
@@ -2175,8 +2181,8 @@
 #define Dynarr_reset(d) Dynarr_set_lengthr (d, 0)
 
 #ifdef MEMORY_USAGE_STATS
-struct overhead_stats;
-Bytecount Dynarr_memory_usage (void *d, struct overhead_stats *stats);
+struct usage_stats;
+Bytecount Dynarr_memory_usage (void *d, struct usage_stats *stats);
 #endif
 
 /************* Adding/deleting elements to/from a dynarr *************/
@@ -4779,12 +4785,15 @@
 MODULE_API Lisp_Object list3 (Lisp_Object, Lisp_Object, Lisp_Object);
 MODULE_API Lisp_Object list4 (Lisp_Object, Lisp_Object, Lisp_Object,
 			      Lisp_Object);
-MODULE_API Lisp_Object list5 (Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object,
-			      Lisp_Object);
-MODULE_API Lisp_Object list6 (Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object,
+MODULE_API Lisp_Object list5 (Lisp_Object, Lisp_Object, Lisp_Object,
 			      Lisp_Object, Lisp_Object);
+MODULE_API Lisp_Object list6 (Lisp_Object, Lisp_Object, Lisp_Object,
+			      Lisp_Object, Lisp_Object, Lisp_Object);
+MODULE_API Lisp_Object listn (int numargs, ...);
+MODULE_API Lisp_Object listu (Lisp_Object, ...);
 DECLARE_DOESNT_RETURN (memory_full (void));
 void disksave_object_finalization (void);
+void finish_object_memory_usage_stats (void);
 extern int purify_flag;
 #ifndef NEW_GC
 extern EMACS_INT gc_generation_number[1];
@@ -4831,7 +4840,7 @@
 void recompute_funcall_allocation_flag (void);
 
 #ifdef MEMORY_USAGE_STATS
-Bytecount malloced_storage_size (void *, Bytecount, struct overhead_stats *);
+Bytecount malloced_storage_size (void *, Bytecount, struct usage_stats *);
 Bytecount fixed_type_block_overhead (Bytecount);
 #endif
 
@@ -5926,7 +5935,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
-int compute_buffer_marker_usage (struct buffer *, struct overhead_stats *);
+int compute_buffer_marker_usage (struct buffer *, struct usage_stats *);
 #endif
 void init_buffer_markers (struct buffer *b);
 void uninit_buffer_markers (struct buffer *b);
@@ -6601,9 +6610,9 @@
 extern Lisp_Object Qutf_16, Qutf_8, Qucs_4, Qutf_7, Qutf_32;
 #ifdef MEMORY_USAGE_STATS
 Bytecount compute_from_unicode_table_size (Lisp_Object charset,
-					      struct overhead_stats *stats);
+					   struct usage_stats *stats);
 Bytecount compute_to_unicode_table_size (Lisp_Object charset,
-					    struct overhead_stats *stats);
+					 struct usage_stats *stats);
 #endif /* MEMORY_USAGE_STATS */
 
 /* Defined in undo.c */
--- a/src/lrecord.h	Thu Mar 18 23:12:41 2010 -0500
+++ b/src/lrecord.h	Fri Mar 19 17:02:11 2010 -0500
@@ -364,9 +364,7 @@
   lrecord_type_frame,
   lrecord_type_window,
   lrecord_type_window_mirror,
-  lrecord_type_window_configuration,
   lrecord_type_gui_item,
-  lrecord_type_popup_data,
   lrecord_type_toolbar_button,
   lrecord_type_scrollbar_instance,
   lrecord_type_color_instance,
@@ -490,29 +488,6 @@
   /* Data layout description for your object.  See long comment below. */
   const struct memory_description *description;
 
-  /* These functions allow any object type to have builtin property
-     lists that can be manipulated from the lisp level with
-     `get', `put', `remprop', and `object-plist'. */
-  Lisp_Object (*getprop) (Lisp_Object obj, Lisp_Object prop);
-  int (*putprop) (Lisp_Object obj, Lisp_Object prop, Lisp_Object val);
-  int (*remprop) (Lisp_Object obj, Lisp_Object prop);
-  Lisp_Object (*plist) (Lisp_Object obj);
-
-  /* `disksaver' is called at dump time.  It is used for objects that
-     contain pointers or handles to objects created in external libraries,
-     such as window-system windows or file handles.  Such external objects
-     cannot be dumped, so it is necessary to release them at dump time and
-     arrange somehow or other for them to be resurrected if necessary later
-     on.
-
-     It seems that even non-dumpable objects may be around at dump time,
-     and a disksaver may be provided. (In fact, the only object currently
-     with a disksaver, lstream, is non-dumpable.)
-     
-     Objects rarely need to provide this method; most of the time it will
-     be NULL. */
-  void (*disksaver) (Lisp_Object);
-
   /* Only one of `static_size' and `size_in_bytes_method' is non-0.  If
      `static_size' is 0, this type is not instantiable by
      ALLOC_NORMAL_LISP_OBJECT().  If both are 0 (this should never happen),
@@ -530,6 +505,66 @@
      is (usually) allocated in frob blocks. */
   unsigned int frob_block_p :1;
 #endif /* not NEW_GC */
+
+  /**********************************************************************/
+  /* Remaining stuff is not assignable statically using
+     DEFINE_*_LISP_OBJECT, but must be assigned with OBJECT_HAS_METHOD
+     or the like. */
+
+  /* These functions allow any object type to have builtin property
+     lists that can be manipulated from the lisp level with
+     `get', `put', `remprop', and `object-plist'. */
+  Lisp_Object (*getprop) (Lisp_Object obj, Lisp_Object prop);
+  int (*putprop) (Lisp_Object obj, Lisp_Object prop, Lisp_Object val);
+  int (*remprop) (Lisp_Object obj, Lisp_Object prop);
+  Lisp_Object (*plist) (Lisp_Object obj);
+
+  /* `disksave' is called at dump time.  It is used for objects that
+     contain pointers or handles to objects created in external libraries,
+     such as window-system windows or file handles.  Such external objects
+     cannot be dumped, so it is necessary to release them at dump time and
+     arrange somehow or other for them to be resurrected if necessary later
+     on.
+
+     It seems that even non-dumpable objects may be around at dump time,
+     and a disksave may be provided. (In fact, the only object currently
+     with a disksave, lstream, is non-dumpable.)
+     
+     Objects rarely need to provide this method; most of the time it will
+     be NULL. */
+  void (*disksave) (Lisp_Object);
+
+#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);
+
+  /* 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;
+
+  /* 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;
+
+  /* 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.
+     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. */
+  Lisp_Object memusage_stats_list;
+#endif /* MEMORY_USAGE_STATS */
 };
 
 /* All the built-in lisp object types are enumerated in `enum lrecord_type'.
@@ -537,7 +572,7 @@
    room in `lrecord_implementations_table' for such new lisp object types. */
 #define MODULE_DEFINABLE_TYPE_COUNT 32
 
-extern MODULE_API const struct lrecord_implementation *
+extern MODULE_API struct lrecord_implementation *
 lrecord_implementations_table[lrecord_type_last_built_in_type + MODULE_DEFINABLE_TYPE_COUNT];
 
 /* Given a Lisp object, return its implementation
@@ -593,8 +628,8 @@
     {									\
       const struct lrecord_implementation *MCACF_implementation		\
 	= LHEADER_IMPLEMENTATION (MCACF_lheader);			\
-      if (MCACF_implementation && MCACF_implementation->disksaver)	\
-	MCACF_implementation->disksaver (MCACF_obj);			\
+      if (MCACF_implementation && MCACF_implementation->disksave)	\
+	MCACF_implementation->disksave (MCACF_obj);			\
     }									\
 } while (0)
 
@@ -1271,12 +1306,6 @@
    customize the print method, use the normal DEFINE_*_LISP_OBJECT
    mechanism for defining these objects.
 
-   DEFINE_*_GENERAL_LISP_OBJECT is for objects that need to provide one of
-   the less common methods that are omitted on most objects.  These methods
-   include the methods supporting the unified property interface using
-   `get', `put', `remprop' and `object-plist', and (for dumpable objects
-   only) the `disksaver' method.
-
    DEFINE_MODULE_* is for objects defined in an external module.
 
    MAKE_LISP_OBJECT and MAKE_MODULE_LISP_OBJECT are what underlies all of
@@ -1294,133 +1323,130 @@
 /********* The dumpable versions *********** */
 
 #define DEFINE_DUMPABLE_LISP_OBJECT(name,c_name,marker,printer,nuker,equal,hash,desc,structtype) \
-DEFINE_DUMPABLE_GENERAL_LISP_OBJECT(name,c_name,marker,printer,nuker,equal,hash,desc,0,0,0,0,0,structtype)
-
-#define DEFINE_DUMPABLE_GENERAL_LISP_OBJECT(name,c_name,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,disksaver,structtype) \
-MAKE_LISP_OBJECT(name,c_name,1 /*dumpable*/,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,disksaver,sizeof (structtype),0,0,structtype)
+MAKE_LISP_OBJECT(name,c_name,1 /*dumpable*/,marker,printer,nuker,equal,hash,desc,sizeof (structtype),0,0,structtype)
 
 #define DEFINE_DUMPABLE_SIZABLE_LISP_OBJECT(name,c_name,marker,printer,nuker,equal,hash,desc,sizer,structtype) \
-DEFINE_DUMPABLE_SIZABLE_GENERAL_LISP_OBJECT(name,c_name,marker,printer,nuker,equal,hash,desc,0,0,0,0,0,sizer,structtype)
-
-#define DEFINE_DUMPABLE_SIZABLE_GENERAL_LISP_OBJECT(name,c_name,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,disksaver,sizer,structtype) \
-MAKE_LISP_OBJECT(name,c_name,1 /*dumpable*/,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,disksaver,0,sizer,0,structtype)
+MAKE_LISP_OBJECT(name,c_name,1 /*dumpable*/,marker,printer,nuker,equal,hash,desc,0,sizer,0,structtype)
 
 #define DEFINE_DUMPABLE_FROB_BLOCK_LISP_OBJECT(name,c_name,marker,printer,nuker,equal,hash,desc,structtype) \
-DEFINE_DUMPABLE_FROB_BLOCK_GENERAL_LISP_OBJECT(name,c_name,marker,printer,nuker,equal,hash,desc,0,0,0,0,0,structtype)
-
-#define DEFINE_DUMPABLE_FROB_BLOCK_GENERAL_LISP_OBJECT(name,c_name,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,disksaver,structtype) \
-MAKE_LISP_OBJECT(name,c_name,1 /*dumpable*/,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,disksaver,sizeof(structtype),0,1,structtype)
+MAKE_LISP_OBJECT(name,c_name,1 /*dumpable*/,marker,printer,nuker,equal,hash,desc,sizeof(structtype),0,1,structtype)
 
 #define DEFINE_DUMPABLE_FROB_BLOCK_SIZABLE_LISP_OBJECT(name,c_name,marker,printer,nuker,equal,hash,desc,sizer,structtype) \
-MAKE_LISP_OBJECT(name,c_name,1 /*dumpable*/,marker,printer,nuker,equal,hash,desc,0,0,0,0,0,0,sizer,1,structtype)
+MAKE_LISP_OBJECT(name,c_name,1 /*dumpable*/,marker,printer,nuker,equal,hash,desc,0,sizer,1,structtype)
 
 #define DEFINE_DUMPABLE_INTERNAL_LISP_OBJECT(name,c_name,marker,desc,structtype) \
-DEFINE_DUMPABLE_GENERAL_LISP_OBJECT(name,c_name,marker,internal_object_printer,0,0,0,desc,0,0,0,0,0,structtype)
+DEFINE_DUMPABLE_LISP_OBJECT(name,c_name,marker,internal_object_printer,0,0,0,desc,structtype)
 
 #define DEFINE_DUMPABLE_SIZABLE_INTERNAL_LISP_OBJECT(name,c_name,marker,desc,sizer,structtype) \
-DEFINE_DUMPABLE_SIZABLE_GENERAL_LISP_OBJECT(name,c_name,marker,internal_object_printer,0,0,0,desc,0,0,0,0,0,sizer,structtype)
+DEFINE_DUMPABLE_SIZABLE_LISP_OBJECT(name,c_name,marker,internal_object_printer,0,0,0,desc,sizer,structtype)
 
 /********* The non-dumpable versions *********** */
 
 #define DEFINE_NODUMP_LISP_OBJECT(name,c_name,marker,printer,nuker,equal,hash,desc,structtype) \
-DEFINE_NODUMP_GENERAL_LISP_OBJECT(name,c_name,marker,printer,nuker,equal,hash,desc,0,0,0,0,0,structtype)
-
-#define DEFINE_NODUMP_GENERAL_LISP_OBJECT(name,c_name,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,disksaver,structtype) \
-MAKE_LISP_OBJECT(name,c_name,0 /*non-dumpable*/,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,disksaver,sizeof (structtype),0,0,structtype)
+MAKE_LISP_OBJECT(name,c_name,0 /*non-dumpable*/,marker,printer,nuker,equal,hash,desc,sizeof (structtype),0,0,structtype)
 
 #define DEFINE_NODUMP_SIZABLE_LISP_OBJECT(name,c_name,marker,printer,nuker,equal,hash,desc,sizer,structtype) \
-DEFINE_NODUMP_SIZABLE_GENERAL_LISP_OBJECT(name,c_name,marker,printer,nuker,equal,hash,desc,0,0,0,0,0,sizer,structtype)
-
-#define DEFINE_NODUMP_SIZABLE_GENERAL_LISP_OBJECT(name,c_name,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,disksaver,sizer,structtype) \
-MAKE_LISP_OBJECT(name,c_name,0 /*non-dumpable*/,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,disksaver,0,sizer,0,structtype)
+MAKE_LISP_OBJECT(name,c_name,0 /*non-dumpable*/,marker,printer,nuker,equal,hash,desc,0,sizer,0,structtype)
 
 #define DEFINE_NODUMP_FROB_BLOCK_LISP_OBJECT(name,c_name,marker,printer,nuker,equal,hash,desc,structtype) \
-DEFINE_NODUMP_FROB_BLOCK_GENERAL_LISP_OBJECT(name,c_name,marker,printer,nuker,equal,hash,desc,0,0,0,0,0,structtype)
-
-#define DEFINE_NODUMP_FROB_BLOCK_GENERAL_LISP_OBJECT(name,c_name,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,disksaver,structtype) \
-MAKE_LISP_OBJECT(name,c_name,0 /*non-dumpable*/,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,disksaver,sizeof(structtype),0,1,structtype)
+MAKE_LISP_OBJECT(name,c_name,0 /*non-dumpable*/,marker,printer,nuker,equal,hash,desc,sizeof(structtype),0,1,structtype)
 
 #define DEFINE_NODUMP_FROB_BLOCK_SIZABLE_LISP_OBJECT(name,c_name,marker,printer,nuker,equal,hash,desc,sizer,structtype) \
-MAKE_LISP_OBJECT(name,c_name,0 /*non-dumpable*/,marker,printer,nuker,equal,hash,desc,0,0,0,0,0,0,sizer,1,structtype)
+MAKE_LISP_OBJECT(name,c_name,0 /*non-dumpable*/,marker,printer,nuker,equal,hash,desc,0,sizer,1,structtype)
 
 #define DEFINE_NODUMP_INTERNAL_LISP_OBJECT(name,c_name,marker,desc,structtype) \
-DEFINE_NODUMP_GENERAL_LISP_OBJECT(name,c_name,marker,internal_object_printer,0,0,0,desc,0,0,0,0,0,structtype)
+DEFINE_NODUMP_LISP_OBJECT(name,c_name,marker,internal_object_printer,0,0,0,desc,structtype)
 
 #define DEFINE_NODUMP_SIZABLE_INTERNAL_LISP_OBJECT(name,c_name,marker,desc,sizer,structtype) \
-DEFINE_NODUMP_SIZABLE_GENERAL_LISP_OBJECT(name,c_name,marker,internal_object_printer,0,0,0,desc,0,0,0,0,0,sizer,structtype)
+DEFINE_NODUMP_SIZABLE_LISP_OBJECT(name,c_name,marker,internal_object_printer,0,0,0,desc,sizer,structtype)
 
 /********* MAKE_LISP_OBJECT, the underlying macro *********** */
 
 #ifdef NEW_GC
-#define MAKE_LISP_OBJECT(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,disksaver,size,sizer,frob_block_p,structtype)    \
+#define MAKE_LISP_OBJECT(name,c_name,dumpable,marker,printer,nuker,	\
+equal,hash,desc,size,sizer,frob_block_p,structtype)			\
 DECLARE_ERROR_CHECK_TYPES(c_name, structtype)				\
-const struct lrecord_implementation lrecord_##c_name =			\
+struct lrecord_implementation lrecord_##c_name =			\
   { name, dumpable, marker, printer, nuker, equal, hash, desc,		\
-    getprop, putprop, remprop, plist, disksaver, size, sizer,		\
-    lrecord_type_##c_name }
+    size, sizer, lrecord_type_##c_name }
 #else /* not NEW_GC */
-#define MAKE_LISP_OBJECT(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,disksaver,size,sizer,frob_block_p,structtype)    \
+#define MAKE_LISP_OBJECT(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,size,sizer,frob_block_p,structtype) \
 DECLARE_ERROR_CHECK_TYPES(c_name, structtype)				\
-const struct lrecord_implementation lrecord_##c_name =			\
+struct lrecord_implementation lrecord_##c_name =			\
   { name, dumpable, marker, printer, nuker, equal, hash, desc,		\
-    getprop, putprop, remprop, plist, disksaver, size, sizer,		\
-    lrecord_type_##c_name, frob_block_p }
+    size, sizer, lrecord_type_##c_name, frob_block_p }
 #endif /* not NEW_GC */
 
 
 /********* The module dumpable versions *********** */
 
 #define DEFINE_DUMPABLE_MODULE_LISP_OBJECT(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,structtype) \
-DEFINE_DUMPABLE_MODULE_GENERAL_LISP_OBJECT(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,0,0,0,0,0,structtype)
-
-#define DEFINE_DUMPABLE_MODULE_GENERAL_LISP_OBJECT(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,disksaver,structtype) \
-MAKE_MODULE_LISP_OBJECT(name,c_name,1 /*dumpable*/,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,disksaver,sizeof (structtype),0,0,structtype)
+MAKE_MODULE_LISP_OBJECT(name,c_name,1 /*dumpable*/,marker,printer,nuker,equal,hash,desc,sizeof (structtype),0,0,structtype)
 
 #define DEFINE_DUMPABLE_MODULE_SIZABLE_LISP_OBJECT(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,sizer,structtype) \
-DEFINE_DUMPABLE_MODULE_SIZABLE_GENERAL_LISP_OBJECT(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,0,0,0,0,0,sizer,structtype)
-
-#define DEFINE_DUMPABLE_MODULE_SIZABLE_GENERAL_LISP_OBJECT(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,disksaver,sizer,structtype) \
-MAKE_MODULE_LISP_OBJECT(name,c_name,1 /*dumpable*/,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,disksaver,0,sizer,0,structtype)
+MAKE_MODULE_LISP_OBJECT(name,c_name,1 /*dumpable*/,marker,printer,nuker,equal,hash,desc,0,sizer,0,structtype)
 
 /********* The module non-dumpable versions *********** */
 
-#define DEFINE_NODUMP_MODULE_LISP_OBJECT(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,structtype) \
-DEFINE_NODUMP_MODULE_GENERAL_LISP_OBJECT(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,0,0,0,0,0,structtype)
-
-#define DEFINE_NODUMP_MODULE_GENERAL_LISP_OBJECT(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,disksaver,structtype) \
-MAKE_MODULE_LISP_OBJECT(name,c_name,0 /*non-dumpable*/,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,disksaver,sizeof (structtype),0,0,structtype)
+#define DEFINE_NODUMP_MODULE_LISP_OBJECT(name,c_name,dumpable,marker,	\
+printer,nuker,equal,hash,desc,structtype)				\
+MAKE_MODULE_LISP_OBJECT(name,c_name,0 /*non-dumpable*/,marker,printer,	\
+nuker,equal,hash,desc,sizeof (structtype),0,0,structtype)
 
-#define DEFINE_NODUMP_MODULE_SIZABLE_LISP_OBJECT(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,sizer,structtype) \
-DEFINE_NODUMP_MODULE_SIZABLE_GENERAL_LISP_OBJECT(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,0,0,0,0,0,sizer,structtype)
-
-#define DEFINE_NODUMP_MODULE_SIZABLE_GENERAL_LISP_OBJECT(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,disksaver,sizer,structtype) \
-MAKE_MODULE_LISP_OBJECT(name,c_name,0 /*non-dumpable*/,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,disksaver,0,sizer,0,structtype)
+#define DEFINE_NODUMP_MODULE_SIZABLE_LISP_OBJECT(name,c_name,dumpable,	\
+marker,printer,nuker,equal,hash,desc,sizer,structtype)			\
+MAKE_MODULE_LISP_OBJECT(name,c_name,0 /*non-dumpable*/,marker,printer,	\
+nuker,equal,hash,desc,0,sizer,0,structtype)
 
 /********* MAKE_MODULE_LISP_OBJECT, the underlying macro *********** */
 
 #ifdef NEW_GC
-#define MAKE_MODULE_LISP_OBJECT(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,disksaver,size,sizer,frob_block_p,structtype) \
+#define MAKE_MODULE_LISP_OBJECT(name,c_name,dumpable,marker,printer,	\
+nuker,equal,hash,desc,size,sizer,frob_block_p,structtype)		\
+DECLARE_ERROR_CHECK_TYPES(c_name, structtype)				\
+int lrecord_type_##c_name;						\
+struct lrecord_implementation lrecord_##c_name =			\
+  { name, dumpable, marker, printer, nuker, equal, hash, desc,		\
+    size, sizer, lrecord_type_last_built_in_type }
+#else /* not NEW_GC */
+#define MAKE_MODULE_LISP_OBJECT(name,c_name,dumpable,marker,printer,	\
+nuker,equal,hash,desc,size,sizer,frob_block_p,structtype)		\
 DECLARE_ERROR_CHECK_TYPES(c_name, structtype)				\
 int lrecord_type_##c_name;						\
 struct lrecord_implementation lrecord_##c_name =			\
   { name, dumpable, marker, printer, nuker, equal, hash, desc,		\
-    getprop, putprop, remprop, plist, disksaver, size, sizer,		\
-    lrecord_type_last_built_in_type }
-#else /* not NEW_GC */
-#define MAKE_MODULE_LISP_OBJECT(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,disksaver,size,sizer,frob_block_p,structtype) \
-DECLARE_ERROR_CHECK_TYPES(c_name, structtype)				\
-int lrecord_type_##c_name;						\
-struct lrecord_implementation lrecord_##c_name =			\
-  { name, dumpable, marker, printer, nuker, equal, hash, desc,		\
-    getprop, putprop, remprop, plist, disksaver, size, sizer,		\
-    lrecord_type_last_built_in_type, frob_block_p }
+    size, sizer, lrecord_type_last_built_in_type, frob_block_p }
 #endif /* not NEW_GC */
 
+#ifdef MEMORY_USAGE_STATS
+#define INIT_MEMORY_USAGE_STATS(type)					\
+do									\
+{									\
+  lrecord_implementations_table[lrecord_type_##type]->			\
+    memusage_stats_list = Qnil;						\
+  lrecord_implementations_table[lrecord_type_##type]->			\
+    num_extra_memusage_stats = -1;					\
+  lrecord_implementations_table[lrecord_type_##type]->			\
+    num_extra_nonlisp_memusage_stats = -1;				\
+  staticpro (&lrecord_implementations_table[lrecord_type_##type]->	\
+	     memusage_stats_list);					\
+} while (0)
+#else
+#define INIT_MEMORY_USAGE_STATS(type) DO_NOTHING
+#endif /* (not) MEMORY_USAGE_STATS */
+
+#define INIT_LISP_OBJECT_BEGINNING(type)				\
+do									\
+{									\
+  lrecord_implementations_table[lrecord_type_##type] = &lrecord_##type;	\
+  INIT_MEMORY_USAGE_STATS (type);					\
+} while (0)
+
 #ifdef USE_KKCC
 extern MODULE_API const struct memory_description *lrecord_memory_descriptions[];
 
-#define INIT_LISP_OBJECT(type) do {				\
-  lrecord_implementations_table[lrecord_type_##type] = &lrecord_##type;	\
+#define INIT_LISP_OBJECT(type) do {					\
+  INIT_LISP_OBJECT_BEGINNING (type);					\
   lrecord_memory_descriptions[lrecord_type_##type] =			\
     lrecord_implementations_table[lrecord_type_##type]->description;	\
 } while (0)
@@ -1428,16 +1454,16 @@
 extern MODULE_API Lisp_Object (*lrecord_markers[]) (Lisp_Object);
 
 #define INIT_LISP_OBJECT(type) do {				\
-  lrecord_implementations_table[lrecord_type_##type] = &lrecord_##type;	\
-  lrecord_markers[lrecord_type_##type] =				\
-    lrecord_implementations_table[lrecord_type_##type]->marker;		\
+  INIT_LISP_OBJECT_BEGINNING (type);				\
+  lrecord_markers[lrecord_type_##type] =			\
+    lrecord_implementations_table[lrecord_type_##type]->marker;	\
 } while (0)
 #endif /* not USE_KKCC */
 
 #define INIT_MODULE_LISP_OBJECT(type) do {			\
-  lrecord_type_##type = lrecord_type_count++;				\
-  lrecord_##type.lrecord_type_index = lrecord_type_##type;		\
-  INIT_LISP_OBJECT(type);					\
+  lrecord_type_##type = lrecord_type_count++;			\
+  lrecord_##type.lrecord_type_index = lrecord_type_##type;	\
+  INIT_LISP_OBJECT (type);					\
 } while (0)
 
 #ifdef HAVE_SHLIB
@@ -1445,26 +1471,69 @@
 
 #ifdef USE_KKCC
 #define UNDEF_LISP_OBJECT(type) do {				\
-  lrecord_implementations_table[lrecord_type_##type] = NULL;		\
-  lrecord_memory_descriptions[lrecord_type_##type] = NULL;		\
+  lrecord_implementations_table[lrecord_type_##type] = NULL;	\
+  lrecord_memory_descriptions[lrecord_type_##type] = NULL;	\
 } while (0)
 #else /* not USE_KKCC */
 #define UNDEF_LISP_OBJECT(type) do {				\
-  lrecord_implementations_table[lrecord_type_##type] = NULL;		\
-  lrecord_markers[lrecord_type_##type] = NULL;				\
+  lrecord_implementations_table[lrecord_type_##type] = NULL;	\
+  lrecord_markers[lrecord_type_##type] = NULL;			\
 } while (0)
 #endif /* not USE_KKCC */
 
-#define UNDEF_MODULE_LISP_OBJECT(type) do {		\
+#define UNDEF_MODULE_LISP_OBJECT(type) do {				\
   if (lrecord_##type.lrecord_type_index == lrecord_type_count - 1) {	\
     /* This is the most recently defined type.  Clean up nicely. */	\
     lrecord_type_##type = lrecord_type_count--;				\
   } /* Else we can't help leaving a hole with this implementation. */	\
-  UNDEF_LISP_OBJECT(type);					\
+  UNDEF_LISP_OBJECT(type);						\
 } while (0)
 
 #endif /* HAVE_SHLIB */
 
+/*************** Macros for declaring that a Lisp object has a
+                 particular method, or for calling such a method. ********/
+
+/* Declare that object-type TYPE has method M; used in
+   initialization routines */
+#define OBJECT_HAS_METHOD(type, m) \
+  (lrecord_##type.m = type##_##m)
+/* Same but the method name come before the type */
+#define OBJECT_HAS_PREMETHOD(type, m) \
+  (lrecord_##type.m = m##_##type)
+/* Same but the name of the method is explicitly given */
+#define OBJECT_HAS_NAMED_METHOD(type, m, func) \
+  (lrecord_##type.m = (func))
+/* Object type has a property with the given value. */
+#define OBJECT_HAS_PROPERTY(type, prop, val) \
+  (lrecord_##type.prop = (val))
+
+/* Does the given object method exist? */
+#define HAS_OBJECT_METH_P(obj, m) \
+  (!!(XRECORD_LHEADER_IMPLEMENTATION (obj)->m))
+/* Call an object method. */
+#define OBJECT_METH(obj, m, args) \
+  ((XRECORD_LHEADER_IMPLEMENTATION (obj)->m) args)
+
+/* Call an object method, if it exists. */
+#define MAYBE_OBJECT_METH(obj, m, args)			\
+do							\
+{							\
+  const struct lrecord_implementation *_mom_imp =	\
+    XRECORD_LHEADER_IMPLEMENTATION (obj);		\
+  if (_mom_imp->m)					\
+    ((_mom_imp->m) args);				\
+} while (0)
+
+/* Call an object method, if it exists, or return GIVEN.  NOTE:
+   Multiply-evaluates OBJ. */
+#define OBJECT_METH_OR_GIVEN(obj, m, args, given)  \
+  (HAS_OBJECT_METH_P (obj, m) ?	OBJECT_METH (obj, m, args) : (given))
+
+#define OBJECT_PROPERTY(obj, prop) (XRECORD_LHEADER_IMPLEMENTATION (obj)->prop)
+
+/************** Other stuff **************/
+
 #define LRECORDP(a) (XTYPE (a) == Lisp_Type_Record)
 #define XRECORD_LHEADER(a) ((struct lrecord_header *) XPNTR (a))
 
@@ -1675,41 +1744,41 @@
 
 #ifdef ERROR_CHECK_TYPES
 
-# define DECLARE_LISP_OBJECT(c_name, structtype)			  \
-extern const struct lrecord_implementation lrecord_##c_name;		  \
-DECLARE_INLINE_HEADER (							  \
-structtype *								  \
-error_check_##c_name (Lisp_Object obj, const Ascbyte *file, int line)	  \
-)									  \
-{									  \
+# define DECLARE_LISP_OBJECT(c_name, structtype)			\
+extern struct lrecord_implementation lrecord_##c_name;			\
+DECLARE_INLINE_HEADER (							\
+structtype *								\
+error_check_##c_name (Lisp_Object obj, const Ascbyte *file, int line)	\
+)									\
+{									\
   assert_at_line (RECORD_TYPEP (obj, lrecord_type_##c_name), file, line); \
-  return (structtype *) XPNTR (obj);					  \
-}									  \
+  return (structtype *) XPNTR (obj);					\
+}									\
 extern Lisp_Object Q##c_name##p
 
-# define DECLARE_MODULE_API_LISP_OBJECT(c_name, structtype)		  \
-extern MODULE_API const struct lrecord_implementation lrecord_##c_name;	  \
-DECLARE_INLINE_HEADER (							  \
-structtype *								  \
-error_check_##c_name (Lisp_Object obj, const Ascbyte *file, int line)	  \
-)									  \
-{									  \
+# define DECLARE_MODULE_API_LISP_OBJECT(c_name, structtype)		\
+extern MODULE_API struct lrecord_implementation lrecord_##c_name;	\
+DECLARE_INLINE_HEADER (							\
+structtype *								\
+error_check_##c_name (Lisp_Object obj, const Ascbyte *file, int line)	\
+)									\
+{									\
   assert_at_line (RECORD_TYPEP (obj, lrecord_type_##c_name), file, line); \
-  return (structtype *) XPNTR (obj);					  \
-}									  \
+  return (structtype *) XPNTR (obj);					\
+}									\
 extern MODULE_API Lisp_Object Q##c_name##p
 
-# define DECLARE_MODULE_LISP_OBJECT(c_name, structtype)			  \
-extern int lrecord_type_##c_name;					  \
-extern struct lrecord_implementation lrecord_##c_name;			  \
-DECLARE_INLINE_HEADER (							  \
-structtype *								  \
-error_check_##c_name (Lisp_Object obj, const Ascbyte *file, int line)	  \
-)									  \
-{									  \
+# define DECLARE_MODULE_LISP_OBJECT(c_name, structtype)			\
+extern int lrecord_type_##c_name;					\
+extern struct lrecord_implementation lrecord_##c_name;			\
+DECLARE_INLINE_HEADER (							\
+structtype *								\
+error_check_##c_name (Lisp_Object obj, const Ascbyte *file, int line)	\
+)									\
+{									\
   assert_at_line (RECORD_TYPEP (obj, lrecord_type_##c_name), file, line); \
-  return (structtype *) XPNTR (obj);					  \
-}									  \
+  return (structtype *) XPNTR (obj);					\
+}									\
 extern Lisp_Object Q##c_name##p
 
 # define XRECORD(x, c_name, structtype) \
@@ -1734,10 +1803,10 @@
 
 # define DECLARE_LISP_OBJECT(c_name, structtype)		\
 extern Lisp_Object Q##c_name##p;				\
-extern const struct lrecord_implementation lrecord_##c_name
+extern struct lrecord_implementation lrecord_##c_name
 # define DECLARE_MODULE_API_LISP_OBJECT(c_name, structtype)	\
 extern MODULE_API Lisp_Object Q##c_name##p;			\
-extern MODULE_API const struct lrecord_implementation lrecord_##c_name
+extern MODULE_API struct lrecord_implementation lrecord_##c_name
 # define DECLARE_MODULE_LISP_OBJECT(c_name, structtype)		\
 extern Lisp_Object Q##c_name##p;				\
 extern int lrecord_type_##c_name;				\
@@ -1948,14 +2017,14 @@
   return detagged_lisp_object_size (XRECORD_LHEADER (o));
 }
 
-struct overhead_stats;
+struct usage_stats;
 
 MODULE_API void copy_lisp_object (Lisp_Object dst, Lisp_Object src);
 MODULE_API void zero_sized_lisp_object (Lisp_Object obj, Bytecount size);
 MODULE_API void zero_nonsized_lisp_object (Lisp_Object obj);
 #ifdef MEMORY_USAGE_STATS
 Bytecount lisp_object_storage_size (Lisp_Object obj,
-				    struct overhead_stats *ovstats);
+				    struct usage_stats *ustats);
 #endif /* MEMORY_USAGE_STATS */
 void free_normal_lisp_object (Lisp_Object obj);
 
--- a/src/lstream.c	Thu Mar 18 23:12:41 2010 -0500
+++ b/src/lstream.c	Fri Mar 19 17:02:11 2010 -0500
@@ -144,14 +144,12 @@
   0, lstream_empty_extra_description_1
 };
 
-DEFINE_NODUMP_SIZABLE_GENERAL_LISP_OBJECT ("stream", lstream,
-					   mark_lstream, print_lstream,
-					   finalize_lstream,
-					   0, 0, /* no equal or hash */
-					   lstream_description,
-					   0, 0, 0, 0, /* no property meths */
-					   disksave_lstream,
-					   sizeof_lstream, Lstream);
+DEFINE_NODUMP_SIZABLE_LISP_OBJECT ("stream", lstream,
+				   mark_lstream, print_lstream,
+				   finalize_lstream,
+				   0, 0, /* no equal or hash */
+				   lstream_description,
+				   sizeof_lstream, Lstream);
 
 
 /* Change the buffering of a stream.  See lstream.h.  By default the
@@ -1822,6 +1820,18 @@
 /************************************************************************/
 
 void
+syms_of_lstream (void)
+{
+  INIT_LISP_OBJECT (lstream);
+}
+
+void
+lstream_objects_create (void)
+{
+  OBJECT_HAS_PREMETHOD (lstream, disksave);
+}
+
+void
 lstream_type_create (void)
 {
   LSTREAM_HAS_METHOD (stdio, reader);
@@ -1877,5 +1887,4 @@
 void
 vars_of_lstream (void)
 {
-  INIT_LISP_OBJECT (lstream);
 }
--- a/src/marker.c	Thu Mar 18 23:12:41 2010 -0500
+++ b/src/marker.c	Fri Mar 19 17:02:11 2010 -0500
@@ -498,7 +498,7 @@
 #ifdef MEMORY_USAGE_STATS
 
 int
-compute_buffer_marker_usage (struct buffer *b, struct overhead_stats *ovstats)
+compute_buffer_marker_usage (struct buffer *b, struct usage_stats *ustats)
 {
   Lisp_Marker *m;
   int total = 0;
@@ -506,7 +506,7 @@
 
   for (m = BUF_MARKERS (b); m; m = m->next)
     total += sizeof (Lisp_Marker);
-  ovstats->was_requested += total;
+  ustats->was_requested += total;
 #ifdef NEW_GC
   overhead = mc_alloced_storage_size (total, 0) - total;
 #else /* not NEW_GC */
@@ -514,7 +514,7 @@
 #endif /* not NEW_GC */
   /* #### claiming this is all malloc overhead is not really right,
      but it has to go somewhere. */
-  ovstats->malloc_overhead += overhead;
+  ustats->malloc_overhead += overhead;
   return total + overhead;
 }
 
--- a/src/mc-alloc.c	Thu Mar 18 23:12:41 2010 -0500
+++ b/src/mc-alloc.c	Fri Mar 19 17:02:11 2010 -0500
@@ -964,7 +964,7 @@
 
 #ifdef MEMORY_USAGE_STATS
 Bytecount
-mc_alloced_storage_size (Bytecount claimed_size, struct overhead_stats *stats)
+mc_alloced_storage_size (Bytecount claimed_size, struct usage_stats *stats)
 {
   size_t used_size = 
     get_used_list_size_value (get_used_list_index (claimed_size));
--- a/src/mc-alloc.h	Thu Mar 18 23:12:41 2010 -0500
+++ b/src/mc-alloc.h	Fri Mar 19 17:02:11 2010 -0500
@@ -126,7 +126,7 @@
 /* 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 overhead_stats *stats);
+				   struct usage_stats *stats);
 #endif /* MEMORY_USAGE_STATS */
 
 
--- a/src/mule-charset.c	Thu Mar 18 23:12:41 2010 -0500
+++ b/src/mule-charset.c	Fri Mar 19 17:02:11 2010 -0500
@@ -990,57 +990,25 @@
 
 struct charset_stats
 {
-  int from_unicode;
-  int to_unicode;
-  int other;
+  struct usage_stats u;
+  Bytecount from_unicode;
+  Bytecount to_unicode;
 };
 
 static void
 compute_charset_usage (Lisp_Object charset, struct charset_stats *stats,
-		      struct overhead_stats *ovstats)
+		      struct usage_stats *ustats)
 {
-  xzero (*stats);
-  stats->other   += lisp_object_storage_size (charset, ovstats);
-  stats->from_unicode += compute_from_unicode_table_size (charset, ovstats);
-  stats->to_unicode += compute_to_unicode_table_size (charset, ovstats);
+  stats->from_unicode += compute_from_unicode_table_size (charset, ustats);
+  stats->to_unicode += compute_to_unicode_table_size (charset, ustats);
 }
 
-DEFUN ("charset-memory-usage", Fcharset_memory_usage, 1, 1, 0, /*
-Return stats about the memory usage of charset CHARSET.
-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 charset (separate from the memory logically associated with a
-charset or frame), including internal structures and any malloc()
-overhead associated with them.  In practice, the byte counts are
-underestimated for various reasons, e.g. 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).
+static void
+charset_memory_usage (Lisp_Object charset, struct generic_usage_stats *gustats)
+{
+  struct charset_stats *stats = (struct charset_stats *) gustats;
 
-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.
-*/
-       (charset))
-{
-  struct charset_stats stats;
-  struct overhead_stats ovstats;
-  Lisp_Object val = Qnil;
-
-  charset = Fget_charset (charset);
-  xzero (ovstats);
-  compute_charset_usage (charset, &stats, &ovstats);
-
-  val = acons (Qfrom_unicode,       make_int (stats.from_unicode),      val);
-  val = acons (Qto_unicode,         make_int (stats.to_unicode),        val);
-  val = Fcons (Qnil, val);
-  val = acons (Qactually_requested, make_int (ovstats.was_requested),   val);
-  val = acons (Qmalloc_overhead,    make_int (ovstats.malloc_overhead), val);
-  val = acons (Qgap_overhead,       make_int (ovstats.gap_overhead),    val);
-  val = acons (Qdynarr_overhead,    make_int (ovstats.dynarr_overhead), val);
-
-  return Fnreverse (val);
+  compute_charset_usage (charset, stats, &stats->u);
 }
 
 #endif /* MEMORY_USAGE_STATS */
@@ -1051,6 +1019,14 @@
 /************************************************************************/
 
 void
+mule_charset_objects_create (void)
+{
+#ifdef MEMORY_USAGE_STATS
+  OBJECT_HAS_METHOD (charset, memory_usage);
+#endif
+}
+
+void
 syms_of_mule_charset (void)
 {
   INIT_LISP_OBJECT (charset);
@@ -1074,10 +1050,6 @@
   DEFSUBR (Fset_charset_registries);
   DEFSUBR (Fcharsets_in_region);
 
-#ifdef MEMORY_USAGE_STATS
-  DEFSUBR (Fcharset_memory_usage);
-#endif
-
   DEFSYMBOL (Qcharsetp);
   DEFSYMBOL (Qregistries);
   DEFSYMBOL (Qfinal);
@@ -1126,6 +1098,11 @@
 {
   int i, j, k;
 
+#ifdef MEMORY_USAGE_STATS
+  OBJECT_HAS_PROPERTY
+    (charset, memusage_stats_list, list2 (Qfrom_unicode, Qto_unicode));
+#endif /* MEMORY_USAGE_STATS */
+
   chlook = xnew_and_zero (struct charset_lookup); /* zero for Purify. */
   dump_add_root_block_ptr (&chlook, &charset_lookup_description);
 
--- a/src/redisplay.c	Thu Mar 18 23:12:41 2010 -0500
+++ b/src/redisplay.c	Fri Mar 19 17:02:11 2010 -0500
@@ -9665,50 +9665,50 @@
 /***************************************************************************/
 
 static int
-compute_rune_dynarr_usage (rune_dynarr *dyn, struct overhead_stats *ovstats)
-{
-  return dyn ? Dynarr_memory_usage (dyn, ovstats) : 0;
+compute_rune_dynarr_usage (rune_dynarr *dyn, struct usage_stats *ustats)
+{
+  return dyn ? Dynarr_memory_usage (dyn, ustats) : 0;
 }
 
 static int
 compute_display_block_dynarr_usage (display_block_dynarr *dyn,
-				    struct overhead_stats *ovstats)
+				    struct usage_stats *ustats)
 {
   int total, i;
 
   if (!dyn)
     return 0;
 
-  total = Dynarr_memory_usage (dyn, ovstats);
+  total = Dynarr_memory_usage (dyn, ustats);
   for (i = 0; i < Dynarr_largest (dyn); i++)
-    total += compute_rune_dynarr_usage (Dynarr_at (dyn, i).runes, ovstats);
+    total += compute_rune_dynarr_usage (Dynarr_at (dyn, i).runes, ustats);
 
   return total;
 }
 
 static int
 compute_glyph_block_dynarr_usage (glyph_block_dynarr *dyn,
-				  struct overhead_stats *ovstats)
-{
-  return dyn ? Dynarr_memory_usage (dyn, ovstats) : 0;
+				  struct usage_stats *ustats)
+{
+  return dyn ? Dynarr_memory_usage (dyn, ustats) : 0;
 }
 
 int
 compute_display_line_dynarr_usage (display_line_dynarr *dyn,
-				   struct overhead_stats *ovstats)
+				   struct usage_stats *ustats)
 {
   int total, i;
 
   if (!dyn)
     return 0;
 
-  total = Dynarr_memory_usage (dyn, ovstats);
+  total = Dynarr_memory_usage (dyn, ustats);
   for (i = 0; i < Dynarr_largest (dyn); i++)
     {
       struct display_line *dl = &Dynarr_at (dyn, i);
-      total += compute_display_block_dynarr_usage(dl->display_blocks, ovstats);
-      total += compute_glyph_block_dynarr_usage  (dl->left_glyphs,    ovstats);
-      total += compute_glyph_block_dynarr_usage  (dl->right_glyphs,   ovstats);
+      total += compute_display_block_dynarr_usage(dl->display_blocks, ustats);
+      total += compute_glyph_block_dynarr_usage  (dl->left_glyphs,    ustats);
+      total += compute_glyph_block_dynarr_usage  (dl->right_glyphs,   ustats);
     }
 
   return total;
@@ -9716,9 +9716,9 @@
 
 int
 compute_line_start_cache_dynarr_usage (line_start_cache_dynarr *dyn,
-				       struct overhead_stats *ovstats)
-{
-  return dyn ? Dynarr_memory_usage (dyn, ovstats) : 0;
+				       struct usage_stats *ustats)
+{
+  return dyn ? Dynarr_memory_usage (dyn, ustats) : 0;
 }
 
 #endif /* MEMORY_USAGE_STATS */
--- a/src/redisplay.h	Thu Mar 18 23:12:41 2010 -0500
+++ b/src/redisplay.h	Fri Mar 19 17:02:11 2010 -0500
@@ -777,9 +777,9 @@
 
 #ifdef MEMORY_USAGE_STATS
 int compute_display_line_dynarr_usage (display_line_dynarr *dyn,
-				       struct overhead_stats *ovstats);
+				       struct usage_stats *ustats);
 int compute_line_start_cache_dynarr_usage (line_start_cache_dynarr *dyn,
-					   struct overhead_stats *ovstats);
+					   struct usage_stats *ustats);
 #endif
 
 
--- a/src/scrollbar-gtk.c	Thu Mar 18 23:12:41 2010 -0500
+++ b/src/scrollbar-gtk.c	Fri Mar 19 17:02:11 2010 -0500
@@ -477,7 +477,7 @@
 static int
 gtk_compute_scrollbar_instance_usage (struct device *UNUSED (d),
 				      struct scrollbar_instance *inst,
-				      struct overhead_stats *ovstats)
+				      struct usage_stats *ustats)
 {
   int total = 0;
 
@@ -486,7 +486,7 @@
       struct gtk_scrollbar_data *data =
 	(struct gtk_scrollbar_data *) inst->scrollbar_data;
 
-      total += malloced_storage_size (data, sizeof (*data), ovstats);
+      total += malloced_storage_size (data, sizeof (*data), ustats);
       inst = inst->next;
     }
 
--- a/src/scrollbar-msw.c	Thu Mar 18 23:12:41 2010 -0500
+++ b/src/scrollbar-msw.c	Fri Mar 19 17:02:11 2010 -0500
@@ -426,7 +426,7 @@
 static int
 mswindows_compute_scrollbar_instance_usage (struct device *UNUSED (d),
 					    struct scrollbar_instance *inst,
-					    struct overhead_stats *ovstats)
+					    struct usage_stats *ustats)
 {
   int total = 0;
 
@@ -435,7 +435,7 @@
       struct mswindows_scrollbar_data *data =
 	(struct mswindows_scrollbar_data *) inst->scrollbar_data;
 
-      total += malloced_storage_size (data, sizeof (*data), ovstats);
+      total += malloced_storage_size (data, sizeof (*data), ustats);
       inst = inst->next;
     }
 
--- a/src/scrollbar-x.c	Thu Mar 18 23:12:41 2010 -0500
+++ b/src/scrollbar-x.c	Fri Mar 19 17:02:11 2010 -0500
@@ -697,7 +697,7 @@
 static int
 x_compute_scrollbar_instance_usage (struct device *UNUSED (d),
 				    struct scrollbar_instance *inst,
-				    struct overhead_stats *ovstats)
+				    struct usage_stats *ustats)
 {
   int total = 0;
 
@@ -706,9 +706,9 @@
       struct x_scrollbar_data *data =
 	(struct x_scrollbar_data *) inst->scrollbar_data;
 
-      total += malloced_storage_size (data, sizeof (*data), ovstats);
+      total += malloced_storage_size (data, sizeof (*data), ustats);
       total += malloced_storage_size (data->name, 1 + strlen (data->name),
-				      ovstats);
+				      ustats);
       inst = inst->next;
     }
 
--- a/src/scrollbar.c	Thu Mar 18 23:12:41 2010 -0500
+++ b/src/scrollbar.c	Fri Mar 19 17:02:11 2010 -0500
@@ -260,17 +260,17 @@
 int
 compute_scrollbar_instance_usage (struct device *d,
 				  struct scrollbar_instance *inst,
-				  struct overhead_stats *ovstats)
+				  struct usage_stats *ustats)
 {
   int total = 0;
 
   if (HAS_DEVMETH_P(d, compute_scrollbar_instance_usage))
-    total += DEVMETH (d, compute_scrollbar_instance_usage, (d, inst, ovstats));
+    total += DEVMETH (d, compute_scrollbar_instance_usage, (d, inst, ustats));
 
   while (inst)
     {
       total += lisp_object_storage_size (wrap_scrollbar_instance (inst),
-					 ovstats);
+					 ustats);
       inst = inst->next;
     }
 
--- a/src/scrollbar.h	Thu Mar 18 23:12:41 2010 -0500
+++ b/src/scrollbar.h	Fri Mar 19 17:02:11 2010 -0500
@@ -67,7 +67,7 @@
 #ifdef MEMORY_USAGE_STATS
 int compute_scrollbar_instance_usage (struct device *d,
 				      struct scrollbar_instance *inst,
-				      struct overhead_stats *ovstats);
+				      struct usage_stats *ustats);
 #endif
 
 extern Lisp_Object Vscrollbar_width, Vscrollbar_height;
--- a/src/symbols.c	Thu Mar 18 23:12:41 2010 -0500
+++ b/src/symbols.c	Fri Mar 19 17:02:11 2010 -0500
@@ -141,15 +141,10 @@
   return external_remprop (&XSYMBOL (symbol)->plist, property, 0, ERROR_ME);
 }
 
-DEFINE_DUMPABLE_FROB_BLOCK_GENERAL_LISP_OBJECT ("symbol", symbol,
-						mark_symbol, print_symbol,
-						0, 0, 0, symbol_description,
-						symbol_getprop,
-						symbol_putprop,
-						symbol_remprop,
-						Fsymbol_plist,
-						0 /* no disksaver */,
-						Lisp_Symbol);
+DEFINE_DUMPABLE_FROB_BLOCK_LISP_OBJECT ("symbol", symbol,
+					mark_symbol, print_symbol,
+					0, 0, 0, symbol_description,
+					Lisp_Symbol);
 
 /**********************************************************************/
 /*                              Intern				      */
@@ -3527,6 +3522,15 @@
 };
 #endif /* not NEW_GC */
 
+static void
+reinit_symbol_objects_early (void)
+{
+  OBJECT_HAS_METHOD (symbol, getprop);
+  OBJECT_HAS_METHOD (symbol, putprop);
+  OBJECT_HAS_METHOD (symbol, remprop);
+  OBJECT_HAS_NAMED_METHOD (symbol, plist, Fsymbol_plist);
+}
+
 void
 init_symbols_once_early (void)
 {
@@ -3536,13 +3540,13 @@
   INIT_LISP_OBJECT (symbol_value_lisp_magic);
   INIT_LISP_OBJECT (symbol_value_varalias);
 
-  reinit_symbols_early ();
+  reinit_symbol_objects_early ();
 
   /* Bootstrapping problem: Qnil isn't set when make_string_nocopy is
      called the first time. */
   Qnil = Fmake_symbol (make_string_nocopy ((const Ibyte *) "nil", 3));
   XSTRING_PLIST (XSYMBOL (Qnil)->name) = Qnil;
-  XSYMBOL (Qnil)->value = Qnil; /* Nihil ex nihil */
+  XSYMBOL (Qnil)->value = Qnil; /* Nihil ex nihilo */
   XSYMBOL (Qnil)->plist = Qnil;
 
   Vobarray = make_vector (OBARRAY_SIZE, Qzero);
@@ -3591,6 +3595,7 @@
 void
 reinit_symbols_early (void)
 {
+  reinit_symbol_objects_early ();
 }
 
 static void
--- a/src/symsinit.h	Thu Mar 18 23:12:41 2010 -0500
+++ b/src/symsinit.h	Fri Mar 19 17:02:11 2010 -0500
@@ -147,6 +147,7 @@
 void syms_of_intl_x (void);
 void syms_of_keymap (void);
 void syms_of_lread (void);
+void syms_of_lstream (void);
 void syms_of_macros (void);
 void syms_of_marker (void);
 void syms_of_mc_alloc (void);
@@ -202,6 +203,21 @@
 void syms_of_win32 (void);
 void syms_of_window (void);
 
+/* Initialize dynamic properties of objects (i.e. those properties not
+   initialized statically through a DEFINE_*_LISP_OBJECT declaration).
+   Dump time and post-pdump-load-time. */
+
+void buffer_objects_create (void);
+void extent_objects_create (void);
+void face_objects_create (void);
+void frame_objects_create (void);
+void glyph_objects_create (void);
+void hash_table_objects_create (void);
+void lstream_objects_create (void);
+void mule_charset_objects_create (void);
+void ui_gtk_objects_create (void);
+void window_objects_create (void);
+
 /* Initialize the console types (dump-time only for console_type_(),
    post-pdump-load-time only for reinit_). */
 
@@ -329,6 +345,7 @@
 
 void vars_of_abbrev (void);
 void vars_of_alloc (void);
+void reinit_vars_of_alloc (void);
 void vars_of_balloon_x (void);
 void vars_of_buffer (void);
 void reinit_vars_of_buffer (void);
@@ -366,6 +383,7 @@
 void vars_of_dragdrop (void);
 void vars_of_editfns (void);
 EXTERN_C void vars_of_eldap (void);
+void vars_of_elhash (void);
 void vars_of_emacs (void);
 void vars_of_eval (void);
 void reinit_vars_of_eval (void);
--- a/src/tests.c	Thu Mar 18 23:12:41 2010 -0500
+++ b/src/tests.c	Fri Mar 19 17:02:11 2010 -0500
@@ -49,7 +49,7 @@
        ())
 {
   void *ptr; Bytecount len;
-  Lisp_Object string, opaque, conversion_result = Qnil;
+  Lisp_Object string = Qnil, opaque = Qnil, conversion_result = Qnil;
 
   Ibyte int_foo[] = "\n\nfoo\nbar";
   Extbyte ext_unix[]= "\n\nfoo\nbar";
@@ -72,6 +72,20 @@
   Lisp_Object string_latin1 = make_string (int_latin1, sizeof (int_latin1) - 1);
   int autodetect_eol_p =
     !NILP (Fsymbol_value (intern ("eol-detection-enabled-p")));
+  struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
+  struct gcpro ngcpro1, ngcpro2, ngcpro3;
+#ifdef MULE
+  struct gcpro ngcpro4;
+#endif
+
+  /* DFC conversion inhibits GC, but we have a call2() below which calls
+     Lisp, which can trigger GC, so we need to GC-protect everything here. */
+  GCPRO5 (string, opaque, conversion_result, opaque_dos, string_foo);
+#ifdef MULE
+  NGCPRO4 (string_latin2, opaque_latin, opaque0_latin, string_latin1);
+#else
+  NGCPRO3 (opaque_latin, opaque0_latin, string_latin1);
+#endif
 
   /* Check for expected strings before and after conversion.
      Conversions depend on whether MULE is defined. */
@@ -541,6 +555,8 @@
 		      Qbinary);
   DFC_CHECK_DATA (ptr, len, ext_dos, "DOS Lisp opaque, ALLOCA, binary");
 
+  NUNGCPRO;
+  UNGCPRO;
   return conversion_result;
 }
 
--- a/src/ui-gtk.c	Thu Mar 18 23:12:41 2010 -0500
+++ b/src/ui-gtk.c	Fri Mar 19 17:02:11 2010 -0500
@@ -807,7 +807,7 @@
 }
 
 static Lisp_Object
-object_getprop (Lisp_Object obj, Lisp_Object prop)
+emacs_gtk_object_getprop (Lisp_Object obj, Lisp_Object prop)
 {
   Lisp_Object rval = Qnil;
   Lisp_Object prop_name = Qnil;
@@ -871,7 +871,7 @@
 }
 
 static int
-object_putprop (Lisp_Object obj, Lisp_Object prop, Lisp_Object value)
+emacs_gtk_object_putprop (Lisp_Object obj, Lisp_Object prop, Lisp_Object value)
 {
   GtkArgInfo *info = NULL;
   Lisp_Object prop_name = Qnil;
@@ -932,19 +932,14 @@
     gtk_object_unref (data->object);
 }
 
-DEFINE_NODUMP_GENERAL_LISP_OBJECT ("GtkObject", emacs_gtk_object,
-				   mark_gtk_object_data,
-				   emacs_gtk_object_printer,
-				   emacs_gtk_object_finalizer,
-				   0, /* equality */
-				   0, /* hash */
-				   gtk_object_data_description,
-				   object_getprop,
-				   object_putprop,
-				   0, /* rem prop */
-				   0, /* plist */
-				   0, /* disksaver */
-				   emacs_gtk_object_data);
+DEFINE_NODUMP_LISP_OBJECT ("GtkObject", emacs_gtk_object,
+			   mark_gtk_object_data,
+			   emacs_gtk_object_printer,
+			   emacs_gtk_object_finalizer,
+			   0, /* equality */
+			   0, /* hash */
+			   gtk_object_data_description,
+			   emacs_gtk_object_data);
 
 static emacs_gtk_object_data *
 allocate_emacs_gtk_object_data (void)
@@ -1338,6 +1333,14 @@
 
 
 void
+ui_gtk_objects_create (void)
+{
+  OBJECT_HAS_METHOD (emacs_gtk_object, getprop);
+  OBJECT_HAS_METHOD (emacs_gtk_object, putprop);
+  /* #### No remprop or plist methods */
+}
+
+void
 syms_of_ui_gtk (void)
 {
   INIT_LISP_OBJECT (emacs_ffi);
--- a/src/unicode.c	Thu Mar 18 23:12:41 2010 -0500
+++ b/src/unicode.c	Fri Mar 19 17:02:11 2010 -0500
@@ -542,7 +542,7 @@
 
 static Bytecount
 compute_from_unicode_table_size_1 (void *table, int level,
-				   struct overhead_stats *stats)
+				   struct usage_stats *stats)
 {
   int i;
   Bytecount size = 0;
@@ -590,7 +590,7 @@
 
 static Bytecount
 compute_to_unicode_table_size_1 (void *table, int level,
-				 struct overhead_stats *stats)
+				 struct usage_stats *stats)
 {
   Bytecount size = 0;
 
@@ -615,7 +615,7 @@
 
 Bytecount
 compute_from_unicode_table_size (Lisp_Object charset,
-				 struct overhead_stats *stats)
+				 struct usage_stats *stats)
 {
   return (compute_from_unicode_table_size_1
 	  (XCHARSET_FROM_UNICODE_TABLE (charset),
@@ -625,7 +625,7 @@
 
 Bytecount
 compute_to_unicode_table_size (Lisp_Object charset,
-			       struct overhead_stats *stats)
+			       struct usage_stats *stats)
 {
   return (compute_to_unicode_table_size_1
 	  (XCHARSET_TO_UNICODE_TABLE (charset),
--- a/src/window.c	Thu Mar 18 23:12:41 2010 -0500
+++ b/src/window.c	Fri Mar 19 17:02:11 2010 -0500
@@ -5158,101 +5158,63 @@
 
 struct window_stats
 {
-  int face;
-  int glyph;
+  struct usage_stats u;
+  Bytecount face;
+  Bytecount glyph;
+  Bytecount line_start;
+  Bytecount other_redisplay;
 #ifdef HAVE_SCROLLBARS
-  int scrollbar;
+  Bytecount scrollbar;
 #endif
-  int line_start;
-  int other_redisplay;
-  int other;
 };
 
 static void
 compute_window_mirror_usage (struct window_mirror *mir,
 			     struct window_stats *stats,
-			     struct overhead_stats *ovstats)
+			     struct usage_stats *ustats)
 {
   if (!mir)
     return;
-  stats->other += lisp_object_storage_size (wrap_window_mirror (mir), ovstats);
 #ifdef HAVE_SCROLLBARS
   {
     struct device *d = XDEVICE (FRAME_DEVICE (mir->frame));
 
     stats->scrollbar +=
       compute_scrollbar_instance_usage (d, mir->scrollbar_vertical_instance,
-					ovstats);
+					ustats);
     stats->scrollbar +=
       compute_scrollbar_instance_usage (d, mir->scrollbar_horizontal_instance,
-					ovstats);
+					ustats);
   }
 #endif /* HAVE_SCROLLBARS */
   stats->other_redisplay +=
-    compute_display_line_dynarr_usage (mir->current_display_lines, ovstats);
+    compute_display_line_dynarr_usage (mir->current_display_lines, ustats);
   stats->other_redisplay +=
-    compute_display_line_dynarr_usage (mir->desired_display_lines, ovstats);
+    compute_display_line_dynarr_usage (mir->desired_display_lines, ustats);
 }
 
 static void
 compute_window_usage (struct window *w, struct window_stats *stats,
-		      struct overhead_stats *ovstats)
+		      struct usage_stats *ustats)
 {
-  xzero (*stats);
-  stats->other += lisp_object_storage_size (wrap_window (w), ovstats);
-  stats->face += compute_face_cachel_usage (w->face_cachels, ovstats);
-  stats->glyph += compute_glyph_cachel_usage (w->glyph_cachels, ovstats);
+  stats->face += compute_face_cachel_usage (w->face_cachels, ustats);
+  stats->glyph += compute_glyph_cachel_usage (w->glyph_cachels, ustats);
   stats->line_start +=
-    compute_line_start_cache_dynarr_usage (w->line_start_cache, ovstats);
-  compute_window_mirror_usage (find_window_mirror (w), stats, ovstats);
+    compute_line_start_cache_dynarr_usage (w->line_start_cache, ustats);
+  compute_window_mirror_usage (find_window_mirror (w), stats, ustats);
 }
 
-DEFUN ("window-memory-usage", Fwindow_memory_usage, 1, 1, 0, /*
-Return stats about the memory usage of window WINDOW.
-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 window (separate from the memory logically associated with a
-buffer or frame), 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) and because there is other stuff that might logically
-be associated with a window, buffer, or frame (e.g. window configurations,
-glyphs) but should not obviously be included in the usage counts.
-
-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.
-*/
-       (window))
+static void
+window_memory_usage (Lisp_Object window, struct generic_usage_stats *gustats)
 {
-  struct window_stats stats;
-  struct overhead_stats ovstats;
-  Lisp_Object val = Qnil;
-
-  CHECK_WINDOW (window); /* dead windows should be allowed, no? */
-  xzero (ovstats);
-  compute_window_usage (XWINDOW (window), &stats, &ovstats);
-
-  val = acons (Qface_cache,          make_int (stats.face),              val);
-  val = acons (Qglyph_cache,         make_int (stats.glyph),             val);
-#ifdef HAVE_SCROLLBARS
-  val = acons (Qscrollbar_instances, make_int (stats.scrollbar),         val);
-#endif
-  val = acons (Qline_start_cache,    make_int (stats.line_start),        val);
-  val = acons (Qother_redisplay,     make_int (stats.other_redisplay),   val);
-  val = acons (Qother,               make_int (stats.other),             val);
-  val = Fcons (Qnil, val);
-  val = acons (Qactually_requested,  make_int (ovstats.was_requested),   val);
-  val = acons (Qmalloc_overhead,     make_int (ovstats.malloc_overhead), val);
-  val = acons (Qdynarr_overhead,     make_int (ovstats.dynarr_overhead), val);
-
-  return Fnreverse (val);
+  struct window_stats *stats = (struct window_stats *) gustats;
+
+  compute_window_usage (XWINDOW (window), stats, &stats->u);
 }
 
 #endif /* MEMORY_USAGE_STATS */
+
+
 
 /* Mark all subwindows of a window as deleted.  The argument
    W is actually the subwindow tree of the window in question. */
@@ -5430,6 +5392,14 @@
 /************************************************************************/
 
 void
+window_objects_create (void)
+{
+#ifdef MEMORY_USAGE_STATS
+  OBJECT_HAS_METHOD (window, memory_usage);
+#endif
+}
+
+void
 syms_of_window (void)
 {
   INIT_LISP_OBJECT (window);
@@ -5453,7 +5423,6 @@
   DEFSYMBOL (Qscrollbar_instances);
 #endif
   DEFSYMBOL (Qother_redisplay);
-  /* Qother in general.c */
 #endif
 
   DEFSYMBOL (Qtruncate_partial_width_windows);
@@ -5531,9 +5500,6 @@
   DEFSUBR (Fscroll_other_window);
   DEFSUBR (Fcenter_to_window_line);
   DEFSUBR (Fmove_to_window_line);
-#ifdef MEMORY_USAGE_STATS
-  DEFSUBR (Fwindow_memory_usage);
-#endif
   DEFSUBR (Fcurrent_pixel_column);
   DEFSUBR (Fcurrent_pixel_row);
 }
@@ -5549,6 +5515,17 @@
 void
 vars_of_window (void)
 {
+#ifdef MEMORY_USAGE_STATS
+  OBJECT_HAS_PROPERTY
+    (window, memusage_stats_list,
+     listu (Qface_cache, Qglyph_cache,
+	    Qline_start_cache, Qother_redisplay,
+#ifdef HAVE_SCROLLBARS
+	    Qscrollbar_instances,
+#endif
+	    Qunbound));
+#endif /* MEMORY_USAGE_STATS */
+
   DEFVAR_BOOL ("scroll-on-clipped-lines", &scroll_on_clipped_lines /*
 *Non-nil means to scroll if point lands on a line which is clipped.
 */ );
--- a/src/window.h	Thu Mar 18 23:12:41 2010 -0500
+++ b/src/window.h	Fri Mar 19 17:02:11 2010 -0500
@@ -88,8 +88,6 @@
 #define CHECK_WINDOW_MIRROR(x) CHECK_RECORD (x, window_mirror)
 #define CONCHECK_WINDOW_MIRROR(x) CONCHECK_RECORD (x, window_mirror)
 
-DECLARE_LISP_OBJECT (window_configuration, struct window_config);
-
 EXFUN (Fget_buffer_window, 3);
 EXFUN (Fmove_to_window_line, 2);
 EXFUN (Frecenter, 2);
--- a/tests/ChangeLog	Thu Mar 18 23:12:41 2010 -0500
+++ b/tests/ChangeLog	Fri Mar 19 17:02:11 2010 -0500
@@ -1,3 +1,10 @@
+2010-03-18  Ben Wing  <ben@xemacs.org>
+
+	* automated/c-tests.el:
+	* automated/c-tests.el (when):
+	Use `with-temp-buffer' so results don't get written into source
+	file.
+
 2010-03-12  Ben Wing  <ben@xemacs.org>
 
 	* automated/base64-tests.el (bt-base64-encode-string):
--- a/tests/automated/c-tests.el	Thu Mar 18 23:12:41 2010 -0500
+++ b/tests/automated/c-tests.el	Fri Mar 19 17:02:11 2010 -0500
@@ -1,4 +1,5 @@
 ;; Copyright (C) 2000 Martin Buchholz
+;; Copyright (C) 2010 Ben Wing.
 
 ;; Author: Martin Buchholz <martin@xemacs.org>
 ;; Maintainer: Martin Buchholz <martin@xemacs.org>
@@ -38,8 +39,9 @@
        (push (file-name-directory load-file-name) load-path))
      (require 'test-harness))))
 
-(when (boundp 'test-function-list)	; Only if configure --debug
-  (loop for fun in test-function-list do
-    ;; #### I hope there's no way we can signal ...
-    (loop for result in (funcall fun) do
-      (Assert (nth 1 result) (nth 2 result) (nth 0 result)))))
+(with-temp-buffer
+    (when (boundp 'test-function-list)	; Only if configure --debug
+      (loop for fun in test-function-list do
+	;; #### I hope there's no way we can signal ...
+	(loop for result in (funcall fun) do
+	  (Assert (nth 1 result) (nth 2 result) (nth 0 result))))))