turn on TYPECHECK_DEBUG, turn off TYPECHECK_VERBOSE
[cacao.git] / src / vm / jit / verify / typeinfo.h
1 /* typeinfo.h - type system used by the type checker
2
3    Copyright (C) 1996-2005 R. Grafl, A. Krall, C. Kruegel, C. Oates,
4    R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner,
5    C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger,
6    Institut f. Computersprachen - TU Wien
7
8    This file is part of CACAO.
9
10    This program is free software; you can redistribute it and/or
11    modify it under the terms of the GNU General Public License as
12    published by the Free Software Foundation; either version 2, or (at
13    your option) any later version.
14
15    This program is distributed in the hope that it will be useful, but
16    WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
23    02111-1307, USA.
24
25    Contact: cacao@complang.tuwien.ac.at
26
27    Authors: Edwin Steiner
28
29    $Id: typeinfo.h 2749 2005-06-20 15:04:31Z edwin $
30
31 */
32
33 #ifndef _TYPEINFO_H
34 #define _TYPEINFO_H
35
36 #include "vm/global.h"
37 #include "vm/references.h"
38
39 /* configuration **************************************************************/
40
41 /*
42  * TYPECHECK_STATISTICS activates gathering statistical information.
43  * TYPEINFO_DEBUG activates debug checks and debug helpers in typeinfo.c
44  * TYPECHECK_DEBUG activates debug checks in typecheck.c
45  * TYPEINFO_DEBUG_TEST activates the typeinfo test at startup.
46  * TYPECHECK_VERBOSE_IMPORTANT activates important debug messages
47  * TYPECHECK_VERBOSE activates all debug messages
48  * TYPEINFO_VERBOSE activates debug prints in typeinfo.c
49  */
50 #ifdef CACAO_TYPECHECK
51 /*#define TYPECHECK_STATISTICS*/
52 #define TYPEINFO_DEBUG
53 /*#define TYPEINFO_VERBOSE*/
54 #define TYPECHECK_DEBUG
55 /*#define TYPEINFO_DEBUG_TEST*/
56 /*#define TYPECHECK_VERBOSE*/
57 /*#define TYPECHECK_VERBOSE_IMPORTANT*/
58 #if defined(TYPECHECK_VERBOSE) || defined(TYPECHECK_VERBOSE_IMPORTANT)
59 #define TYPECHECK_VERBOSE_OPT
60 #endif
61 #endif
62
63 #ifdef TYPECHECK_VERBOSE_OPT
64 extern bool typecheckverbose;
65 #endif
66
67 /* resolve typedef cycles *****************************************************/
68
69 typedef struct typeinfo typeinfo;
70 typedef struct typeinfo_mergedlist typeinfo_mergedlist;
71 typedef struct typedescriptor typedescriptor;
72 typedef struct typevector typevector;
73 typedef struct typeinfo_retaddr_set typeinfo_retaddr_set;
74
75 /* constants ******************************************************************/
76
77 #define MAYBE  2
78
79 #if MAYBE == true
80 #error "`MAYBE` must not be the same as `true`"
81 #endif
82 #if MAYBE == false
83 #error "`MAYBE` must not be the same as `false`"
84 #endif
85
86 /* types **********************************************************************/
87
88 /* a tristate_t is one of {true,false,MAYBE} */
89 typedef int tristate_t;
90
91 /* data structures for the type system ****************************************/
92
93 /* The typeinfo structure stores detailed information on address types.
94  * (stack elements, variables, etc. with type == TYPE_ADR.)
95  *
96  * There are two kinds of address types which can be distinguished by
97  * the value of the typeclass field:
98  *
99  * 1) typeclass == NULL: returnAddress type
100  *                       use TYPEINFO_IS_PRIMITIVE to test for this
101  *
102  * 2) typeclass != NULL: reference type
103  *                       use TYPEINFO_IS_REFERENCE to test for this
104  *
105  * Note: For non-address types either there is no typeinfo allocated
106  * or the fields of the typeinfo struct contain undefined values!
107  * DO NOT access the typeinfo for non-address types!
108  *
109  * CAUTION: The typeinfo structure should be considered opaque outside of
110  *          typeinfo.[ch]. Please use the macros and functions defined here to
111  *          access typeinfo structures!
112  */
113
114 /* At all times *exactly one* of the following conditions is true for
115  * a particular typeinfo struct:
116  *
117  * A) typeclass == NULL
118  *
119  *        This is a returnAddress type. The interpretation of the
120  *        elementclass field depends on wether this typeinfo describes
121  *        a stack slot or a local variable:
122  *
123  *        stack slot: elementclass is a pointer to a
124  *            typeinfo_retaddr_set which contains a return target for
125  *            every vector in the current set of local variable vectors.
126  *            See typeinfo_retaddr_set and typevector below.
127  *
128  *        local variable: elementclass is the return target (when cast
129  *            to basicblock *)
130  *
131  *        Use TYPEINFO_IS_PRIMITIVE to check for this.
132  *        Use TYPEINFO_RETURNADDRESS to access the pointer in elementclass.
133  *        Don't access other fields of the struct.
134  *
135  * B) typeclass == pseudo_class_Null
136  *
137  *        This is the null-reference type. 
138  *        Use TYPEINFO_IS_NULLTYPE to check for this.
139  *        Don't access other fields of the struct.
140  *
141  * C) typeclass == pseudo_class_New
142  *
143  *        This is an 'uninitialized object' type. elementclass can be
144  *        cast to instruction* and points to the NEW instruction
145  *        responsible for creating this type.
146  *
147  *        Use TYPEINFO_NEWOBJECT_INSTRUCTION to access the pointer in
148  *        elementclass.
149  *        Don't access other fields of the struct.
150  *
151  * D) typeclass == pseudo_class_Arraystub
152  *
153  *        This type is used to represent the result of merging array types
154  *        with incompatible component types. An arraystub allows no access
155  *        to its components (since their type is undefined), but it allows
156  *        operations which act directly on an arbitrary array type (such as
157  *        requesting the array size).
158  *
159  *        NOTE: An array stub does *not* count as an array. It has dimension
160  *              zero.
161  *
162  *        Otherwise like a normal class reference type.
163  *        Don't access other fields of the struct.
164  *
165  * E) typeclass is an array class
166  *
167  *        An array reference.
168  *            elementclass...typeclass of the element type
169  *            dimension......dimension of the array (>=1)
170  *            elementtype....element type (ARRAYTYPE_...)
171  *            merged.........mergedlist of the element type
172  *
173  *        Use TYPEINFO_IS_ARRAY to check for this case.
174  *
175  *        The elementclass may be one of the following:
176  *        1) pseudo_class_Arraystub
177  *        2) an unresolved type
178  *        3) a loaded interface
179  *        4) a loaded (non-pseudo-,non-array-)class != (BOOTSTRAP)java.lang.Object
180  *                Note: `merged` may be used
181  *        5) (BOOTSTRAP)java.lang.Object
182  *                Note: `merged` may be used
183  *
184  *        For the semantics of the merged field in cases 4) and 5) consult the 
185  *        corresponding descriptions with `elementclass` replaced by `typeclass`.
186  *
187  * F) typeclass is an unresolved type (a symbolic class/interface reference)
188  *
189  *        The type has not been resolved yet. (Meaning it corresponds to an
190  *        unloaded class or interface).
191  *        Don't access other fields of the struct.
192  *
193  * G) typeclass is a loaded interface
194  *
195  *        An interface reference type.
196  *        Don't access other fields of the struct.
197  *
198  * H) typeclass is a loaded (non-pseudo-,non-array-)class != (BOOTSTRAP)java.lang.Object
199  *
200  *        A loaded class type.
201  *        All classref_or_classinfos in u.merged.list (if any) are
202  *        loaded subclasses of typeclass (no interfaces, array classes, or
203  *        unresolved types).
204  *        Don't access other fields of the struct.
205  *
206  * I) typeclass is (BOOTSTRAP)java.lang.Object
207  *
208  *        The most general kind of reference type.
209  *        In this case u.merged.count and u.merged.list
210  *        are valid and may be non-zero.
211  *        The classref_or_classinfos in u.merged.list (if any) may be
212  *        classes, interfaces, pseudo classes or unresolved types.
213  *        Don't access other fields of the struct.
214  */
215
216 /* The following algorithm is used to determine if the type described
217  * by this typeinfo struct supports the interface X:  * XXX add MAYBE *
218  *
219  *     1) If typeclass is X or a subinterface of X the answer is "yes".
220  *     2) If typeclass is a (pseudo) class implementing X the answer is "yes".
221  *     3) If typeclass is not an array and u.merged.count>0
222  *        and all classes/interfaces in u.merged.list implement X
223  *        the answer is "yes".
224  *     4) If none of the above is true the answer is "no".
225  */
226
227 /*
228  * CAUTION: The typeinfo structure should be considered opaque outside of
229  *          typeinfo.[ch]. Please use the macros and functions defined here to
230  *          access typeinfo structures!
231  */
232 struct typeinfo {
233         classref_or_classinfo  typeclass;
234         classref_or_classinfo  elementclass; /* valid if dimension>0 */ /* various uses! */
235         typeinfo_mergedlist   *merged;
236         u1                     dimension;
237         u1                     elementtype;  /* valid if dimension>0           */
238 };
239
240 struct typeinfo_mergedlist {
241         s4                    count;
242         classref_or_classinfo list[1];       /* variable length!                        */
243 };
244
245 /*-----------------------------------------------------------------------*/
246 /* a typeinfo_retaddr_set stores the set of possible returnAddresses     */
247 /* that may be in a particular stack slot at a particular point in the   */
248 /* program.                                                              */
249 /*                                                                       */
250 /* There may be one or more alternative returnAddresses if the           */
251 /* instruction can be reached via one or more JSR jumps (among other     */
252 /* control-flow paths                                                    */
253 /*-----------------------------------------------------------------------*/
254
255 struct typeinfo_retaddr_set {
256         typeinfo_retaddr_set *alt;  /* next alternative in set               */
257         void                 *addr; /* return address                        */
258 };
259
260 /* a type descriptor stores a basic type and the typeinfo                */
261 /* this is used for storing the type of a local variable, and for        */
262 /* storing types in the signature of a method                            */
263
264 struct typedescriptor {
265         typeinfo        info;     /* valid if type == TYPE_ADR               */
266         u1              type;     /* basic type (TYPE_INT, ...)              */
267 };
268
269 /*-----------------------------------------------------------------------*/
270 /* typevectors are used to store the types of all local variables        */
271 /* at a given point in the program.                                      */
272 /*                                                                       */
273 /* There may be more than one possible typevector for the local          */
274 /* variables at a given instruction if the instruction can be reached    */
275 /* via one or more JSR jumps (among other control-flow paths).           */
276 /*                                                                       */
277 /* This is called the set of alternative type vectors at that            */
278 /* particular point in the program.                                      */
279 /*-----------------------------------------------------------------------*/
280
281 struct typevector {
282         typevector      *alt;     /* next alternative in typevector set      */
283         int              k;       /* for lining up with the stack set        */
284         typedescriptor   td[1];   /* types of locals, variable length!       */
285 };
286
287 /****************************************************************************/
288 /* MACROS                                                                   */
289 /****************************************************************************/
290
291 /* NOTE: The TYPEINFO macros take typeinfo *structs*, not pointers as
292  *       arguments.  You have to dereference any pointers.
293  */
294
295 /* typevectors **************************************************************/
296
297 #define TYPEVECTOR_SIZE(size)                                           \
298     ((sizeof(typevector) - sizeof(typedescriptor))      \
299      + (size)*sizeof(typedescriptor))
300
301 #define DNEW_TYPEVECTOR(size)                                           \
302     ((typevector*)dump_alloc(TYPEVECTOR_SIZE(size)))
303
304 #define DMNEW_TYPEVECTOR(num,size)                                              \
305     ((void*)dump_alloc((num) * TYPEVECTOR_SIZE(size)))
306
307 #define MGET_TYPEVECTOR(array,index,size) \
308     ((typevector*) (((u1*)(array)) + TYPEVECTOR_SIZE(size) * (index)))
309
310 #define COPY_TYPEVECTORSET(src,dst,size)                                                \
311     do {memcpy(dst,src,TYPEVECTOR_SIZE(size));                                  \
312         dst->k = 0;                                             \
313         if ((src)->alt) {                                                                               \
314                 (dst)->alt = typevectorset_copy((src)->alt,1,size);     \
315         }} while(0)
316
317 /* internally used macros ***************************************************/
318
319 /* internal, don't use this explicitly! */
320 #define TYPEINFO_ALLOCMERGED(mergedlist,count)                  \
321     do {(mergedlist) = (typeinfo_mergedlist*)dump_alloc(        \
322             sizeof(typeinfo_mergedlist)                         \
323             + ((count)-1)*sizeof(classinfo*));} while(0)
324
325 /* internal, don't use this explicitly! */
326 #define TYPEINFO_FREEMERGED(mergedlist)
327
328 /* internal, don't use this explicitly! */
329 #define TYPEINFO_FREEMERGED_IF_ANY(mergedlist)
330
331 /* macros for type queries **************************************************/
332
333 #define TYPEINFO_IS_PRIMITIVE(info)                             \
334             ((info).typeclass.any == NULL)
335
336 #define TYPEINFO_IS_REFERENCE(info)                             \
337             ((info).typeclass.any != NULL)
338
339 #define TYPEINFO_IS_NULLTYPE(info)                              \
340             ((info).typeclass.cls == pseudo_class_Null)
341
342 #define TYPEINFO_IS_NEWOBJECT(info)                             \
343             ((info).typeclass.cls == pseudo_class_New)
344
345 /* only use this if TYPEINFO_IS_PRIMITIVE returned true! */
346 #define TYPEINFO_RETURNADDRESS(info)                            \
347             ((void *)(info).elementclass.any)
348
349 /* only use this if TYPEINFO_IS_NEWOBJECT returned true! */
350 #define TYPEINFO_NEWOBJECT_INSTRUCTION(info)                    \
351             ((void *)(info).elementclass.any)
352
353 /* macros for array type queries ********************************************/
354
355 #define TYPEINFO_IS_ARRAY(info)                                 \
356             ( TYPEINFO_IS_REFERENCE(info)                       \
357               && ((info).dimension != 0) )
358
359 #define TYPEINFO_IS_SIMPLE_ARRAY(info)                          \
360             ( ((info).dimension == 1) )
361
362 #define TYPEINFO_IS_ARRAY_ARRAY(info)                           \
363             ( ((info).dimension >= 2) )
364
365 #define TYPEINFO_IS_PRIMITIVE_ARRAY(info,arraytype)             \
366             ( TYPEINFO_IS_SIMPLE_ARRAY(info)                    \
367               && ((info).elementtype == (arraytype)) )
368
369 #define TYPEINFO_IS_OBJECT_ARRAY(info)                          \
370             ( TYPEINFO_IS_SIMPLE_ARRAY(info)                    \
371               && ((info).elementclass.any != NULL) )
372
373 /* assumes that info describes an array type */
374 #define TYPEINFO_IS_ARRAY_OF_REFS_NOCHECK(info)                 \
375             ( ((info).elementclass.any != NULL)                 \
376               || ((info).dimension >= 2) )
377
378 #define TYPEINFO_IS_ARRAY_OF_REFS(info)                         \
379             ( TYPEINFO_IS_ARRAY(info)                           \
380               && TYPEINFO_IS_ARRAY_OF_REFS_NOCHECK(info) )
381
382 #define TYPE_IS_RETURNADDRESS(type,info)                        \
383             ( ((type)==TYPE_ADDRESS)                            \
384               && TYPEINFO_IS_PRIMITIVE(info) )
385
386 #define TYPE_IS_REFERENCE(type,info)                            \
387             ( ((type)==TYPE_ADDRESS)                            \
388               && !TYPEINFO_IS_PRIMITIVE(info) )
389
390 #define TYPEDESC_IS_RETURNADDRESS(td)                           \
391             TYPE_IS_RETURNADDRESS((td).type,(td).info)
392
393 #define TYPEDESC_IS_REFERENCE(td)                               \
394             TYPE_IS_REFERENCE((td).type,(td).info)
395
396 /* queries allowing the null type ********************************************/
397
398 #define TYPEINFO_MAYBE_ARRAY(info)                              \
399     (TYPEINFO_IS_ARRAY(info) || TYPEINFO_IS_NULLTYPE(info))
400
401 #define TYPEINFO_MAYBE_PRIMITIVE_ARRAY(info,at)                 \
402     (TYPEINFO_IS_PRIMITIVE_ARRAY(info,at) || TYPEINFO_IS_NULLTYPE(info))
403
404 #define TYPEINFO_MAYBE_ARRAY_OF_REFS(info)                      \
405     (TYPEINFO_IS_ARRAY_OF_REFS(info) || TYPEINFO_IS_NULLTYPE(info))
406
407 /* macros for initializing typeinfo structures ******************************/
408
409 #define TYPEINFO_INIT_PRIMITIVE(info)                           \
410          do {(info).typeclass.any = NULL;                       \
411              (info).elementclass.any = NULL;                    \
412              (info).merged = NULL;                              \
413              (info).dimension = 0;                              \
414              (info).elementtype = 0;} while(0)
415
416 #define TYPEINFO_INIT_RETURNADDRESS(info,adr)                   \
417          do {(info).typeclass.any = NULL;                       \
418              (info).elementclass.any = (adr);                   \
419              (info).merged = NULL;                              \
420              (info).dimension = 0;                              \
421              (info).elementtype = 0;} while(0)
422
423 #define TYPEINFO_INIT_NON_ARRAY_CLASSINFO(info,cinfo)   \
424          do {(info).typeclass.cls = (cinfo);            \
425              (info).elementclass.any = NULL;            \
426              (info).merged = NULL;                      \
427              (info).dimension = 0;                      \
428              (info).elementtype = 0;} while(0)
429
430 #define TYPEINFO_INIT_NULLTYPE(info)                            \
431             TYPEINFO_INIT_NON_ARRAY_CLASSINFO(info,pseudo_class_Null)
432
433 #define TYPEINFO_INIT_NEWOBJECT(info,instr)             \
434          do {(info).typeclass.cls = pseudo_class_New;   \
435              (info).elementclass.any = (instr);         \
436              (info).merged = NULL;                      \
437              (info).dimension = 0;                      \
438              (info).elementtype = 0;} while(0)
439
440 #define TYPEINFO_INIT_PRIMITIVE_ARRAY(info,arraytype)                   \
441     TYPEINFO_INIT_CLASSINFO(info,primitivetype_table[arraytype].arrayclass);
442
443 #define TYPEINFO_INIT_CLASSINFO(info,c)                                 \
444         do {if (((info).typeclass.cls = (c))->vftbl->arraydesc) {       \
445                 if ((c)->vftbl->arraydesc->elementvftbl)                \
446                     (info).elementclass.cls = (c)->vftbl->arraydesc->elementvftbl->class; \
447                 else                                                    \
448                     (info).elementclass.any = NULL;                     \
449                 (info).dimension = (c)->vftbl->arraydesc->dimension;    \
450                 (info).elementtype = (c)->vftbl->arraydesc->elementtype;\
451             }                                                           \
452             else {                                                      \
453                 (info).elementclass.any = NULL;                         \
454                 (info).dimension = 0;                                   \
455                 (info).elementtype = 0;                                 \
456             }                                                           \
457             (info).merged = NULL;} while(0)
458
459 #define TYPEINFO_INIT_CLASSREF(info,c)    \
460             typeinfo_init_class(&(info),CLASSREF_OR_CLASSINFO(c))
461
462 #define TYPEINFO_INIT_CLASSREF_OR_CLASSINFO(info,c)    \
463             typeinfo_init_class(&(info),c)
464
465 /* macros for copying types (destinition is not checked or freed) ***********/
466
467 /* TYPEINFO_COPY makes a shallow copy, the merged pointer is simply copied. */
468 #define TYPEINFO_COPY(src,dst)                                  \
469     do {(dst) = (src);} while(0)
470
471 /* TYPEINFO_CLONE makes a deep copy, the merged list (if any) is duplicated
472  * into a newly allocated array.
473  */
474 #define TYPEINFO_CLONE(src,dst)                                 \
475     do {(dst) = (src);                                          \
476         if ((dst).merged) typeinfo_clone(&(src),&(dst));} while(0)
477
478 /****************************************************************************/
479 /* FUNCTIONS                                                                */
480 /****************************************************************************/
481
482 /* typevector functions *****************************************************/
483
484 /* element read-only access */
485 bool typevectorset_checktype(typevector *set,int index,int type);
486 bool typevectorset_checkreference(typevector *set,int index);
487 bool typevectorset_checkretaddr(typevector *set,int index);
488 int typevectorset_copymergedtype(typevector *set,int index,typeinfo *dst);
489 typeinfo *typevectorset_mergedtypeinfo(typevector *set,int index,typeinfo *temp);
490 int typevectorset_mergedtype(typevector *set,int index,typeinfo *temp,typeinfo **result);
491
492 /* element write access */
493 void typevectorset_store(typevector *set,int index,int type,typeinfo *info);
494 void typevectorset_store_retaddr(typevector *set,int index,typeinfo *info);
495 void typevectorset_store_twoword(typevector *set,int index,int type);
496 void typevectorset_init_object(typevector *set,void *ins,classref_or_classinfo initclass,int size);
497
498 /* vector functions */
499 bool typevector_separable_from(typevector *a,typevector *b,int size);
500 bool typevector_merge(typevector *dst,typevector *y,int size);
501
502 /* vector set functions */
503 typevector *typevectorset_copy(typevector *src,int k,int size);
504 bool typevectorset_separable_with(typevector *set,typevector *add,int size);
505 bool typevectorset_collapse(typevector *dst,int size);
506 void typevectorset_add(typevector *dst,typevector *v,int size);
507 typevector *typevectorset_select(typevector **set,int retindex,void *retaddr);
508
509 /* inquiry functions (read-only) ********************************************/
510
511 bool typeinfo_is_array(typeinfo *info);
512 bool typeinfo_is_primitive_array(typeinfo *info,int arraytype);
513 bool typeinfo_is_array_of_refs(typeinfo *info);
514
515 tristate_t typeinfo_implements_interface(typeinfo *info,classinfo *interf);
516 tristate_t typeinfo_is_assignable(typeinfo *value,typeinfo *dest);
517 tristate_t typeinfo_is_assignable_to_class(typeinfo *value,classref_or_classinfo dest);
518
519 /* initialization functions *************************************************/
520
521 bool typeinfo_init_class(typeinfo *info,classref_or_classinfo c);
522 void typeinfo_init_component(typeinfo *srcarray,typeinfo *dst);
523
524 void typeinfo_init_from_typedesc(typedesc *desc,u1 *type,typeinfo *info);
525 void typeinfo_init_from_methoddesc(methoddesc *desc,u1 *typebuf,
526                                    typeinfo *infobuf,
527                                    int buflen,bool twoword,
528                                    u1 *returntype,typeinfo *returntypeinfo);
529 void  typedescriptor_init_from_typedesc(typedescriptor *td,
530                                                                             typedesc *desc);
531 int  typedescriptors_init_from_methoddesc(typedescriptor *td,
532                                                                                   methoddesc *desc,
533                                                                                   int buflen,bool twoword,int startindex,
534                                                                                   typedescriptor *returntype);
535
536 void typeinfo_clone(typeinfo *src,typeinfo *dest);
537
538 /* freeing memory ***********************************************************/
539
540 void typeinfo_free(typeinfo *info);
541
542 /* functions for merging types **********************************************/
543
544 bool typeinfo_merge(typeinfo *dest,typeinfo* y);
545
546 /* debugging helpers ********************************************************/
547
548 #ifdef TYPEINFO_DEBUG
549
550 #include <stdio.h>
551
552 void typeinfo_test();
553 void typeinfo_print_class(FILE *file,classref_or_classinfo c);
554 void typeinfo_print(FILE *file,typeinfo *info,int indent);
555 void typeinfo_print_short(FILE *file,typeinfo *info);
556 void typeinfo_print_type(FILE *file,int type,typeinfo *info);
557 void typeinfo_print_stacktype(FILE *file,int type,typeinfo *info);
558 void typedescriptor_print(FILE *file,typedescriptor *td);
559 void typevector_print(FILE *file,typevector *vec,int size);
560 void typevectorset_print(FILE *file,typevector *set,int size);
561
562 #endif /* TYPEINFO_DEBUG */
563
564 #endif /* _TYPEINFO_H */
565
566
567 /*
568  * These are local overrides for various environment variables in Emacs.
569  * Please do not remove this and leave it at the end of the file, where
570  * Emacs will automagically detect them.
571  * ---------------------------------------------------------------------
572  * Local variables:
573  * mode: c
574  * indent-tabs-mode: t
575  * c-basic-offset: 4
576  * tab-width: 4
577  * End:
578  */