* src/vm/jit/alpha/codegen.c,
[cacao.git] / src / vmcore / options.c
1 /* src/vmcore/options.c - contains global options
2
3    Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel,
4    C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5    E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6    J. Wenninger, 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., 51 Franklin Street, Fifth Floor, Boston, MA
23    02110-1301, USA.
24
25 */
26
27
28 #include "config.h"
29
30 #include <errno.h>
31 #include <stdint.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34
35 #if defined(HAVE_STRING_H)
36 # include <string.h>
37 #endif
38
39 #include <limits.h>
40
41 #include "mm/memory.h"
42
43 #include "native/jni.h"
44
45 #include "vm/vm.h"
46
47 #include "vmcore/options.h"
48
49
50 /* command line option ********************************************************/
51
52 s4    opt_index = 0;            /* index of processed arguments               */
53 char *opt_arg;                  /* this one exports the option argument       */
54
55 bool opt_foo = false;           /* option for development                     */
56
57 bool opt_jar = false;
58
59 #if defined(ENABLE_JIT)
60 bool opt_jit = true;            /* JIT mode execution (default)               */
61 bool opt_intrp = false;         /* interpreter mode execution                 */
62 #else
63 bool opt_jit = false;           /* JIT mode execution                         */
64 bool opt_intrp = true;          /* interpreter mode execution (default)       */
65 #endif
66
67 bool opt_run = true;
68
69 s4   opt_heapmaxsize   = 0;     /* maximum heap size                          */
70 s4   opt_heapstartsize = 0;     /* initial heap size                          */
71 s4   opt_stacksize     = 0;     /* thread stack size                          */
72
73 bool opt_verbose = false;
74 bool opt_debugcolor = false;    /* use ANSI terminal sequences                */
75 bool compileall = false;
76
77 bool loadverbose = false;
78 bool initverbose = false;
79
80 bool opt_verboseclass     = false;
81 bool opt_verbosegc        = false;
82 bool opt_verbosejni       = false;
83 bool opt_verbosecall      = false;      /* trace all method invocation        */
84
85 bool showmethods = false;
86 bool showconstantpool = false;
87 bool showutf = false;
88
89 char *opt_method = NULL;
90 char *opt_signature = NULL;
91
92 bool compileverbose =  false;           /* trace compiler actions             */
93 bool showstack = false;
94
95 bool opt_showdisassemble    = false;    /* generate disassembler listing      */
96 bool opt_shownops           = false;
97 bool opt_showddatasegment   = false;    /* generate data segment listing      */
98 bool opt_showintermediate   = false;    /* generate intermediate code listing */
99
100 bool checkbounds = true;       /* check array bounds                         */
101 bool opt_noieee = false;       /* don't implement ieee compliant floats      */
102 bool checksync = true;         /* do synchronization                         */
103 #if defined(ENABLE_LOOP)
104 bool opt_loops = false;        /* optimize array accesses in loops           */
105 #endif
106
107 bool makeinitializations = true;
108
109 #if defined(ENABLE_STATISTICS)
110 bool opt_stat    = false;
111 bool opt_getloadingtime = false;   /* to measure the runtime                 */
112 bool opt_getcompilingtime = false; /* compute compile time                   */
113 #endif
114 #if defined(ENABLE_VERIFIER)
115 bool opt_verify  = true;       /* true if classfiles should be verified      */
116 #endif
117
118 #if defined(ENABLE_PROFILING)
119 bool opt_prof    = false;
120 bool opt_prof_bb = false;
121 #endif
122
123
124 /* inlining options ***********************************************************/
125
126 #if defined(ENABLE_INLINING)
127 bool opt_inlining = false;
128 #if defined(ENABLE_INLINING_DEBUG) || !defined(NDEBUG)
129 s4 opt_inline_debug_min_size = 0;
130 s4 opt_inline_debug_max_size = INT_MAX;
131 s4 opt_inline_debug_end_counter = INT_MAX;
132 bool opt_inline_debug_all = false;
133 #endif /* defined(ENABLE_INLINING_DEBUG) || !defined(NDEBUG) */
134 #if !defined(NDEBUG)
135 bool opt_inline_debug_log = false;
136 #endif /* !defined(NDEBUG) */
137 #endif /* defined(ENABLE_INLINING) */
138
139
140 /* optimization options *******************************************************/
141
142 #if defined(ENABLE_IFCONV)
143 bool opt_ifconv = false;
144 #endif
145
146 #if defined(ENABLE_LSRA) || defined(ENABLE_SSA)
147 bool opt_lsra = false;
148 #endif
149 #if defined(ENABLE_SSA)
150 bool opt_ssa_dce = false;          /* enable dead code elemination */
151 bool opt_ssa_cp = false;           /* enable copy propagation      */
152 #endif
153
154
155 /* interpreter options ********************************************************/
156
157 #if defined(ENABLE_INTRP)
158 bool opt_no_dynamic = false;            /* suppress dynamic superinstructions */
159 bool opt_no_replication = false;        /* don't use replication in intrp     */
160 bool opt_no_quicksuper = false;         /* instructions for quickening cannot be
161                                                                                    part of dynamic superinstructions */
162
163 s4   opt_static_supers = 0x7fffffff;
164 bool vm_debug = false;          /* XXX this should be called `opt_trace'      */
165 #endif
166
167 #if defined(ENABLE_DEBUG_FILTER)
168 const char *opt_filter_verbosecall_include = 0;
169 const char *opt_filter_verbosecall_exclude = 0;
170 const char *opt_filter_show_method = 0;
171 #endif
172
173
174 /* -XX options ****************************************************************/
175
176 /* NOTE: For better readability keep these alpha-sorted. */
177
178 int      opt_DebugExceptions           = 0;
179 int      opt_DebugFinalizer            = 0;
180 int      opt_DebugLocalReferences      = 0;
181 int      opt_DebugLocks                = 0;
182 int      opt_DebugPackage              = 0;
183 int      opt_DebugPatcher              = 0;
184 int      opt_DebugProperties           = 0;
185 int32_t  opt_DebugStackFrameInfo       = 0;
186 int      opt_DebugStackTrace           = 0;
187 int      opt_DebugThreads              = 0;
188 #if defined(ENABLE_DISASSEMBLER)
189 int      opt_DisassembleStubs          = 0;
190 #endif
191 #if defined(ENABLE_GC_CACAO)
192 int32_t  opt_GCDebugRootSet            = 0;
193 int32_t  opt_GCStress                  = 0;
194 #endif
195 int32_t  opt_MaxPermSize               = 0;
196 int32_t  opt_PermSize                  = 0;
197 int      opt_PrintConfig               = 0;
198 int32_t  opt_ProfileGCMemoryUsage      = 0;
199 int32_t  opt_ProfileMemoryUsage        = 0;
200 FILE    *opt_ProfileMemoryUsageGNUPlot = NULL;
201 #if defined(ENABLE_REPLACEMENT)
202 int      opt_TestReplacement           = 0;
203 #endif
204 int32_t  opt_ThreadStackSize           = 0;
205 int      opt_TraceCompilerCalls        = 0;
206 int32_t  opt_TraceExceptions           = 0;
207 int32_t  opt_TraceJavaCalls            = 0;
208 int32_t  opt_TraceJNICalls             = 0;
209 int32_t  opt_TraceJVMCalls             = 0;
210 int32_t  opt_TraceJVMCallsVerbose      = 0;
211 int32_t  opt_TraceLinkClass            = 0;
212 #if defined(ENABLE_REPLACEMENT)
213 int32_t  opt_TraceReplacement          = 0;
214 #endif
215
216
217 enum {
218         OPT_TYPE_BOOLEAN,
219         OPT_TYPE_VALUE
220 };
221
222 enum {
223         OPT_DebugExceptions,
224         OPT_DebugFinalizer,
225         OPT_DebugLocalReferences,
226         OPT_DebugLocks,
227         OPT_DebugPackage,
228         OPT_DebugPatcher,
229         OPT_DebugProperties,
230         OPT_DebugStackFrameInfo,
231         OPT_DebugStackTrace,
232         OPT_DebugThreads,
233         OPT_DisassembleStubs,
234         OPT_GCDebugRootSet,
235         OPT_GCStress,
236         OPT_MaxPermSize,
237         OPT_PermSize,
238         OPT_PrintConfig,
239         OPT_ProfileGCMemoryUsage,
240         OPT_ProfileMemoryUsage,
241         OPT_ProfileMemoryUsageGNUPlot,
242         OPT_TestReplacement,
243         OPT_ThreadStackSize,
244         OPT_TraceCompilerCalls,
245         OPT_TraceExceptions,
246         OPT_TraceJavaCalls,
247         OPT_TraceJNICalls,
248         OPT_TraceJVMCalls,
249         OPT_TraceJVMCallsVerbose,
250         OPT_TraceLinkClass,
251         OPT_TraceReplacement
252 };
253
254
255 option_t options_XX[] = {
256         { "DebugExceptions",           OPT_DebugExceptions,           OPT_TYPE_BOOLEAN, "debug exceptions" },
257         { "DebugFinalizer",            OPT_DebugFinalizer,            OPT_TYPE_BOOLEAN, "debug finalizer thread" },
258         { "DebugLocalReferences",      OPT_DebugLocalReferences,      OPT_TYPE_BOOLEAN, "print debug information for local reference tables" },
259         { "DebugLocks",                OPT_DebugLocks,                OPT_TYPE_BOOLEAN, "print debug information for locks" },
260         { "DebugPackage",              OPT_DebugPackage,              OPT_TYPE_BOOLEAN, "debug Java boot-packages" },
261         { "DebugPatcher",              OPT_DebugPatcher,              OPT_TYPE_BOOLEAN, "debug JIT code patching" },
262         { "DebugProperties",           OPT_DebugProperties,           OPT_TYPE_BOOLEAN, "print debug information for properties" },
263         { "DebugStackFrameInfo",       OPT_DebugStackFrameInfo,       OPT_TYPE_BOOLEAN, "TODO" },
264         { "DebugStackTrace",           OPT_DebugStackTrace,           OPT_TYPE_BOOLEAN, "debug stacktrace creation" },
265         { "DebugThreads",              OPT_DebugThreads,              OPT_TYPE_BOOLEAN, "print debug information for threads" },
266 #if defined(ENABLE_DISASSEMBLER)
267         { "DisassembleStubs",          OPT_DisassembleStubs,          OPT_TYPE_BOOLEAN, "disassemble builtin and native stubs when generated" },
268 #endif
269 #if defined(ENABLE_GC_CACAO)
270         { "GCDebugRootSet",            OPT_GCDebugRootSet,            OPT_TYPE_BOOLEAN, "GC: print root-set at collection" },
271         { "GCStress",                  OPT_GCStress,                  OPT_TYPE_BOOLEAN, "GC: forced collection at every allocation" },
272 #endif
273         { "MaxPermSize",               OPT_MaxPermSize,               OPT_TYPE_VALUE,   "not implemented" },
274         { "PermSize",                  OPT_PermSize,                  OPT_TYPE_VALUE,   "not implemented" },
275         { "PrintConfig",               OPT_PrintConfig,               OPT_TYPE_BOOLEAN, "print VM configuration" },
276         { "ProfileGCMemoryUsage",      OPT_ProfileGCMemoryUsage,      OPT_TYPE_VALUE,   "profiles GC memory usage in the given interval, <value> is in seconds (default: 5)" },
277         { "ProfileMemoryUsage",        OPT_ProfileMemoryUsage,        OPT_TYPE_VALUE,   "TODO" },
278         { "ProfileMemoryUsageGNUPlot", OPT_ProfileMemoryUsageGNUPlot, OPT_TYPE_VALUE,   "TODO" },
279 #if defined(ENABLE_REPLACEMENT)
280         { "TestReplacement"          , OPT_TestReplacement,           OPT_TYPE_BOOLEAN, "activate all replacement points during code generation" },
281 #endif
282         { "ThreadStackSize",           OPT_ThreadStackSize,           OPT_TYPE_VALUE,   "TODO" },
283         { "TraceCompilerCalls",        OPT_TraceCompilerCalls,        OPT_TYPE_BOOLEAN, "trace JIT compiler calls" },
284         { "TraceExceptions",           OPT_TraceExceptions,           OPT_TYPE_BOOLEAN, "trace Exception throwing" },
285         { "TraceJavaCalls",            OPT_TraceJavaCalls,            OPT_TYPE_BOOLEAN, "trace Java method calls" },
286         { "TraceJNICalls",             OPT_TraceJNICalls,             OPT_TYPE_BOOLEAN, "trace JNI method calls" },
287         { "TraceJVMCalls",             OPT_TraceJVMCalls,             OPT_TYPE_BOOLEAN, "trace JVM method calls but omit very frequent ones" },
288         { "TraceJVMCallsVerbose",      OPT_TraceJVMCallsVerbose,      OPT_TYPE_BOOLEAN, "trace all JVM method calls" },
289         { "TraceLinkClass",            OPT_TraceLinkClass,            OPT_TYPE_BOOLEAN, "trace class linking" },
290 #if defined(ENABLE_REPLACEMENT)
291         { "TraceReplacement",          OPT_TraceReplacement,          OPT_TYPE_VALUE,   "trace on-stack replacement with the given verbosity level (default: 1)" },
292 #endif
293
294         /* end marker */
295
296         { NULL,                        -1,                            -1, NULL }
297 };
298
299
300 /* options_get *****************************************************************
301
302    DOCUMENT ME!!!
303
304 *******************************************************************************/
305
306 s4 options_get(opt_struct *opts, JavaVMInitArgs *vm_args)
307 {
308         char *option;
309         s4    i;
310
311         if (opt_index >= vm_args->nOptions)
312                 return OPT_DONE;
313
314         /* get the current option */
315
316         option = vm_args->options[opt_index].optionString;
317
318         if ((option == NULL) || (option[0] != '-'))
319                 return OPT_DONE;
320
321         for (i = 0; opts[i].name; i++) {
322                 if (!opts[i].arg) {
323                         /* boolean option found */
324
325                         if (strcmp(option + 1, opts[i].name) == 0) {
326                                 opt_index++;
327                                 return opts[i].value;
328                         }
329
330                 } else {
331                         /* parameter option found */
332
333                         /* with a space between */
334
335                         if (strcmp(option + 1, opts[i].name) == 0) {
336                                 opt_index++;
337
338                                 if (opt_index < vm_args->nOptions) {
339
340 #if defined(HAVE_STRDUP)
341                                         opt_arg = strdup(vm_args->options[opt_index].optionString);
342 #else
343 # error !HAVE_STRDUP
344 #endif
345
346                                         opt_index++;
347                                         return opts[i].value;
348                                 }
349
350                                 return OPT_ERROR;
351
352                         } else {
353                                 /* parameter and option have no space between */
354
355                                 /* FIXME: this assumption is plain wrong, hits you if there is a
356                                  * parameter with no argument starting with same letter as param with argument
357                                  * but named after that one, ouch! */
358
359                                 size_t l = strlen(opts[i].name);
360
361                                 if (strlen(option + 1) > l) {
362                                         if (memcmp(option + 1, opts[i].name, l) == 0) {
363                                                 opt_index++;
364
365 #if defined(HAVE_STRDUP)
366                                                 opt_arg = strdup(option + 1 + l);
367 #else
368 # error !HAVE_STRDUP
369 #endif
370
371                                                 return opts[i].value;
372                                         }
373                                 }
374                         }
375                 }
376         }
377
378         return OPT_ERROR;
379 }
380
381
382 /* options_xxusage *************************************************************
383
384    Print usage message for debugging options.
385
386 *******************************************************************************/
387
388 static void options_xxusage(void)
389 {
390         option_t *opt;
391         int       length;
392         int       i;
393         char     *c;
394
395         for (opt = options_XX; opt->name != NULL; opt++) {
396                 printf("    -XX:");
397
398                 switch (opt->type) {
399                 case OPT_TYPE_BOOLEAN:
400                         printf("+%s", opt->name);
401                         length = strlen("    -XX:+") + strlen(opt->name);
402                         break;
403                 case OPT_TYPE_VALUE:
404                         printf("%s=<value>", opt->name);
405                         length = strlen("    -XX:") + strlen(opt->name) + strlen("=<value>");
406                         break;
407                 }
408
409                 /* Check if the help fits into one 80-column line.
410                    Documentation starts at column 29. */
411
412                 if (length < (29 - 1)) {
413                         /* Print missing spaces up to column 29. */
414
415                         for (i = length; i < 29; i++)
416                                 printf(" ");
417                 }
418                 else {
419                         printf("\n");
420                         printf("                             "); /* 29 spaces */
421                 }
422
423                 /* Check documentation length. */
424
425                 length = strlen(opt->doc);
426
427                 if (length < (80 - 29)) {
428                         printf("%s", opt->doc);
429                 }
430                 else {
431                         for (c = opt->doc, i = 29; *c != 0; c++, i++) {
432                                 /* If we are at the end of the line, break it. */
433
434                                 if (i == 80) {
435                                         printf("\n");
436                                         printf("                             "); /* 29 spaces */
437                                         i = 29;
438                                 }
439
440                                 printf("%c", *c);
441                         }
442                 }
443
444                 printf("\n");
445         }
446
447         /* exit with error code */
448
449         exit(1);
450 }
451
452
453 /* options_xx ******************************************************************
454
455    Handle -XX: options.
456
457 *******************************************************************************/
458
459 void options_xx(JavaVMInitArgs *vm_args)
460 {
461         const char *name;
462         const char *start;
463         char       *end;
464         int         length;
465         int         enable;
466         char       *value;
467         option_t   *opt;
468         char       *filename;
469         FILE       *file;
470         int         i;
471
472         /* Iterate over all passed options. */
473
474         for (i = 0; i < vm_args->nOptions; i++) {
475                 /* Get the current option. */
476
477                 name = vm_args->options[i].optionString;
478
479                 /* Check for help (-XX). */
480
481                 if (strcmp(name, "-XX") == 0)
482                         options_xxusage();
483
484                 /* Check if the option start with -XX. */
485
486                 start = strstr(name, "-XX:");
487
488                 if ((start == NULL) || (start != name))
489                         continue;
490
491                 /* Check if the option is a boolean option. */
492
493                 if (name[4] == '+') {
494                         start  = name + 4 + 1;
495                         enable = 1;
496                 }
497                 else if (name[4] == '-') {
498                         start  = name + 4 + 1;
499                         enable = 0;
500                 }
501                 else {
502                         start  = name + 4;
503                         enable = -1;
504                 }
505
506                 /* Search for a '=' in the option name and get the option name
507                    length and the value of the option. */
508
509                 end = strchr(start, '=');
510
511                 if (end == NULL) {
512                         length = strlen(start);
513                         value  = NULL;
514                 }
515                 else {
516                         length = end - start;
517                         value  = end + 1;
518                 }
519
520                 /* Search the option in the option array. */
521
522                 for (opt = options_XX; opt->name != NULL; opt++) {
523                         if (strncmp(opt->name, start, length) == 0) {
524                                 /* Check if the options passed fits to the type. */
525
526                                 switch (opt->type) {
527                                 case OPT_TYPE_BOOLEAN:
528                                         if ((enable == -1) || (value != NULL))
529                                                 options_xxusage();
530                                         break;
531                                 case OPT_TYPE_VALUE:
532                                         if ((enable != -1) || (value == NULL))
533                                                 options_xxusage();
534                                         break;
535                                 default:
536                                         vm_abort("options_xx: unknown option type %d for option %s",
537                                                          opt->type, opt->name);
538                                 }
539
540                                 break;
541                         }
542                 }
543
544                 /* Process the option. */
545
546                 switch (opt->value) {
547                 case OPT_DebugExceptions:
548                         opt_DebugExceptions = enable;
549                         break;
550
551                 case OPT_DebugFinalizer:
552                         opt_DebugFinalizer = enable;
553                         break;
554
555                 case OPT_DebugLocalReferences:
556                         opt_DebugLocalReferences = enable;
557                         break;
558
559                 case OPT_DebugLocks:
560                         opt_DebugLocks = enable;
561                         break;
562
563                 case OPT_DebugPackage:
564                         opt_DebugPackage = enable;
565                         break;
566
567                 case OPT_DebugPatcher:
568                         opt_DebugPatcher = enable;
569                         break;
570
571                 case OPT_DebugProperties:
572                         opt_DebugProperties = enable;
573                         break;
574
575                 case OPT_DebugStackFrameInfo:
576                         opt_DebugStackFrameInfo = enable;
577                         break;
578
579                 case OPT_DebugStackTrace:
580                         opt_DebugStackTrace = enable;
581                         break;
582
583                 case OPT_DebugThreads:
584                         opt_DebugThreads = enable;
585                         break;
586
587 #if defined(ENABLE_DISASSEMBLER)
588                 case OPT_DisassembleStubs:
589                         opt_DisassembleStubs = enable;
590                         break;
591 #endif
592
593 #if defined(ENABLE_GC_CACAO)
594                 case OPT_GCDebugRootSet:
595                         opt_GCDebugRootSet = enable;
596                         break;
597
598                 case OPT_GCStress:
599                         opt_GCStress = enable;
600                         break;
601 #endif
602
603                 case OPT_MaxPermSize:
604                         /* currently ignored */
605                         break;
606
607                 case OPT_PermSize:
608                         /* currently ignored */
609                         break;
610
611                 case OPT_PrintConfig:
612                         opt_PrintConfig = enable;
613                         break;
614
615                 case OPT_ProfileGCMemoryUsage:
616                         if (value == NULL)
617                                 opt_ProfileGCMemoryUsage = 5;
618                         else
619                                 opt_ProfileGCMemoryUsage = atoi(value);
620                         break;
621
622                 case OPT_ProfileMemoryUsage:
623                         if (value == NULL)
624                                 opt_ProfileMemoryUsage = 5;
625                         else
626                                 opt_ProfileMemoryUsage = atoi(value);
627
628 # if defined(ENABLE_STATISTICS)
629                         /* we also need statistics */
630
631                         opt_stat = true;
632 # endif
633                         break;
634
635                 case OPT_ProfileMemoryUsageGNUPlot:
636                         if (value == NULL)
637                                 filename = "profile.dat";
638                         else
639                                 filename = value;
640
641                         file = fopen(filename, "w");
642
643                         if (file == NULL)
644                                 vm_abort("options_xx: fopen failed: %s", strerror(errno));
645
646                         opt_ProfileMemoryUsageGNUPlot = file;
647                         break;
648
649 #if defined(ENABLE_REPLACEMENT)
650                 case OPT_TestReplacement:
651                         opt_TestReplacement = enable;
652                         break;
653 #endif
654
655                 case OPT_ThreadStackSize:
656                         /* currently ignored */
657                         break;
658
659                 case OPT_TraceCompilerCalls:
660                         opt_TraceCompilerCalls = enable;
661                         break;
662
663                 case OPT_TraceExceptions:
664                         opt_TraceExceptions = enable;
665                         break;
666
667                 case OPT_TraceJavaCalls:
668                         opt_verbosecall = enable;
669                         opt_TraceJavaCalls = enable;
670                         break;
671
672                 case OPT_TraceJNICalls:
673                         opt_TraceJNICalls = enable;
674                         break;
675
676                 case OPT_TraceJVMCalls:
677                         opt_TraceJVMCalls = enable;
678                         break;
679
680                 case OPT_TraceJVMCallsVerbose:
681                         opt_TraceJVMCallsVerbose = enable;
682                         break;
683
684                 case OPT_TraceLinkClass:
685                         opt_TraceLinkClass = enable;
686                         break;
687
688 #if defined(ENABLE_REPLACEMENT)
689                 case OPT_TraceReplacement:
690                         if (value == NULL)
691                                 opt_TraceReplacement = 1;
692                         else
693                                 opt_TraceReplacement = atoi(value);
694                         break;
695 #endif
696
697                 default:
698                         printf("Unknown -XX option: %s\n", name);
699                         break;
700                 }
701         }
702 }
703
704
705 /*
706  * These are local overrides for various environment variables in Emacs.
707  * Please do not remove this and leave it at the end of the file, where
708  * Emacs will automagically detect them.
709  * ---------------------------------------------------------------------
710  * Local variables:
711  * mode: c
712  * indent-tabs-mode: t
713  * c-basic-offset: 4
714  * tab-width: 4
715  * End:
716  */