Mercurial > hg > xemacs-beta
comparison src/lrecord.h @ 412:697ef44129c6 r21-2-14
Import from CVS: tag r21-2-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 11:20:41 +0200 |
parents | de805c49cfc1 |
children | 41dbb7a9d5f2 |
comparison
equal
deleted
inserted
replaced
411:12e008d41344 | 412:697ef44129c6 |
---|---|
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | 19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
20 Boston, MA 02111-1307, USA. */ | 20 Boston, MA 02111-1307, USA. */ |
21 | 21 |
22 /* Synched up with: Not in FSF. */ | 22 /* Synched up with: Not in FSF. */ |
23 | 23 |
24 #ifndef INCLUDED_lrecord_h_ | 24 #ifndef _XEMACS_LRECORD_H_ |
25 #define INCLUDED_lrecord_h_ | 25 #define _XEMACS_LRECORD_H_ |
26 | 26 |
27 /* The "lrecord" type of Lisp object is used for all object types | 27 /* The "lrecord" type of Lisp object is used for all object types |
28 other than a few simple ones. This allows many types to be | 28 other than a few simple ones. This allows many types to be |
29 implemented but only a few bits required in a Lisp object for type | 29 implemented but only a few bits required in a Lisp object for |
30 information. (The tradeoff is that each object has its type marked | 30 type information. (The tradeoff is that each object has its |
31 in it, thereby increasing its size.) All lrecords begin with a | 31 type marked in it, thereby increasing its size.) The first |
32 `struct lrecord_header', which identifies the lisp object type, by | 32 four bytes of all lrecords is either a pointer to a struct |
33 providing an index into a table of `struct lrecord_implementation', | 33 lrecord_implementation, which contains methods describing how |
34 which describes the behavior of the lisp object. It also contains | 34 to process this object, or an index into an array of pointers |
35 some other data bits. | 35 to struct lrecord_implementations plus some other data bits. |
36 | 36 |
37 Lrecords are of two types: straight lrecords, and lcrecords. | 37 Lrecords are of two types: straight lrecords, and lcrecords. |
38 Straight lrecords are used for those types of objects that have | 38 Straight lrecords are used for those types of objects that have |
39 their own allocation routines (typically allocated out of 2K chunks | 39 their own allocation routines (typically allocated out of 2K chunks |
40 of memory called `frob blocks'). These objects have a `struct | 40 of memory called `frob blocks'). These objects have a `struct |
41 lrecord_header' at the top, containing only the bits needed to find | 41 lrecord_header' at the top, containing only the bits needed to find |
42 the lrecord_implementation for the object. There are special | 42 the lrecord_implementation for the object. There are special |
43 routines in alloc.c to deal with each such object type. | 43 routines in alloc.c to deal with each such object type. |
44 | 44 |
45 Lcrecords are used for less common sorts of objects that don't do | 45 Lcrecords are used for less common sorts of objects that don't |
46 their own allocation. Each such object is malloc()ed individually, | 46 do their own allocation. Each such object is malloc()ed |
47 and the objects are chained together through a `next' pointer. | 47 individually, and the objects are chained together through |
48 Lcrecords have a `struct lcrecord_header' at the top, which | 48 a `next' pointer. Lcrecords have a `struct lcrecord_header' |
49 contains a `struct lrecord_header' and a `next' pointer, and are | 49 at the top, which contains a `struct lrecord_header' and |
50 allocated using alloc_lcrecord(). | 50 a `next' pointer, and are allocated using alloc_lcrecord(). |
51 | 51 |
52 Creating a new lcrecord type is fairly easy; just follow the | 52 Creating a new lcrecord type is fairly easy; just follow the |
53 lead of some existing type (e.g. hash tables). Note that you | 53 lead of some existing type (e.g. hash tables). Note that you |
54 do not need to supply all the methods (see below); reasonable | 54 do not need to supply all the methods (see below); reasonable |
55 defaults are provided for many of them. Alternatively, if you're | 55 defaults are provided for many of them. Alternatively, if you're |
58 the opaque type. */ | 58 the opaque type. */ |
59 | 59 |
60 struct lrecord_header | 60 struct lrecord_header |
61 { | 61 { |
62 /* index into lrecord_implementations_table[] */ | 62 /* index into lrecord_implementations_table[] */ |
63 unsigned int type :8; | 63 unsigned char type; |
64 | 64 struct { |
65 /* If `mark' is 0 after the GC mark phase, the object will be freed | 65 /* 1 if the object is marked during GC. */ |
66 during the GC sweep phase. There are 2 ways that `mark' can be 1: | 66 unsigned mark :1; |
67 - by being referenced from other objects during the GC mark phase | 67 /* 1 if the object resides in read-only space */ |
68 - because it is permanently on, for c_readonly objects */ | 68 unsigned c_readonly : 1; |
69 unsigned int mark :1; | 69 /* 1 if the object is readonly from lisp */ |
70 | 70 unsigned lisp_readonly : 1; |
71 /* 1 if the object resides in logically read-only space, and does not | 71 } flags; |
72 reference other non-c_readonly objects. | |
73 Invariant: if (c_readonly == 1), then (mark == 1 && lisp_readonly == 1) */ | |
74 unsigned int c_readonly :1; | |
75 | |
76 /* 1 if the object is readonly from lisp */ | |
77 unsigned int lisp_readonly :1; | |
78 }; | 72 }; |
79 | 73 |
80 struct lrecord_implementation; | 74 struct lrecord_implementation; |
81 int lrecord_type_index (const struct lrecord_implementation *implementation); | 75 int lrecord_type_index (CONST struct lrecord_implementation *implementation); |
82 | 76 |
83 #define set_lheader_implementation(header,imp) do { \ | 77 # define set_lheader_implementation(header,imp) do { \ |
84 struct lrecord_header* SLI_header = (header); \ | 78 struct lrecord_header* SLI_header = (header); \ |
85 SLI_header->type = (imp)->lrecord_type_index; \ | 79 (SLI_header)->type = lrecord_type_index (imp); \ |
86 SLI_header->mark = 0; \ | 80 (SLI_header)->flags.mark = 0; \ |
87 SLI_header->c_readonly = 0; \ | 81 (SLI_header)->flags.c_readonly = 0; \ |
88 SLI_header->lisp_readonly = 0; \ | 82 (SLI_header)->flags.lisp_readonly = 0; \ |
89 } while (0) | 83 } while (0) |
90 | 84 |
91 struct lcrecord_header | 85 struct lcrecord_header |
92 { | 86 { |
93 struct lrecord_header lheader; | 87 struct lrecord_header lheader; |
94 | 88 |
95 /* The `next' field is normally used to chain all lcrecords together | 89 /* The `next' field is normally used to chain all lrecords together |
96 so that the GC can find (and free) all of them. | 90 so that the GC can find (and free) all of them. |
97 `alloc_lcrecord' threads lcrecords together. | 91 `alloc_lcrecord' threads records together. |
98 | 92 |
99 The `next' field may be used for other purposes as long as some | 93 The `next' field may be used for other purposes as long as some |
100 other mechanism is provided for letting the GC do its work. | 94 other mechanism is provided for letting the GC do its work. |
101 | 95 |
102 For example, the event and marker object types allocate members | 96 For example, the event and marker object types allocate members |
124 { | 118 { |
125 struct lcrecord_header lcheader; | 119 struct lcrecord_header lcheader; |
126 Lisp_Object chain; | 120 Lisp_Object chain; |
127 }; | 121 }; |
128 | 122 |
129 enum lrecord_type | 123 /* see alloc.c for an explanation */ |
130 { | 124 Lisp_Object this_one_is_unmarkable (Lisp_Object obj, |
131 /* Symbol value magic types come first to make SYMBOL_VALUE_MAGIC_P fast. | 125 void (*markobj) (Lisp_Object)); |
132 #### This should be replaced by a symbol_value_magic_p flag | |
133 in the Lisp_Symbol lrecord_header. */ | |
134 lrecord_type_symbol_value_forward, | |
135 lrecord_type_symbol_value_varalias, | |
136 lrecord_type_symbol_value_lisp_magic, | |
137 lrecord_type_symbol_value_buffer_local, | |
138 lrecord_type_max_symbol_value_magic = lrecord_type_symbol_value_buffer_local, | |
139 | |
140 lrecord_type_symbol, | |
141 lrecord_type_subr, | |
142 lrecord_type_cons, | |
143 lrecord_type_vector, | |
144 lrecord_type_string, | |
145 lrecord_type_lcrecord_list, | |
146 lrecord_type_compiled_function, | |
147 lrecord_type_weak_list, | |
148 lrecord_type_bit_vector, | |
149 lrecord_type_float, | |
150 lrecord_type_hash_table, | |
151 lrecord_type_lstream, | |
152 lrecord_type_process, | |
153 lrecord_type_charset, | |
154 lrecord_type_coding_system, | |
155 lrecord_type_char_table, | |
156 lrecord_type_char_table_entry, | |
157 lrecord_type_range_table, | |
158 lrecord_type_opaque, | |
159 lrecord_type_opaque_ptr, | |
160 lrecord_type_buffer, | |
161 lrecord_type_extent, | |
162 lrecord_type_extent_info, | |
163 lrecord_type_extent_auxiliary, | |
164 lrecord_type_marker, | |
165 lrecord_type_event, | |
166 lrecord_type_keymap, | |
167 lrecord_type_command_builder, | |
168 lrecord_type_timeout, | |
169 lrecord_type_specifier, | |
170 lrecord_type_console, | |
171 lrecord_type_device, | |
172 lrecord_type_frame, | |
173 lrecord_type_window, | |
174 lrecord_type_window_configuration, | |
175 lrecord_type_gui_item, | |
176 lrecord_type_popup_data, | |
177 lrecord_type_toolbar_button, | |
178 lrecord_type_color_instance, | |
179 lrecord_type_font_instance, | |
180 lrecord_type_image_instance, | |
181 lrecord_type_glyph, | |
182 lrecord_type_face, | |
183 lrecord_type_database, | |
184 lrecord_type_tooltalk_message, | |
185 lrecord_type_tooltalk_pattern, | |
186 lrecord_type_ldap, | |
187 lrecord_type_pgconn, | |
188 lrecord_type_pgresult, | |
189 lrecord_type_devmode, | |
190 lrecord_type_count /* must be last */ | |
191 }; | |
192 | 126 |
193 struct lrecord_implementation | 127 struct lrecord_implementation |
194 { | 128 { |
195 const char *name; | 129 CONST char *name; |
196 | 130 /* This function is called at GC time, to make sure that all Lisp_Objects |
197 /* `marker' is called at GC time, to make sure that all Lisp_Objects | |
198 pointed to by this object get properly marked. It should call | 131 pointed to by this object get properly marked. It should call |
199 the mark_object function on all Lisp_Objects in the object. If | 132 the mark_object function on all Lisp_Objects in the object. If |
200 the return value is non-nil, it should be a Lisp_Object to be | 133 the return value is non-nil, it should be a Lisp_Object to be |
201 marked (don't call the mark_object function explicitly on it, | 134 marked (don't call the mark_object function explicitly on it, |
202 because the GC routines will do this). Doing it this way reduces | 135 because the GC routines will do this). Doing it this way reduces |
203 recursion, so the object returned should preferably be the one | 136 recursion, so the object returned should preferably be the one |
204 with the deepest level of Lisp_Object pointers. This function | 137 with the deepest level of Lisp_Object pointers. This function |
205 can be NULL, meaning no GC marking is necessary. */ | 138 can be NULL, meaning no GC marking is necessary. */ |
206 Lisp_Object (*marker) (Lisp_Object); | 139 Lisp_Object (*marker) (Lisp_Object, void (*mark_object) (Lisp_Object)); |
207 | 140 /* This can be NULL if the object is an lcrecord; the |
208 /* `printer' converts the object to a printed representation. | 141 default_object_printer() in print.c will be used. */ |
209 This can be NULL; in this case default_object_printer() will be | |
210 used instead. */ | |
211 void (*printer) (Lisp_Object, Lisp_Object printcharfun, int escapeflag); | 142 void (*printer) (Lisp_Object, Lisp_Object printcharfun, int escapeflag); |
212 | 143 /* This function is called at GC time when the object is about to |
213 /* `finalizer' is called at GC time when the object is about to | |
214 be freed, and at dump time (FOR_DISKSAVE will be non-zero in this | 144 be freed, and at dump time (FOR_DISKSAVE will be non-zero in this |
215 case). It should perform any necessary cleanup (e.g. freeing | 145 case). It should perform any necessary cleanup (e.g. freeing |
216 malloc()ed memory). This can be NULL, meaning no special | 146 malloc()ed memory. This can be NULL, meaning no special |
217 finalization is necessary. | 147 finalization is necessary. |
218 | 148 |
219 WARNING: remember that `finalizer' is called at dump time even | 149 WARNING: remember that the finalizer is called at dump time even |
220 though the object is not being freed. */ | 150 though the object is not being freed. */ |
221 void (*finalizer) (void *header, int for_disksave); | 151 void (*finalizer) (void *header, int for_disksave); |
222 | |
223 /* This can be NULL, meaning compare objects with EQ(). */ | 152 /* This can be NULL, meaning compare objects with EQ(). */ |
224 int (*equal) (Lisp_Object obj1, Lisp_Object obj2, int depth); | 153 int (*equal) (Lisp_Object obj1, Lisp_Object obj2, int depth); |
225 | 154 /* This can be NULL, meaning use the Lisp_Object itself as the hash; |
226 /* `hash' generates hash values for use with hash tables that have | 155 but *only* if the `equal' function is EQ (if two objects are |
227 `equal' as their test function. This can be NULL, meaning use | 156 `equal', they *must* hash to the same value or the hashing won't |
228 the Lisp_Object itself as the hash. But, you must still satisfy | 157 work). */ |
229 the constraint that if two objects are `equal', then they *must* | |
230 hash to the same value in order for hash tables to work properly. | |
231 This means that `hash' can be NULL only if the `equal' method is | |
232 also NULL. */ | |
233 unsigned long (*hash) (Lisp_Object, int); | 158 unsigned long (*hash) (Lisp_Object, int); |
234 | |
235 /* External data layout description */ | |
236 const struct lrecord_description *description; | |
237 | |
238 /* These functions allow any object type to have builtin property | |
239 lists that can be manipulated from the lisp level with | |
240 `get', `put', `remprop', and `object-plist'. */ | |
241 Lisp_Object (*getprop) (Lisp_Object obj, Lisp_Object prop); | 159 Lisp_Object (*getprop) (Lisp_Object obj, Lisp_Object prop); |
242 int (*putprop) (Lisp_Object obj, Lisp_Object prop, Lisp_Object val); | 160 int (*putprop) (Lisp_Object obj, Lisp_Object prop, Lisp_Object val); |
243 int (*remprop) (Lisp_Object obj, Lisp_Object prop); | 161 int (*remprop) (Lisp_Object obj, Lisp_Object prop); |
244 Lisp_Object (*plist) (Lisp_Object obj); | 162 Lisp_Object (*plist) (Lisp_Object obj); |
245 | 163 |
246 /* Only one of `static_size' and `size_in_bytes_method' is non-0. | 164 /* Only one of these is non-0. If both are 0, it means that this type |
247 If both are 0, this type is not instantiable by alloc_lcrecord(). */ | 165 is not instantiable by alloc_lcrecord(). */ |
248 size_t static_size; | 166 size_t static_size; |
249 size_t (*size_in_bytes_method) (const void *header); | 167 size_t (*size_in_bytes_method) (CONST void *header); |
250 | 168 /* A unique subtag-code (dynamically) assigned to this datatype. */ |
251 /* The (constant) index into lrecord_implementations_table */ | 169 /* (This is a pointer so the rest of this structure can be read-only.) */ |
252 enum lrecord_type lrecord_type_index; | 170 int *lrecord_type_index; |
253 | |
254 /* A "basic" lrecord is any lrecord that's not an lcrecord, i.e. | 171 /* A "basic" lrecord is any lrecord that's not an lcrecord, i.e. |
255 one that does not have an lcrecord_header at the front and which | 172 one that does not have an lcrecord_header at the front and which |
256 is (usually) allocated in frob blocks. We only use this flag for | 173 is (usually) allocated in frob blocks. We only use this flag for |
257 some consistency checking, and that only when error-checking is | 174 some consistency checking, and that only when error-checking is |
258 enabled. */ | 175 enabled. */ |
259 unsigned int basic_p :1; | 176 int basic_p; |
260 }; | 177 }; |
261 | 178 |
262 extern const struct lrecord_implementation *lrecord_implementations_table[]; | 179 extern CONST struct lrecord_implementation *lrecord_implementations_table[]; |
263 | 180 |
264 #define XRECORD_LHEADER_IMPLEMENTATION(obj) \ | 181 #define XRECORD_LHEADER_IMPLEMENTATION(obj) \ |
265 LHEADER_IMPLEMENTATION (XRECORD_LHEADER (obj)) | 182 (lrecord_implementations_table[XRECORD_LHEADER (obj)->type]) |
266 #define LHEADER_IMPLEMENTATION(lh) lrecord_implementations_table[(lh)->type] | 183 #define LHEADER_IMPLEMENTATION(lh) (lrecord_implementations_table[(lh)->type]) |
267 | 184 |
268 extern int gc_in_progress; | 185 extern int gc_in_progress; |
269 | 186 |
270 #define MARKED_RECORD_P(obj) (XRECORD_LHEADER (obj)->mark) | 187 #define MARKED_RECORD_P(obj) (gc_in_progress && XRECORD_LHEADER (obj)->flags.mark) |
271 #define MARKED_RECORD_HEADER_P(lheader) ((lheader)->mark) | 188 #define MARKED_RECORD_HEADER_P(lheader) ((lheader)->flags.mark) |
272 #define MARK_RECORD_HEADER(lheader) ((void) ((lheader)->mark = 1)) | 189 #define MARK_RECORD_HEADER(lheader) ((void) ((lheader)->flags.mark = 1)) |
273 #define UNMARK_RECORD_HEADER(lheader) ((void) ((lheader)->mark = 0)) | 190 #define UNMARK_RECORD_HEADER(lheader) ((void) ((lheader)->flags.mark = 0)) |
274 | 191 |
275 #define C_READONLY_RECORD_HEADER_P(lheader) ((lheader)->c_readonly) | 192 #define UNMARKABLE_RECORD_HEADER_P(lheader) \ |
276 #define LISP_READONLY_RECORD_HEADER_P(lheader) ((lheader)->lisp_readonly) | 193 (LHEADER_IMPLEMENTATION (lheader)->marker == this_one_is_unmarkable) |
277 #define SET_C_READONLY_RECORD_HEADER(lheader) do { \ | 194 |
278 struct lrecord_header *SCRRH_lheader = (lheader); \ | 195 #define C_READONLY_RECORD_HEADER_P(lheader) ((lheader)->flags.c_readonly) |
279 SCRRH_lheader->c_readonly = 1; \ | 196 #define LISP_READONLY_RECORD_HEADER_P(lheader) ((lheader)->flags.lisp_readonly) |
280 SCRRH_lheader->lisp_readonly = 1; \ | 197 #define SET_C_READONLY_RECORD_HEADER(lheader) \ |
281 SCRRH_lheader->mark = 1; \ | 198 ((void) ((lheader)->flags.c_readonly = (lheader)->flags.lisp_readonly = 1)) |
282 } while (0) | |
283 #define SET_LISP_READONLY_RECORD_HEADER(lheader) \ | 199 #define SET_LISP_READONLY_RECORD_HEADER(lheader) \ |
284 ((void) ((lheader)->lisp_readonly = 1)) | 200 ((void) ((lheader)->flags.lisp_readonly = 1)) |
285 #define RECORD_MARKER(lheader) lrecord_markers[(lheader)->type] | 201 |
286 | 202 /* Declaring the following structures as const puts them in the |
287 /* External description stuff | 203 text (read-only) segment, which makes debugging inconvenient |
288 | 204 because this segment is not mapped when processing a core- |
289 A lrecord external description is an array of values. The first | 205 dump file */ |
290 value of each line is a type, the second the offset in the lrecord | 206 |
291 structure. Following values are parameters, their presence, type | 207 #ifdef DEBUG_XEMACS |
292 and number is type-dependant. | 208 #define CONST_IF_NOT_DEBUG |
293 | 209 #else |
294 The description ends with a "XD_END" or "XD_SPECIFIER_END" record. | 210 #define CONST_IF_NOT_DEBUG CONST |
295 | 211 #endif |
296 Some example descriptions : | |
297 | |
298 static const struct lrecord_description cons_description[] = { | |
299 { XD_LISP_OBJECT, offsetof (Lisp_Cons, car) }, | |
300 { XD_LISP_OBJECT, offsetof (Lisp_Cons, cdr) }, | |
301 { XD_END } | |
302 }; | |
303 | |
304 Which means "two lisp objects starting at the 'car' and 'cdr' elements" | |
305 | |
306 static const struct lrecord_description string_description[] = { | |
307 { XD_BYTECOUNT, offsetof (Lisp_String, size) }, | |
308 { XD_OPAQUE_DATA_PTR, offsetof (Lisp_String, data), XD_INDIRECT(0, 1) }, | |
309 { XD_LISP_OBJECT, offsetof (Lisp_String, plist) }, | |
310 { XD_END } | |
311 }; | |
312 "A pointer to string data at 'data', the size of the pointed array being the value | |
313 of the size variable plus 1, and one lisp object at 'plist'" | |
314 | |
315 The existing types : | |
316 XD_LISP_OBJECT | |
317 A Lisp object. This is also the type to use for pointers to other lrecords. | |
318 | |
319 XD_LISP_OBJECT_ARRAY | |
320 An array of Lisp objects or pointers to lrecords. | |
321 The third element is the count. | |
322 | |
323 XD_LO_RESET_NIL | |
324 Lisp objects which will be reset to Qnil when dumping. Useful for cleaning | |
325 up caches. | |
326 | |
327 XD_LO_LINK | |
328 Link in a linked list of objects of the same type. | |
329 | |
330 XD_OPAQUE_PTR | |
331 Pointer to undumpable data. Must be NULL when dumping. | |
332 | |
333 XD_STRUCT_PTR | |
334 Pointer to described struct. Parameters are number of structures and | |
335 struct_description. | |
336 | |
337 XD_OPAQUE_DATA_PTR | |
338 Pointer to dumpable opaque data. Parameter is the size of the data. | |
339 Pointed data must be relocatable without changes. | |
340 | |
341 XD_C_STRING | |
342 Pointer to a C string. | |
343 | |
344 XD_DOC_STRING | |
345 Pointer to a doc string (C string if positive, opaque value if negative) | |
346 | |
347 XD_INT_RESET | |
348 An integer which will be reset to a given value in the dump file. | |
349 | |
350 | |
351 XD_SIZE_T | |
352 size_t value. Used for counts. | |
353 | |
354 XD_INT | |
355 int value. Used for counts. | |
356 | |
357 XD_LONG | |
358 long value. Used for counts. | |
359 | |
360 XD_BYTECOUNT | |
361 bytecount value. Used for counts. | |
362 | |
363 XD_END | |
364 Special type indicating the end of the array. | |
365 | |
366 XD_SPECIFIER_END | |
367 Special type indicating the end of the array for a specifier. Extra | |
368 description is going to be fetched from the specifier methods. | |
369 | |
370 | |
371 Special macros: | |
372 XD_INDIRECT(line, delta) | |
373 Usable where a "count" or "size" is requested. Gives the value of | |
374 the element which is at line number 'line' in the description (count | |
375 starts at zero) and adds delta to it. | |
376 */ | |
377 | |
378 enum lrecord_description_type { | |
379 XD_LISP_OBJECT_ARRAY, | |
380 XD_LISP_OBJECT, | |
381 XD_LO_RESET_NIL, | |
382 XD_LO_LINK, | |
383 XD_OPAQUE_PTR, | |
384 XD_STRUCT_PTR, | |
385 XD_OPAQUE_DATA_PTR, | |
386 XD_C_STRING, | |
387 XD_DOC_STRING, | |
388 XD_INT_RESET, | |
389 XD_SIZE_T, | |
390 XD_INT, | |
391 XD_LONG, | |
392 XD_BYTECOUNT, | |
393 XD_END, | |
394 XD_SPECIFIER_END | |
395 }; | |
396 | |
397 struct lrecord_description { | |
398 enum lrecord_description_type type; | |
399 int offset; | |
400 EMACS_INT data1; | |
401 const struct struct_description *data2; | |
402 }; | |
403 | |
404 struct struct_description { | |
405 size_t size; | |
406 const struct lrecord_description *description; | |
407 }; | |
408 | |
409 #define XD_INDIRECT(val, delta) (-1-((val)|(delta<<8))) | |
410 | |
411 #define XD_IS_INDIRECT(code) (code<0) | |
412 #define XD_INDIRECT_VAL(code) ((-1-code) & 255) | |
413 #define XD_INDIRECT_DELTA(code) (((-1-code)>>8) & 255) | |
414 | |
415 #define XD_DYNARR_DESC(base_type, sub_desc) \ | |
416 { XD_STRUCT_PTR, offsetof (base_type, base), XD_INDIRECT(1, 0), sub_desc }, \ | |
417 { XD_INT, offsetof (base_type, cur) }, \ | |
418 { XD_INT_RESET, offsetof (base_type, max), XD_INDIRECT(1, 0) } | |
419 | 212 |
420 /* DEFINE_LRECORD_IMPLEMENTATION is for objects with constant size. | 213 /* DEFINE_LRECORD_IMPLEMENTATION is for objects with constant size. |
421 DEFINE_LRECORD_SEQUENCE_IMPLEMENTATION is for objects whose size varies. | 214 DEFINE_LRECORD_SEQUENCE_IMPLEMENTATION is for objects whose size varies. |
422 */ | 215 */ |
423 | 216 |
425 # define DECLARE_ERROR_CHECK_TYPECHECK(c_name, structtype) | 218 # define DECLARE_ERROR_CHECK_TYPECHECK(c_name, structtype) |
426 #else | 219 #else |
427 # define DECLARE_ERROR_CHECK_TYPECHECK(c_name, structtype) | 220 # define DECLARE_ERROR_CHECK_TYPECHECK(c_name, structtype) |
428 #endif | 221 #endif |
429 | 222 |
430 #define DEFINE_BASIC_LRECORD_IMPLEMENTATION(name,c_name,marker,printer,nuker,equal,hash,desc,structtype) \ | 223 #define DEFINE_BASIC_LRECORD_IMPLEMENTATION(name,c_name,marker,printer,nuker,equal,hash,structtype) \ |
431 DEFINE_BASIC_LRECORD_IMPLEMENTATION_WITH_PROPS(name,c_name,marker,printer,nuker,equal,hash,desc,0,0,0,0,structtype) | 224 DEFINE_BASIC_LRECORD_IMPLEMENTATION_WITH_PROPS(name,c_name,marker,printer,nuker,equal,hash,0,0,0,0,structtype) |
432 | 225 |
433 #define DEFINE_BASIC_LRECORD_IMPLEMENTATION_WITH_PROPS(name,c_name,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,structtype) \ | 226 #define DEFINE_BASIC_LRECORD_IMPLEMENTATION_WITH_PROPS(name,c_name,marker,printer,nuker,equal,hash,getprop,putprop,remprop,props,structtype) \ |
434 MAKE_LRECORD_IMPLEMENTATION(name,c_name,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,sizeof(structtype),0,1,structtype) | 227 MAKE_LRECORD_IMPLEMENTATION(name,c_name,marker,printer,nuker,equal,hash,getprop,putprop,remprop,props,sizeof(structtype),0,1,structtype) |
435 | 228 |
436 #define DEFINE_LRECORD_IMPLEMENTATION(name,c_name,marker,printer,nuker,equal,hash,desc,structtype) \ | 229 #define DEFINE_LRECORD_IMPLEMENTATION(name,c_name,marker,printer,nuker,equal,hash,structtype) \ |
437 DEFINE_LRECORD_IMPLEMENTATION_WITH_PROPS(name,c_name,marker,printer,nuker,equal,hash,desc,0,0,0,0,structtype) | 230 DEFINE_LRECORD_IMPLEMENTATION_WITH_PROPS(name,c_name,marker,printer,nuker,equal,hash,0,0,0,0,structtype) |
438 | 231 |
439 #define DEFINE_LRECORD_IMPLEMENTATION_WITH_PROPS(name,c_name,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,structtype) \ | 232 #define DEFINE_LRECORD_IMPLEMENTATION_WITH_PROPS(name,c_name,marker,printer,nuker,equal,hash,getprop,putprop,remprop,props,structtype) \ |
440 MAKE_LRECORD_IMPLEMENTATION(name,c_name,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,sizeof (structtype),0,0,structtype) | 233 MAKE_LRECORD_IMPLEMENTATION(name,c_name,marker,printer,nuker,equal,hash,getprop,putprop,remprop,props,sizeof (structtype),0,0,structtype) |
441 | 234 |
442 #define DEFINE_LRECORD_SEQUENCE_IMPLEMENTATION(name,c_name,marker,printer,nuker,equal,hash,desc,sizer,structtype) \ | 235 #define DEFINE_LRECORD_SEQUENCE_IMPLEMENTATION(name,c_name,marker,printer,nuker,equal,hash,sizer,structtype) \ |
443 DEFINE_LRECORD_SEQUENCE_IMPLEMENTATION_WITH_PROPS(name,c_name,marker,printer,nuker,equal,hash,desc,0,0,0,0,sizer,structtype) | 236 DEFINE_LRECORD_SEQUENCE_IMPLEMENTATION_WITH_PROPS(name,c_name,marker,printer,nuker,equal,hash,0,0,0,0,sizer,structtype) |
444 | 237 |
445 #define DEFINE_BASIC_LRECORD_SEQUENCE_IMPLEMENTATION(name,c_name,marker,printer,nuker,equal,hash,desc,sizer,structtype) \ | 238 #define DEFINE_LRECORD_SEQUENCE_IMPLEMENTATION_WITH_PROPS(name,c_name,marker,printer,nuker,equal,hash,getprop,putprop,remprop,props,sizer,structtype) \ |
446 MAKE_LRECORD_IMPLEMENTATION(name,c_name,marker,printer,nuker,equal,hash,desc,0,0,0,0,0,sizer,1,structtype) | 239 MAKE_LRECORD_IMPLEMENTATION(name,c_name,marker,printer,nuker,equal,hash,getprop,putprop,remprop,props,0,sizer,0,structtype) \ |
447 | 240 |
448 #define DEFINE_LRECORD_SEQUENCE_IMPLEMENTATION_WITH_PROPS(name,c_name,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,sizer,structtype) \ | 241 #define MAKE_LRECORD_IMPLEMENTATION(name,c_name,marker,printer,nuker,equal,hash,getprop,putprop,remprop,props,size,sizer,basic_p,structtype) \ |
449 MAKE_LRECORD_IMPLEMENTATION(name,c_name,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,0,sizer,0,structtype) \ | |
450 | |
451 #define MAKE_LRECORD_IMPLEMENTATION(name,c_name,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,size,sizer,basic_p,structtype) \ | |
452 DECLARE_ERROR_CHECK_TYPECHECK(c_name, structtype) \ | 242 DECLARE_ERROR_CHECK_TYPECHECK(c_name, structtype) \ |
453 const struct lrecord_implementation lrecord_##c_name = \ | 243 static int lrecord_##c_name##_lrecord_type_index; \ |
454 { name, marker, printer, nuker, equal, hash, desc, \ | 244 CONST_IF_NOT_DEBUG struct lrecord_implementation lrecord_##c_name = \ |
455 getprop, putprop, remprop, plist, size, sizer, \ | 245 { name, marker, printer, nuker, equal, hash, \ |
456 lrecord_type_##c_name, basic_p } | 246 getprop, putprop, remprop, props, size, sizer, \ |
457 | 247 &(lrecord_##c_name##_lrecord_type_index), basic_p } \ |
458 extern Lisp_Object (*lrecord_markers[]) (Lisp_Object); | 248 |
459 | 249 #define LRECORDP(a) (XTYPE ((a)) == Lisp_Type_Record) |
460 #define INIT_LRECORD_IMPLEMENTATION(type) do { \ | |
461 lrecord_implementations_table[lrecord_type_##type] = &lrecord_##type; \ | |
462 lrecord_markers[lrecord_type_##type] = \ | |
463 lrecord_implementations_table[lrecord_type_##type]->marker; \ | |
464 } while (0) | |
465 | |
466 #define LRECORDP(a) (XTYPE (a) == Lisp_Type_Record) | |
467 #define XRECORD_LHEADER(a) ((struct lrecord_header *) XPNTR (a)) | 250 #define XRECORD_LHEADER(a) ((struct lrecord_header *) XPNTR (a)) |
468 | 251 |
469 #define RECORD_TYPEP(x, ty) \ | 252 #define RECORD_TYPEP(x, ty) \ |
470 (LRECORDP (x) && XRECORD_LHEADER (x)->type == (ty)) | 253 (LRECORDP (x) && \ |
254 lrecord_implementations_table[XRECORD_LHEADER (x)->type] == (ty)) | |
471 | 255 |
472 /* NOTE: the DECLARE_LRECORD() must come before the associated | 256 /* NOTE: the DECLARE_LRECORD() must come before the associated |
473 DEFINE_LRECORD_*() or you will get compile errors. | 257 DEFINE_LRECORD_*() or you will get compile errors. |
474 | 258 |
475 Furthermore, you always need to put the DECLARE_LRECORD() in a header | 259 Furthermore, you always need to put the DECLARE_LRECORD() in a header |
479 under GCC. */ | 263 under GCC. */ |
480 | 264 |
481 #ifdef ERROR_CHECK_TYPECHECK | 265 #ifdef ERROR_CHECK_TYPECHECK |
482 | 266 |
483 # define DECLARE_LRECORD(c_name, structtype) \ | 267 # define DECLARE_LRECORD(c_name, structtype) \ |
484 extern const struct lrecord_implementation lrecord_##c_name; \ | 268 extern CONST_IF_NOT_DEBUG struct lrecord_implementation \ |
485 INLINE_HEADER structtype * \ | 269 lrecord_##c_name; \ |
486 error_check_##c_name (Lisp_Object obj); \ | 270 INLINE structtype *error_check_##c_name (Lisp_Object obj); \ |
487 INLINE_HEADER structtype * \ | 271 INLINE structtype * \ |
488 error_check_##c_name (Lisp_Object obj) \ | 272 error_check_##c_name (Lisp_Object obj) \ |
489 { \ | 273 { \ |
490 assert (RECORD_TYPEP (obj, lrecord_type_##c_name)); \ | 274 assert (RECORD_TYPEP (obj, &lrecord_##c_name) || \ |
275 MARKED_RECORD_P (obj)); \ | |
491 return (structtype *) XPNTR (obj); \ | 276 return (structtype *) XPNTR (obj); \ |
492 } \ | 277 } \ |
493 extern Lisp_Object Q##c_name##p | 278 extern Lisp_Object Q##c_name##p |
494 | 279 |
495 # define DECLARE_NONRECORD(c_name, type_enum, structtype) \ | 280 # define DECLARE_NONRECORD(c_name, type_enum, structtype) \ |
496 INLINE_HEADER structtype * \ | 281 INLINE structtype *error_check_##c_name (Lisp_Object obj); \ |
497 error_check_##c_name (Lisp_Object obj); \ | 282 INLINE structtype * \ |
498 INLINE_HEADER structtype * \ | |
499 error_check_##c_name (Lisp_Object obj) \ | 283 error_check_##c_name (Lisp_Object obj) \ |
500 { \ | 284 { \ |
501 assert (XTYPE (obj) == type_enum); \ | 285 assert (XGCTYPE (obj) == type_enum); \ |
502 return (structtype *) XPNTR (obj); \ | 286 return (structtype *) XPNTR (obj); \ |
503 } \ | 287 } \ |
504 extern Lisp_Object Q##c_name##p | 288 extern Lisp_Object Q##c_name##p |
505 | 289 |
506 # define XRECORD(x, c_name, structtype) error_check_##c_name (x) | 290 # define XRECORD(x, c_name, structtype) error_check_##c_name (x) |
507 # define XNONRECORD(x, c_name, type_enum, structtype) error_check_##c_name (x) | 291 # define XNONRECORD(x, c_name, type_enum, structtype) error_check_##c_name (x) |
508 | 292 |
509 # define XSETRECORD(var, p, c_name) do \ | 293 # define XSETRECORD(var, p, c_name) do \ |
510 { \ | 294 { \ |
511 XSETOBJ (var, Lisp_Type_Record, p); \ | 295 XSETOBJ (var, Lisp_Type_Record, p); \ |
512 assert (RECORD_TYPEP (var, lrecord_type_##c_name)); \ | 296 assert (RECORD_TYPEP (var, &lrecord_##c_name) || \ |
297 MARKED_RECORD_P (var)); \ | |
513 } while (0) | 298 } while (0) |
514 | 299 |
515 #else /* not ERROR_CHECK_TYPECHECK */ | 300 #else /* not ERROR_CHECK_TYPECHECK */ |
516 | 301 |
517 # define DECLARE_LRECORD(c_name, structtype) \ | 302 # define DECLARE_LRECORD(c_name, structtype) \ |
518 extern Lisp_Object Q##c_name##p; \ | 303 extern Lisp_Object Q##c_name##p; \ |
519 extern const struct lrecord_implementation lrecord_##c_name | 304 extern CONST_IF_NOT_DEBUG struct lrecord_implementation \ |
305 lrecord_##c_name | |
520 # define DECLARE_NONRECORD(c_name, type_enum, structtype) \ | 306 # define DECLARE_NONRECORD(c_name, type_enum, structtype) \ |
521 extern Lisp_Object Q##c_name##p | 307 extern Lisp_Object Q##c_name##p |
522 # define XRECORD(x, c_name, structtype) ((structtype *) XPNTR (x)) | 308 # define XRECORD(x, c_name, structtype) ((structtype *) XPNTR (x)) |
523 # define XNONRECORD(x, c_name, type_enum, structtype) \ | 309 # define XNONRECORD(x, c_name, type_enum, structtype) \ |
524 ((structtype *) XPNTR (x)) | 310 ((structtype *) XPNTR (x)) |
525 # define XSETRECORD(var, p, c_name) XSETOBJ (var, Lisp_Type_Record, p) | 311 # define XSETRECORD(var, p, c_name) XSETOBJ (var, Lisp_Type_Record, p) |
526 | 312 |
527 #endif /* not ERROR_CHECK_TYPECHECK */ | 313 #endif /* not ERROR_CHECK_TYPECHECK */ |
528 | 314 |
529 #define RECORDP(x, c_name) RECORD_TYPEP (x, lrecord_type_##c_name) | 315 #define RECORDP(x, c_name) RECORD_TYPEP (x, &lrecord_##c_name) |
316 #define GC_RECORDP(x, c_name) gc_record_type_p (x, &lrecord_##c_name) | |
530 | 317 |
531 /* Note: we now have two different kinds of type-checking macros. | 318 /* Note: we now have two different kinds of type-checking macros. |
532 The "old" kind has now been renamed CONCHECK_foo. The reason for | 319 The "old" kind has now been renamed CONCHECK_foo. The reason for |
533 this is that the CONCHECK_foo macros signal a continuable error, | 320 this is that the CONCHECK_foo macros signal a continuable error, |
534 allowing the user (through debug-on-error) to substitute a different | 321 allowing the user (through debug-on-error) to substitute a different |
550 | 337 |
551 FSF Emacs does not have this problem because RMS took the cheesy | 338 FSF Emacs does not have this problem because RMS took the cheesy |
552 way out and disabled returning from a signal entirely. */ | 339 way out and disabled returning from a signal entirely. */ |
553 | 340 |
554 #define CONCHECK_RECORD(x, c_name) do { \ | 341 #define CONCHECK_RECORD(x, c_name) do { \ |
555 if (!RECORD_TYPEP (x, lrecord_type_##c_name)) \ | 342 if (!RECORD_TYPEP (x, &lrecord_##c_name)) \ |
556 x = wrong_type_argument (Q##c_name##p, x); \ | 343 x = wrong_type_argument (Q##c_name##p, x); \ |
557 } while (0) | 344 } while (0) |
558 #define CONCHECK_NONRECORD(x, lisp_enum, predicate) do {\ | 345 #define CONCHECK_NONRECORD(x, lisp_enum, predicate) do {\ |
559 if (XTYPE (x) != lisp_enum) \ | 346 if (XTYPE (x) != lisp_enum) \ |
560 x = wrong_type_argument (predicate, x); \ | 347 x = wrong_type_argument (predicate, x); \ |
561 } while (0) | 348 } while (0) |
562 #define CHECK_RECORD(x, c_name) do { \ | 349 #define CHECK_RECORD(x, c_name) do { \ |
563 if (!RECORD_TYPEP (x, lrecord_type_##c_name)) \ | 350 if (!RECORD_TYPEP (x, &lrecord_##c_name)) \ |
564 dead_wrong_type_argument (Q##c_name##p, x); \ | 351 dead_wrong_type_argument (Q##c_name##p, x); \ |
565 } while (0) | 352 } while (0) |
566 #define CHECK_NONRECORD(x, lisp_enum, predicate) do { \ | 353 #define CHECK_NONRECORD(x, lisp_enum, predicate) do { \ |
567 if (XTYPE (x) != lisp_enum) \ | 354 if (XTYPE (x) != lisp_enum) \ |
568 dead_wrong_type_argument (predicate, x); \ | 355 dead_wrong_type_argument (predicate, x); \ |
569 } while (0) | 356 } while (0) |
570 | 357 |
571 void *alloc_lcrecord (size_t size, const struct lrecord_implementation *); | 358 void *alloc_lcrecord (size_t size, CONST struct lrecord_implementation *); |
572 | 359 |
573 #define alloc_lcrecord_type(type, lrecord_implementation) \ | 360 #define alloc_lcrecord_type(type, lrecord_implementation) \ |
574 ((type *) alloc_lcrecord (sizeof (type), lrecord_implementation)) | 361 ((type *) alloc_lcrecord (sizeof (type), lrecord_implementation)) |
575 | 362 |
363 int gc_record_type_p (Lisp_Object frob, | |
364 CONST struct lrecord_implementation *type); | |
365 | |
576 /* Copy the data from one lcrecord structure into another, but don't | 366 /* Copy the data from one lcrecord structure into another, but don't |
577 overwrite the header information. */ | 367 overwrite the header information. */ |
578 | 368 |
579 #define copy_lcrecord(dst, src) \ | 369 #define copy_lcrecord(dst, src) \ |
580 memcpy ((char *) (dst) + sizeof (struct lcrecord_header), \ | 370 memcpy ((char *) dst + sizeof (struct lcrecord_header), \ |
581 (char *) (src) + sizeof (struct lcrecord_header), \ | 371 (char *) src + sizeof (struct lcrecord_header), \ |
582 sizeof (*(dst)) - sizeof (struct lcrecord_header)) | 372 sizeof (*dst) - sizeof (struct lcrecord_header)) |
583 | 373 |
584 #define zero_lcrecord(lcr) \ | 374 #define zero_lcrecord(lcr) \ |
585 memset ((char *) (lcr) + sizeof (struct lcrecord_header), 0, \ | 375 memset ((char *) lcr + sizeof (struct lcrecord_header), 0, \ |
586 sizeof (*(lcr)) - sizeof (struct lcrecord_header)) | 376 sizeof (*lcr) - sizeof (struct lcrecord_header)) |
587 | 377 |
588 #endif /* INCLUDED_lrecord_h_ */ | 378 #endif /* _XEMACS_LRECORD_H_ */ |