Mercurial > hg > xemacs-beta
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 */