diff src/lrecord.h @ 5178:97eb4942aec8

merge
author Ben Wing <ben@xemacs.org>
date Mon, 29 Mar 2010 21:28:13 -0500
parents b785049378e3 5ddbab03b0e6
children 4cd28c29a7a1
line wrap: on
line diff
--- a/src/lrecord.h	Tue Feb 23 07:28:35 2010 -0600
+++ b/src/lrecord.h	Mon Mar 29 21:28:13 2010 -0500
@@ -1,6 +1,6 @@
 /* The "lrecord" structure (header of a compound lisp object).
    Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc.
-   Copyright (C) 1996, 2001, 2002, 2004, 2005, 2010 Ben Wing.
+   Copyright (C) 1996, 2001, 2002, 2004, 2005, 2009, 2010 Ben Wing.
 
 This file is part of XEmacs.
 
@@ -26,40 +26,132 @@
 #ifndef INCLUDED_lrecord_h_
 #define INCLUDED_lrecord_h_
 
-/* The "lrecord" type of Lisp object is used for all object types other
-   than a few simple ones (like char and int). This allows many types to be
-   implemented but only a few bits required in a Lisp object for type
-   information. (The tradeoff is that each object has its type marked in
-   it, thereby increasing its size.) All lrecords begin with a `struct
-   lrecord_header', which identifies the lisp object type, by providing an
-   index into a table of `struct lrecord_implementation', which describes
-   the behavior of the lisp object.  It also contains some other data bits.
+/* All objects other than char and int are implemented as structures and
+   passed by reference.  Such objects are called "record objects" ("record"
+   is another term for "structure").  The "wrapped" value of such an object
+   (i.e. when stored in a variable of type Lisp_Object) is simply the raw
+   pointer coerced to an integral type the same size as the pointer
+   (usually `long').
+   
+   Under old-GC (i.e. when NEW_GC is not defined), there are two kinds of
+   record objects: normal objects (those allocated on their own with
+   xmalloc()) and frob-block objects (those allocated as pieces of large,
+   usually 2K, chunks of memory known as "frob blocks").  Under NEW_GC,
+   there is only one type of record object.  Stuff below that applies to
+   frob-block objects is assumed to apply to the same type of object as
+   normal objects under NEW_GC.
+
+   Record objects have a header at the beginning of their structure, which
+   is used internally to identify the type of the object (so that an
+   object's type can be recovered from its pointer); in addition, it holds
+   a few flags and a "UID", which for most objects is shown when it is
+   printed, and is primarily useful for debugging purposes.  The header of
+   a normal object is declared as NORMAL_LISP_OBJECT_HEADER and that of a
+   frob-block object FROB_BLOCK_LISP_OBJECT_HEADER.
+
+   FROB_BLOCK_LISP_OBJECT_HEADER boils down to a `struct lrecord_header'.
+   This is a 32-bit value made up of bit fields, where 8 bits are used to
+   hold the type, 2 or 3 bits are used for flags associated with the
+   garbage collector, and the remaining 21 or 22 bits hold the UID.
+
+   Under NEW_GC, NORMAL_LISP_OBJECT_HEADER also resolves to `struct
+   lrecord_header'.  Under old-GC, however, NORMAL_LISP_OBJECT_HEADER
+   resolves to a `struct old_lcrecord_header' (note the `c'), which is a
+   larger structure -- on 32-bit machines it occupies 2 machine words
+   instead of 1.  Such an object is known internally as an "lcrecord".  The
+   first word of `struct old_lcrecord_header' is an embedded `struct
+   lrecord_header' with the same information as for frob-block objects;
+   that way, all objects can be cast to a `struct lrecord_header' to
+   determine their type or other info.  The other word is a pointer, used
+   to thread all lcrecords together in one big linked list.
+
+   Under old-GC, normal objects (i.e. lcrecords) are allocated in
+   individual chunks using the underlying allocator (i.e. xmalloc(), which
+   is a thin wrapper around malloc()).  Frob-block objects are more
+   efficient than normal objects, as they have a smaller header and don't
+   have the additional memory overhead associated with malloc() -- instead,
+   as mentioned above, they are carved out of 2K chunks of memory called
+   "frob blocks").  However, it is slightly more tricky to create such
+   objects, as they require special routines in alloc.c to create an object
+   of each such type and to sweep them during garbage collection.  In
+   addition, there is currently no mechanism for handling variable-sized
+   frob-block objects (e.g. vectors), whereas variable-sized normal objects
+   are not a problem.  Frob-block objects are typically used for basic
+   objects that exist in large numbers, such as `cons' or `string'.
 
-#ifndef NEW_GC
-   Lrecords are of two types: straight lrecords, and lcrecords.
-   Straight lrecords are used for those types of objects that have
-   their own allocation routines (typically allocated out of 2K chunks
-   of memory called `frob blocks').  These objects have a `struct
-   lrecord_header' at the top, containing only the bits needed to find
-   the lrecord_implementation for the object.  There are special
-   routines in alloc.c to create an object of each such type.
+   Note that strings are an apparent exception to the statement above that
+   variable-sized objects can't be handled.  Under old-GC strings work as
+   follows.  A string consists of two parts -- a fixed-size "string header"
+   that is allocated as a standard frob-block object, and a "string-chars"
+   structure that is allocated out of special 8K-sized frob blocks that
+   have a dedicated garbage-collection handler that compacts the blocks
+   during the sweep stage, relocating the string-chars data (but not the
+   string headers) to eliminate gaps.  Strings larger than 8K are not
+   placed in frob blocks, but instead are stored as individually malloc()ed
+   blocks of memory.  Strings larger than 8K are called "big strings" and
+   those smaller than 8K are called "small strings".
+
+   Under new-GC, there is no difference between big and small strings,
+   just as there is no difference between normal and frob-block objects.
+   There is only one allocation method, which is capable of handling
+   variable-sized objects.  This apparently allocates all objects in
+   frob blocks according to the size of the object.
+
+   To create a new normal Lisp object, see the toolbar-button example
+   below.  To create a new frob-block Lisp object, follow the lead of
+   one of the existing frob-block objects, such as extents or events.
+   Note that you do not need to supply all the methods (see below);
+   reasonable defaults are provided for many of them.  Alternatively, if
+   you're just looking for a way of encapsulating data (which possibly
+   could contain Lisp_Objects in it), you may well be able to use the
+   opaque type.
+*/
+
+/*
+  How to declare a Lisp object:
+
+   NORMAL_LISP_OBJECT_HEADER:
+      Header for normal objects
+
+   FROB_BLOCK_LISP_OBJECT_HEADER:
+      Header for frob-block objects
 
-   Lcrecords are used for less common sorts of objects that don't do
-   their own allocation.  Each such object is malloc()ed individually,
-   and the objects are chained together through a `next' pointer.
-   Lcrecords have a `struct old_lcrecord_header' at the top, which
-   contains a `struct lrecord_header' and a `next' pointer, and are
-   allocated using old_alloc_lcrecord_type() or its variants.
-#endif
+  How to allocate a Lisp object:
+
+   - For normal objects of a fixed size, simply call
+     ALLOC_NORMAL_LISP_OBJECT (type), where TYPE is the name of the type
+     (e.g. toolbar_button).  Such objects can be freed manually using
+     free_normal_lisp_object.
+
+   - For normal objects whose size can vary (and hence which have a
+     size_in_bytes_method rather than a static_size), call
+     ALLOC_SIZED_LISP_OBJECT (size, type), where TYPE is the
+     name of the type. NOTE: You cannot call free_normal_lisp_object() on such
+     on object! (At least when not NEW_GC)
+
+   - For frob-block objects, use
+     ALLOC_FROB_BLOCK_LISP_OBJECT (type, lisp_type, var, lrec_ptr).
+     But these objects need special handling; if you don't understand this,
+     just ignore it.
 
-   Creating a new Lisp object type is fairly easy; just follow the
-   lead of some existing type (e.g. hash tables).  Note that you
-   do not need to supply all the methods (see below); reasonable
-   defaults are provided for many of them.  Alternatively, if you're
-   just looking for a way of encapsulating data (which possibly
-   could contain Lisp_Objects in it), you may well be able to use
-   the opaque type.
-*/
+   - Some lrecords, which are used totally internally, use the
+     noseeum-* functions for debugging reasons.
+
+  Other operations:
+
+   - copy_lisp_object (dst, src)
+
+   - zero_nonsized_lisp_object (obj), zero_sized_lisp_object (obj, size):
+     BUT NOTE, it is not necessary to zero out newly allocated Lisp objects.
+     This happens automatically.
+
+   - lisp_object_size (obj): Return the size of a Lisp object. NOTE: This
+     requires that the object is properly initialized.
+
+   - lisp_object_storage_size (obj, stats): Return the storage size of a
+     Lisp objcet, including malloc or frob-block overhead; also, if STATS
+     is non-NULL, accumulate info about the size and overhead into STATS.
+ */
 
 #ifdef NEW_GC
 /*
@@ -74,44 +166,42 @@
   object descriptions exist to indicate the size of these structures and
   the Lisp object pointers within them.
 
- At least one definite issue is that under New-GC dumpable objects cannot
- contain any finalizers (see pdump_register_object()).  This means that any
- substructures in dumpable objects that are allocated separately and
- normally freed in a finalizer need instead to be made into actual Lisp
- objects.  If those structures are Dynarrs, they need to be made into
- Dynarr Lisp objects (e.g. face-cachel-dynarr or glyph-cachel-dynarr),
- which are created using Dynarr_lisp_new() or Dynarr_new_new2().
- Furthermore, the objects contained in the Dynarr also need to be Lisp
- objects (e.g. face-cachel or glyph-cachel).
+  At least one definite issue is that under New-GC dumpable objects cannot
+  contain any finalizers (see pdump_register_object()).  This means that
+  any substructures in dumpable objects that are allocated separately and
+  normally freed in a finalizer need instead to be made into actual Lisp
+  objects.  If those structures are Dynarrs, they need to be made into
+  Dynarr Lisp objects (e.g. face-cachel-dynarr or glyph-cachel-dynarr),
+  which are created using Dynarr_lisp_new() or Dynarr_new_new2().
+  Furthermore, the objects contained in the Dynarr also need to be Lisp
+  objects (e.g. face-cachel or glyph-cachel).
 
  --ben
  */
-
 #endif
 
-
-
 #ifdef NEW_GC
-#define ALLOC_LCRECORD_TYPE alloc_lrecord_type
-#define COPY_SIZED_LCRECORD copy_sized_lrecord
-#define COPY_LCRECORD copy_lrecord
-#define LISPOBJ_STORAGE_SIZE(ptr, size, stats) \
-  mc_alloced_storage_size (size, stats)
-#define ZERO_LCRECORD zero_lrecord
-#define LCRECORD_HEADER lrecord_header
-#define BASIC_ALLOC_LCRECORD alloc_lrecord
-#define FREE_LCRECORD free_lrecord
+#define ALLOC_NORMAL_LISP_OBJECT(type) alloc_lrecord (&lrecord_##type)
+#define ALLOC_SIZED_LISP_OBJECT(size, type) \
+  alloc_sized_lrecord (size, &lrecord_##type)
+#define NORMAL_LISP_OBJECT_HEADER struct lrecord_header
+#define FROB_BLOCK_LISP_OBJECT_HEADER struct lrecord_header
+#define LISP_OBJECT_FROB_BLOCK_P(obj) 0
+#define IF_NEW_GC(x) x
+#define IF_OLD_GC(x) 0
 #else /* not NEW_GC */
-#define ALLOC_LCRECORD_TYPE old_alloc_lcrecord_type
-#define COPY_SIZED_LCRECORD old_copy_sized_lcrecord
-#define COPY_LCRECORD old_copy_lcrecord
-#define LISPOBJ_STORAGE_SIZE malloced_storage_size
-#define ZERO_LCRECORD old_zero_lcrecord
-#define LCRECORD_HEADER old_lcrecord_header
-#define BASIC_ALLOC_LCRECORD old_basic_alloc_lcrecord
-#define FREE_LCRECORD old_free_lcrecord
+#define ALLOC_NORMAL_LISP_OBJECT(type) alloc_automanaged_lcrecord (&lrecord_##type)
+#define ALLOC_SIZED_LISP_OBJECT(size, type) \
+  old_alloc_sized_lcrecord (size, &lrecord_##type)
+#define NORMAL_LISP_OBJECT_HEADER struct old_lcrecord_header
+#define FROB_BLOCK_LISP_OBJECT_HEADER struct lrecord_header
+#define LISP_OBJECT_FROB_BLOCK_P(obj) (XRECORD_LHEADER_IMPLEMENTATION(obj)->frob_block_p)
+#define IF_NEW_GC(x) 0
+#define IF_OLD_GC(x) x
 #endif /* not NEW_GC */
 
+#define LISP_OBJECT_UID(obj) (XRECORD_LHEADER (obj)->uid)
+
 BEGIN_C_DECLS
 
 struct lrecord_header
@@ -150,34 +240,45 @@
   /* 1 if the object is readonly from lisp */
   unsigned int lisp_readonly :1;
 
+  /* The `free' field is currently used only for lcrecords under old-GC.
+     It is a flag that indicates whether this lcrecord is on a "free list".
+     Free lists are used to minimize the number of calls to malloc() when
+     we're repeatedly allocating and freeing a number of the same sort of
+     lcrecord.  Lcrecords on a free list always get marked in a different
+     fashion, so we can use this flag as a sanity check to make sure that
+     free lists only have freed lcrecords and there are no freed lcrecords
+     elsewhere. */
+  unsigned int free :1;
+
   /* The `uid' field is just for debugging/printing convenience.  Having
      this slot doesn't hurt us spacewise, since the bits are unused
      anyway. (The bits are used for strings, though.) */
-  unsigned int uid :21;
+  unsigned int uid :20;
 
 #endif /* not NEW_GC */
 };
 
 struct lrecord_implementation;
 int lrecord_type_index (const struct lrecord_implementation *implementation);
-extern int lrecord_uid_counter;
+extern int lrecord_uid_counter[];
 
 #ifdef NEW_GC
-#define set_lheader_implementation(header,imp) do {	\
-  struct lrecord_header* SLI_header = (header);		\
-  SLI_header->type = (imp)->lrecord_type_index;		\
-  SLI_header->lisp_readonly = 0;			\
-  SLI_header->free = 0;					\
-  SLI_header->uid = lrecord_uid_counter++;		\
+#define set_lheader_implementation(header,imp) do {			\
+  struct lrecord_header* SLI_header = (header);				\
+  SLI_header->type = (imp)->lrecord_type_index;				\
+  SLI_header->lisp_readonly = 0;					\
+  SLI_header->free = 0;							\
+  SLI_header->uid = lrecord_uid_counter[(imp)->lrecord_type_index]++;   \
 } while (0)
 #else /* not NEW_GC */
-#define set_lheader_implementation(header,imp) do {	\
-  struct lrecord_header* SLI_header = (header);		\
-  SLI_header->type = (imp)->lrecord_type_index;		\
-  SLI_header->mark = 0;					\
-  SLI_header->c_readonly = 0;				\
-  SLI_header->lisp_readonly = 0;			\
-  SLI_header->uid = lrecord_uid_counter++;		\
+#define set_lheader_implementation(header,imp) do {			\
+  struct lrecord_header* SLI_header = (header);				\
+  SLI_header->type = (imp)->lrecord_type_index;				\
+  SLI_header->mark = 0;							\
+  SLI_header->c_readonly = 0;						\
+  SLI_header->lisp_readonly = 0;					\
+  SLI_header->free = 0;							\
+  SLI_header->uid = lrecord_uid_counter[(imp)->lrecord_type_index]++;   \
 } while (0)
 #endif /* not NEW_GC */
 
@@ -188,7 +289,7 @@
 
   /* The `next' field is normally used to chain all lcrecords together
      so that the GC can find (and free) all of them.
-     `old_basic_alloc_lcrecord' threads lcrecords together.
+     `old_alloc_sized_lcrecord' threads lcrecords together.
 
      The `next' field may be used for other purposes as long as some
      other mechanism is provided for letting the GC do its work.
@@ -197,20 +298,6 @@
      out of memory chunks, and are able to find all unmarked members
      by sweeping through the elements of the list of chunks.  */
   struct old_lcrecord_header *next;
-
-  /* The `uid' field is just for debugging/printing convenience.
-     Having this slot doesn't hurt us much spacewise, since an
-     lcrecord already has the above slots plus malloc overhead. */
-  unsigned int uid :31;
-
-  /* The `free' field is a flag that indicates whether this lcrecord
-     is on a "free list".  Free lists are used to minimize the number
-     of calls to malloc() when we're repeatedly allocating and freeing
-     a number of the same sort of lcrecord.  Lcrecords on a free list
-     always get marked in a different fashion, so we can use this flag
-     as a sanity check to make sure that free lists only have freed
-     lcrecords and there are no freed lcrecords elsewhere. */
-  unsigned int free :1;
 };
 
 /* Used for lcrecords in an lcrecord-list. */
@@ -227,7 +314,9 @@
   /* Symbol value magic types come first to make SYMBOL_VALUE_MAGIC_P fast.
      #### This should be replaced by a symbol_value_magic_p flag
      in the Lisp_Symbol lrecord_header. */
-  lrecord_type_symbol_value_forward,      /*  0 */
+  /* Don't assign any type to 0, so in case we come across zeroed memory
+     it will be more obvious when printed */
+  lrecord_type_symbol_value_forward = 1,
   lrecord_type_symbol_value_varalias,
   lrecord_type_symbol_value_lisp_magic,
   lrecord_type_symbol_value_buffer_local,
@@ -281,9 +370,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,
@@ -376,21 +463,20 @@
      mark methods will be removed. */
   Lisp_Object (*marker) (Lisp_Object);
 
-  /* `printer' converts the object to a printed representation.
-     This can be NULL; in this case default_object_printer() will be
-     used instead. */
+  /* `printer' converts the object to a printed representation.  `printer'
+     should never be NULL (if so, you will get an assertion failure when
+     trying to print such an object).  Either supply a specific printing
+     method, or use the default methods internal_object_printer() (for
+     internal objects that should not be visible at Lisp level) or
+     external_object_printer() (for objects visible at Lisp level). */
   void (*printer) (Lisp_Object, Lisp_Object printcharfun, int escapeflag);
 
-  /* `finalizer' is called at GC time when the object is about to be freed,
-     and at dump time (FOR_DISKSAVE will be non-zero in this case).  It
-     should perform any necessary cleanup (e.g. freeing malloc()ed memory
-     or releasing objects created in external libraries, such as
-     window-system windows or file handles).  This can be NULL, meaning no
-     special finalization is necessary.
-
-     WARNING: remember that `finalizer' is called at dump time even though
-     the object is not being freed -- check the FOR_DISKSAVE argument.   */
-  void (*finalizer) (void *header, int for_disksave);
+  /* `finalizer' is called at GC time when the object is about to be freed.
+     It should perform any necessary cleanup, such as freeing malloc()ed
+     memory or releasing pointers or handles to objects created in external
+     libraries, such as window-system windows or file handles.  This can be
+     NULL, meaning no special finalization is necessary. */
+  void (*finalizer) (Lisp_Object obj);
 
   /* This can be NULL, meaning compare objects with EQ(). */
   int (*equal) (Lisp_Object obj1, Lisp_Object obj2, int depth,
@@ -408,6 +494,29 @@
   /* Data layout description for your object.  See long comment below. */
   const struct memory_description *description;
 
+  /* 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),
+     this object cannot be instantiated; you will get an abort() if you
+     try.*/
+  Bytecount static_size;
+  Bytecount (*size_in_bytes_method) (Lisp_Object);
+
+  /* The (constant) index into lrecord_implementations_table */
+  enum lrecord_type lrecord_type_index;
+
+#ifndef NEW_GC
+  /* A "frob-block" lrecord is any lrecord that's not an lcrecord, i.e.
+     one that does not have an old_lcrecord_header at the front and which
+     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,
+     OBJECT_HAS_PROPERTY or the like. */
+
   /* These functions allow any object type to have builtin property
      lists that can be manipulated from the lisp level with
      `get', `put', `remprop', and `object-plist'. */
@@ -416,25 +525,91 @@
   int (*remprop) (Lisp_Object obj, Lisp_Object prop);
   Lisp_Object (*plist) (Lisp_Object obj);
 
-#ifdef NEW_GC
-  /* Only one of `static_size' and `size_in_bytes_method' is non-0. */
-#else /* not NEW_GC */
-  /* Only one of `static_size' and `size_in_bytes_method' is non-0.
-     If both are 0, this type is not instantiable by
-     old_basic_alloc_lcrecord(). */
-#endif /* not NEW_GC */
-  Bytecount static_size;
-  Bytecount (*size_in_bytes_method) (const void *header);
+  /* `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.
+
+     Two types of information are stored: storage (including overhead) for
+     ancillary non-Lisp structures attached to the object, and storage
+     (including overhead) for ancillary Lisp objects attached to the
+     object.  The third type of memory-usage information (storage for the
+     object itself) is not noted here, because it's computed automatically
+     by the calling function.  Also, the computed storage for ancillary
+     Lisp objects is the sum of all three source of memory associated with
+     the Lisp object: the object itself, ancillary non-Lisp structures and
+     ancillary Lisp objects.  Note also that the `struct usage_stats u' at
+     the beginning of the STATS structure is for ancillary non-Lisp usage
+     *ONLY*; do not store any memory into it related to ancillary Lisp
+     objects.
+
+     Note that it may be subjective which Lisp objects are considered
+     "attached" to the object.  Some guidelines:
+
+     -- Lisp objects which are "internal" to the main object and not
+        accessible except through the main object should be included
+     -- Objects linked by a weak reference should *NOT* be included
+  */
+  void (*memory_usage) (Lisp_Object obj, struct generic_usage_stats *stats);
 
-  /* The (constant) index into lrecord_implementations_table */
-  enum lrecord_type lrecord_type_index;
+  /* 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 group of statistics.
+     These represent different ways of partitioning the same memory space.
+     Qt separates different groups; these represent different spaces of
+     memory.
+
+     If Qt is not present, all slices describe extra non-Lisp-Object memory
+     associated with a Lisp object.  If Qt is present, slices before Qt
+     describe non-Lisp-Object memory, as before, and slices after Qt
+     describe ancillary Lisp-Object memory logically associated with the
+     object.  For example, if the object is a table, then ancillary
+     Lisp-Object memory might be the entries in the table.  This info is
+     only advisory since it will duplicate memory described elsewhere and
+     since it may not be possible to be completely accurate, e.g. it may
+     not be clear what to count in "ancillary objects", and the value may
+     be too high if the same object occurs multiple times in the table. */
+  Lisp_Object memusage_stats_list;
+
+  /* --------------------------------------------------------------------- */
 
-#ifndef NEW_GC
-  /* A "basic" lrecord is any lrecord that's not an lcrecord, i.e.
-     one that does not have an old_lcrecord_header at the front and which
-     is (usually) allocated in frob blocks. */
-  unsigned int basic_p :1;
-#endif /* not NEW_GC */
+  /* The following are automatically computed based on the value in
+     `memusage_stats_list' (see compute_memusage_stats_length()). */
+
+  /* Total number of additional type-specific statistics related to memory
+     usage. */
+  Elemcount num_extra_memusage_stats;
+
+  /* Number of additional type-specific statistics belonging to the first
+     slice of the group describing non-Lisp-Object memory usage for this
+     object.  These stats occur starting at offset 0. */
+  Elemcount num_extra_nonlisp_memusage_stats;
+
+  /* The offset into the extra statistics at which the Lisp-Object
+     memory-usage statistics begin. */
+  Elemcount offset_lisp_ancillary_memusage_stats;
+
+  /* Number of additional type-specific statistics belonging to the first
+     slice of the group describing Lisp-Object memory usage for this
+     object.  These stats occur starting at offset
+     `offset_lisp_ancillary_memusage_stats'. */
+  Elemcount num_extra_lisp_ancillary_memusage_stats;
+
+#endif /* MEMORY_USAGE_STATS */
 };
 
 /* All the built-in lisp object types are enumerated in `enum lrecord_type'.
@@ -442,9 +617,11 @@
    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
+   (struct lrecord_implementation) */
 #define XRECORD_LHEADER_IMPLEMENTATION(obj) \
    LHEADER_IMPLEMENTATION (XRECORD_LHEADER (obj))
 #define LHEADER_IMPLEMENTATION(lh) lrecord_implementations_table[(lh)->type]
@@ -481,7 +658,7 @@
       if (MCACF_implementation && MCACF_implementation->finalizer)	\
         {								\
 	  GC_STAT_FINALIZED;						\
-          MCACF_implementation->finalizer (ptr, 0);			\
+          MCACF_implementation->finalizer (MCACF_obj);			\
         }								\
     }									\
 } while (0)
@@ -496,8 +673,8 @@
     {									\
       const struct lrecord_implementation *MCACF_implementation		\
 	= LHEADER_IMPLEMENTATION (MCACF_lheader);			\
-      if (MCACF_implementation && MCACF_implementation->finalizer)	\
-	MCACF_implementation->finalizer (ptr, 1);			\
+      if (MCACF_implementation && MCACF_implementation->disksave)	\
+	MCACF_implementation->disksave (MCACF_obj);			\
     }									\
 } while (0)
 
@@ -645,12 +822,10 @@
    doesn't care about the dumper flag and makes use of some of the stuff
    normally omitted from the "abbreviated" description -- see above.
 
-   A memory_description is an array of values. (This is actually
-   misnamed, in that it does not just describe lrecords, but any
-   blocks of memory.) The first value of each line is a type, the
-   second the offset in the lrecord structure.  The third and
-   following elements are parameters; their presence, type and number
-   is type-dependent.
+   A memory_description is an array of values.  The first value of each
+   line is a type, the second the offset in the lrecord structure.  The
+   third and following elements are parameters; their presence, type and
+   number is type-dependent.
 
    The description ends with an "XD_END" record.
 
@@ -754,7 +929,7 @@
    
    struct Lisp_Hash_Table
    {
-     struct LCRECORD_HEADER header;
+     NORMAL_LISP_OBJECT_HEADER header;
      Elemcount size;
      Elemcount count;
      Elemcount rehash_count;
@@ -819,7 +994,7 @@
 
    struct Lisp_Specifier
    {
-     struct LCRECORD_HEADER header;
+     NORMAL_LISP_OBJECT_HEADER header;
      struct specifier_methods *methods;
    
      ...
@@ -844,17 +1019,28 @@
 
     XD_LISP_OBJECT
 
-  A Lisp object.  This is also the type to use for pointers to other lrecords
+  A Lisp_Object.  This is also the type to use for pointers to other lrecords
   (e.g. struct frame *).
 
     XD_LISP_OBJECT_ARRAY
 
-  An array of Lisp objects or (equivalently) pointers to lrecords.
+  An array of Lisp_Objects or (equivalently) pointers to lrecords.
   The parameter (i.e. third element) is the count.  This would be declared
   as Lisp_Object foo[666].  For something declared as Lisp_Object *foo,
   use XD_BLOCK_PTR, whose description parameter is a sized_memory_description
   consisting of only XD_LISP_OBJECT and XD_END.
 
+    XD_INLINE_LISP_OBJECT_BLOCK_PTR
+
+  An pointer to a contiguous block of inline Lisp objects -- i.e., the Lisp
+  object itself rather than a Lisp_Object pointer is stored in the block.
+  This is used only under NEW_GC and is useful for increased efficiency when
+  an array of the same kind of object is needed.  Examples of the use of this
+  type are Lisp dynarrs, where the array elements are inline Lisp objects
+  rather than non-Lisp structures, as is normally the case; and hash tables,
+  where the key/value pairs are encapsulated as hash-table-entry objects and
+  an array of inline hash-table-entry objects is stored.
+
     XD_LO_LINK
 
   Weak link in a linked list of objects of the same type.  This is a
@@ -1020,7 +1206,7 @@
   XD_LISP_OBJECT_ARRAY,
   XD_LISP_OBJECT,
 #ifdef NEW_GC
-  XD_LISP_OBJECT_BLOCK_PTR,
+  XD_INLINE_LISP_OBJECT_BLOCK_PTR,
 #endif /* NEW_GC */
   XD_LO_LINK,
   XD_OPAQUE_PTR,
@@ -1070,10 +1256,9 @@
      lcrecord-lists, where the objects have had their type changed to
      lrecord_type_free and also have had their free bit set, but we mark
      them as normal. */
-  XD_FLAG_FREE_LISP_OBJECT = 8
+  XD_FLAG_FREE_LISP_OBJECT = 8,
 #endif /* not NEW_GC */
 #if 0
-  ,
   /* Suggestions for other possible flags: */
 
   /* Eliminate XD_UNION_DYNAMIC_SIZE and replace it with a flag, like this. */
@@ -1085,7 +1270,7 @@
      expanded and we need to stick a pointer in the second slot (although
      we could still ensure that the second slot in the first entry was NULL
      or <0). */
-  XD_FLAG_DESCRIPTION_MAP = 32
+  XD_FLAG_DESCRIPTION_MAP = 32,
 #endif
 };
 
@@ -1128,20 +1313,20 @@
 
      This function must put a pointer to the opaque result in *data
      and its size in *size. */
-  void (*convert)(const void *object, void **data, Bytecount *size);
+  void (*convert) (const void *object, void **data, Bytecount *size);
 
   /* Post-conversion cleanup.  Optional (null if not provided).
 
      When provided it will be called post-dumping to free any storage
      allocated for the conversion results. */
-  void (*convert_free)(const void *object, void *data, Bytecount size);
+  void (*convert_free) (const void *object, void *data, Bytecount size);
 
   /* De-conversion.
 
      At reload time, rebuilds the object from the converted form.
      "object" is 0 for the PTR case, return is ignored in the DATA
      case. */
-  void *(*deconvert)(void *object, void *data, Bytecount size);
+  void *(*deconvert) (void *object, void *data, Bytecount size);
 
 };
 
@@ -1153,133 +1338,257 @@
 #define XD_INDIRECT_VAL(code) ((-1 - (code)) & 255)
 #define XD_INDIRECT_DELTA(code) ((-1 - (code)) >> 8)
 
-/* DEFINE_LRECORD_IMPLEMENTATION is for objects with constant size.
-   DEFINE_LRECORD_SEQUENCE_IMPLEMENTATION is for objects whose size varies.
+/* DEFINE_*_LISP_OBJECT is for objects with constant size. (Either
+   DEFINE_DUMPABLE_LISP_OBJECT for objects that can be saved in a dumped
+   executable, or DEFINE_NODUMP_LISP_OBJECT for objects that cannot be
+   saved -- e.g. that contain pointers to non-persistent external objects
+   such as window-system windows.)
+
+   DEFINE_*_SIZABLE_LISP_OBJECT is for objects whose size varies.
+
+   DEFINE_*_FROB_BLOCK_LISP_OBJECT is for objects that are allocated in
+   large blocks ("frob blocks"), which are parceled up individually.  Such
+   objects need special handling in alloc.c.  This does not apply to
+   NEW_GC, because it does this automatically.
+
+   DEFINE_*_INTERNAL_LISP_OBJECT is for "internal" objects that should
+   never be visible on the Lisp level.  This is a shorthand for the most
+   common type of internal objects, which have no equal or hash method
+   (since they generally won't appear in hash tables), no finalizer and
+   internal_object_printer() as their print method (which prints that the
+   object is internal and shouldn't be visible externally).  For internal
+   objects needing a finalizer, equal or hash method, or wanting to
+   customize the print method, use the normal DEFINE_*_LISP_OBJECT
+   mechanism for defining these objects.
+
+   DEFINE_MODULE_* is for objects defined in an external module.
+
+   MAKE_LISP_OBJECT and MAKE_MODULE_LISP_OBJECT are what underlies all of
+   these; they define a structure containing pointers to object methods
+   and other info such as the size of the structure containing the object.
  */
 
+/* #### FIXME What's going on here? */
 #if defined (ERROR_CHECK_TYPES)
 # define DECLARE_ERROR_CHECK_TYPES(c_name, structtype)
 #else
 # define DECLARE_ERROR_CHECK_TYPES(c_name, structtype)
 #endif
 
+/********* The dumpable versions *********** */
 
-#define DEFINE_BASIC_LRECORD_IMPLEMENTATION(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,structtype) \
-DEFINE_BASIC_LRECORD_IMPLEMENTATION_WITH_PROPS(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,0,0,0,0,structtype)
+#define DEFINE_DUMPABLE_LISP_OBJECT(name,c_name,marker,printer,nuker,equal,hash,desc,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) \
+MAKE_LISP_OBJECT(name,c_name,1 /*dumpable*/,marker,printer,nuker,equal,hash,desc,0,sizer,0,structtype)
 
-#define DEFINE_BASIC_LRECORD_IMPLEMENTATION_WITH_PROPS(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,structtype) \
-MAKE_LRECORD_IMPLEMENTATION(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,sizeof(structtype),0,1,structtype)
+#define DEFINE_DUMPABLE_FROB_BLOCK_LISP_OBJECT(name,c_name,marker,printer,nuker,equal,hash,desc,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,sizer,1,structtype)
 
-#define DEFINE_LRECORD_IMPLEMENTATION(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,structtype) \
-DEFINE_LRECORD_IMPLEMENTATION_WITH_PROPS(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,0,0,0,0,structtype)
+#define DEFINE_DUMPABLE_INTERNAL_LISP_OBJECT(name,c_name,marker,desc,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_LISP_OBJECT(name,c_name,marker,internal_object_printer,0,0,0,desc,sizer,structtype)
 
-#define DEFINE_LRECORD_IMPLEMENTATION_WITH_PROPS(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,structtype) \
-MAKE_LRECORD_IMPLEMENTATION(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,sizeof (structtype),0,0,structtype)
+/********* The non-dumpable versions *********** */
+
+#define DEFINE_NODUMP_LISP_OBJECT(name,c_name,marker,printer,nuker,equal,hash,desc,structtype) \
+MAKE_LISP_OBJECT(name,c_name,0 /*non-dumpable*/,marker,printer,nuker,equal,hash,desc,sizeof (structtype),0,0,structtype)
 
-#define DEFINE_LRECORD_SEQUENCE_IMPLEMENTATION(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,sizer,structtype) \
-DEFINE_LRECORD_SEQUENCE_IMPLEMENTATION_WITH_PROPS(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,0,0,0,0,sizer,structtype)
+#define DEFINE_NODUMP_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,sizer,0,structtype)
+
+#define DEFINE_NODUMP_FROB_BLOCK_LISP_OBJECT(name,c_name,marker,printer,nuker,equal,hash,desc,structtype) \
+MAKE_LISP_OBJECT(name,c_name,0 /*non-dumpable*/,marker,printer,nuker,equal,hash,desc,sizeof(structtype),0,1,structtype)
 
-#define DEFINE_BASIC_LRECORD_SEQUENCE_IMPLEMENTATION(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,sizer,structtype) \
-MAKE_LRECORD_IMPLEMENTATION(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,0,0,0,0,0,sizer,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,sizer,1,structtype)
 
-#define DEFINE_LRECORD_SEQUENCE_IMPLEMENTATION_WITH_PROPS(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,sizer,structtype) \
-MAKE_LRECORD_IMPLEMENTATION(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,0,sizer,0,structtype)
+#define DEFINE_NODUMP_INTERNAL_LISP_OBJECT(name,c_name,marker,desc,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_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_LRECORD_IMPLEMENTATION(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,size,sizer,basic_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, size, sizer,			\
-    lrecord_type_##c_name }
+    size, sizer, lrecord_type_##c_name }
 #else /* not NEW_GC */
-#define MAKE_LRECORD_IMPLEMENTATION(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,size,sizer,basic_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, size, sizer,			\
-    lrecord_type_##c_name, basic_p }
+    size, sizer, lrecord_type_##c_name, frob_block_p }
 #endif /* not NEW_GC */
 
-#define DEFINE_EXTERNAL_LRECORD_IMPLEMENTATION(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,structtype) \
-DEFINE_EXTERNAL_LRECORD_IMPLEMENTATION_WITH_PROPS(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,0,0,0,0,structtype)
+
+/********* The module dumpable versions *********** */
 
-#define DEFINE_EXTERNAL_LRECORD_IMPLEMENTATION_WITH_PROPS(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,structtype) \
-MAKE_EXTERNAL_LRECORD_IMPLEMENTATION(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,sizeof (structtype),0,0,structtype)
+#define DEFINE_DUMPABLE_MODULE_LISP_OBJECT(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,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) \
+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_EXTERNAL_LRECORD_SEQUENCE_IMPLEMENTATION(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,sizer,structtype) \
-DEFINE_EXTERNAL_LRECORD_SEQUENCE_IMPLEMENTATION_WITH_PROPS(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,0,0,0,0,sizer,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_EXTERNAL_LRECORD_SEQUENCE_IMPLEMENTATION_WITH_PROPS(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,sizer,structtype) \
-MAKE_EXTERNAL_LRECORD_IMPLEMENTATION(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,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_EXTERNAL_LRECORD_IMPLEMENTATION(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,size,sizer,basic_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,		\
-    getprop, putprop, remprop, plist, size, sizer,			\
-    lrecord_type_last_built_in_type }
+    size, sizer, lrecord_type_last_built_in_type }
 #else /* not NEW_GC */
-#define MAKE_EXTERNAL_LRECORD_IMPLEMENTATION(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,size,sizer,basic_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,		\
-    getprop, putprop, remprop, plist, size, sizer,			\
-    lrecord_type_last_built_in_type, basic_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_LRECORD_IMPLEMENTATION(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)
 #else /* not USE_KKCC */
 extern MODULE_API Lisp_Object (*lrecord_markers[]) (Lisp_Object);
 
-#define INIT_LRECORD_IMPLEMENTATION(type) do {				\
-  lrecord_implementations_table[lrecord_type_##type] = &lrecord_##type;	\
-  lrecord_markers[lrecord_type_##type] =				\
-    lrecord_implementations_table[lrecord_type_##type]->marker;		\
+#define INIT_LISP_OBJECT(type) do {				\
+  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_EXTERNAL_LRECORD_IMPLEMENTATION(type) do {			\
-  lrecord_type_##type = lrecord_type_count++;				\
-  lrecord_##type.lrecord_type_index = lrecord_type_##type;		\
-  INIT_LRECORD_IMPLEMENTATION(type);					\
+#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);					\
 } while (0)
 
 #ifdef HAVE_SHLIB
 /* Allow undefining types in order to support module unloading. */
 
 #ifdef USE_KKCC
-#define UNDEF_LRECORD_IMPLEMENTATION(type) do {				\
-  lrecord_implementations_table[lrecord_type_##type] = NULL;		\
-  lrecord_memory_descriptions[lrecord_type_##type] = NULL;		\
+#define UNDEF_LISP_OBJECT(type) do {				\
+  lrecord_implementations_table[lrecord_type_##type] = NULL;	\
+  lrecord_memory_descriptions[lrecord_type_##type] = NULL;	\
 } while (0)
 #else /* not USE_KKCC */
-#define UNDEF_LRECORD_IMPLEMENTATION(type) do {				\
-  lrecord_implementations_table[lrecord_type_##type] = NULL;		\
-  lrecord_markers[lrecord_type_##type] = NULL;				\
+#define UNDEF_LISP_OBJECT(type) do {				\
+  lrecord_implementations_table[lrecord_type_##type] = NULL;	\
+  lrecord_markers[lrecord_type_##type] = NULL;			\
 } while (0)
 #endif /* not USE_KKCC */
 
-#define UNDEF_EXTERNAL_LRECORD_IMPLEMENTATION(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_LRECORD_IMPLEMENTATION(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))
 
@@ -1291,9 +1600,9 @@
    1. Declare the struct for your object in a header file somewhere.
    Remember that it must begin with
 
-   struct LCRECORD_HEADER header;
+   NORMAL_LISP_OBJECT_HEADER header;
 
-   2. Put the "standard junk" (DECLARE_RECORD()/XFOO/etc.) below the
+   2. Put the "standard junk" (DECLARE_LISP_OBJECT()/XFOO/etc.) below the
       struct definition -- see below.
 
    3. Add this header file to inline.c.
@@ -1306,12 +1615,17 @@
    describing the purpose of the descriptions; and comments elsewhere in
    this file describing the exact syntax of the description structures.
 
-   6. Define your object with DEFINE_LRECORD_IMPLEMENTATION() or some
-   variant.
+   6. Define your object with DEFINE_*_LISP_OBJECT() or some
+   variant.  At the minimum, you need to decide whether your object can
+   be dumped.  Objects that are created as part of the loadup process and
+   need to be persistent across dumping should be created dumpable.
+   Nondumpable objects are generally those associated with display,
+   particularly those containing a pointer to an external library object
+   (e.g. a window-system window).
 
    7. Include the header file in the .c file where you defined the object.
 
-   8. Put a call to INIT_LRECORD_IMPLEMENTATION() for the object in the
+   8. Put a call to INIT_LISP_OBJECT() for the object in the
    .c file's syms_of_foo() function.
 
    9. Add a type enum for the object to enum lrecord_type, earlier in this
@@ -1319,132 +1633,165 @@
 
    --ben
 
-An example:
+  An example:
 
 ------------------------------ in toolbar.h -----------------------------
 
-struct toolbar_button
-{
-  struct LCRECORD_HEADER header;
-
-  Lisp_Object next;
-  Lisp_Object frame;
-
-  Lisp_Object up_glyph;
-  Lisp_Object down_glyph;
-  Lisp_Object disabled_glyph;
-
-  Lisp_Object cap_up_glyph;
-  Lisp_Object cap_down_glyph;
-  Lisp_Object cap_disabled_glyph;
-
-  Lisp_Object callback;
-  Lisp_Object enabled_p;
-  Lisp_Object help_string;
-
-  char enabled;
-  char down;
-  char pushright;
-  char blank;
-
-  int x, y;
-  int width, height;
-  int dirty;
-  int vertical;
-  int border_width;
-};
-
-[[ the standard junk: ]]
-
-DECLARE_LRECORD (toolbar_button, struct toolbar_button);
-#define XTOOLBAR_BUTTON(x) XRECORD (x, toolbar_button, struct toolbar_button)
-#define wrap_toolbar_button(p) wrap_record (p, toolbar_button)
-#define TOOLBAR_BUTTONP(x) RECORDP (x, toolbar_button)
-#define CHECK_TOOLBAR_BUTTON(x) CHECK_RECORD (x, toolbar_button)
-#define CONCHECK_TOOLBAR_BUTTON(x) CONCHECK_RECORD (x, toolbar_button)
-
+  struct toolbar_button
+  {
+    NORMAL_LISP_OBJECT_HEADER header;
+  
+    Lisp_Object next;
+    Lisp_Object frame;
+  
+    Lisp_Object up_glyph;
+    Lisp_Object down_glyph;
+    Lisp_Object disabled_glyph;
+  
+    Lisp_Object cap_up_glyph;
+    Lisp_Object cap_down_glyph;
+    Lisp_Object cap_disabled_glyph;
+  
+    Lisp_Object callback;
+    Lisp_Object enabled_p;
+    Lisp_Object help_string;
+  
+    char enabled;
+    char down;
+    char pushright;
+    char blank;
+  
+    int x, y;
+    int width, height;
+    int dirty;
+    int vertical;
+    int border_width;
+  };
+  
+  [[ the standard junk: ]]
+  
+  DECLARE_LISP_OBJECT (toolbar_button, struct toolbar_button);
+  #define XTOOLBAR_BUTTON(x) XRECORD (x, toolbar_button, struct toolbar_button)
+  #define wrap_toolbar_button(p) wrap_record (p, toolbar_button)
+  #define TOOLBAR_BUTTONP(x) RECORDP (x, toolbar_button)
+  #define CHECK_TOOLBAR_BUTTON(x) CHECK_RECORD (x, toolbar_button)
+  #define CONCHECK_TOOLBAR_BUTTON(x) CONCHECK_RECORD (x, toolbar_button)
+  
 ------------------------------ in toolbar.c -----------------------------
-
-#include "toolbar.h"
-
-...
+  
+  #include "toolbar.h"
+  
+  ...
+  
+  static const struct memory_description toolbar_button_description [] = {
+    { XD_LISP_OBJECT, offsetof (struct toolbar_button, next) },
+    { XD_LISP_OBJECT, offsetof (struct toolbar_button, frame) },
+    { XD_LISP_OBJECT, offsetof (struct toolbar_button, up_glyph) },
+    { XD_LISP_OBJECT, offsetof (struct toolbar_button, down_glyph) },
+    { XD_LISP_OBJECT, offsetof (struct toolbar_button, disabled_glyph) },
+    { XD_LISP_OBJECT, offsetof (struct toolbar_button, cap_up_glyph) },
+    { XD_LISP_OBJECT, offsetof (struct toolbar_button, cap_down_glyph) },
+    { XD_LISP_OBJECT, offsetof (struct toolbar_button, cap_disabled_glyph) },
+    { XD_LISP_OBJECT, offsetof (struct toolbar_button, callback) },
+    { XD_LISP_OBJECT, offsetof (struct toolbar_button, enabled_p) },
+    { XD_LISP_OBJECT, offsetof (struct toolbar_button, help_string) },
+    { XD_END }
+  };
+  
+  static Lisp_Object
+  allocate_toolbar_button (struct frame *f, int pushright)
+  {
+    struct toolbar_button *tb;
+  
+    tb = XTOOLBAR_BUTTON (ALLOC_NORMAL_LISP_OBJECT (toolbar_button));
+    tb->next = Qnil;
+    tb->frame = wrap_frame (f);
+    tb->up_glyph = Qnil;
+    tb->down_glyph = Qnil;
+    tb->disabled_glyph = Qnil;
+    tb->cap_up_glyph = Qnil;
+    tb->cap_down_glyph = Qnil;
+    tb->cap_disabled_glyph = Qnil;
+    tb->callback = Qnil;
+    tb->enabled_p = Qnil;
+    tb->help_string = Qnil;
+  
+    tb->pushright = pushright;
+    tb->x = tb->y = tb->width = tb->height = -1;
+    tb->dirty = 1;
+  
+    return wrap_toolbar_button (tb);
+  }
+   
+  static Lisp_Object
+  mark_toolbar_button (Lisp_Object obj)
+  {
+    struct toolbar_button *data = XTOOLBAR_BUTTON (obj);
+    mark_object (data->next);
+    mark_object (data->frame);
+    mark_object (data->up_glyph);
+    mark_object (data->down_glyph);
+    mark_object (data->disabled_glyph);
+    mark_object (data->cap_up_glyph);
+    mark_object (data->cap_down_glyph);
+    mark_object (data->cap_disabled_glyph);
+    mark_object (data->callback);
+    mark_object (data->enabled_p);
+    return data->help_string;
+  }
+  
+  DEFINE_NODUMP_LISP_OBJECT ("toolbar-button", toolbar_button,
+  			     mark_toolbar_button,
+  			     external_object_printer, 0, 0, 0,
+  			     toolbar_button_description,
+  			     struct toolbar_button);
+  
+  ...
+  
+  void
+  syms_of_toolbar (void)
+  {
+    INIT_LISP_OBJECT (toolbar_button);
+  
+    ...;
+  }
+  
+------------------------------ in inline.c -----------------------------
+  
+  #ifdef HAVE_TOOLBARS
+  #include "toolbar.h"
+  #endif
+  
+------------------------------ in lrecord.h -----------------------------
+  
+  enum lrecord_type
+  {
+    ...
+    lrecord_type_toolbar_button,
+    ...
+  };
 
-static const struct memory_description toolbar_button_description [] = {
-  { XD_LISP_OBJECT, offsetof (struct toolbar_button, next) },
-  { XD_LISP_OBJECT, offsetof (struct toolbar_button, frame) },
-  { XD_LISP_OBJECT, offsetof (struct toolbar_button, up_glyph) },
-  { XD_LISP_OBJECT, offsetof (struct toolbar_button, down_glyph) },
-  { XD_LISP_OBJECT, offsetof (struct toolbar_button, disabled_glyph) },
-  { XD_LISP_OBJECT, offsetof (struct toolbar_button, cap_up_glyph) },
-  { XD_LISP_OBJECT, offsetof (struct toolbar_button, cap_down_glyph) },
-  { XD_LISP_OBJECT, offsetof (struct toolbar_button, cap_disabled_glyph) },
-  { XD_LISP_OBJECT, offsetof (struct toolbar_button, callback) },
-  { XD_LISP_OBJECT, offsetof (struct toolbar_button, enabled_p) },
-  { XD_LISP_OBJECT, offsetof (struct toolbar_button, help_string) },
-  { XD_END }
-};
-
-static Lisp_Object
-mark_toolbar_button (Lisp_Object obj)
-\{
-  struct toolbar_button *data = XTOOLBAR_BUTTON (obj);
-  mark_object (data->next);
-  mark_object (data->frame);
-  mark_object (data->up_glyph);
-  mark_object (data->down_glyph);
-  mark_object (data->disabled_glyph);
-  mark_object (data->cap_up_glyph);
-  mark_object (data->cap_down_glyph);
-  mark_object (data->cap_disabled_glyph);
-  mark_object (data->callback);
-  mark_object (data->enabled_p);
-  return data->help_string;
-}
+------------------------------ in .gdbinit.in.in -----------------------------
 
-[[ If your object should never escape to Lisp, declare its print method
-   as internal_object_printer instead of 0. ]]
-
-DEFINE_LRECORD_IMPLEMENTATION ("toolbar-button", toolbar_button,
- 			       0, mark_toolbar_button, 0, 0, 0, 0,
-                               toolbar_button_description,
- 			       struct toolbar_button);
-
-...
-
-void
-syms_of_toolbar (void)
-{
-  INIT_LRECORD_IMPLEMENTATION (toolbar_button);
-
-  ...;
-}
+  ...
+  else
+  if $lrecord_type == lrecord_type_toolbar_button
+    pstructtype toolbar_button
+  ...
+  ...
+  ...
+  end
 
------------------------------- in inline.c -----------------------------
-
-#ifdef HAVE_TOOLBARS
-#include "toolbar.h"
-#endif
-
------------------------------- in lrecord.h -----------------------------
-
-enum lrecord_type
-{
-  ...
-  lrecord_type_toolbar_button,
-  ...
-};
-
-
---ben
+  --ben
 
 */
 
 /*
 
 Note: Object types defined in external dynamically-loaded modules (not
-part of the XEmacs main source code) should use DECLARE_EXTERNAL_LRECORD
-and DEFINE_EXTERNAL_LRECORD_IMPLEMENTATION rather than DECLARE_LRECORD
-and DEFINE_LRECORD_IMPLEMENTATION.  The EXTERNAL versions declare and
+part of the XEmacs main source code) should use DECLARE_*_MODULE_LISP_OBJECT
+and DEFINE_*_MODULE_LISP_OBJECT rather than DECLARE_*_LISP_OBJECT
+and DEFINE_*_LISP_OBJECT.  The MODULE versions declare and
 allocate an enumerator for the type being defined.
 
 */
@@ -1452,58 +1799,45 @@
 
 #ifdef ERROR_CHECK_TYPES
 
-# define DECLARE_LRECORD(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_LRECORD(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)	  \
-)									  \
-{									  \
-  assert_at_line (RECORD_TYPEP (obj, lrecord_type_##c_name), file, line); \
-  return (structtype *) XPNTR (obj);					  \
-}									  \
-extern MODULE_API Lisp_Object Q##c_name##p
-
-# define DECLARE_EXTERNAL_LRECORD(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);					  \
-}									  \
-extern Lisp_Object Q##c_name##p
-
-# define DECLARE_NONRECORD(c_name, type_enum, structtype)		\
+# 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 (XTYPE (obj) == type_enum, file, line);		\
+  assert_at_line (RECORD_TYPEP (obj, lrecord_type_##c_name), file, line); \
+  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)	\
+)									\
+{									\
+  assert_at_line (RECORD_TYPEP (obj, lrecord_type_##c_name), file, line); \
   return (structtype *) XPNTR (obj);					\
 }									\
 extern Lisp_Object Q##c_name##p
 
 # define XRECORD(x, c_name, structtype) \
   error_check_##c_name (x, __FILE__, __LINE__)
-# define XNONRECORD(x, c_name, type_enum, structtype) \
-  error_check_##c_name (x, __FILE__, __LINE__)
 
 DECLARE_INLINE_HEADER (
 Lisp_Object
@@ -1522,21 +1856,17 @@
 
 #else /* not ERROR_CHECK_TYPES */
 
-# define DECLARE_LRECORD(c_name, structtype)			\
+# define DECLARE_LISP_OBJECT(c_name, structtype)		\
 extern Lisp_Object Q##c_name##p;				\
-extern const struct lrecord_implementation lrecord_##c_name
-# define DECLARE_MODULE_API_LRECORD(c_name, structtype)			\
-extern MODULE_API Lisp_Object Q##c_name##p;				\
-extern MODULE_API const struct lrecord_implementation lrecord_##c_name
-# define DECLARE_EXTERNAL_LRECORD(c_name, structtype)		\
+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 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;				\
 extern struct lrecord_implementation lrecord_##c_name
-# define DECLARE_NONRECORD(c_name, type_enum, structtype)	\
-extern Lisp_Object Q##c_name##p
 # define XRECORD(x, c_name, structtype) ((structtype *) XPNTR (x))
-# define XNONRECORD(x, c_name, type_enum, structtype)		\
-  ((structtype *) XPNTR (x))
 /* wrap_pointer_1 is so named as a suggestion not to use it unless you
    know what you're doing. */
 #define wrap_record(ptr, ty) wrap_pointer_1 (ptr)
@@ -1590,13 +1920,13 @@
 
 struct lcrecord_list
 {
-  struct LCRECORD_HEADER header;
+  NORMAL_LISP_OBJECT_HEADER header;
   Lisp_Object free;
   Elemcount size;
   const struct lrecord_implementation *implementation;
 };
 
-DECLARE_LRECORD (lcrecord_list, struct lcrecord_list);
+DECLARE_LISP_OBJECT (lcrecord_list, struct lcrecord_list);
 #define XLCRECORD_LIST(x) XRECORD (x, lcrecord_list, struct lcrecord_list)
 #define wrap_lcrecord_list(p) wrap_record (p, lcrecord_list)
 #define LCRECORD_LISTP(x) RECORDP (x, lcrecord_list)
@@ -1611,13 +1941,13 @@
    lrecords.  lcrecords themselves are divided into three types: (1)
    auto-managed, (2) hand-managed, and (3) unmanaged.  "Managed" refers to
    using a special object called an lcrecord-list to keep track of freed
-   lcrecords, which can freed with FREE_LCRECORD() or the like and later be
-   recycled when a new lcrecord is required, rather than requiring new
-   malloc().  Thus, allocation of lcrecords can be very
+   lcrecords, which can freed with free_normal_lisp_object() or the like
+   and later be recycled when a new lcrecord is required, rather than
+   requiring new malloc().  Thus, allocation of lcrecords can be very
    cheap. (Technically, the lcrecord-list manager could divide up large
    chunks of memory and allocate out of that, mimicking what happens with
    lrecords.  At that point, however, we'd want to rethink the whole
-   division between lrecords and lcrecords.) 
+   division between lrecords and lcrecords.)
 
    NOTE: There is a fundamental limitation of lcrecord-lists, which is that
    they only handle blocks of a particular, fixed size.  Thus, objects that
@@ -1625,9 +1955,9 @@
    in particular dictate the various types of management:
 
    -- "Auto-managed" means that you just go ahead and allocate the lcrecord
-   whenever you want, using old_alloc_lcrecord_type(), and the appropriate
+   whenever you want, using ALLOC_NORMAL_LISP_OBJECT(), and the appropriate
    lcrecord-list manager is automatically created.  To free, you just call
-   "FREE_LCRECORD()" and the appropriate lcrecord-list manager is
+   "free_normal_lisp_object()" and the appropriate lcrecord-list manager is
    automatically located and called.  The limitation here of course is that
    all your objects are of the same size. (#### Eventually we should have a
    more sophisticated system that tracks the sizes seen and creates one
@@ -1648,7 +1978,7 @@
    to hand-manage them, or (b) the objects you create are always or almost
    always Lisp-visible, and thus there's no point in freeing them (and it
    wouldn't be safe to do so).  You just create them with
-   BASIC_ALLOC_LCRECORD(), and that's it.
+   ALLOC_SIZED_LISP_OBJECT(), and that's it.
 
    --ben
 
@@ -1661,10 +1991,10 @@
    1) Create an lcrecord-list object using make_lcrecord_list().  This is
       often done at initialization.  Remember to staticpro_nodump() this
       object!  The arguments to make_lcrecord_list() are the same as would be
-      passed to BASIC_ALLOC_LCRECORD().
+      passed to ALLOC_SIZED_LISP_OBJECT().
 
-   2) Instead of calling BASIC_ALLOC_LCRECORD(), call alloc_managed_lcrecord()
-      and pass the lcrecord-list earlier created.
+   2) Instead of calling ALLOC_SIZED_LISP_OBJECT(), call
+      alloc_managed_lcrecord() and pass the lcrecord-list earlier created.
 
    3) When done with the lcrecord, call free_managed_lcrecord().  The
       standard freeing caveats apply: ** make sure there are no pointers to
@@ -1674,7 +2004,7 @@
       lcrecord goodbye as if it were garbage-collected.  This means:
       -- the contents of the freed lcrecord are undefined, and the
          contents of something produced by alloc_managed_lcrecord()
-	 are undefined, just like for BASIC_ALLOC_LCRECORD().
+	 are undefined, just like for ALLOC_SIZED_LISP_OBJECT().
       -- the mark method for the lcrecord's type will *NEVER* be called
          on freed lcrecords.
       -- the finalize method for the lcrecord's type will be called
@@ -1682,8 +2012,9 @@
  */
 
 /* UNMANAGED MODEL: */
-void *old_basic_alloc_lcrecord (Bytecount size,
-				const struct lrecord_implementation *);
+Lisp_Object old_alloc_lcrecord (const struct lrecord_implementation *);
+Lisp_Object old_alloc_sized_lcrecord (Bytecount size,
+				      const struct lrecord_implementation *);
 
 /* HAND-MANAGED MODEL: */
 Lisp_Object make_lcrecord_list (Elemcount size,
@@ -1693,85 +2024,34 @@
 void free_managed_lcrecord (Lisp_Object lcrecord_list, Lisp_Object lcrecord);
 
 /* AUTO-MANAGED MODEL: */
-MODULE_API void *
-alloc_automanaged_lcrecord (Bytecount size,
-			    const struct lrecord_implementation *);
+MODULE_API Lisp_Object
+alloc_automanaged_sized_lcrecord (Bytecount size,
+				  const struct lrecord_implementation *imp);
+MODULE_API Lisp_Object
+alloc_automanaged_lcrecord (const struct lrecord_implementation *imp);
 
-#define old_alloc_lcrecord_type(type, lrecord_implementation) \
-  ((type *) alloc_automanaged_lcrecord (sizeof (type), lrecord_implementation))
+#define old_alloc_lcrecord_type(type, imp) \
+  ((type *) XPNTR (alloc_automanaged_lcrecord (sizeof (type), imp)))
 
 void old_free_lcrecord (Lisp_Object rec);
 
-
-/* Copy the data from one lcrecord structure into another, but don't
-   overwrite the header information. */
-
-#define old_copy_sized_lcrecord(dst, src, size)				\
-  memcpy ((Rawbyte *) (dst) + sizeof (struct old_lcrecord_header),	\
-	  (Rawbyte *) (src) + sizeof (struct old_lcrecord_header),	\
-	  (size) - sizeof (struct old_lcrecord_header))
-
-#define old_copy_lcrecord(dst, src) \
-  old_copy_sized_lcrecord (dst, src, sizeof (*(dst)))
-
-#define old_zero_sized_lcrecord(lcr, size)				\
-   memset ((Rawbyte *) (lcr) + sizeof (struct old_lcrecord_header), 0,	\
-	   (size) - sizeof (struct old_lcrecord_header))
-
-#define old_zero_lcrecord(lcr) old_zero_sized_lcrecord (lcr, sizeof (*(lcr)))
-
 #else /* NEW_GC */
 
-/* How to allocate a lrecord:
-   
-   - If the size of the lrecord is fix, say it equals its size of its
-   struct, then use alloc_lrecord_type.
-
-   - If the size varies, i.e. it is not equal to the size of its
-   struct, use alloc_lrecord and specify the amount of storage you
-   need for the object.
-
-   - Some lrecords, which are used totally internally, use the
-   noseeum-* functions for the reason of debugging. 
-
-   - To free a Lisp_Object manually, use free_lrecord. */
-
-void *alloc_lrecord (Bytecount size,
-		     const struct lrecord_implementation *);
-
-void *alloc_lrecord_array (Bytecount size, int elemcount,
-			   const struct lrecord_implementation *);
+MODULE_API Lisp_Object alloc_sized_lrecord (Bytecount size,
+					    const struct lrecord_implementation *imp);
+Lisp_Object noseeum_alloc_sized_lrecord (Bytecount size,
+					 const struct lrecord_implementation *imp);
+MODULE_API Lisp_Object alloc_lrecord (const struct lrecord_implementation *imp);
+Lisp_Object noseeum_alloc_lrecord (const struct lrecord_implementation *imp);
 
-#define alloc_lrecord_type(type, lrecord_implementation) \
-  ((type *) alloc_lrecord (sizeof (type), lrecord_implementation))
-
-void *noseeum_alloc_lrecord (Bytecount size,
-			     const struct lrecord_implementation *);
-
-#define noseeum_alloc_lrecord_type(type, lrecord_implementation) \
-  ((type *) noseeum_alloc_lrecord (sizeof (type), lrecord_implementation))
-
-void free_lrecord (Lisp_Object rec);
-
-
-/* Copy the data from one lrecord structure into another, but don't
-   overwrite the header information. */
-
-#define copy_sized_lrecord(dst, src, size)			\
-  memcpy ((char *) (dst) + sizeof (struct lrecord_header),	\
-	  (char *) (src) + sizeof (struct lrecord_header),	\
-	  (size) - sizeof (struct lrecord_header))
-
-#define copy_lrecord(dst, src) copy_sized_lrecord (dst, src, sizeof (*(dst)))
+MODULE_API Lisp_Object alloc_lrecord_array (int elemcount,
+				 const struct lrecord_implementation *imp);
+MODULE_API Lisp_Object alloc_sized_lrecord_array (Bytecount size,
+						  int elemcount,
+						  const struct lrecord_implementation *imp);
 
 #endif /* NEW_GC */
 
-#define zero_sized_lrecord(lcr, size)				\
-   memset ((char *) (lcr) + sizeof (struct lrecord_header), 0,	\
-	   (size) - sizeof (struct lrecord_header))
-
-#define zero_lrecord(lcr) zero_sized_lrecord (lcr, sizeof (*(lcr)))
-
 DECLARE_INLINE_HEADER (
 Bytecount
 detagged_lisp_object_size (const struct lrecord_header *h)
@@ -1780,7 +2060,7 @@
   const struct lrecord_implementation *imp = LHEADER_IMPLEMENTATION (h);
 
   return (imp->size_in_bytes_method ?
-	  imp->size_in_bytes_method (h) :
+	  imp->size_in_bytes_method (wrap_pointer_1 (h)) :
 	  imp->static_size);
 }
 
@@ -1792,6 +2072,21 @@
   return detagged_lisp_object_size (XRECORD_LHEADER (o));
 }
 
+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);
+Bytecount lisp_object_storage_size (Lisp_Object obj,
+				    struct usage_stats *ustats);
+Bytecount lisp_object_memory_usage_full (Lisp_Object object,
+					 Bytecount *storage_size,
+					 Bytecount *extra_nonlisp_storage,
+					 Bytecount *extra_lisp_storage,
+					 struct generic_usage_stats *stats);
+Bytecount lisp_object_memory_usage (Lisp_Object object);
+void free_normal_lisp_object (Lisp_Object obj);
+
 
 /************************************************************************/
 /*		                 Dumping                		*/