Mercurial > hg > xemacs-beta
comparison src/lrecord.h @ 0:376386a54a3c r19-14
Import from CVS: tag r19-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:45:50 +0200 |
parents | |
children | ac2d302a0011 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:376386a54a3c |
---|---|
1 /* The "lrecord" structure (header of a compound lisp object). | |
2 Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc. | |
3 Copyright (C) 1996 Ben Wing. | |
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 | |
24 #ifndef _XEMACS_LRECORD_H_ | |
25 #define _XEMACS_LRECORD_H_ | |
26 | |
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 | |
29 implemented but only a few bits required in a Lisp object for | |
30 type information. (The tradeoff is that each object has its | |
31 type marked in it, thereby increasing its size.) The first | |
32 four bytes of all lrecords is a pointer to a struct | |
33 lrecord_implementation, which contains methods describing | |
34 how to process this object. | |
35 | |
36 lrecords are of two types: straight lrecords, and lcrecords. | |
37 Straight lrecords are used for those types of objects that | |
38 have their own allocation routines (typically allocated out | |
39 of 2K chunks of memory). These objects have a | |
40 `struct lrecord_header' at the top, containing only the | |
41 implementation pointer. There are special routines in alloc.c | |
42 to deal with each such object type. | |
43 | |
44 Lcrecords are used for less common sorts of objects that don't | |
45 do their own allocation. Each such object is malloc()ed | |
46 individually, and the objects are chained together through | |
47 a `next' pointer. Lcrecords have a `struct lcrecord_header' | |
48 at the top, which contains an implementation pointer and | |
49 a `next' pointer, and are allocated using alloc_lcrecord(). | |
50 | |
51 Creating a new lcrecord type is fairly easy; just follow the | |
52 lead of some existing type (e.g. hashtables). Note that you | |
53 do not need to supply all the methods (see below); reasonable | |
54 defaults are provided for many of them. Alternatively, if you're | |
55 just looking for a way of encapsulating data (which possibly | |
56 could contain Lisp_Objects in it), you may well be able to use | |
57 the opaque type. */ | |
58 | |
59 struct lrecord_header | |
60 { | |
61 /* It would be better to put the mark-bit together with the | |
62 * following datatype identification field in an 8- or 16-bit integer | |
63 * rather than playing funny games with changing header->implementation | |
64 * and "wasting" 32 bits on the below pointer. | |
65 * The type-id would then be a 7 or 15 | |
66 * bit index into a table of lrecord-implementations rather than a | |
67 * direct pointer. There would be 24 (or 16) bits left over for | |
68 * datatype-specific per-instance flags. | |
69 * The below is the simplest thing to do for the present, | |
70 * and doesn't incur that much overhead as most Emacs records | |
71 * are of such a size that the overhead isn't too bad. | |
72 * (The marker datatype is the worst case.) | |
73 * It also has the very very very slight advantage that type-checking | |
74 * involves one memory read (of the "implementation" slot) and a | |
75 * comparison against a link-time constant address rather than a | |
76 * read and a comparison against a variable value. (Variable since | |
77 * it is a very good idea to assign the indices into the hypothetical | |
78 * type-code table dynamically rather that pre-defining them.) | |
79 * I think I remember that Elk Lisp does something like this. | |
80 * Gee, I wonder if some cretin has patented it? | |
81 */ | |
82 CONST struct lrecord_implementation *implementation; | |
83 }; | |
84 #define set_lheader_implementation(header,imp) (header)->implementation=(imp) | |
85 | |
86 struct lcrecord_header | |
87 { | |
88 struct lrecord_header lheader; | |
89 /* The "next" field is normally used to chain all lrecords together | |
90 * so that the GC can find (and free) all of them. | |
91 * "alloc_lcrecord" threads records together. | |
92 * The "next" field may be used for other purposes as long as some | |
93 * other mechanism is provided for letting the GC do its work. | |
94 * (For example, the event and marker datatypes allocates members out | |
95 * of memory chunks, and it are able to find all unmarked | |
96 * events by sweeping through the elements of the list of chunks) | |
97 */ | |
98 struct lcrecord_header *next; | |
99 /* This is just for debugging/printing convenience. | |
100 Having this slot doesn't hurt us much spacewise, since an lcrecord | |
101 already has the above slots together with malloc overhead. */ | |
102 int uid :31; | |
103 /* A flag that indicates whether this lcrecord is on a "free list". | |
104 Free lists are used to minimize the number of calls to malloc() | |
105 when we're repeatedly allocating and freeing a number of the | |
106 same sort of lcrecord. Lcrecords on a free list always get | |
107 marked in a different fashion, so we can use this flag as a | |
108 sanity check to make sure that free lists only have freed lcrecords | |
109 and no freed lcrecords are elsewhere. */ | |
110 int free :1; | |
111 }; | |
112 | |
113 /* Used for lcrecords in an lcrecord-list. */ | |
114 struct free_lcrecord_header | |
115 { | |
116 struct lcrecord_header lcheader; | |
117 Lisp_Object chain; | |
118 }; | |
119 | |
120 /* This as the value of lheader->implementation->finalizer | |
121 * means that this record is already marked */ | |
122 extern void this_marks_a_marked_record (void *, int); | |
123 | |
124 /* see alloc.c for an explanation */ | |
125 extern Lisp_Object this_one_is_unmarkable (Lisp_Object obj, | |
126 void (*markobj) (Lisp_Object)); | |
127 | |
128 struct lrecord_implementation | |
129 { | |
130 CONST char *name; | |
131 /* This function is called at GC time, to make sure that all Lisp_Objects | |
132 pointed to by this object get properly marked. It should call | |
133 the mark_object function on all Lisp_Objects in the object. If | |
134 the return value is non-nil, it should be a Lisp_Object to be | |
135 marked (don't call the mark_object function explicitly on it, | |
136 because the GC routines will do this). Doing it this way reduces | |
137 recursion, so the object returned should preferably be the one | |
138 with the deepest level of Lisp_Object pointers. This function | |
139 can be NULL, meaning no GC marking is necessary. */ | |
140 Lisp_Object (*marker) (Lisp_Object, void (*mark_object) (Lisp_Object)); | |
141 /* This can be NULL if the object is an lcrecord; the | |
142 default_object_printer() in print.c will be used. */ | |
143 void (*printer) (Lisp_Object, Lisp_Object printcharfun, int escapeflag); | |
144 /* This function is called at GC time when the object is about to | |
145 be freed, and at dump time (FOR_DISKSAVE will be non-zero in this | |
146 case). It should perform any necessary cleanup (e.g. freeing | |
147 malloc()ed memory. This can be NULL, meaning no special | |
148 finalization is necessary. | |
149 | |
150 WARNING: remember that the finalizer is called at dump time even | |
151 though the object is not being freed. */ | |
152 void (*finalizer) (void *header, int for_disksave); | |
153 /* This can be NULL, meaning compare objects with EQ(). */ | |
154 int (*equal) (Lisp_Object obj1, Lisp_Object obj2, int depth); | |
155 /* This can be NULL, meaning use the Lisp_Object itself as the hash; | |
156 but *only* if the `equal' function is EQ (if two objects are | |
157 `equal', they *must* hash to the same value or the hashing won't | |
158 work). */ | |
159 unsigned long (*hash) (Lisp_Object, int); | |
160 Lisp_Object (*getprop) (Lisp_Object obj, Lisp_Object prop); | |
161 int (*putprop) (Lisp_Object obj, Lisp_Object prop, Lisp_Object val); | |
162 int (*remprop) (Lisp_Object obj, Lisp_Object prop); | |
163 Lisp_Object (*plist) (Lisp_Object obj); | |
164 | |
165 /* Only one of these is non-0. If both are 0, it means that this type | |
166 is not instantiable by alloc_lcrecord(). */ | |
167 unsigned int static_size; | |
168 unsigned int (*size_in_bytes_method) (CONST void *header); | |
169 /* A unique subtag-code (dynamically) assigned to this datatype. */ | |
170 /* (This is a pointer so the rest of this structure can be read-only.) */ | |
171 int *lrecord_type_index; | |
172 /* A "basic" lrecord is any lrecord that's not an lcrecord, i.e. | |
173 one that does not have an lcrecord_header at the front and which | |
174 is (usually) allocated in frob blocks. We only use this flag | |
175 for some consistency checking, and that only when error-checking | |
176 is enabled. */ | |
177 int basic_p; | |
178 }; | |
179 | |
180 extern int gc_in_progress; | |
181 | |
182 #define MARKED_RECORD_P(obj) (gc_in_progress && \ | |
183 XRECORD_LHEADER (obj)->implementation->finalizer == \ | |
184 this_marks_a_marked_record) | |
185 | |
186 /* Declaring the following structures as const puts them in the | |
187 text (read-only) segment, which makes debugging inconvenient | |
188 because this segment is not mapped when processing a core- | |
189 dump file */ | |
190 | |
191 #ifdef DEBUG_XEMACS | |
192 #define CONST_IF_NOT_DEBUG | |
193 #else | |
194 #define CONST_IF_NOT_DEBUG CONST | |
195 #endif | |
196 | |
197 /* DEFINE_LRECORD_IMPLEMENTATION is for objects with constant size. | |
198 DEFINE_LRECORD_SEQUENCE_IMPLEMENTATION is for objects whose size varies. | |
199 */ | |
200 | |
201 #if defined (ERROR_CHECK_TYPECHECK) | |
202 # define DECLARE_ERROR_CHECK_TYPECHECK(c_name, structtype) | |
203 #else | |
204 # define DECLARE_ERROR_CHECK_TYPECHECK(c_name, structtype) | |
205 #endif | |
206 | |
207 #define DEFINE_BASIC_LRECORD_IMPLEMENTATION(name,c_name,marker,printer,nuker,equal,hash,structtype) \ | |
208 DECLARE_ERROR_CHECK_TYPECHECK(c_name, structtype) \ | |
209 static int lrecord_##c_name##_lrecord_type_index; \ | |
210 CONST_IF_NOT_DEBUG struct lrecord_implementation lrecord_##c_name[2] = \ | |
211 { { name, marker, printer, nuker, equal, hash, \ | |
212 0, 0, 0, 0, sizeof (structtype), 0, \ | |
213 &(lrecord_##c_name##_lrecord_type_index), 1 }, \ | |
214 { 0, 0, 0, this_marks_a_marked_record, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 } } | |
215 | |
216 #define DEFINE_BASIC_LRECORD_IMPLEMENTATION_WITH_PROPS(name,c_name,marker,printer,nuker,equal,hash,getprop,putprop,remprop,props,structtype) \ | |
217 DECLARE_ERROR_CHECK_TYPECHECK(c_name, structtype) \ | |
218 static int lrecord_##c_name##_lrecord_type_index; \ | |
219 CONST_IF_NOT_DEBUG struct lrecord_implementation lrecord_##c_name[2] = \ | |
220 { { name, marker, printer, nuker, equal, hash, \ | |
221 getprop, putprop, remprop, props, sizeof (structtype), 0, \ | |
222 &(lrecord_##c_name##_lrecord_type_index), 1 }, \ | |
223 { 0, 0, 0, this_marks_a_marked_record, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 } } | |
224 | |
225 #define DEFINE_LRECORD_IMPLEMENTATION(name,c_name,marker,printer,nuker,equal,hash,structtype) \ | |
226 DECLARE_ERROR_CHECK_TYPECHECK(c_name, structtype) \ | |
227 static int lrecord_##c_name##_lrecord_type_index; \ | |
228 CONST_IF_NOT_DEBUG struct lrecord_implementation lrecord_##c_name[2] = \ | |
229 { { name, marker, printer, nuker, equal, hash, \ | |
230 0, 0, 0, 0, sizeof (structtype), 0, \ | |
231 &(lrecord_##c_name##_lrecord_type_index), 0 }, \ | |
232 { 0, 0, 0, this_marks_a_marked_record, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } | |
233 | |
234 #define DEFINE_LRECORD_IMPLEMENTATION_WITH_PROPS(name,c_name,marker,printer,nuker,equal,hash,getprop,putprop,remprop,props,structtype) \ | |
235 DECLARE_ERROR_CHECK_TYPECHECK(c_name, structtype) \ | |
236 static int lrecord_##c_name##_lrecord_type_index; \ | |
237 CONST_IF_NOT_DEBUG struct lrecord_implementation lrecord_##c_name[2] = \ | |
238 { { name, marker, printer, nuker, equal, hash, \ | |
239 getprop, putprop, remprop, props, sizeof (structtype), 0, \ | |
240 &(lrecord_##c_name##_lrecord_type_index), 0 }, \ | |
241 { 0, 0, 0, this_marks_a_marked_record, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } | |
242 | |
243 #define DEFINE_LRECORD_SEQUENCE_IMPLEMENTATION(name,c_name,marker,printer,nuker,equal,hash,sizer,structtype) \ | |
244 DECLARE_ERROR_CHECK_TYPECHECK(c_name, structtype) \ | |
245 static int lrecord_##c_name##_lrecord_type_index; \ | |
246 CONST_IF_NOT_DEBUG struct lrecord_implementation lrecord_##c_name[2] = \ | |
247 { { name, marker, printer, nuker, equal, hash, \ | |
248 0, 0, 0, 0, 0, sizer, \ | |
249 &(lrecord_##c_name##_lrecord_type_index), 0 }, \ | |
250 { 0, 0, 0, this_marks_a_marked_record, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } | |
251 | |
252 #define DEFINE_LRECORD_SEQUENCE_IMPLEMENTATION_WITH_PROPS(name,c_name,marker,printer,nuker,equal,hash,getprop,putprop,remprop,props,sizer,structtype) \ | |
253 DECLARE_ERROR_CHECK_TYPECHECK(c_name, structtype) \ | |
254 static int lrecord_##c_name##_lrecord_type_index; \ | |
255 CONST_IF_NOT_DEBUG struct lrecord_implementation lrecord_##c_name[2] = \ | |
256 { { name, marker, printer, nuker, equal, hash, \ | |
257 getprop, putprop, remprop, props, 0, sizer, \ | |
258 &(lrecord_##c_name##_lrecord_type_index), 0 }, \ | |
259 { 0, 0, 0, this_marks_a_marked_record, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } | |
260 | |
261 #define LRECORDP(a) (XTYPE ((a)) == Lisp_Record) | |
262 #define XRECORD_LHEADER(a) ((struct lrecord_header *) XPNTR (a)) | |
263 #define RECORD_TYPEP(x, ty) \ | |
264 (LRECORDP (x) && XRECORD_LHEADER (x)->implementation == (ty)) | |
265 | |
266 /* NOTE: the DECLARE_LRECORD() must come before the associated | |
267 DEFINE_LRECORD_*() or you will get compile errors. | |
268 | |
269 Furthermore, you always need to put the DECLARE_LRECORD() in a header | |
270 file, and make sure the header file is included in inline.c, even | |
271 if the type is private to a particular file. Otherwise, you will | |
272 get undefined references for the error_check_foo() inline function | |
273 under GCC. */ | |
274 | |
275 #ifdef ERROR_CHECK_TYPECHECK | |
276 | |
277 # define DECLARE_LRECORD(c_name, structtype) \ | |
278 extern CONST_IF_NOT_DEBUG struct lrecord_implementation \ | |
279 lrecord_##c_name[]; \ | |
280 INLINE structtype *error_check_##c_name (Lisp_Object _obj); \ | |
281 INLINE structtype * \ | |
282 error_check_##c_name (Lisp_Object _obj) \ | |
283 { \ | |
284 XUNMARK (_obj); \ | |
285 assert (RECORD_TYPEP (_obj, lrecord_##c_name) || \ | |
286 MARKED_RECORD_P (_obj)); \ | |
287 return (structtype *) XPNTR (_obj); \ | |
288 } \ | |
289 extern Lisp_Object Q##c_name##p | |
290 | |
291 # define DECLARE_NONRECORD(c_name, type_enum, structtype) \ | |
292 INLINE structtype *error_check_##c_name (Lisp_Object _obj); \ | |
293 INLINE structtype * \ | |
294 error_check_##c_name (Lisp_Object _obj) \ | |
295 { \ | |
296 XUNMARK (_obj); \ | |
297 assert (XGCTYPE (_obj) == type_enum); \ | |
298 return (structtype *) XPNTR (_obj); \ | |
299 } \ | |
300 extern Lisp_Object Q##c_name##p | |
301 | |
302 # define XRECORD(x, c_name, structtype) error_check_##c_name (x) | |
303 # define XNONRECORD(x, c_name, type_enum, structtype) error_check_##c_name (x) | |
304 | |
305 # define XSETRECORD(var, p, c_name) do \ | |
306 { \ | |
307 XSETOBJ (var, Lisp_Record, p); \ | |
308 assert (RECORD_TYPEP (var, lrecord_##c_name) || \ | |
309 MARKED_RECORD_P (var)); \ | |
310 } while (0) | |
311 | |
312 #else /* not ERROR_CHECK_TYPECHECK */ | |
313 | |
314 # define DECLARE_LRECORD(c_name, structtype) \ | |
315 extern Lisp_Object Q##c_name##p; \ | |
316 extern CONST_IF_NOT_DEBUG struct lrecord_implementation \ | |
317 lrecord_##c_name[] | |
318 # define DECLARE_NONRECORD(c_name, type_enum, structtype) \ | |
319 extern Lisp_Object Q##c_name##p | |
320 # define XRECORD(x, c_name, structtype) ((structtype *) XPNTR (x)) | |
321 # define XNONRECORD(x, c_name, type_enum, structtype) \ | |
322 ((structtype *) XPNTR (x)) | |
323 # define XSETRECORD(var, p, c_name) XSETOBJ (var, Lisp_Record, p) | |
324 | |
325 #endif /* not ERROR_CHECK_TYPECHECK */ | |
326 | |
327 #define RECORDP(x, c_name) RECORD_TYPEP (x, lrecord_##c_name) | |
328 #define GC_RECORDP(x, c_name) gc_record_type_p (x, lrecord_##c_name) | |
329 | |
330 /* Note: we now have two different kinds of type-checking macros. | |
331 The "old" kind has now been renamed CONCHECK_foo. The reason for | |
332 this is that the CONCHECK_foo macros signal a continuable error, | |
333 allowing the user (through debug-on-error) to subsitute a different | |
334 value and return from the signal, which causes the lvalue argument | |
335 to get changed. Quite a lot of code would crash if that happened, | |
336 because it did things like | |
337 | |
338 foo = XCAR (list); | |
339 CHECK_STRING (foo); | |
340 | |
341 and later on did XSTRING (XCAR (list)), assuming that the type | |
342 is correct (when it might be wrong, if the user substituted a | |
343 correct value in the debugger). | |
344 | |
345 To get around this, I made all the CHECK_foo macros signal a | |
346 non-continuable error. Places where a continuable error is OK | |
347 (generally only when called directly on the argument of a Lisp | |
348 primitive) should be changed to use CONCHECK(). | |
349 | |
350 FSF Emacs does not have this problem because RMS took the cheesy | |
351 way out and disabled returning from a signal entirely. */ | |
352 | |
353 #define CONCHECK_RECORD(x, c_name) do \ | |
354 { if (!RECORD_TYPEP (x, lrecord_##c_name)) \ | |
355 x = wrong_type_argument (Q##c_name##p, x); } \ | |
356 while (0) | |
357 #define CONCHECK_NONRECORD(x, lisp_enum, predicate) do \ | |
358 { if (XTYPE (x) != lisp_enum) \ | |
359 x = wrong_type_argument (predicate, x); } \ | |
360 while (0) | |
361 #define CHECK_RECORD(x, c_name) do \ | |
362 { if (!RECORD_TYPEP (x, lrecord_##c_name)) \ | |
363 dead_wrong_type_argument (Q##c_name##p, x); } \ | |
364 while (0) | |
365 #define CHECK_NONRECORD(x, lisp_enum, predicate) do \ | |
366 { if (XTYPE (x) != lisp_enum) \ | |
367 dead_wrong_type_argument (predicate, x); } \ | |
368 while (0) | |
369 | |
370 void *alloc_lcrecord (int size, CONST struct lrecord_implementation *); | |
371 | |
372 int gc_record_type_p (Lisp_Object frob, | |
373 CONST struct lrecord_implementation *type); | |
374 | |
375 /* Copy the data from one lcrecord structure into another, but don't | |
376 overwrite the header information. */ | |
377 | |
378 #define copy_lcrecord(dst, src) \ | |
379 memcpy ((char *) dst + sizeof (struct lcrecord_header), \ | |
380 (char *) src + sizeof (struct lcrecord_header), \ | |
381 sizeof (*dst) - sizeof (struct lcrecord_header)) | |
382 | |
383 #define zero_lcrecord(lcr) \ | |
384 memset ((char *) lcr + sizeof (struct lcrecord_header), 0, \ | |
385 sizeof (*lcr) - sizeof (struct lcrecord_header)) | |
386 | |
387 #endif /* _XEMACS_LRECORD_H_ */ |