Mercurial > hg > xemacs-beta
annotate src/lrecord.h @ 4938:299dce99bdad
(for main branch) when freeing check against DEADBEEF_CONSTANT since that's what we use elsewhere
| author | Ben Wing <ben@xemacs.org> |
|---|---|
| date | Tue, 19 Jan 2010 11:25:37 -0600 |
| parents | 195ceb7d6229 |
| children | 19a72041c5ed |
| rev | line source |
|---|---|
| 428 | 1 /* The "lrecord" structure (header of a compound lisp object). |
| 2 Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc. | |
|
4930
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
3 Copyright (C) 1996, 2001, 2002, 2004, 2005, 2010 Ben Wing. |
| 428 | 4 |
| 5 This file is part of XEmacs. | |
| 6 | |
| 7 XEmacs is free software; you can redistribute it and/or modify it | |
| 8 under the terms of the GNU General Public License as published by the | |
| 9 Free Software Foundation; either version 2, or (at your option) any | |
| 10 later version. | |
| 11 | |
| 12 XEmacs is distributed in the hope that it will be useful, but WITHOUT | |
| 13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 15 for more details. | |
| 16 | |
| 17 You should have received a copy of the GNU General Public License | |
| 18 along with XEmacs; see the file COPYING. If not, write to | |
| 19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
| 20 Boston, MA 02111-1307, USA. */ | |
| 21 | |
| 22 /* Synched up with: Not in FSF. */ | |
| 23 | |
| 2367 | 24 /* This file has been Mule-ized, Ben Wing, 10-13-04. */ |
| 25 | |
| 440 | 26 #ifndef INCLUDED_lrecord_h_ |
| 27 #define INCLUDED_lrecord_h_ | |
| 428 | 28 |
|
4930
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
29 /* The "lrecord" type of Lisp object is used for all object types other |
|
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
30 than a few simple ones (like char and int). This allows many types to be |
|
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
31 implemented but only a few bits required in a Lisp object for type |
|
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
32 information. (The tradeoff is that each object has its type marked in |
|
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
33 it, thereby increasing its size.) All lrecords begin with a `struct |
|
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
34 lrecord_header', which identifies the lisp object type, by providing an |
|
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
35 index into a table of `struct lrecord_implementation', which describes |
|
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
36 the behavior of the lisp object. It also contains some other data bits. |
| 2720 | 37 |
|
4930
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
38 #ifndef NEW_GC |
| 428 | 39 Lrecords are of two types: straight lrecords, and lcrecords. |
| 40 Straight lrecords are used for those types of objects that have | |
| 41 their own allocation routines (typically allocated out of 2K chunks | |
| 42 of memory called `frob blocks'). These objects have a `struct | |
| 43 lrecord_header' at the top, containing only the bits needed to find | |
| 44 the lrecord_implementation for the object. There are special | |
| 1204 | 45 routines in alloc.c to create an object of each such type. |
| 428 | 46 |
| 442 | 47 Lcrecords are used for less common sorts of objects that don't do |
| 48 their own allocation. Each such object is malloc()ed individually, | |
| 49 and the objects are chained together through a `next' pointer. | |
| 3024 | 50 Lcrecords have a `struct old_lcrecord_header' at the top, which |
| 442 | 51 contains a `struct lrecord_header' and a `next' pointer, and are |
| 3024 | 52 allocated using old_alloc_lcrecord_type() or its variants. |
|
4930
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
53 #endif |
| 428 | 54 |
|
4930
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
55 Creating a new Lisp object type is fairly easy; just follow the |
| 428 | 56 lead of some existing type (e.g. hash tables). Note that you |
| 57 do not need to supply all the methods (see below); reasonable | |
| 58 defaults are provided for many of them. Alternatively, if you're | |
| 59 just looking for a way of encapsulating data (which possibly | |
| 60 could contain Lisp_Objects in it), you may well be able to use | |
|
4930
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
61 the opaque type. |
| 1204 | 62 */ |
|
4930
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
63 |
|
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
64 #ifdef NEW_GC |
|
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
65 /* |
|
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
66 There are some limitations under New-GC that lead to the creation of a |
|
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
67 large number of new internal object types. I'm not completely sure what |
|
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
68 all of them are, but they are at least partially related to limitations |
|
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
69 on finalizers. Something else must be going on as well, because |
|
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
70 non-dumpable, non-finalizable objects like devices and frames also have |
|
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
71 their window-system-specific substructures converted into Lisp objects. |
|
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
72 It must have something to do with the fact that these substructures |
|
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
73 contain pointers to Lisp objects, but it's not completely clear why -- |
|
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
74 object descriptions exist to indicate the size of these structures and |
|
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
75 the Lisp object pointers within them. |
|
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
76 |
|
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
77 At least one definite issue is that under New-GC dumpable objects cannot |
|
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
78 contain any finalizers (see pdump_register_object()). This means that any |
|
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
79 substructures in dumpable objects that are allocated separately and |
|
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
80 normally freed in a finalizer need instead to be made into actual Lisp |
|
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
81 objects. If those structures are Dynarrs, they need to be made into |
|
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
82 Dynarr Lisp objects (e.g. face-cachel-dynarr or glyph-cachel-dynarr), |
|
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
83 which are created using Dynarr_lisp_new() or Dynarr_new_new2(). |
|
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
84 Furthermore, the objects contained in the Dynarr also need to be Lisp |
|
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
85 objects (e.g. face-cachel or glyph-cachel). |
|
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
86 |
|
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
87 --ben |
|
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
88 */ |
|
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
89 |
|
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
90 #endif |
|
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
91 |
|
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
92 |
| 428 | 93 |
| 3263 | 94 #ifdef NEW_GC |
| 3024 | 95 #define ALLOC_LCRECORD_TYPE alloc_lrecord_type |
| 96 #define COPY_SIZED_LCRECORD copy_sized_lrecord | |
| 97 #define COPY_LCRECORD copy_lrecord | |
| 98 #define LISPOBJ_STORAGE_SIZE(ptr, size, stats) \ | |
| 99 mc_alloced_storage_size (size, stats) | |
| 100 #define ZERO_LCRECORD zero_lrecord | |
| 101 #define LCRECORD_HEADER lrecord_header | |
| 102 #define BASIC_ALLOC_LCRECORD alloc_lrecord | |
| 103 #define FREE_LCRECORD free_lrecord | |
| 3263 | 104 #else /* not NEW_GC */ |
| 3024 | 105 #define ALLOC_LCRECORD_TYPE old_alloc_lcrecord_type |
| 106 #define COPY_SIZED_LCRECORD old_copy_sized_lcrecord | |
| 107 #define COPY_LCRECORD old_copy_lcrecord | |
| 108 #define LISPOBJ_STORAGE_SIZE malloced_storage_size | |
| 109 #define ZERO_LCRECORD old_zero_lcrecord | |
| 110 #define LCRECORD_HEADER old_lcrecord_header | |
| 111 #define BASIC_ALLOC_LCRECORD old_basic_alloc_lcrecord | |
| 112 #define FREE_LCRECORD old_free_lcrecord | |
| 3263 | 113 #endif /* not NEW_GC */ |
| 3024 | 114 |
| 1743 | 115 BEGIN_C_DECLS |
| 1650 | 116 |
| 428 | 117 struct lrecord_header |
| 118 { | |
| 1204 | 119 /* Index into lrecord_implementations_table[]. Objects that have been |
| 120 explicitly freed using e.g. free_cons() have lrecord_type_free in this | |
| 121 field. */ | |
| 442 | 122 unsigned int type :8; |
| 123 | |
| 3263 | 124 #ifdef NEW_GC |
| 2720 | 125 /* 1 if the object is readonly from lisp */ |
| 126 unsigned int lisp_readonly :1; | |
| 127 | |
| 128 /* The `free' field is a flag that indicates whether this lrecord | |
| 129 is currently free or not. This is used for error checking and | |
| 130 debugging. */ | |
| 131 unsigned int free :1; | |
| 132 | |
| 3063 | 133 /* The `uid' field is just for debugging/printing convenience. Having |
| 134 this slot doesn't hurt us spacewise, since the bits are unused | |
| 135 anyway. (The bits are used for strings, though.) */ | |
| 2720 | 136 unsigned int uid :22; |
| 137 | |
| 3263 | 138 #else /* not NEW_GC */ |
| 442 | 139 /* If `mark' is 0 after the GC mark phase, the object will be freed |
| 140 during the GC sweep phase. There are 2 ways that `mark' can be 1: | |
| 141 - by being referenced from other objects during the GC mark phase | |
| 142 - because it is permanently on, for c_readonly objects */ | |
| 143 unsigned int mark :1; | |
| 144 | |
| 145 /* 1 if the object resides in logically read-only space, and does not | |
| 146 reference other non-c_readonly objects. | |
| 147 Invariant: if (c_readonly == 1), then (mark == 1 && lisp_readonly == 1) */ | |
| 148 unsigned int c_readonly :1; | |
| 149 | |
| 428 | 150 /* 1 if the object is readonly from lisp */ |
| 442 | 151 unsigned int lisp_readonly :1; |
| 771 | 152 |
| 3063 | 153 /* The `uid' field is just for debugging/printing convenience. Having |
| 154 this slot doesn't hurt us spacewise, since the bits are unused | |
| 155 anyway. (The bits are used for strings, though.) */ | |
| 156 unsigned int uid :21; | |
| 934 | 157 |
| 3263 | 158 #endif /* not NEW_GC */ |
| 428 | 159 }; |
| 160 | |
| 161 struct lrecord_implementation; | |
| 442 | 162 int lrecord_type_index (const struct lrecord_implementation *implementation); |
| 3063 | 163 extern int lrecord_uid_counter; |
| 428 | 164 |
| 3263 | 165 #ifdef NEW_GC |
| 2720 | 166 #define set_lheader_implementation(header,imp) do { \ |
| 167 struct lrecord_header* SLI_header = (header); \ | |
| 168 SLI_header->type = (imp)->lrecord_type_index; \ | |
| 169 SLI_header->lisp_readonly = 0; \ | |
| 170 SLI_header->free = 0; \ | |
| 3063 | 171 SLI_header->uid = lrecord_uid_counter++; \ |
| 2720 | 172 } while (0) |
| 3263 | 173 #else /* not NEW_GC */ |
| 430 | 174 #define set_lheader_implementation(header,imp) do { \ |
| 428 | 175 struct lrecord_header* SLI_header = (header); \ |
| 442 | 176 SLI_header->type = (imp)->lrecord_type_index; \ |
| 430 | 177 SLI_header->mark = 0; \ |
| 178 SLI_header->c_readonly = 0; \ | |
| 179 SLI_header->lisp_readonly = 0; \ | |
| 3063 | 180 SLI_header->uid = lrecord_uid_counter++; \ |
| 428 | 181 } while (0) |
| 3263 | 182 #endif /* not NEW_GC */ |
| 428 | 183 |
| 3263 | 184 #ifndef NEW_GC |
| 3024 | 185 struct old_lcrecord_header |
| 428 | 186 { |
| 187 struct lrecord_header lheader; | |
| 188 | |
| 442 | 189 /* The `next' field is normally used to chain all lcrecords together |
| 428 | 190 so that the GC can find (and free) all of them. |
| 3024 | 191 `old_basic_alloc_lcrecord' threads lcrecords together. |
| 428 | 192 |
| 193 The `next' field may be used for other purposes as long as some | |
| 194 other mechanism is provided for letting the GC do its work. | |
| 195 | |
| 196 For example, the event and marker object types allocate members | |
| 197 out of memory chunks, and are able to find all unmarked members | |
| 198 by sweeping through the elements of the list of chunks. */ | |
| 3024 | 199 struct old_lcrecord_header *next; |
| 428 | 200 |
| 201 /* The `uid' field is just for debugging/printing convenience. | |
| 202 Having this slot doesn't hurt us much spacewise, since an | |
| 203 lcrecord already has the above slots plus malloc overhead. */ | |
| 204 unsigned int uid :31; | |
| 205 | |
| 206 /* The `free' field is a flag that indicates whether this lcrecord | |
| 207 is on a "free list". Free lists are used to minimize the number | |
| 208 of calls to malloc() when we're repeatedly allocating and freeing | |
| 209 a number of the same sort of lcrecord. Lcrecords on a free list | |
| 210 always get marked in a different fashion, so we can use this flag | |
| 211 as a sanity check to make sure that free lists only have freed | |
| 212 lcrecords and there are no freed lcrecords elsewhere. */ | |
| 213 unsigned int free :1; | |
| 214 }; | |
| 215 | |
| 216 /* Used for lcrecords in an lcrecord-list. */ | |
| 217 struct free_lcrecord_header | |
| 218 { | |
| 3024 | 219 struct old_lcrecord_header lcheader; |
| 428 | 220 Lisp_Object chain; |
| 221 }; | |
| 3263 | 222 #endif /* not NEW_GC */ |
| 428 | 223 |
| 3931 | 224 /* DON'T FORGET to update .gdbinit.in if you change this list. */ |
| 442 | 225 enum lrecord_type |
| 226 { | |
| 227 /* Symbol value magic types come first to make SYMBOL_VALUE_MAGIC_P fast. | |
| 228 #### This should be replaced by a symbol_value_magic_p flag | |
| 229 in the Lisp_Symbol lrecord_header. */ | |
| 2720 | 230 lrecord_type_symbol_value_forward, /* 0 */ |
| 3092 | 231 lrecord_type_symbol_value_varalias, |
| 232 lrecord_type_symbol_value_lisp_magic, | |
| 233 lrecord_type_symbol_value_buffer_local, | |
| 442 | 234 lrecord_type_max_symbol_value_magic = lrecord_type_symbol_value_buffer_local, |
| 3092 | 235 lrecord_type_symbol, |
| 236 lrecord_type_subr, | |
|
4677
8f1ee2d15784
Support full Common Lisp multiple values in C.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3931
diff
changeset
|
237 lrecord_type_multiple_value, |
| 3092 | 238 lrecord_type_cons, |
| 239 lrecord_type_vector, | |
| 240 lrecord_type_string, | |
| 3263 | 241 #ifndef NEW_GC |
| 442 | 242 lrecord_type_lcrecord_list, |
| 3263 | 243 #endif /* not NEW_GC */ |
| 3092 | 244 lrecord_type_compiled_function, |
| 245 lrecord_type_weak_list, | |
| 246 lrecord_type_bit_vector, | |
| 247 lrecord_type_float, | |
| 248 lrecord_type_hash_table, | |
| 249 lrecord_type_lstream, | |
| 250 lrecord_type_process, | |
| 251 lrecord_type_charset, | |
| 252 lrecord_type_coding_system, | |
| 253 lrecord_type_char_table, | |
| 254 lrecord_type_char_table_entry, | |
| 255 lrecord_type_range_table, | |
| 256 lrecord_type_opaque, | |
| 257 lrecord_type_opaque_ptr, | |
| 258 lrecord_type_buffer, | |
| 259 lrecord_type_extent, | |
| 260 lrecord_type_extent_info, | |
| 261 lrecord_type_extent_auxiliary, | |
| 262 lrecord_type_marker, | |
| 263 lrecord_type_event, | |
| 2720 | 264 #ifdef EVENT_DATA_AS_OBJECTS /* not defined */ |
| 934 | 265 lrecord_type_key_data, |
| 266 lrecord_type_button_data, | |
| 267 lrecord_type_motion_data, | |
| 268 lrecord_type_process_data, | |
| 269 lrecord_type_timeout_data, | |
| 270 lrecord_type_eval_data, | |
| 271 lrecord_type_misc_user_data, | |
| 272 lrecord_type_magic_eval_data, | |
| 273 lrecord_type_magic_data, | |
| 1204 | 274 #endif /* EVENT_DATA_AS_OBJECTS */ |
| 3092 | 275 lrecord_type_keymap, |
| 276 lrecord_type_command_builder, | |
| 277 lrecord_type_timeout, | |
| 278 lrecord_type_specifier, | |
| 279 lrecord_type_console, | |
| 280 lrecord_type_device, | |
| 281 lrecord_type_frame, | |
| 282 lrecord_type_window, | |
| 283 lrecord_type_window_mirror, | |
| 284 lrecord_type_window_configuration, | |
| 285 lrecord_type_gui_item, | |
| 286 lrecord_type_popup_data, | |
| 287 lrecord_type_toolbar_button, | |
| 288 lrecord_type_scrollbar_instance, | |
| 289 lrecord_type_color_instance, | |
| 290 lrecord_type_font_instance, | |
| 291 lrecord_type_image_instance, | |
| 292 lrecord_type_glyph, | |
| 293 lrecord_type_face, | |
| 3931 | 294 lrecord_type_fc_config, |
| 3094 | 295 lrecord_type_fc_pattern, |
| 3092 | 296 lrecord_type_database, |
| 297 lrecord_type_tooltalk_message, | |
| 298 lrecord_type_tooltalk_pattern, | |
| 299 lrecord_type_ldap, | |
| 300 lrecord_type_pgconn, | |
| 301 lrecord_type_pgresult, | |
| 302 lrecord_type_devmode, | |
| 303 lrecord_type_mswindows_dialog_id, | |
| 304 lrecord_type_case_table, | |
| 305 lrecord_type_emacs_ffi, | |
| 306 lrecord_type_emacs_gtk_object, | |
| 307 lrecord_type_emacs_gtk_boxed, | |
| 308 lrecord_type_weak_box, | |
| 309 lrecord_type_ephemeron, | |
| 310 lrecord_type_bignum, | |
| 311 lrecord_type_ratio, | |
| 312 lrecord_type_bigfloat, | |
| 3263 | 313 #ifndef NEW_GC |
| 454 | 314 lrecord_type_free, /* only used for "free" lrecords */ |
| 315 lrecord_type_undefined, /* only used for debugging */ | |
| 3263 | 316 #endif /* not NEW_GC */ |
| 3092 | 317 #ifdef NEW_GC |
|
4930
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
318 /* See comment up top explaining why these extra object types must exist. */ |
| 3092 | 319 lrecord_type_string_indirect_data, |
| 320 lrecord_type_string_direct_data, | |
| 321 lrecord_type_hash_table_entry, | |
| 322 lrecord_type_syntax_cache, | |
| 323 lrecord_type_buffer_text, | |
| 324 lrecord_type_compiled_function_args, | |
| 325 lrecord_type_tty_console, | |
| 326 lrecord_type_stream_console, | |
| 327 lrecord_type_dynarr, | |
| 328 lrecord_type_face_cachel, | |
| 329 lrecord_type_face_cachel_dynarr, | |
| 330 lrecord_type_glyph_cachel, | |
| 331 lrecord_type_glyph_cachel_dynarr, | |
| 332 lrecord_type_x_device, | |
| 333 lrecord_type_gtk_device, | |
| 334 lrecord_type_tty_device, | |
| 335 lrecord_type_mswindows_device, | |
| 336 lrecord_type_msprinter_device, | |
| 337 lrecord_type_x_frame, | |
| 338 lrecord_type_gtk_frame, | |
| 339 lrecord_type_mswindows_frame, | |
| 340 lrecord_type_gap_array_marker, | |
| 341 lrecord_type_gap_array, | |
| 342 lrecord_type_extent_list_marker, | |
| 343 lrecord_type_extent_list, | |
| 344 lrecord_type_stack_of_extents, | |
| 345 lrecord_type_tty_color_instance_data, | |
| 346 lrecord_type_tty_font_instance_data, | |
| 347 lrecord_type_specifier_caching, | |
| 348 lrecord_type_expose_ignore, | |
| 349 #endif /* NEW_GC */ | |
| 350 lrecord_type_last_built_in_type /* must be last */ | |
| 442 | 351 }; |
| 352 | |
| 1632 | 353 extern MODULE_API int lrecord_type_count; |
| 428 | 354 |
| 355 struct lrecord_implementation | |
| 356 { | |
| 2367 | 357 const Ascbyte *name; |
| 442 | 358 |
| 934 | 359 /* information for the dumper: is the object dumpable and should it |
| 360 be dumped. */ | |
| 361 unsigned int dumpable :1; | |
| 362 | |
| 442 | 363 /* `marker' is called at GC time, to make sure that all Lisp_Objects |
| 428 | 364 pointed to by this object get properly marked. It should call |
| 365 the mark_object function on all Lisp_Objects in the object. If | |
| 366 the return value is non-nil, it should be a Lisp_Object to be | |
| 367 marked (don't call the mark_object function explicitly on it, | |
| 368 because the GC routines will do this). Doing it this way reduces | |
| 369 recursion, so the object returned should preferably be the one | |
| 370 with the deepest level of Lisp_Object pointers. This function | |
| 1204 | 371 can be NULL, meaning no GC marking is necessary. |
| 372 | |
| 373 NOTE NOTE NOTE: This is not used by KKCC (which uses the data | |
| 374 description below instead), unless the data description is missing. | |
| 375 Yes, this currently means there is logic duplication. Eventually the | |
| 376 mark methods will be removed. */ | |
| 428 | 377 Lisp_Object (*marker) (Lisp_Object); |
| 442 | 378 |
| 379 /* `printer' converts the object to a printed representation. | |
| 380 This can be NULL; in this case default_object_printer() will be | |
| 381 used instead. */ | |
| 428 | 382 void (*printer) (Lisp_Object, Lisp_Object printcharfun, int escapeflag); |
| 442 | 383 |
|
4930
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
384 /* `finalizer' is called at GC time when the object is about to be freed, |
|
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
385 and at dump time (FOR_DISKSAVE will be non-zero in this case). It |
|
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
386 should perform any necessary cleanup (e.g. freeing malloc()ed memory |
|
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
387 or releasing objects created in external libraries, such as |
|
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
388 window-system windows or file handles). This can be NULL, meaning no |
|
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
389 special finalization is necessary. |
| 428 | 390 |
|
4930
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
391 WARNING: remember that `finalizer' is called at dump time even though |
|
9f04877ce07e
fix up comments about finalizers and NEWGC internal objects
Ben Wing <ben@xemacs.org>
parents:
4844
diff
changeset
|
392 the object is not being freed -- check the FOR_DISKSAVE argument. */ |
| 428 | 393 void (*finalizer) (void *header, int for_disksave); |
| 442 | 394 |
| 428 | 395 /* This can be NULL, meaning compare objects with EQ(). */ |
| 396 int (*equal) (Lisp_Object obj1, Lisp_Object obj2, int depth); | |
| 442 | 397 |
| 398 /* `hash' generates hash values for use with hash tables that have | |
| 399 `equal' as their test function. This can be NULL, meaning use | |
| 400 the Lisp_Object itself as the hash. But, you must still satisfy | |
| 401 the constraint that if two objects are `equal', then they *must* | |
| 402 hash to the same value in order for hash tables to work properly. | |
| 403 This means that `hash' can be NULL only if the `equal' method is | |
| 404 also NULL. */ | |
| 2515 | 405 Hashcode (*hash) (Lisp_Object, int); |
| 428 | 406 |
| 1204 | 407 /* Data layout description for your object. See long comment below. */ |
| 408 const struct memory_description *description; | |
| 428 | 409 |
| 442 | 410 /* These functions allow any object type to have builtin property |
| 411 lists that can be manipulated from the lisp level with | |
| 412 `get', `put', `remprop', and `object-plist'. */ | |
| 428 | 413 Lisp_Object (*getprop) (Lisp_Object obj, Lisp_Object prop); |
| 414 int (*putprop) (Lisp_Object obj, Lisp_Object prop, Lisp_Object val); | |
| 415 int (*remprop) (Lisp_Object obj, Lisp_Object prop); | |
| 416 Lisp_Object (*plist) (Lisp_Object obj); | |
| 417 | |
| 3263 | 418 #ifdef NEW_GC |
| 2720 | 419 /* Only one of `static_size' and `size_in_bytes_method' is non-0. */ |
| 3263 | 420 #else /* not NEW_GC */ |
| 442 | 421 /* Only one of `static_size' and `size_in_bytes_method' is non-0. |
| 3024 | 422 If both are 0, this type is not instantiable by |
| 423 old_basic_alloc_lcrecord(). */ | |
| 3263 | 424 #endif /* not NEW_GC */ |
| 665 | 425 Bytecount static_size; |
| 426 Bytecount (*size_in_bytes_method) (const void *header); | |
| 442 | 427 |
| 428 /* The (constant) index into lrecord_implementations_table */ | |
| 429 enum lrecord_type lrecord_type_index; | |
| 430 | |
| 3263 | 431 #ifndef NEW_GC |
| 428 | 432 /* A "basic" lrecord is any lrecord that's not an lcrecord, i.e. |
| 3024 | 433 one that does not have an old_lcrecord_header at the front and which |
| 1204 | 434 is (usually) allocated in frob blocks. */ |
| 442 | 435 unsigned int basic_p :1; |
| 3263 | 436 #endif /* not NEW_GC */ |
| 428 | 437 }; |
| 438 | |
| 617 | 439 /* All the built-in lisp object types are enumerated in `enum lrecord_type'. |
| 442 | 440 Additional ones may be defined by a module (none yet). We leave some |
| 441 room in `lrecord_implementations_table' for such new lisp object types. */ | |
| 442 #define MODULE_DEFINABLE_TYPE_COUNT 32 | |
| 443 | |
| 1632 | 444 extern MODULE_API const struct lrecord_implementation * |
| 445 lrecord_implementations_table[lrecord_type_last_built_in_type + MODULE_DEFINABLE_TYPE_COUNT]; | |
| 428 | 446 |
| 447 #define XRECORD_LHEADER_IMPLEMENTATION(obj) \ | |
| 442 | 448 LHEADER_IMPLEMENTATION (XRECORD_LHEADER (obj)) |
| 449 #define LHEADER_IMPLEMENTATION(lh) lrecord_implementations_table[(lh)->type] | |
| 428 | 450 |
| 3092 | 451 #include "gc.h" |
| 452 | |
| 453 #ifdef NEW_GC | |
| 454 #include "vdb.h" | |
| 455 #endif /* NEW_GC */ | |
| 456 | |
| 428 | 457 extern int gc_in_progress; |
| 458 | |
| 3263 | 459 #ifdef NEW_GC |
| 2720 | 460 #include "mc-alloc.h" |
| 461 | |
| 2994 | 462 #ifdef ALLOC_TYPE_STATS |
| 2720 | 463 void init_lrecord_stats (void); |
| 464 void inc_lrecord_stats (Bytecount size, const struct lrecord_header *h); | |
| 465 void dec_lrecord_stats (Bytecount size_including_overhead, | |
| 466 const struct lrecord_header *h); | |
| 3092 | 467 int lrecord_stats_heap_size (void); |
| 2994 | 468 #endif /* ALLOC_TYPE_STATS */ |
| 2720 | 469 |
| 470 /* Tell mc-alloc how to call a finalizer. */ | |
| 3092 | 471 #define MC_ALLOC_CALL_FINALIZER(ptr) \ |
| 472 { \ | |
| 473 Lisp_Object MCACF_obj = wrap_pointer_1 (ptr); \ | |
| 474 struct lrecord_header *MCACF_lheader = XRECORD_LHEADER (MCACF_obj); \ | |
| 475 if (XRECORD_LHEADER (MCACF_obj) && LRECORDP (MCACF_obj) \ | |
| 476 && !LRECORD_FREE_P (MCACF_lheader) ) \ | |
| 477 { \ | |
| 478 const struct lrecord_implementation *MCACF_implementation \ | |
| 479 = LHEADER_IMPLEMENTATION (MCACF_lheader); \ | |
| 480 if (MCACF_implementation && MCACF_implementation->finalizer) \ | |
| 481 { \ | |
| 482 GC_STAT_FINALIZED; \ | |
| 483 MCACF_implementation->finalizer (ptr, 0); \ | |
| 484 } \ | |
| 485 } \ | |
| 486 } while (0) | |
| 2720 | 487 |
| 488 /* Tell mc-alloc how to call a finalizer for disksave. */ | |
| 489 #define MC_ALLOC_CALL_FINALIZER_FOR_DISKSAVE(ptr) \ | |
| 490 { \ | |
| 491 Lisp_Object MCACF_obj = wrap_pointer_1 (ptr); \ | |
| 492 struct lrecord_header *MCACF_lheader = XRECORD_LHEADER (MCACF_obj); \ | |
| 493 if (XRECORD_LHEADER (MCACF_obj) && LRECORDP (MCACF_obj) \ | |
| 494 && !LRECORD_FREE_P (MCACF_lheader) ) \ | |
| 495 { \ | |
| 496 const struct lrecord_implementation *MCACF_implementation \ | |
| 497 = LHEADER_IMPLEMENTATION (MCACF_lheader); \ | |
| 498 if (MCACF_implementation && MCACF_implementation->finalizer) \ | |
| 499 MCACF_implementation->finalizer (ptr, 1); \ | |
| 500 } \ | |
| 501 } while (0) | |
| 502 | |
| 503 #define LRECORD_FREE_P(ptr) \ | |
| 504 (((struct lrecord_header *) ptr)->free) | |
| 505 | |
| 506 #define MARK_LRECORD_AS_FREE(ptr) \ | |
| 507 ((void) (((struct lrecord_header *) ptr)->free = 1)) | |
| 508 | |
| 509 #define MARK_LRECORD_AS_NOT_FREE(ptr) \ | |
| 510 ((void) (((struct lrecord_header *) ptr)->free = 0)) | |
| 511 | |
| 512 #define MARKED_RECORD_P(obj) MARKED_P (obj) | |
| 513 #define MARKED_RECORD_HEADER_P(lheader) MARKED_P (lheader) | |
| 514 #define MARK_RECORD_HEADER(lheader) MARK (lheader) | |
| 515 #define UNMARK_RECORD_HEADER(lheader) UNMARK (lheader) | |
| 516 | |
| 517 #define LISP_READONLY_RECORD_HEADER_P(lheader) ((lheader)->lisp_readonly) | |
| 518 #define SET_LISP_READONLY_RECORD_HEADER(lheader) \ | |
| 519 ((void) ((lheader)->lisp_readonly = 1)) | |
| 520 #define MARK_LRECORD_AS_LISP_READONLY(ptr) \ | |
| 521 ((void) (((struct lrecord_header *) ptr)->lisp_readonly = 1)) | |
| 522 | |
| 3263 | 523 #else /* not NEW_GC */ |
| 2720 | 524 |
| 525 #define LRECORD_FREE_P(ptr) \ | |
| 526 (((struct lrecord_header *) ptr)->type == lrecord_type_free) | |
| 527 | |
| 528 #define MARK_LRECORD_AS_FREE(ptr) \ | |
| 529 ((void) (((struct lrecord_header *) ptr)->type = lrecord_type_free)) | |
| 530 | |
| 442 | 531 #define MARKED_RECORD_P(obj) (XRECORD_LHEADER (obj)->mark) |
| 428 | 532 #define MARKED_RECORD_HEADER_P(lheader) ((lheader)->mark) |
| 533 #define MARK_RECORD_HEADER(lheader) ((void) ((lheader)->mark = 1)) | |
| 534 #define UNMARK_RECORD_HEADER(lheader) ((void) ((lheader)->mark = 0)) | |
| 535 | |
| 536 #define C_READONLY_RECORD_HEADER_P(lheader) ((lheader)->c_readonly) | |
| 537 #define LISP_READONLY_RECORD_HEADER_P(lheader) ((lheader)->lisp_readonly) | |
| 442 | 538 #define SET_C_READONLY_RECORD_HEADER(lheader) do { \ |
| 539 struct lrecord_header *SCRRH_lheader = (lheader); \ | |
| 540 SCRRH_lheader->c_readonly = 1; \ | |
| 541 SCRRH_lheader->lisp_readonly = 1; \ | |
| 542 SCRRH_lheader->mark = 1; \ | |
| 543 } while (0) | |
| 428 | 544 #define SET_LISP_READONLY_RECORD_HEADER(lheader) \ |
| 545 ((void) ((lheader)->lisp_readonly = 1)) | |
| 3263 | 546 #endif /* not NEW_GC */ |
| 1676 | 547 |
| 548 #ifdef USE_KKCC | |
| 549 #define RECORD_DESCRIPTION(lheader) lrecord_memory_descriptions[(lheader)->type] | |
| 550 #else /* not USE_KKCC */ | |
| 442 | 551 #define RECORD_MARKER(lheader) lrecord_markers[(lheader)->type] |
| 1676 | 552 #endif /* not USE_KKCC */ |
| 428 | 553 |
| 934 | 554 #define RECORD_DUMPABLE(lheader) (lrecord_implementations_table[(lheader)->type])->dumpable |
| 1204 | 555 |
| 556 /* Data description stuff | |
| 934 | 557 |
| 1204 | 558 Data layout descriptions describe blocks of memory (in particular, Lisp |
| 559 objects and other objects on the heap, and global objects with pointers | |
| 560 to such heap objects), including their size and a list of the elements | |
| 561 that need relocating, marking or other special handling. They are | |
| 562 currently used in two places: by pdump [the new, portable dumper] and | |
| 563 KKCC [the new garbage collector]. The two subsystems use the | |
| 564 descriptions in different ways, and as a result some of the descriptions | |
| 565 are appropriate only for one or the other, when it is known that only | |
| 566 that subsystem will use the description. (This is particularly the case | |
| 567 with objects that can't be dumped, because pdump needs more info than | |
| 568 KKCC.) However, properly written descriptions are appropriate for both, | |
| 569 and you should strive to write your descriptions that way, since the | |
| 570 dumpable status of an object may change and new uses for the | |
| 571 descriptions may be created. (An example that comes to mind is a | |
| 572 facility for determining the memory usage of XEmacs data structures -- | |
| 573 like `buffer-memory-usage', `window-memory-usage', etc. but more | |
| 574 general.) | |
| 575 | |
| 576 More specifically: | |
| 428 | 577 |
| 1204 | 578 Pdump (the portable dumper) needs to write out all objects in heap |
| 579 space, and later on (in another invocation of XEmacs) load them back | |
| 580 into the heap, relocating all pointers to the heap objects in the global | |
| 581 data space. ("Heap" means anything malloc()ed, including all Lisp | |
| 582 objects, and "global data" means anything declared globally or | |
| 583 `static'.) Pdump, then, needs to be told about the location of all | |
| 584 global pointers to heap objects, all the description of all such | |
| 585 objects, including their size and any pointers to other heap (aka | |
| 586 "relocatable") objects. (Pdump assumes that the heap may occur in | |
| 587 different places in different invocations -- therefore, it is not enough | |
| 588 simply to write out the entire heap and later reload it at the same | |
| 589 location -- but that global data is always in the same place, and hence | |
| 590 pointers to it do not need to be relocated. This assumption holds true | |
| 591 in general for modern operating systems, but would be broken, for | |
| 592 example, in a system without virtual memory, or when dealing with shared | |
| 593 libraries. Also, unlike unexec, pdump does not usually write out or | |
| 594 restore objects in the global data space, and thus they need to be | |
| 595 initialized every time XEmacs is loaded. This is the purpose of the | |
| 596 reinit_*() functions throughout XEmacs. [It's possible, however, to make | |
| 597 pdump restore global data. This must be done, of course, for heap | |
| 598 pointers, but is also done for other values that are not easy to | |
| 599 recompute -- in particular, values established by the Lisp code loaded | |
| 600 at dump time.]) Note that the data type `Lisp_Object' is basically just | |
| 601 a relocatable pointer disguised as a long, and in general pdump treats | |
| 602 the Lisp_Object values and pointers to Lisp objects (e.g. Lisp_Object | |
| 603 vs. `struct frame *') identically. (NOTE: This equivalence depends | |
| 604 crucially on the current "minimal tagbits" implementation of Lisp_Object | |
| 605 pointers.) | |
| 428 | 606 |
| 1204 | 607 Descriptions are used by pdump in three places: (a) descriptions of Lisp |
| 608 objects, referenced in the DEFINE_*LRECORD_*IMPLEMENTATION*() call; (b) | |
| 609 descriptions of global objects to be dumped, registered by | |
| 610 dump_add_root_block(); (c) descriptions of global pointers to | |
| 2367 | 611 non-Lisp_Object heap objects, registered by dump_add_root_block_ptr(). |
| 1204 | 612 The descriptions need to tell pdump which elements of your structure are |
| 613 Lisp_Objects or structure pointers, plus the descriptions in turn of the | |
| 614 non-Lisp_Object structures pointed to. If these structures are you own | |
| 615 private ones, you will have to write these recursive descriptions | |
| 616 yourself; otherwise, you are reusing a structure already in existence | |
| 617 elsewhere and there is probably already a description for it. | |
| 618 | |
| 619 Pdump does not care about Lisp objects that cannot be dumped (the | |
| 620 dumpable flag to DEFINE_*LRECORD_*IMPLEMENTATION*() is 0). | |
| 621 | |
| 622 KKCC also uses data layout descriptions, but differently. It cares | |
| 623 about all objects, dumpable or not, but specifically only wants to know | |
| 624 about Lisp_Objects in your object and in structures pointed to. Thus, | |
| 625 it doesn't care about things like pointers to structures ot other blocks | |
| 626 of memory with no Lisp Objects in them, which pdump would care a lot | |
| 627 about. | |
| 628 | |
| 629 Technically, then, you could write your description differently | |
| 630 depending on whether your object is dumpable -- the full pdump | |
| 631 description if so, the abbreviated KKCC description if not. In fact, | |
| 632 some descriptions are written this way. This is dangerous, though, | |
| 633 because another use might come along for the data descriptions, that | |
| 634 doesn't care about the dumper flag and makes use of some of the stuff | |
| 635 normally omitted from the "abbreviated" description -- see above. | |
| 636 | |
| 637 A memory_description is an array of values. (This is actually | |
| 771 | 638 misnamed, in that it does not just describe lrecords, but any |
| 639 blocks of memory.) The first value of each line is a type, the | |
| 640 second the offset in the lrecord structure. The third and | |
| 641 following elements are parameters; their presence, type and number | |
| 642 is type-dependent. | |
| 643 | |
| 1204 | 644 The description ends with an "XD_END" record. |
| 771 | 645 |
| 646 The top-level description of an lrecord or lcrecord does not need | |
| 647 to describe every element, just the ones that need to be relocated, | |
| 648 since the size of the lrecord is known. (The same goes for nested | |
| 649 structures, whenever the structure size is given, rather than being | |
| 650 defaulted by specifying 0 for the size.) | |
| 651 | |
| 1204 | 652 A sized_memory_description is a memory_description plus the size of the |
| 653 block of memory. The size field in a sized_memory_description can be | |
| 654 given as zero, i.e. unspecified, meaning that the last element in the | |
| 655 structure is described in the description and the size of the block can | |
| 656 therefore be computed from it. (This is useful for stretchy arrays.) | |
| 657 | |
| 658 memory_descriptions are used to describe lrecords (the size of the | |
| 659 lrecord is elsewhere in its description, attached to its methods, so it | |
| 660 does not need to be given here) and global objects, where the size is an | |
| 661 argument to the call to dump_add_root_block(). | |
| 662 sized_memory_descriptions are used for pointers and arrays in | |
| 2367 | 663 memory_descriptions and for calls to dump_add_root_block_ptr(). (#### |
| 1204 | 664 It is not obvious why this is so in the latter case. Probably, calls to |
| 2367 | 665 dump_add_root_block_ptr() should use plain memory_descriptions and have |
| 1204 | 666 the size be an argument to the call.) |
| 667 | |
| 668 NOTE: Anywhere that a sized_memory_description occurs inside of a plain | |
| 669 memory_description, a "description map" can be substituted. Rather than | |
| 670 being an actual description, this describes how to find the description | |
| 671 by looking inside of the object being described. This is a convenient | |
| 672 way to describe Lisp objects with subtypes and corresponding | |
| 673 type-specific data. | |
| 428 | 674 |
| 675 Some example descriptions : | |
| 440 | 676 |
| 814 | 677 struct Lisp_String |
| 678 { | |
| 679 struct lrecord_header lheader; | |
| 680 Bytecount size; | |
| 867 | 681 Ibyte *data; |
| 814 | 682 Lisp_Object plist; |
| 683 }; | |
| 684 | |
| 1204 | 685 static const struct memory_description cons_description[] = { |
| 440 | 686 { XD_LISP_OBJECT, offsetof (Lisp_Cons, car) }, |
| 687 { XD_LISP_OBJECT, offsetof (Lisp_Cons, cdr) }, | |
| 428 | 688 { XD_END } |
| 689 }; | |
| 690 | |
| 440 | 691 Which means "two lisp objects starting at the 'car' and 'cdr' elements" |
| 428 | 692 |
| 1204 | 693 static const struct memory_description string_description[] = { |
| 814 | 694 { XD_BYTECOUNT, offsetof (Lisp_String, size) }, |
| 1204 | 695 { XD_OPAQUE_DATA_PTR, offsetof (Lisp_String, data), XD_INDIRECT (0, 1) }, |
| 814 | 696 { XD_LISP_OBJECT, offsetof (Lisp_String, plist) }, |
| 697 { XD_END } | |
| 698 }; | |
| 699 | |
| 700 "A pointer to string data at 'data', the size of the pointed array being | |
| 701 the value of the size variable plus 1, and one lisp object at 'plist'" | |
| 702 | |
| 703 If your object has a pointer to an array of Lisp_Objects in it, something | |
| 704 like this: | |
| 705 | |
| 706 struct Lisp_Foo | |
| 707 { | |
| 708 ...; | |
| 709 int count; | |
| 710 Lisp_Object *objects; | |
| 711 ...; | |
| 712 } | |
| 713 | |
| 2367 | 714 You'd use XD_BLOCK_PTR, something like: |
| 814 | 715 |
| 1204 | 716 static const struct memory_description foo_description[] = { |
| 717 ... | |
| 718 { XD_INT, offsetof (Lisp_Foo, count) }, | |
| 2367 | 719 { XD_BLOCK_PTR, offsetof (Lisp_Foo, objects), |
| 2551 | 720 XD_INDIRECT (0, 0), { &lisp_object_description } }, |
| 1204 | 721 ... |
| 722 }; | |
| 723 | |
| 724 lisp_object_description is declared in alloc.c, like this: | |
| 725 | |
| 726 static const struct memory_description lisp_object_description_1[] = { | |
| 814 | 727 { XD_LISP_OBJECT, 0 }, |
| 728 { XD_END } | |
| 729 }; | |
| 730 | |
| 1204 | 731 const struct sized_memory_description lisp_object_description = { |
| 814 | 732 sizeof (Lisp_Object), |
| 1204 | 733 lisp_object_description_1 |
| 814 | 734 }; |
| 735 | |
| 2367 | 736 Another example of XD_BLOCK_PTR: |
| 428 | 737 |
| 1204 | 738 typedef struct htentry |
| 814 | 739 { |
| 740 Lisp_Object key; | |
| 741 Lisp_Object value; | |
| 1204 | 742 } htentry; |
| 814 | 743 |
| 744 struct Lisp_Hash_Table | |
| 745 { | |
| 3017 | 746 struct LCRECORD_HEADER header; |
| 814 | 747 Elemcount size; |
| 748 Elemcount count; | |
| 749 Elemcount rehash_count; | |
| 750 double rehash_size; | |
| 751 double rehash_threshold; | |
| 752 Elemcount golden_ratio; | |
| 753 hash_table_hash_function_t hash_function; | |
| 754 hash_table_test_function_t test_function; | |
| 1204 | 755 htentry *hentries; |
| 814 | 756 enum hash_table_weakness weakness; |
| 757 Lisp_Object next_weak; // Used to chain together all of the weak | |
| 758 // hash tables. Don't mark through this. | |
| 759 }; | |
| 760 | |
| 1204 | 761 static const struct memory_description htentry_description_1[] = { |
| 762 { XD_LISP_OBJECT, offsetof (htentry, key) }, | |
| 763 { XD_LISP_OBJECT, offsetof (htentry, value) }, | |
| 814 | 764 { XD_END } |
| 765 }; | |
| 766 | |
| 1204 | 767 static const struct sized_memory_description htentry_description = { |
| 768 sizeof (htentry), | |
| 769 htentry_description_1 | |
| 814 | 770 }; |
| 771 | |
| 1204 | 772 const struct memory_description hash_table_description[] = { |
| 814 | 773 { XD_ELEMCOUNT, offsetof (Lisp_Hash_Table, size) }, |
| 2367 | 774 { XD_BLOCK_PTR, offsetof (Lisp_Hash_Table, hentries), XD_INDIRECT (0, 1), |
| 2551 | 775 { &htentry_description } }, |
| 814 | 776 { XD_LO_LINK, offsetof (Lisp_Hash_Table, next_weak) }, |
| 777 { XD_END } | |
| 778 }; | |
| 779 | |
| 780 Note that we don't need to declare all the elements in the structure, just | |
| 781 the ones that need to be relocated (Lisp_Objects and structures) or that | |
| 782 need to be referenced as counts for relocated objects. | |
| 783 | |
| 1204 | 784 A description map looks like this: |
| 785 | |
| 786 static const struct sized_memory_description specifier_extra_description_map [] = { | |
| 787 { offsetof (Lisp_Specifier, methods) }, | |
| 788 { offsetof (struct specifier_methods, extra_description) }, | |
| 789 { -1 } | |
| 790 }; | |
| 791 | |
| 792 const struct memory_description specifier_description[] = { | |
| 793 ... | |
| 2367 | 794 { XD_BLOCK_ARRAY, offset (Lisp_Specifier, data), 1, |
| 2551 | 795 { specifier_extra_description_map } }, |
| 1204 | 796 ... |
| 797 { XD_END } | |
| 798 }; | |
| 799 | |
| 800 This would be appropriate for an object that looks like this: | |
| 801 | |
| 802 struct specifier_methods | |
| 803 { | |
| 804 ... | |
| 805 const struct sized_memory_description *extra_description; | |
| 806 ... | |
| 807 }; | |
| 808 | |
| 809 struct Lisp_Specifier | |
| 810 { | |
| 3017 | 811 struct LCRECORD_HEADER header; |
| 1204 | 812 struct specifier_methods *methods; |
| 813 | |
| 814 ... | |
| 815 // type-specific extra data attached to a specifier | |
| 816 max_align_t data[1]; | |
| 817 }; | |
| 818 | |
| 819 The description map means "retrieve a pointer into the object at offset | |
| 820 `offsetof (Lisp_Specifier, methods)' , then in turn retrieve a pointer | |
| 821 into that object at offset `offsetof (struct specifier_methods, | |
| 822 extra_description)', and that is the sized_memory_description to use." | |
| 823 There can be any number of indirections, which can be either into | |
| 824 straight pointers or Lisp_Objects. The way that description maps are | |
| 825 distinguished from normal sized_memory_descriptions is that in the | |
| 826 former, the memory_description pointer is NULL. | |
| 827 | |
| 828 --ben | |
| 829 | |
| 814 | 830 |
| 831 The existing types : | |
| 832 | |
| 833 | |
| 428 | 834 XD_LISP_OBJECT |
| 1204 | 835 |
| 836 A Lisp object. This is also the type to use for pointers to other lrecords | |
| 837 (e.g. struct frame *). | |
| 428 | 838 |
| 440 | 839 XD_LISP_OBJECT_ARRAY |
| 1204 | 840 |
| 771 | 841 An array of Lisp objects or (equivalently) pointers to lrecords. |
| 842 The parameter (i.e. third element) is the count. This would be declared | |
| 843 as Lisp_Object foo[666]. For something declared as Lisp_Object *foo, | |
| 2367 | 844 use XD_BLOCK_PTR, whose description parameter is a sized_memory_description |
| 771 | 845 consisting of only XD_LISP_OBJECT and XD_END. |
| 440 | 846 |
| 428 | 847 XD_LO_LINK |
| 1204 | 848 |
| 771 | 849 Weak link in a linked list of objects of the same type. This is a |
| 850 link that does NOT generate a GC reference. Thus the pdumper will | |
| 851 not automatically add the referenced object to the table of all | |
| 852 objects to be dumped, and when storing and loading the dumped data | |
| 853 will automatically prune unreferenced objects in the chain and link | |
| 854 each referenced object to the next referenced object, even if it's | |
| 855 many links away. We also need to special handling of a similar | |
| 856 nature for the root of the chain, which will be a staticpro()ed | |
| 857 object. | |
| 432 | 858 |
| 428 | 859 XD_OPAQUE_PTR |
| 1204 | 860 |
| 428 | 861 Pointer to undumpable data. Must be NULL when dumping. |
| 862 | |
| 2551 | 863 XD_OPAQUE_PTR_CONVERTIBLE |
| 864 | |
| 865 Pointer to data which is not directly dumpable but can be converted | |
| 866 to a dumpable, opaque external representation. The parameter is | |
| 867 a pointer to an opaque_convert_functions struct. | |
| 868 | |
| 869 XD_OPAQUE_DATA_CONVERTIBLE | |
| 870 | |
| 871 Data which is not directly dumpable but can be converted to a | |
| 872 dumpable, opaque external representation. The parameter is a | |
| 873 pointer to an opaque_convert_functions struct. | |
| 874 | |
| 2367 | 875 XD_BLOCK_PTR |
| 1204 | 876 |
| 771 | 877 Pointer to block of described memory. (This is misnamed: It is NOT |
| 878 necessarily a pointer to a struct foo.) Parameters are number of | |
| 1204 | 879 contiguous blocks and sized_memory_description. |
| 771 | 880 |
| 2367 | 881 XD_BLOCK_ARRAY |
| 1204 | 882 |
| 771 | 883 Array of blocks of described memory. Parameters are number of |
| 2367 | 884 structures and sized_memory_description. This differs from XD_BLOCK_PTR |
| 771 | 885 in that the parameter is declared as struct foo[666] instead of |
| 886 struct *foo. In other words, the block of memory holding the | |
| 887 structures is within the containing structure, rather than being | |
| 888 elsewhere, with a pointer in the containing structure. | |
| 428 | 889 |
| 1204 | 890 NOTE NOTE NOTE: Be sure that you understand the difference between |
| 2367 | 891 XD_BLOCK_PTR and XD_BLOCK_ARRAY: |
| 1204 | 892 - struct foo bar[666], i.e. 666 inline struct foos |
| 2367 | 893 --> XD_BLOCK_ARRAY, argument 666, pointing to a description of |
| 1204 | 894 struct foo |
| 895 - struct foo *bar, i.e. pointer to a block of 666 struct foos | |
| 2367 | 896 --> XD_BLOCK_PTR, argument 666, pointing to a description of |
| 1204 | 897 struct foo |
| 898 - struct foo *bar[666], i.e. 666 pointers to separate blocks of struct foos | |
| 2367 | 899 --> XD_BLOCK_ARRAY, argument 666, pointing to a description of |
| 1204 | 900 a single pointer to struct foo; the description is a single |
| 2367 | 901 XD_BLOCK_PTR, argument 1, which in turn points to a description |
| 1204 | 902 of struct foo. |
| 903 | |
| 2367 | 904 NOTE also that an XD_BLOCK_PTR of 666 foos is equivalent to an |
| 905 XD_BLOCK_PTR of 1 bar, where the description of `bar' is an | |
| 906 XD_BLOCK_ARRAY of 666 foos. | |
| 907 | |
| 428 | 908 XD_OPAQUE_DATA_PTR |
| 1204 | 909 |
| 428 | 910 Pointer to dumpable opaque data. Parameter is the size of the data. |
| 911 Pointed data must be relocatable without changes. | |
| 912 | |
| 771 | 913 XD_UNION |
| 1204 | 914 |
| 915 Union of two or more different types of data. Parameters are a constant | |
| 916 which determines which type the data is (this is usually an XD_INDIRECT, | |
| 917 referring to one of the fields in the structure), and a "sizing lobby" (a | |
| 918 sized_memory_description, which points to a memory_description and | |
| 919 indicates its size). The size field in the sizing lobby describes the | |
| 920 size of the union field in the object, and the memory_description in it | |
| 921 is referred to as a "union map" and has a special interpretation: The | |
| 922 offset field is replaced by a constant, which is compared to the first | |
| 923 parameter of the XD_UNION descriptor to determine if this description | |
| 924 applies to the union data, and XD_INDIRECT references refer to the | |
| 925 containing object and description. Note that the description applies | |
| 2367 | 926 "inline" to the union data, like XD_BLOCK_ARRAY and not XD_BLOCK_PTR. |
| 1204 | 927 If the union data is a pointer to different types of structures, each |
| 2367 | 928 element in the memory_description should be an XD_BLOCK_PTR. See |
| 1204 | 929 unicode.c, redisplay.c and objects.c for examples of XD_UNION. |
| 930 | |
| 931 XD_UNION_DYNAMIC_SIZE | |
| 932 | |
| 933 Same as XD_UNION except that this is used for objects where the size of | |
| 934 the object containing the union varies depending on the particular value | |
| 935 of the union constant. That is, an object with plain XD_UNION typically | |
| 936 has the union declared as `union foo' or as `void *', where an object | |
| 937 with XD_UNION_DYNAMIC_SIZE typically has the union as the last element, | |
| 2367 | 938 and declared as something like Rawbyte foo[1]. With plain XD_UNION, the |
| 1204 | 939 object is (usually) of fixed size and always contains enough space for |
| 940 the data associated with all possible union constants, and thus the union | |
| 941 constant can potentially change during the lifetime of the object. With | |
| 942 XD_UNION_DYNAMIC_SIZE, however, the union constant is fixed at the time | |
| 943 of creation of the object, and the size of the object is computed | |
| 944 dynamically at creation time based on the size of the data associated | |
| 945 with the union constant. Currently, the only difference between XD_UNION | |
| 946 and XD_UNION_DYNAMIC_SIZE is how the size of the union data is | |
| 947 calculated, when (a) the structure containing the union has no size | |
| 948 given; (b) the union occurs as the last element in the structure; and (c) | |
| 949 the union has no size given (in the first-level sized_memory_description | |
| 950 pointed to). In this circumstance, the size of XD_UNION comes from the | |
| 951 max size of the data associated with all possible union constants, | |
| 952 whereas the size of XD_UNION_DYNAMIC_SIZE comes from the size of the data | |
| 953 associated with the currently specified (and unchangeable) union | |
| 954 constant. | |
| 771 | 955 |
| 2367 | 956 XD_ASCII_STRING |
| 1204 | 957 |
| 2367 | 958 Pointer to a C string, purely ASCII. |
| 428 | 959 |
| 960 XD_DOC_STRING | |
| 1204 | 961 |
| 2367 | 962 Pointer to a doc string (C string in pure ASCII if positive, |
| 963 opaque value if negative) | |
| 428 | 964 |
| 965 XD_INT_RESET | |
| 1204 | 966 |
| 428 | 967 An integer which will be reset to a given value in the dump file. |
| 968 | |
| 1204 | 969 XD_ELEMCOUNT |
| 771 | 970 |
| 665 | 971 Elemcount value. Used for counts. |
| 647 | 972 |
| 665 | 973 XD_BYTECOUNT |
| 1204 | 974 |
| 665 | 975 Bytecount value. Used for counts. |
| 647 | 976 |
| 665 | 977 XD_HASHCODE |
| 1204 | 978 |
| 665 | 979 Hashcode value. Used for the results of hashing functions. |
| 428 | 980 |
| 981 XD_INT | |
| 1204 | 982 |
| 428 | 983 int value. Used for counts. |
| 984 | |
| 985 XD_LONG | |
| 1204 | 986 |
| 428 | 987 long value. Used for counts. |
| 988 | |
| 771 | 989 XD_BYTECOUNT |
| 1204 | 990 |
| 771 | 991 bytecount value. Used for counts. |
| 992 | |
| 428 | 993 XD_END |
| 1204 | 994 |
| 428 | 995 Special type indicating the end of the array. |
| 996 | |
| 997 | |
| 998 Special macros: | |
| 1204 | 999 |
| 1000 XD_INDIRECT (line, delta) | |
| 1001 Usable where a count, size, offset or union constant is requested. Gives | |
| 1002 the value of the element which is at line number 'line' in the | |
| 1003 description (count starts at zero) and adds delta to it, which must | |
| 1004 (currently) be positive. | |
| 428 | 1005 */ |
| 1006 | |
| 1204 | 1007 enum memory_description_type |
| 647 | 1008 { |
| 440 | 1009 XD_LISP_OBJECT_ARRAY, |
| 428 | 1010 XD_LISP_OBJECT, |
| 3092 | 1011 #ifdef NEW_GC |
| 1012 XD_LISP_OBJECT_BLOCK_PTR, | |
| 1013 #endif /* NEW_GC */ | |
| 428 | 1014 XD_LO_LINK, |
| 1015 XD_OPAQUE_PTR, | |
| 2551 | 1016 XD_OPAQUE_PTR_CONVERTIBLE, |
| 1017 XD_OPAQUE_DATA_CONVERTIBLE, | |
| 1018 XD_OPAQUE_DATA_PTR, | |
| 2367 | 1019 XD_BLOCK_PTR, |
| 1020 XD_BLOCK_ARRAY, | |
| 771 | 1021 XD_UNION, |
| 1204 | 1022 XD_UNION_DYNAMIC_SIZE, |
| 2367 | 1023 XD_ASCII_STRING, |
| 428 | 1024 XD_DOC_STRING, |
| 1025 XD_INT_RESET, | |
| 665 | 1026 XD_BYTECOUNT, |
| 1027 XD_ELEMCOUNT, | |
| 1028 XD_HASHCODE, | |
| 428 | 1029 XD_INT, |
| 1030 XD_LONG, | |
| 1204 | 1031 XD_END |
| 428 | 1032 }; |
| 1033 | |
| 1204 | 1034 enum data_description_entry_flags |
| 647 | 1035 { |
| 1204 | 1036 /* If set, KKCC does not process this entry. |
| 1037 | |
| 1038 (1) One obvious use is with things that pdump saves but which do not get | |
| 1039 marked normally -- for example the next and prev fields in a marker. The | |
| 1040 marker chain is weak, with its entries removed when they are finalized. | |
| 1041 | |
| 1042 (2) This can be set on structures not containing any Lisp objects, or (more | |
| 1043 usefully) on structures that contain Lisp objects but where the objects | |
| 1044 always occur in another structure as well. For example, the extent lists | |
| 1045 kept by a buffer keep the extents in two lists, one sorted by the start | |
| 1046 of the extent and the other by the end. There's no point in marking | |
| 1047 both, since each contains the same objects as the other; but when dumping | |
| 1048 (if we were to dump such a structure), when computing memory size, etc., | |
| 1049 it's crucial to tag both sides. | |
| 1050 */ | |
| 1051 XD_FLAG_NO_KKCC = 1, | |
| 1052 /* If set, pdump does not process this entry. */ | |
| 1053 XD_FLAG_NO_PDUMP = 2, | |
| 1054 /* Indicates that this is a "default" entry in a union map. */ | |
| 1055 XD_FLAG_UNION_DEFAULT_ENTRY = 4, | |
| 3263 | 1056 #ifndef NEW_GC |
| 1204 | 1057 /* Indicates that this is a free Lisp object we're marking. |
| 1058 Only relevant for ERROR_CHECK_GC. This occurs when we're marking | |
| 1059 lcrecord-lists, where the objects have had their type changed to | |
| 1060 lrecord_type_free and also have had their free bit set, but we mark | |
| 1061 them as normal. */ | |
| 1429 | 1062 XD_FLAG_FREE_LISP_OBJECT = 8 |
| 3263 | 1063 #endif /* not NEW_GC */ |
| 1204 | 1064 #if 0 |
| 1429 | 1065 , |
| 1204 | 1066 /* Suggestions for other possible flags: */ |
| 1067 | |
| 1068 /* Eliminate XD_UNION_DYNAMIC_SIZE and replace it with a flag, like this. */ | |
| 1069 XD_FLAG_UNION_DYNAMIC_SIZE = 16, | |
| 1070 /* Require that everyone who uses a description map has to flag it, so | |
| 1071 that it's easy to tell, when looking through the code, where the | |
| 1072 description maps are and who's using them. This might also become | |
| 1073 necessary if for some reason the format of the description map is | |
| 1074 expanded and we need to stick a pointer in the second slot (although | |
| 1075 we could still ensure that the second slot in the first entry was NULL | |
| 1076 or <0). */ | |
| 1429 | 1077 XD_FLAG_DESCRIPTION_MAP = 32 |
| 1204 | 1078 #endif |
| 428 | 1079 }; |
| 1080 | |
| 2551 | 1081 union memory_contents_description |
| 1082 { | |
| 1083 /* The first element is used by static initializers only. We always read | |
| 1084 from one of the other two pointers. */ | |
| 1085 const void *write_only; | |
| 1086 const struct sized_memory_description *descr; | |
| 1087 const struct opaque_convert_functions *funcs; | |
| 1088 }; | |
| 1089 | |
| 1204 | 1090 struct memory_description |
| 1091 { | |
| 1092 enum memory_description_type type; | |
| 1093 Bytecount offset; | |
| 1094 EMACS_INT data1; | |
| 2551 | 1095 union memory_contents_description data2; |
| 1204 | 1096 /* Indicates which subsystems process this entry, plus (potentially) other |
| 1097 flags that apply to this entry. */ | |
| 1098 int flags; | |
| 1099 }; | |
| 428 | 1100 |
| 1204 | 1101 struct sized_memory_description |
| 1102 { | |
| 1103 Bytecount size; | |
| 1104 const struct memory_description *description; | |
| 1105 }; | |
| 1106 | |
| 2551 | 1107 |
| 1108 struct opaque_convert_functions | |
| 1109 { | |
| 1110 /* Used by XD_OPAQUE_PTR_CONVERTIBLE and | |
| 1111 XD_OPAQUE_DATA_CONVERTIBLE */ | |
| 1112 | |
| 1113 /* Converter to external representation, for those objects from | |
| 1114 external libraries that can't be directly dumped as opaque data | |
| 1115 because they contain pointers. This is called at dump time to | |
| 1116 convert to an opaque, pointer-less representation. | |
| 1117 | |
| 1118 This function must put a pointer to the opaque result in *data | |
| 1119 and its size in *size. */ | |
| 1120 void (*convert)(const void *object, void **data, Bytecount *size); | |
| 1121 | |
| 1122 /* Post-conversion cleanup. Optional (null if not provided). | |
| 1123 | |
| 1124 When provided it will be called post-dumping to free any storage | |
| 1125 allocated for the conversion results. */ | |
| 1126 void (*convert_free)(const void *object, void *data, Bytecount size); | |
| 1127 | |
| 1128 /* De-conversion. | |
| 1129 | |
| 1130 At reload time, rebuilds the object from the converted form. | |
| 1131 "object" is 0 for the PTR case, return is ignored in the DATA | |
| 1132 case. */ | |
| 1133 void *(*deconvert)(void *object, void *data, Bytecount size); | |
| 1134 | |
| 1135 }; | |
| 1136 | |
| 1204 | 1137 extern const struct sized_memory_description lisp_object_description; |
| 1138 | |
| 1139 #define XD_INDIRECT(val, delta) (-1 - (Bytecount) ((val) | ((delta) << 8))) | |
| 428 | 1140 |
| 1204 | 1141 #define XD_IS_INDIRECT(code) ((code) < 0) |
| 1142 #define XD_INDIRECT_VAL(code) ((-1 - (code)) & 255) | |
| 1143 #define XD_INDIRECT_DELTA(code) ((-1 - (code)) >> 8) | |
| 1144 | |
|
4936
94bba904528c
(for main branch) Also reset dynarr->largest value during pdump.
Ben Wing <ben@xemacs.org>
parents:
4930
diff
changeset
|
1145 #define XD_DYNARR_DESC(base_type, sub_desc) \ |
|
94bba904528c
(for main branch) Also reset dynarr->largest value during pdump.
Ben Wing <ben@xemacs.org>
parents:
4930
diff
changeset
|
1146 { XD_BLOCK_PTR, offsetof (base_type, base), \ |
|
94bba904528c
(for main branch) Also reset dynarr->largest value during pdump.
Ben Wing <ben@xemacs.org>
parents:
4930
diff
changeset
|
1147 XD_INDIRECT(1, 0), {sub_desc} }, \ |
|
94bba904528c
(for main branch) Also reset dynarr->largest value during pdump.
Ben Wing <ben@xemacs.org>
parents:
4930
diff
changeset
|
1148 { XD_INT, offsetof (base_type, len) }, \ |
|
4937
195ceb7d6229
(for main branch) Proper fix for dynarr->largest value assertion failure.
Ben Wing <ben@xemacs.org>
parents:
4936
diff
changeset
|
1149 { XD_INT_RESET, offsetof (base_type, largest), XD_INDIRECT(1, 0) }, \ |
|
4936
94bba904528c
(for main branch) Also reset dynarr->largest value during pdump.
Ben Wing <ben@xemacs.org>
parents:
4930
diff
changeset
|
1150 { XD_INT_RESET, offsetof (base_type, max), XD_INDIRECT(1, 0) } |
| 1204 | 1151 |
| 3092 | 1152 #ifdef NEW_GC |
| 1153 #define XD_LISP_DYNARR_DESC(base_type, sub_desc) \ | |
| 1154 { XD_LISP_OBJECT_BLOCK_PTR, offsetof (base_type, base), \ | |
| 1155 XD_INDIRECT(1, 0), {sub_desc} }, \ | |
|
4844
91b3d00e717f
Various cleanups for Dynarr code, from Unicode-internal ws
Ben Wing <ben@xemacs.org>
parents:
4677
diff
changeset
|
1156 { XD_INT, offsetof (base_type, len) }, \ |
|
4937
195ceb7d6229
(for main branch) Proper fix for dynarr->largest value assertion failure.
Ben Wing <ben@xemacs.org>
parents:
4936
diff
changeset
|
1157 { XD_INT_RESET, offsetof (base_type, largest), XD_INDIRECT(1, 0) }, \ |
| 3092 | 1158 { XD_INT_RESET, offsetof (base_type, max), XD_INDIRECT(1, 0) } |
|
4936
94bba904528c
(for main branch) Also reset dynarr->largest value during pdump.
Ben Wing <ben@xemacs.org>
parents:
4930
diff
changeset
|
1159 #endif /* NEW_GC */ |
| 3092 | 1160 |
| 428 | 1161 /* DEFINE_LRECORD_IMPLEMENTATION is for objects with constant size. |
| 1162 DEFINE_LRECORD_SEQUENCE_IMPLEMENTATION is for objects whose size varies. | |
| 1163 */ | |
| 1164 | |
| 800 | 1165 #if defined (ERROR_CHECK_TYPES) |
| 1166 # define DECLARE_ERROR_CHECK_TYPES(c_name, structtype) | |
| 428 | 1167 #else |
| 800 | 1168 # define DECLARE_ERROR_CHECK_TYPES(c_name, structtype) |
| 428 | 1169 #endif |
| 1170 | |
| 934 | 1171 |
| 1172 #define DEFINE_BASIC_LRECORD_IMPLEMENTATION(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,structtype) \ | |
| 1173 DEFINE_BASIC_LRECORD_IMPLEMENTATION_WITH_PROPS(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,0,0,0,0,structtype) | |
| 1174 | |
| 1175 #define DEFINE_BASIC_LRECORD_IMPLEMENTATION_WITH_PROPS(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,structtype) \ | |
| 1176 MAKE_LRECORD_IMPLEMENTATION(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,sizeof(structtype),0,1,structtype) | |
| 1177 | |
| 1178 #define DEFINE_LRECORD_IMPLEMENTATION(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,structtype) \ | |
| 1179 DEFINE_LRECORD_IMPLEMENTATION_WITH_PROPS(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,0,0,0,0,structtype) | |
| 1180 | |
| 1181 #define DEFINE_LRECORD_IMPLEMENTATION_WITH_PROPS(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,structtype) \ | |
| 1182 MAKE_LRECORD_IMPLEMENTATION(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,sizeof (structtype),0,0,structtype) | |
| 1183 | |
| 1184 #define DEFINE_LRECORD_SEQUENCE_IMPLEMENTATION(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,sizer,structtype) \ | |
| 1185 DEFINE_LRECORD_SEQUENCE_IMPLEMENTATION_WITH_PROPS(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,0,0,0,0,sizer,structtype) | |
| 1186 | |
| 1187 #define DEFINE_BASIC_LRECORD_SEQUENCE_IMPLEMENTATION(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,sizer,structtype) \ | |
| 1188 MAKE_LRECORD_IMPLEMENTATION(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,0,0,0,0,0,sizer,1,structtype) | |
| 1189 | |
| 1190 #define DEFINE_LRECORD_SEQUENCE_IMPLEMENTATION_WITH_PROPS(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,sizer,structtype) \ | |
| 1191 MAKE_LRECORD_IMPLEMENTATION(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,0,sizer,0,structtype) | |
| 1192 | |
| 3263 | 1193 #ifdef NEW_GC |
| 2720 | 1194 #define MAKE_LRECORD_IMPLEMENTATION(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,size,sizer,basic_p,structtype) \ |
| 1195 DECLARE_ERROR_CHECK_TYPES(c_name, structtype) \ | |
| 1196 const struct lrecord_implementation lrecord_##c_name = \ | |
| 1197 { name, dumpable, marker, printer, nuker, equal, hash, desc, \ | |
| 1198 getprop, putprop, remprop, plist, size, sizer, \ | |
| 1199 lrecord_type_##c_name } | |
| 3263 | 1200 #else /* not NEW_GC */ |
| 934 | 1201 #define MAKE_LRECORD_IMPLEMENTATION(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,size,sizer,basic_p,structtype) \ |
| 1204 | 1202 DECLARE_ERROR_CHECK_TYPES(c_name, structtype) \ |
| 934 | 1203 const struct lrecord_implementation lrecord_##c_name = \ |
| 1204 { name, dumpable, marker, printer, nuker, equal, hash, desc, \ | |
| 1205 getprop, putprop, remprop, plist, size, sizer, \ | |
| 1206 lrecord_type_##c_name, basic_p } | |
| 3263 | 1207 #endif /* not NEW_GC */ |
| 934 | 1208 |
| 1209 #define DEFINE_EXTERNAL_LRECORD_IMPLEMENTATION(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,structtype) \ | |
| 1210 DEFINE_EXTERNAL_LRECORD_IMPLEMENTATION_WITH_PROPS(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,0,0,0,0,structtype) | |
| 1211 | |
| 1212 #define DEFINE_EXTERNAL_LRECORD_IMPLEMENTATION_WITH_PROPS(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,structtype) \ | |
| 1213 MAKE_EXTERNAL_LRECORD_IMPLEMENTATION(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,sizeof (structtype),0,0,structtype) | |
| 1214 | |
| 1215 #define DEFINE_EXTERNAL_LRECORD_SEQUENCE_IMPLEMENTATION(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,sizer,structtype) \ | |
| 1216 DEFINE_EXTERNAL_LRECORD_SEQUENCE_IMPLEMENTATION_WITH_PROPS(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,0,0,0,0,sizer,structtype) | |
| 1217 | |
| 1218 #define DEFINE_EXTERNAL_LRECORD_SEQUENCE_IMPLEMENTATION_WITH_PROPS(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,sizer,structtype) \ | |
| 1219 MAKE_EXTERNAL_LRECORD_IMPLEMENTATION(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,0,sizer,0,structtype) | |
| 1220 | |
| 3263 | 1221 #ifdef NEW_GC |
| 2720 | 1222 #define MAKE_EXTERNAL_LRECORD_IMPLEMENTATION(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,size,sizer,basic_p,structtype) \ |
| 1223 DECLARE_ERROR_CHECK_TYPES(c_name, structtype) \ | |
| 1224 int lrecord_type_##c_name; \ | |
| 1225 struct lrecord_implementation lrecord_##c_name = \ | |
| 1226 { name, dumpable, marker, printer, nuker, equal, hash, desc, \ | |
| 1227 getprop, putprop, remprop, plist, size, sizer, \ | |
| 1228 lrecord_type_last_built_in_type } | |
| 3263 | 1229 #else /* not NEW_GC */ |
| 934 | 1230 #define MAKE_EXTERNAL_LRECORD_IMPLEMENTATION(name,c_name,dumpable,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,size,sizer,basic_p,structtype) \ |
| 1204 | 1231 DECLARE_ERROR_CHECK_TYPES(c_name, structtype) \ |
| 934 | 1232 int lrecord_type_##c_name; \ |
| 1233 struct lrecord_implementation lrecord_##c_name = \ | |
| 1234 { name, dumpable, marker, printer, nuker, equal, hash, desc, \ | |
| 1235 getprop, putprop, remprop, plist, size, sizer, \ | |
| 1236 lrecord_type_last_built_in_type, basic_p } | |
| 3263 | 1237 #endif /* not NEW_GC */ |
| 934 | 1238 |
| 1676 | 1239 #ifdef USE_KKCC |
| 1240 extern MODULE_API const struct memory_description *lrecord_memory_descriptions[]; | |
| 1241 | |
| 1242 #define INIT_LRECORD_IMPLEMENTATION(type) do { \ | |
| 1243 lrecord_implementations_table[lrecord_type_##type] = &lrecord_##type; \ | |
| 1244 lrecord_memory_descriptions[lrecord_type_##type] = \ | |
| 1245 lrecord_implementations_table[lrecord_type_##type]->description; \ | |
| 1246 } while (0) | |
| 1247 #else /* not USE_KKCC */ | |
| 1632 | 1248 extern MODULE_API Lisp_Object (*lrecord_markers[]) (Lisp_Object); |
| 442 | 1249 |
| 1250 #define INIT_LRECORD_IMPLEMENTATION(type) do { \ | |
| 1251 lrecord_implementations_table[lrecord_type_##type] = &lrecord_##type; \ | |
| 1252 lrecord_markers[lrecord_type_##type] = \ | |
| 1253 lrecord_implementations_table[lrecord_type_##type]->marker; \ | |
| 1254 } while (0) | |
| 1676 | 1255 #endif /* not USE_KKCC */ |
| 428 | 1256 |
| 444 | 1257 #define INIT_EXTERNAL_LRECORD_IMPLEMENTATION(type) do { \ |
| 1258 lrecord_type_##type = lrecord_type_count++; \ | |
| 1259 lrecord_##type.lrecord_type_index = lrecord_type_##type; \ | |
| 1260 INIT_LRECORD_IMPLEMENTATION(type); \ | |
| 1261 } while (0) | |
| 1262 | |
| 996 | 1263 #ifdef HAVE_SHLIB |
| 1264 /* Allow undefining types in order to support module unloading. */ | |
| 1265 | |
| 1676 | 1266 #ifdef USE_KKCC |
| 1267 #define UNDEF_LRECORD_IMPLEMENTATION(type) do { \ | |
| 1268 lrecord_implementations_table[lrecord_type_##type] = NULL; \ | |
| 1269 lrecord_memory_descriptions[lrecord_type_##type] = NULL; \ | |
| 1270 } while (0) | |
| 1271 #else /* not USE_KKCC */ | |
| 996 | 1272 #define UNDEF_LRECORD_IMPLEMENTATION(type) do { \ |
| 1273 lrecord_implementations_table[lrecord_type_##type] = NULL; \ | |
| 1274 lrecord_markers[lrecord_type_##type] = NULL; \ | |
| 1275 } while (0) | |
| 1676 | 1276 #endif /* not USE_KKCC */ |
| 996 | 1277 |
| 1278 #define UNDEF_EXTERNAL_LRECORD_IMPLEMENTATION(type) do { \ | |
| 1279 if (lrecord_##type.lrecord_type_index == lrecord_type_count - 1) { \ | |
| 1280 /* This is the most recently defined type. Clean up nicely. */ \ | |
| 1281 lrecord_type_##type = lrecord_type_count--; \ | |
| 1282 } /* Else we can't help leaving a hole with this implementation. */ \ | |
| 1283 UNDEF_LRECORD_IMPLEMENTATION(type); \ | |
| 1284 } while (0) | |
| 1285 | |
| 1286 #endif /* HAVE_SHLIB */ | |
| 1287 | |
| 428 | 1288 #define LRECORDP(a) (XTYPE (a) == Lisp_Type_Record) |
| 1289 #define XRECORD_LHEADER(a) ((struct lrecord_header *) XPNTR (a)) | |
| 1290 | |
| 1291 #define RECORD_TYPEP(x, ty) \ | |
| 647 | 1292 (LRECORDP (x) && (XRECORD_LHEADER (x)->type == (unsigned int) (ty))) |
| 442 | 1293 |
| 1294 /* Steps to create a new object: | |
| 1295 | |
| 1296 1. Declare the struct for your object in a header file somewhere. | |
| 1297 Remember that it must begin with | |
| 1298 | |
| 3017 | 1299 struct LCRECORD_HEADER header; |
| 442 | 1300 |
| 793 | 1301 2. Put the "standard junk" (DECLARE_RECORD()/XFOO/etc.) below the |
| 617 | 1302 struct definition -- see below. |
| 442 | 1303 |
| 1304 3. Add this header file to inline.c. | |
| 1305 | |
| 1306 4. Create the methods for your object. Note that technically you don't | |
| 1307 need any, but you will almost always want at least a mark method. | |
| 1308 | |
| 1204 | 1309 4. Create the data layout description for your object. See |
| 1310 toolbar_button_description below; the comment above in `struct lrecord', | |
| 1311 describing the purpose of the descriptions; and comments elsewhere in | |
| 1312 this file describing the exact syntax of the description structures. | |
| 1313 | |
| 1314 6. Define your object with DEFINE_LRECORD_IMPLEMENTATION() or some | |
| 442 | 1315 variant. |
| 1316 | |
| 1204 | 1317 7. Include the header file in the .c file where you defined the object. |
| 442 | 1318 |
| 1204 | 1319 8. Put a call to INIT_LRECORD_IMPLEMENTATION() for the object in the |
| 442 | 1320 .c file's syms_of_foo() function. |
| 1321 | |
| 1204 | 1322 9. Add a type enum for the object to enum lrecord_type, earlier in this |
| 442 | 1323 file. |
| 1324 | |
| 1204 | 1325 --ben |
| 1326 | |
| 442 | 1327 An example: |
| 428 | 1328 |
| 442 | 1329 ------------------------------ in toolbar.h ----------------------------- |
| 1330 | |
| 1331 struct toolbar_button | |
| 1332 { | |
| 3017 | 1333 struct LCRECORD_HEADER header; |
| 442 | 1334 |
| 1335 Lisp_Object next; | |
| 1336 Lisp_Object frame; | |
| 1337 | |
| 1338 Lisp_Object up_glyph; | |
| 1339 Lisp_Object down_glyph; | |
| 1340 Lisp_Object disabled_glyph; | |
| 1341 | |
| 1342 Lisp_Object cap_up_glyph; | |
| 1343 Lisp_Object cap_down_glyph; | |
| 1344 Lisp_Object cap_disabled_glyph; | |
| 1345 | |
| 1346 Lisp_Object callback; | |
| 1347 Lisp_Object enabled_p; | |
| 1348 Lisp_Object help_string; | |
| 1349 | |
| 1350 char enabled; | |
| 1351 char down; | |
| 1352 char pushright; | |
| 1353 char blank; | |
| 1354 | |
| 1355 int x, y; | |
| 1356 int width, height; | |
| 1357 int dirty; | |
| 1358 int vertical; | |
| 1359 int border_width; | |
| 1360 }; | |
| 428 | 1361 |
| 617 | 1362 [[ the standard junk: ]] |
| 1363 | |
| 442 | 1364 DECLARE_LRECORD (toolbar_button, struct toolbar_button); |
| 1365 #define XTOOLBAR_BUTTON(x) XRECORD (x, toolbar_button, struct toolbar_button) | |
| 617 | 1366 #define wrap_toolbar_button(p) wrap_record (p, toolbar_button) |
| 442 | 1367 #define TOOLBAR_BUTTONP(x) RECORDP (x, toolbar_button) |
| 1368 #define CHECK_TOOLBAR_BUTTON(x) CHECK_RECORD (x, toolbar_button) | |
| 1369 #define CONCHECK_TOOLBAR_BUTTON(x) CONCHECK_RECORD (x, toolbar_button) | |
| 1370 | |
| 1371 ------------------------------ in toolbar.c ----------------------------- | |
| 1372 | |
| 1373 #include "toolbar.h" | |
| 1374 | |
| 1375 ... | |
| 1376 | |
| 1204 | 1377 static const struct memory_description toolbar_button_description [] = { |
| 1378 { XD_LISP_OBJECT, offsetof (struct toolbar_button, next) }, | |
| 1379 { XD_LISP_OBJECT, offsetof (struct toolbar_button, frame) }, | |
| 1380 { XD_LISP_OBJECT, offsetof (struct toolbar_button, up_glyph) }, | |
| 1381 { XD_LISP_OBJECT, offsetof (struct toolbar_button, down_glyph) }, | |
| 1382 { XD_LISP_OBJECT, offsetof (struct toolbar_button, disabled_glyph) }, | |
| 1383 { XD_LISP_OBJECT, offsetof (struct toolbar_button, cap_up_glyph) }, | |
| 1384 { XD_LISP_OBJECT, offsetof (struct toolbar_button, cap_down_glyph) }, | |
| 1385 { XD_LISP_OBJECT, offsetof (struct toolbar_button, cap_disabled_glyph) }, | |
| 1386 { XD_LISP_OBJECT, offsetof (struct toolbar_button, callback) }, | |
| 1387 { XD_LISP_OBJECT, offsetof (struct toolbar_button, enabled_p) }, | |
| 1388 { XD_LISP_OBJECT, offsetof (struct toolbar_button, help_string) }, | |
| 1389 { XD_END } | |
| 1390 }; | |
| 1391 | |
| 442 | 1392 static Lisp_Object |
| 1393 mark_toolbar_button (Lisp_Object obj) | |
| 1204 | 1394 \{ |
| 442 | 1395 struct toolbar_button *data = XTOOLBAR_BUTTON (obj); |
| 1396 mark_object (data->next); | |
| 1397 mark_object (data->frame); | |
| 1398 mark_object (data->up_glyph); | |
| 1399 mark_object (data->down_glyph); | |
| 1400 mark_object (data->disabled_glyph); | |
| 1401 mark_object (data->cap_up_glyph); | |
| 1402 mark_object (data->cap_down_glyph); | |
| 1403 mark_object (data->cap_disabled_glyph); | |
| 1404 mark_object (data->callback); | |
| 1405 mark_object (data->enabled_p); | |
| 1406 return data->help_string; | |
| 1407 } | |
| 1408 | |
| 617 | 1409 [[ If your object should never escape to Lisp, declare its print method |
| 1410 as internal_object_printer instead of 0. ]] | |
| 1411 | |
| 442 | 1412 DEFINE_LRECORD_IMPLEMENTATION ("toolbar-button", toolbar_button, |
| 1204 | 1413 0, mark_toolbar_button, 0, 0, 0, 0, |
| 1414 toolbar_button_description, | |
| 1415 struct toolbar_button); | |
| 442 | 1416 |
| 1417 ... | |
| 1418 | |
| 1419 void | |
| 1420 syms_of_toolbar (void) | |
| 1421 { | |
| 1422 INIT_LRECORD_IMPLEMENTATION (toolbar_button); | |
| 1423 | |
| 1424 ...; | |
| 1425 } | |
| 1426 | |
| 1427 ------------------------------ in inline.c ----------------------------- | |
| 1428 | |
| 1429 #ifdef HAVE_TOOLBARS | |
| 1430 #include "toolbar.h" | |
| 1431 #endif | |
| 1432 | |
| 1433 ------------------------------ in lrecord.h ----------------------------- | |
| 1434 | |
| 1435 enum lrecord_type | |
| 1436 { | |
| 1437 ... | |
| 1438 lrecord_type_toolbar_button, | |
| 1439 ... | |
| 1440 }; | |
| 1441 | |
| 1204 | 1442 |
| 1443 --ben | |
| 1444 | |
| 442 | 1445 */ |
| 1446 | |
| 1447 /* | |
| 1448 | |
| 1449 Note: Object types defined in external dynamically-loaded modules (not | |
| 1450 part of the XEmacs main source code) should use DECLARE_EXTERNAL_LRECORD | |
| 1451 and DEFINE_EXTERNAL_LRECORD_IMPLEMENTATION rather than DECLARE_LRECORD | |
| 3029 | 1452 and DEFINE_LRECORD_IMPLEMENTATION. The EXTERNAL versions declare and |
| 1453 allocate an enumerator for the type being defined. | |
| 442 | 1454 |
| 1455 */ | |
| 1456 | |
| 428 | 1457 |
| 800 | 1458 #ifdef ERROR_CHECK_TYPES |
| 428 | 1459 |
| 788 | 1460 # define DECLARE_LRECORD(c_name, structtype) \ |
| 1461 extern const struct lrecord_implementation lrecord_##c_name; \ | |
| 826 | 1462 DECLARE_INLINE_HEADER ( \ |
| 1463 structtype * \ | |
| 2367 | 1464 error_check_##c_name (Lisp_Object obj, const Ascbyte *file, int line) \ |
| 826 | 1465 ) \ |
| 788 | 1466 { \ |
| 1467 assert_at_line (RECORD_TYPEP (obj, lrecord_type_##c_name), file, line); \ | |
| 1468 return (structtype *) XPNTR (obj); \ | |
| 1469 } \ | |
| 428 | 1470 extern Lisp_Object Q##c_name##p |
| 1471 | |
| 1632 | 1472 # define DECLARE_MODULE_API_LRECORD(c_name, structtype) \ |
| 1473 extern MODULE_API const struct lrecord_implementation lrecord_##c_name; \ | |
| 1474 DECLARE_INLINE_HEADER ( \ | |
| 1475 structtype * \ | |
| 2367 | 1476 error_check_##c_name (Lisp_Object obj, const Ascbyte *file, int line) \ |
| 1632 | 1477 ) \ |
| 1478 { \ | |
| 1479 assert_at_line (RECORD_TYPEP (obj, lrecord_type_##c_name), file, line); \ | |
| 1480 return (structtype *) XPNTR (obj); \ | |
| 1481 } \ | |
| 1482 extern MODULE_API Lisp_Object Q##c_name##p | |
| 1483 | |
| 788 | 1484 # define DECLARE_EXTERNAL_LRECORD(c_name, structtype) \ |
| 1485 extern int lrecord_type_##c_name; \ | |
| 1486 extern struct lrecord_implementation lrecord_##c_name; \ | |
| 826 | 1487 DECLARE_INLINE_HEADER ( \ |
| 1488 structtype * \ | |
| 2367 | 1489 error_check_##c_name (Lisp_Object obj, const Ascbyte *file, int line) \ |
| 826 | 1490 ) \ |
| 788 | 1491 { \ |
| 1492 assert_at_line (RECORD_TYPEP (obj, lrecord_type_##c_name), file, line); \ | |
| 1493 return (structtype *) XPNTR (obj); \ | |
| 1494 } \ | |
| 444 | 1495 extern Lisp_Object Q##c_name##p |
| 442 | 1496 |
| 788 | 1497 # define DECLARE_NONRECORD(c_name, type_enum, structtype) \ |
| 826 | 1498 DECLARE_INLINE_HEADER ( \ |
| 1499 structtype * \ | |
| 2367 | 1500 error_check_##c_name (Lisp_Object obj, const Ascbyte *file, int line) \ |
| 826 | 1501 ) \ |
| 788 | 1502 { \ |
| 1503 assert_at_line (XTYPE (obj) == type_enum, file, line); \ | |
| 1504 return (structtype *) XPNTR (obj); \ | |
| 1505 } \ | |
| 428 | 1506 extern Lisp_Object Q##c_name##p |
| 1507 | |
| 788 | 1508 # define XRECORD(x, c_name, structtype) \ |
| 1509 error_check_##c_name (x, __FILE__, __LINE__) | |
| 1510 # define XNONRECORD(x, c_name, type_enum, structtype) \ | |
| 1511 error_check_##c_name (x, __FILE__, __LINE__) | |
| 428 | 1512 |
| 826 | 1513 DECLARE_INLINE_HEADER ( |
| 1514 Lisp_Object | |
| 2367 | 1515 wrap_record_1 (const void *ptr, enum lrecord_type ty, const Ascbyte *file, |
| 800 | 1516 int line) |
| 826 | 1517 ) |
| 617 | 1518 { |
| 793 | 1519 Lisp_Object obj = wrap_pointer_1 (ptr); |
| 1520 | |
| 788 | 1521 assert_at_line (RECORD_TYPEP (obj, ty), file, line); |
| 617 | 1522 return obj; |
| 1523 } | |
| 1524 | |
| 788 | 1525 #define wrap_record(ptr, ty) \ |
| 1526 wrap_record_1 (ptr, lrecord_type_##ty, __FILE__, __LINE__) | |
| 617 | 1527 |
| 800 | 1528 #else /* not ERROR_CHECK_TYPES */ |
| 428 | 1529 |
| 1530 # define DECLARE_LRECORD(c_name, structtype) \ | |
| 1531 extern Lisp_Object Q##c_name##p; \ | |
| 442 | 1532 extern const struct lrecord_implementation lrecord_##c_name |
| 1638 | 1533 # define DECLARE_MODULE_API_LRECORD(c_name, structtype) \ |
| 1534 extern MODULE_API Lisp_Object Q##c_name##p; \ | |
| 1535 extern MODULE_API const struct lrecord_implementation lrecord_##c_name | |
| 442 | 1536 # define DECLARE_EXTERNAL_LRECORD(c_name, structtype) \ |
| 1537 extern Lisp_Object Q##c_name##p; \ | |
| 647 | 1538 extern int lrecord_type_##c_name; \ |
| 444 | 1539 extern struct lrecord_implementation lrecord_##c_name |
| 428 | 1540 # define DECLARE_NONRECORD(c_name, type_enum, structtype) \ |
| 1541 extern Lisp_Object Q##c_name##p | |
| 1542 # define XRECORD(x, c_name, structtype) ((structtype *) XPNTR (x)) | |
| 1543 # define XNONRECORD(x, c_name, type_enum, structtype) \ | |
| 1544 ((structtype *) XPNTR (x)) | |
| 617 | 1545 /* wrap_pointer_1 is so named as a suggestion not to use it unless you |
| 1546 know what you're doing. */ | |
| 1547 #define wrap_record(ptr, ty) wrap_pointer_1 (ptr) | |
| 428 | 1548 |
| 800 | 1549 #endif /* not ERROR_CHECK_TYPES */ |
| 428 | 1550 |
| 442 | 1551 #define RECORDP(x, c_name) RECORD_TYPEP (x, lrecord_type_##c_name) |
| 428 | 1552 |
| 1553 /* Note: we now have two different kinds of type-checking macros. | |
| 1554 The "old" kind has now been renamed CONCHECK_foo. The reason for | |
| 1555 this is that the CONCHECK_foo macros signal a continuable error, | |
| 1556 allowing the user (through debug-on-error) to substitute a different | |
| 1557 value and return from the signal, which causes the lvalue argument | |
| 1558 to get changed. Quite a lot of code would crash if that happened, | |
| 1559 because it did things like | |
| 1560 | |
| 1561 foo = XCAR (list); | |
| 1562 CHECK_STRING (foo); | |
| 1563 | |
| 1564 and later on did XSTRING (XCAR (list)), assuming that the type | |
| 1565 is correct (when it might be wrong, if the user substituted a | |
| 1566 correct value in the debugger). | |
| 1567 | |
| 1568 To get around this, I made all the CHECK_foo macros signal a | |
| 1569 non-continuable error. Places where a continuable error is OK | |
| 1570 (generally only when called directly on the argument of a Lisp | |
| 1571 primitive) should be changed to use CONCHECK(). | |
| 1572 | |
| 1573 FSF Emacs does not have this problem because RMS took the cheesy | |
| 1574 way out and disabled returning from a signal entirely. */ | |
| 1575 | |
| 1576 #define CONCHECK_RECORD(x, c_name) do { \ | |
| 442 | 1577 if (!RECORD_TYPEP (x, lrecord_type_##c_name)) \ |
| 428 | 1578 x = wrong_type_argument (Q##c_name##p, x); \ |
| 1579 } while (0) | |
| 1580 #define CONCHECK_NONRECORD(x, lisp_enum, predicate) do {\ | |
| 1581 if (XTYPE (x) != lisp_enum) \ | |
| 1582 x = wrong_type_argument (predicate, x); \ | |
| 1583 } while (0) | |
| 1584 #define CHECK_RECORD(x, c_name) do { \ | |
| 442 | 1585 if (!RECORD_TYPEP (x, lrecord_type_##c_name)) \ |
| 428 | 1586 dead_wrong_type_argument (Q##c_name##p, x); \ |
| 1587 } while (0) | |
| 1588 #define CHECK_NONRECORD(x, lisp_enum, predicate) do { \ | |
| 1589 if (XTYPE (x) != lisp_enum) \ | |
| 1590 dead_wrong_type_argument (predicate, x); \ | |
| 1591 } while (0) | |
| 1592 | |
| 3263 | 1593 #ifndef NEW_GC |
| 1204 | 1594 /*-------------------------- lcrecord-list -----------------------------*/ |
| 1595 | |
| 1596 struct lcrecord_list | |
| 1597 { | |
| 3024 | 1598 struct LCRECORD_HEADER header; |
| 1204 | 1599 Lisp_Object free; |
| 1600 Elemcount size; | |
| 1601 const struct lrecord_implementation *implementation; | |
| 1602 }; | |
| 1603 | |
| 1604 DECLARE_LRECORD (lcrecord_list, struct lcrecord_list); | |
| 1605 #define XLCRECORD_LIST(x) XRECORD (x, lcrecord_list, struct lcrecord_list) | |
| 1606 #define wrap_lcrecord_list(p) wrap_record (p, lcrecord_list) | |
| 1607 #define LCRECORD_LISTP(x) RECORDP (x, lcrecord_list) | |
| 1608 /* #define CHECK_LCRECORD_LIST(x) CHECK_RECORD (x, lcrecord_list) | |
| 1609 Lcrecord lists should never escape to the Lisp level, so | |
| 1610 functions should not be doing this. */ | |
| 1611 | |
| 826 | 1612 /* Various ways of allocating lcrecords. All bytes (except lcrecord |
| 1204 | 1613 header) are zeroed in returned structure. |
| 1614 | |
| 1615 See above for a discussion of the difference between plain lrecords and | |
| 1616 lrecords. lcrecords themselves are divided into three types: (1) | |
| 1617 auto-managed, (2) hand-managed, and (3) unmanaged. "Managed" refers to | |
| 1618 using a special object called an lcrecord-list to keep track of freed | |
| 3024 | 1619 lcrecords, which can freed with FREE_LCRECORD() or the like and later be |
| 1204 | 1620 recycled when a new lcrecord is required, rather than requiring new |
| 1621 malloc(). Thus, allocation of lcrecords can be very | |
| 1622 cheap. (Technically, the lcrecord-list manager could divide up large | |
| 1623 chunks of memory and allocate out of that, mimicking what happens with | |
| 1624 lrecords. At that point, however, we'd want to rethink the whole | |
| 1625 division between lrecords and lcrecords.) | |
| 1626 | |
| 1627 NOTE: There is a fundamental limitation of lcrecord-lists, which is that | |
| 1628 they only handle blocks of a particular, fixed size. Thus, objects that | |
| 1629 can be of varying sizes need to do various tricks. These considerations | |
| 1630 in particular dictate the various types of management: | |
| 1631 | |
| 1632 -- "Auto-managed" means that you just go ahead and allocate the lcrecord | |
| 3024 | 1633 whenever you want, using old_alloc_lcrecord_type(), and the appropriate |
| 1204 | 1634 lcrecord-list manager is automatically created. To free, you just call |
| 3024 | 1635 "FREE_LCRECORD()" and the appropriate lcrecord-list manager is |
| 1204 | 1636 automatically located and called. The limitation here of course is that |
| 1637 all your objects are of the same size. (#### Eventually we should have a | |
| 1638 more sophisticated system that tracks the sizes seen and creates one | |
| 1639 lcrecord list per size, indexed in a hash table. Usually there are only | |
| 1640 a limited number of sizes, so this works well.) | |
| 826 | 1641 |
| 1204 | 1642 -- "Hand-managed" exists because we haven't yet written the more |
| 1643 sophisticated scheme for auto-handling different-sized lcrecords, as | |
| 1644 described in the end of the last paragraph. In this model, you go ahead | |
| 1645 and create the lcrecord-list objects yourself for the sizes you will | |
| 1646 need, using make_lcrecord_list(). Then, create lcrecords using | |
| 1647 alloc_managed_lcrecord(), passing in the lcrecord-list you created, and | |
| 1648 free them with free_managed_lcrecord(). | |
| 1649 | |
| 1650 -- "Unmanaged" means you simply allocate lcrecords, period. No | |
| 1651 lcrecord-lists, no way to free them. This may be suitable when the | |
| 1652 lcrecords are variable-sized and (a) you're too lazy to write the code | |
| 1653 to hand-manage them, or (b) the objects you create are always or almost | |
| 1654 always Lisp-visible, and thus there's no point in freeing them (and it | |
| 1655 wouldn't be safe to do so). You just create them with | |
| 3024 | 1656 BASIC_ALLOC_LCRECORD(), and that's it. |
| 1204 | 1657 |
| 1658 --ben | |
| 1659 | |
| 1660 Here is an in-depth look at the steps required to create a allocate an | |
| 1661 lcrecord using the hand-managed style. Since this is the most | |
| 1662 complicated, you will learn a lot about the other styles as well. In | |
| 1663 addition, there is useful general information about what freeing an | |
| 1664 lcrecord really entails, and what are the precautions: | |
| 1665 | |
| 1666 1) Create an lcrecord-list object using make_lcrecord_list(). This is | |
| 1667 often done at initialization. Remember to staticpro_nodump() this | |
| 1668 object! The arguments to make_lcrecord_list() are the same as would be | |
| 3024 | 1669 passed to BASIC_ALLOC_LCRECORD(). |
| 428 | 1670 |
| 3024 | 1671 2) Instead of calling BASIC_ALLOC_LCRECORD(), call alloc_managed_lcrecord() |
| 1204 | 1672 and pass the lcrecord-list earlier created. |
| 1673 | |
| 1674 3) When done with the lcrecord, call free_managed_lcrecord(). The | |
| 1675 standard freeing caveats apply: ** make sure there are no pointers to | |
| 1676 the object anywhere! ** | |
| 1677 | |
| 1678 4) Calling free_managed_lcrecord() is just like kissing the | |
| 1679 lcrecord goodbye as if it were garbage-collected. This means: | |
| 1680 -- the contents of the freed lcrecord are undefined, and the | |
| 1681 contents of something produced by alloc_managed_lcrecord() | |
| 3024 | 1682 are undefined, just like for BASIC_ALLOC_LCRECORD(). |
| 1204 | 1683 -- the mark method for the lcrecord's type will *NEVER* be called |
| 1684 on freed lcrecords. | |
| 1685 -- the finalize method for the lcrecord's type will be called | |
| 1686 at the time that free_managed_lcrecord() is called. | |
| 1687 */ | |
| 1688 | |
| 1689 /* UNMANAGED MODEL: */ | |
| 3024 | 1690 void *old_basic_alloc_lcrecord (Bytecount size, |
| 1691 const struct lrecord_implementation *); | |
| 1204 | 1692 |
| 1693 /* HAND-MANAGED MODEL: */ | |
| 1694 Lisp_Object make_lcrecord_list (Elemcount size, | |
| 1695 const struct lrecord_implementation | |
| 1696 *implementation); | |
| 1697 Lisp_Object alloc_managed_lcrecord (Lisp_Object lcrecord_list); | |
| 1698 void free_managed_lcrecord (Lisp_Object lcrecord_list, Lisp_Object lcrecord); | |
| 1699 | |
| 1700 /* AUTO-MANAGED MODEL: */ | |
| 1632 | 1701 MODULE_API void * |
| 1702 alloc_automanaged_lcrecord (Bytecount size, | |
| 1703 const struct lrecord_implementation *); | |
| 3017 | 1704 |
| 3024 | 1705 #define old_alloc_lcrecord_type(type, lrecord_implementation) \ |
| 771 | 1706 ((type *) alloc_automanaged_lcrecord (sizeof (type), lrecord_implementation)) |
| 2720 | 1707 |
| 3024 | 1708 void old_free_lcrecord (Lisp_Object rec); |
| 771 | 1709 |
| 428 | 1710 |
| 1711 /* Copy the data from one lcrecord structure into another, but don't | |
| 1712 overwrite the header information. */ | |
| 1713 | |
| 3024 | 1714 #define old_copy_sized_lcrecord(dst, src, size) \ |
| 1715 memcpy ((Rawbyte *) (dst) + sizeof (struct old_lcrecord_header), \ | |
| 1716 (Rawbyte *) (src) + sizeof (struct old_lcrecord_header), \ | |
| 1717 (size) - sizeof (struct old_lcrecord_header)) | |
| 771 | 1718 |
| 3024 | 1719 #define old_copy_lcrecord(dst, src) \ |
| 1720 old_copy_sized_lcrecord (dst, src, sizeof (*(dst))) | |
| 428 | 1721 |
| 3024 | 1722 #define old_zero_sized_lcrecord(lcr, size) \ |
| 1723 memset ((Rawbyte *) (lcr) + sizeof (struct old_lcrecord_header), 0, \ | |
| 1724 (size) - sizeof (struct old_lcrecord_header)) | |
| 771 | 1725 |
| 3024 | 1726 #define old_zero_lcrecord(lcr) old_zero_sized_lcrecord (lcr, sizeof (*(lcr))) |
| 1204 | 1727 |
| 3263 | 1728 #else /* NEW_GC */ |
| 2720 | 1729 |
| 1730 /* How to allocate a lrecord: | |
| 1731 | |
| 1732 - If the size of the lrecord is fix, say it equals its size of its | |
| 1733 struct, then use alloc_lrecord_type. | |
| 1734 | |
| 1735 - If the size varies, i.e. it is not equal to the size of its | |
| 1736 struct, use alloc_lrecord and specify the amount of storage you | |
| 1737 need for the object. | |
| 1738 | |
| 1739 - Some lrecords, which are used totally internally, use the | |
| 1740 noseeum-* functions for the reason of debugging. | |
| 1741 | |
| 1742 - To free a Lisp_Object manually, use free_lrecord. */ | |
| 1743 | |
| 1744 void *alloc_lrecord (Bytecount size, | |
| 1745 const struct lrecord_implementation *); | |
| 1746 | |
| 3092 | 1747 void *alloc_lrecord_array (Bytecount size, int elemcount, |
| 1748 const struct lrecord_implementation *); | |
| 1749 | |
| 2720 | 1750 #define alloc_lrecord_type(type, lrecord_implementation) \ |
| 1751 ((type *) alloc_lrecord (sizeof (type), lrecord_implementation)) | |
| 1752 | |
| 1753 void *noseeum_alloc_lrecord (Bytecount size, | |
| 1754 const struct lrecord_implementation *); | |
| 1755 | |
| 1756 #define noseeum_alloc_lrecord_type(type, lrecord_implementation) \ | |
| 1757 ((type *) noseeum_alloc_lrecord (sizeof (type), lrecord_implementation)) | |
| 1758 | |
| 1759 void free_lrecord (Lisp_Object rec); | |
| 1760 | |
| 1761 | |
| 1762 /* Copy the data from one lrecord structure into another, but don't | |
| 1763 overwrite the header information. */ | |
| 1764 | |
| 1765 #define copy_sized_lrecord(dst, src, size) \ | |
| 1766 memcpy ((char *) (dst) + sizeof (struct lrecord_header), \ | |
| 1767 (char *) (src) + sizeof (struct lrecord_header), \ | |
| 1768 (size) - sizeof (struct lrecord_header)) | |
| 1769 | |
| 1770 #define copy_lrecord(dst, src) copy_sized_lrecord (dst, src, sizeof (*(dst))) | |
| 1771 | |
| 3263 | 1772 #endif /* NEW_GC */ |
| 3017 | 1773 |
| 2720 | 1774 #define zero_sized_lrecord(lcr, size) \ |
| 1775 memset ((char *) (lcr) + sizeof (struct lrecord_header), 0, \ | |
| 1776 (size) - sizeof (struct lrecord_header)) | |
| 1777 | |
| 1778 #define zero_lrecord(lcr) zero_sized_lrecord (lcr, sizeof (*(lcr))) | |
| 1779 | |
| 1204 | 1780 DECLARE_INLINE_HEADER ( |
| 1781 Bytecount | |
| 1782 detagged_lisp_object_size (const struct lrecord_header *h) | |
| 1783 ) | |
| 1784 { | |
| 1785 const struct lrecord_implementation *imp = LHEADER_IMPLEMENTATION (h); | |
| 1786 | |
| 1787 return (imp->size_in_bytes_method ? | |
| 1788 imp->size_in_bytes_method (h) : | |
| 1789 imp->static_size); | |
| 1790 } | |
| 1791 | |
| 1792 DECLARE_INLINE_HEADER ( | |
| 1793 Bytecount | |
| 1794 lisp_object_size (Lisp_Object o) | |
| 1795 ) | |
| 1796 { | |
| 1797 return detagged_lisp_object_size (XRECORD_LHEADER (o)); | |
| 1798 } | |
| 1799 | |
| 1800 | |
| 1801 /************************************************************************/ | |
| 1802 /* Dumping */ | |
| 1803 /************************************************************************/ | |
| 1804 | |
| 2367 | 1805 /* dump_add_root_block_ptr (&var, &desc) dumps the structure pointed to by |
| 1204 | 1806 `var'. This is for a single relocatable pointer located in the data |
| 2367 | 1807 segment (i.e. the block pointed to is in the heap). |
| 1808 | |
| 1809 If the structure pointed to is not a `struct' but an array, you should | |
| 1810 set the size field of the sized_memory_description to 0, and use | |
| 1811 XD_BLOCK_ARRAY in the inner memory_description. | |
| 1812 | |
| 1813 NOTE that a "root struct pointer" could also be described using | |
| 1814 dump_add_root_block(), with SIZE == sizeof (void *), and a description | |
| 1815 containing a single XD_BLOCK_PTR entry, offset 0, size 1, with a | |
| 1816 structure description the same as the value passed to | |
| 1817 dump_add_root_block_ptr(). That would require an extra level of | |
| 1818 description, though, as compared to using dump_add_root_block_ptr(), | |
| 1819 and thus this function is generally more convenient. | |
| 1820 */ | |
| 1204 | 1821 #ifdef PDUMP |
| 2367 | 1822 void dump_add_root_block_ptr (void *, const struct sized_memory_description *); |
| 1204 | 1823 #else |
| 2367 | 1824 #define dump_add_root_block_ptr(varaddr, descaddr) DO_NOTHING |
| 1204 | 1825 #endif |
| 1826 | |
| 1827 /* dump_add_opaque (&var, size) dumps the opaque static structure `var'. | |
| 1828 This is for a static block of memory (in the data segment, not the | |
| 1829 heap), with no relocatable pointers in it. */ | |
| 1830 #ifdef PDUMP | |
| 1831 #define dump_add_opaque(varaddr,size) dump_add_root_block (varaddr, size, NULL) | |
| 1832 #else | |
| 1833 #define dump_add_opaque(varaddr,size) DO_NOTHING | |
| 1834 #endif | |
| 1835 | |
| 1836 /* dump_add_root_block (ptr, size, desc) dumps the static structure | |
| 1837 located at `var' of size SIZE and described by DESC. This is for a | |
| 1838 static block of memory (in the data segment, not the heap), with | |
| 1839 relocatable pointers in it. */ | |
| 1840 #ifdef PDUMP | |
| 1841 void dump_add_root_block (const void *ptraddress, Bytecount size, | |
| 1842 const struct memory_description *desc); | |
| 1843 #else | |
| 2367 | 1844 #define dump_add_root_block(ptraddress, size, desc) DO_NOTHING |
| 1204 | 1845 #endif |
| 1846 | |
| 1847 /* Call dump_add_opaque_int (&int_var) to dump `int_var', of type `int'. */ | |
| 1848 #ifdef PDUMP | |
| 1849 #define dump_add_opaque_int(int_varaddr) do { \ | |
| 1850 int *dao_ = (int_varaddr); /* type check */ \ | |
| 1851 dump_add_opaque (dao_, sizeof (*dao_)); \ | |
| 1852 } while (0) | |
| 1853 #else | |
| 1854 #define dump_add_opaque_int(int_varaddr) DO_NOTHING | |
| 1855 #endif | |
| 1856 | |
| 1857 /* Call dump_add_opaque_fixnum (&fixnum_var) to dump `fixnum_var', of type | |
| 1858 `Fixnum'. */ | |
| 1859 #ifdef PDUMP | |
| 1860 #define dump_add_opaque_fixnum(fixnum_varaddr) do { \ | |
| 1861 Fixnum *dao_ = (fixnum_varaddr); /* type check */ \ | |
| 1862 dump_add_opaque (dao_, sizeof (*dao_)); \ | |
| 1863 } while (0) | |
| 1864 #else | |
| 1865 #define dump_add_opaque_fixnum(fixnum_varaddr) DO_NOTHING | |
| 1866 #endif | |
| 1867 | |
| 1868 /* Call dump_add_root_lisp_object (&var) to ensure that var is properly | |
| 1869 updated after pdump. */ | |
| 1870 #ifdef PDUMP | |
| 1871 void dump_add_root_lisp_object (Lisp_Object *); | |
| 1872 #else | |
| 1873 #define dump_add_root_lisp_object(varaddr) DO_NOTHING | |
| 1874 #endif | |
| 1875 | |
| 1876 /* Call dump_add_weak_lisp_object (&var) to ensure that var is properly | |
| 1877 updated after pdump. var must point to a linked list of objects out of | |
| 1878 which some may not be dumped */ | |
| 1879 #ifdef PDUMP | |
| 1880 void dump_add_weak_object_chain (Lisp_Object *); | |
| 1881 #else | |
| 1882 #define dump_add_weak_object_chain(varaddr) DO_NOTHING | |
| 1883 #endif | |
| 1884 | |
| 1885 /* Nonzero means Emacs has already been initialized. | |
| 1886 Used during startup to detect startup of dumped Emacs. */ | |
| 1632 | 1887 extern MODULE_API int initialized; |
| 1204 | 1888 |
| 1889 #ifdef PDUMP | |
| 1688 | 1890 #include "dumper.h" |
| 3263 | 1891 #ifdef NEW_GC |
| 2720 | 1892 #define DUMPEDP(adr) 0 |
| 3263 | 1893 #else /* not NEW_GC */ |
| 2367 | 1894 #define DUMPEDP(adr) ((((Rawbyte *) (adr)) < pdump_end) && \ |
| 1895 (((Rawbyte *) (adr)) >= pdump_start)) | |
| 3263 | 1896 #endif /* not NEW_GC */ |
| 1204 | 1897 #else |
| 1898 #define DUMPEDP(adr) 0 | |
| 1899 #endif | |
| 1900 | |
| 1330 | 1901 #define OBJECT_DUMPED_P(obj) DUMPEDP (XPNTR (obj)) |
| 1902 | |
| 1204 | 1903 /***********************************************************************/ |
| 1904 /* data descriptions */ | |
| 1905 /***********************************************************************/ | |
| 1906 | |
| 1907 | |
| 1908 #if defined (USE_KKCC) || defined (PDUMP) | |
| 1909 | |
| 1910 extern int in_pdump; | |
| 1911 | |
| 1912 EMACS_INT lispdesc_indirect_count_1 (EMACS_INT code, | |
| 1913 const struct memory_description *idesc, | |
| 1914 const void *idata); | |
| 1915 const struct sized_memory_description *lispdesc_indirect_description_1 | |
| 1916 (const void *obj, const struct sized_memory_description *sdesc); | |
| 2367 | 1917 Bytecount lispdesc_block_size_1 (const void *obj, Bytecount size, |
| 1918 const struct memory_description *desc); | |
| 1919 | |
| 1920 DECLARE_INLINE_HEADER ( | |
| 1921 Bytecount lispdesc_block_size (const void *obj, | |
| 1922 const struct sized_memory_description *sdesc)) | |
| 1923 { | |
| 1924 return lispdesc_block_size_1 (obj, sdesc->size, sdesc->description); | |
| 1925 } | |
| 1204 | 1926 |
| 1927 DECLARE_INLINE_HEADER ( | |
| 1928 EMACS_INT | |
| 1929 lispdesc_indirect_count (EMACS_INT code, | |
| 1930 const struct memory_description *idesc, | |
| 1931 const void *idata) | |
| 1932 ) | |
| 1933 { | |
| 1934 if (XD_IS_INDIRECT (code)) | |
| 1935 code = lispdesc_indirect_count_1 (code, idesc, idata); | |
| 1936 return code; | |
| 1937 } | |
| 1938 | |
| 1939 DECLARE_INLINE_HEADER ( | |
| 1940 const struct sized_memory_description * | |
| 1941 lispdesc_indirect_description (const void *obj, | |
| 1942 const struct sized_memory_description *sdesc) | |
| 1943 ) | |
| 1944 { | |
| 1945 if (sdesc->description) | |
| 1946 return sdesc; | |
| 1947 else | |
| 1948 return lispdesc_indirect_description_1 (obj, sdesc); | |
| 1949 } | |
| 1950 | |
| 1951 | |
| 1952 /* Do standard XD_UNION processing. DESC1 is an entry in DESC, which | |
| 1953 describes the entire data structure. Returns NULL (do nothing, nothing | |
| 1954 matched), or a new value for DESC1. In the latter case, assign to DESC1 | |
| 1955 in your function and goto union_switcheroo. */ | |
| 1956 | |
| 1957 DECLARE_INLINE_HEADER ( | |
| 1958 const struct memory_description * | |
| 1959 lispdesc_process_xd_union (const struct memory_description *desc1, | |
| 1960 const struct memory_description *desc, | |
| 1961 const void *data) | |
| 1962 ) | |
| 1963 { | |
| 1964 int count = 0; | |
| 1965 EMACS_INT variant = lispdesc_indirect_count (desc1->data1, desc, | |
| 1966 data); | |
| 1967 desc1 = | |
| 2551 | 1968 lispdesc_indirect_description (data, desc1->data2.descr)->description; |
| 1204 | 1969 |
| 1970 for (count = 0; desc1[count].type != XD_END; count++) | |
| 1971 { | |
| 1972 if ((desc1[count].flags & XD_FLAG_UNION_DEFAULT_ENTRY) || | |
| 1973 desc1[count].offset == variant) | |
| 1974 { | |
| 1975 return &desc1[count]; | |
| 1976 } | |
| 1977 } | |
| 1978 | |
| 1979 return NULL; | |
| 1980 } | |
| 1981 | |
| 1982 #endif /* defined (USE_KKCC) || defined (PDUMP) */ | |
| 428 | 1983 |
| 1743 | 1984 END_C_DECLS |
| 1650 | 1985 |
| 440 | 1986 #endif /* INCLUDED_lrecord_h_ */ |
