1 /* VM default frontend for vmprefix VM.
2 
3    Copyright (C) 2016, 2017, 2018, 2019, 2020 Luca Saiu
4    Written by Luca Saiu
5 
6    This file is part of Jitter.
7 
8    Jitter is free software: you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation, either version 3 of the License, or
11    (at your option) any later version.
12 
13    Jitter is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17 
18    You should have received a copy of the GNU General Public License
19    along with Jitter.  If not, see <http://www.gnu.org/licenses/>. */
20 
21 
22 /* Generated file warning.
23  * ************************************************************************** */
24 
25 /* Unless this file is named exactly "vm-main.c" , without any prefix, you are
26    looking at a machine-generated derived file.  The original source is the
27    vm-main.c template from Jitter. */
28 
29 
30 
31 
32 /* Include headers.
33  * ************************************************************************** */
34 
35 #ifdef HAVE_CONFIG_H
36 /* Use Gnulib, if available; on GNU everything should work even without it.
37 
38    FIXME: I might want to find a solution for other systems, but they are not
39    prioritary. */
40 # include <config.h>
41 #endif // #ifdef HAVE_CONFIG_H
42 
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <unistd.h>
46 #include <string.h>
47 #include <stdbool.h>
48 
49 #include <argp.h>
50 
51 #include <jitter/jitter.h>
52 
53 /* Include optional headers. */
54 #ifdef JITTER_HAVE_SETRLIMIT
55 # include <sys/resource.h> /* For getrlimit and setrlimit . */
56 #endif // #ifdef JITTER_HAVE_SETRLIMIT
57 
58 #include <jitter/jitter-parse-int.h>
59 #include <jitter/jitter-fatal.h>
60 
61 #include "vmprefix-vm.h"
62 
63 
64 
65 
66 /* Command line handling.
67  * ************************************************************************** */
68 
69 /* All the information encoded by the user in the command line. */
70 struct vmprefix_main_command_line
71 {
72   bool debug;
73   bool profile_specialized;
74   bool profile_unspecialized;
75   bool progress_on_stderr;
76   bool print_locations, print_routine, disassemble_routine, run_routine;
77   bool slow_literals_only, slow_registers_only;
78   bool optimization_rewriting;
79   char *input_file;
80   char *objdump_name;
81   char *objdump_options; /* Use default options when NULL. */
82   bool objdump_name_overridden;
83 
84 #ifdef JITTER_HAVE_ALARM
85   /* The wall-clock run time limit in seconds, or 0 if there is no limit. */
86   unsigned int wall_clock_run_time_limit;
87 #endif // #ifdef JITTER_HAVE_ALARM
88 
89 #ifdef JITTER_HAVE_SETRLIMIT
90   /* The CPU time limit in seconds, or RLIM_INFINITY if there is no limit. */
91   rlim_t cpu_time_limit;
92 #endif // #ifdef JITTER_HAVE_SETRLIMIT
93 };
94 
95 /* Numeric identifiers for --no-* , or more in general "default" options having
96    no short equivalent and specifying the default behavior; these are
97    particularly convenient for interactive use where a complex command line is
98    modified frequently.  Each case must have a value which is not an ASCII
99    character. */
100 enum vmprefix_vm_negative_option
101   {
102     vmprefix_vm_negative_option_no_cross_disassemble = -1,
103     vmprefix_vm_negative_option_no_disassemble = -2,
104     vmprefix_vm_negative_option_no_debug = -3,
105     vmprefix_vm_negative_option_no_dry_run = -4,
106     vmprefix_vm_negative_option_no_print_locations = -5,
107     vmprefix_vm_negative_option_no_print_routine = -6,
108     vmprefix_vm_negative_option_no_profile_specialized = -7,
109     vmprefix_vm_negative_option_no_profile_unspecialized = -8,
110     vmprefix_vm_negative_option_no_progress_on_stderr = -9,
111     vmprefix_vm_negative_option_no_slow_literals_only = -10,
112     vmprefix_vm_negative_option_no_slow_registers_only = -11,
113     vmprefix_vm_negative_option_no_slow_only = -12,
114     vmprefix_vm_negative_option_optimization_rewriting = -13
115   };
116 
117 /* Numeric keys for options having only a long format.  These must not conflict
118    with any value in enum vmprefix_vm_negative_option . */
119 enum vmprefix_vm_long_only_option
120   {
121     vmprefix_vm_long_only_option_print_locations = -109,
122     vmprefix_vm_long_only_option_profile_specialized = -110,
123     vmprefix_vm_long_only_option_profile_unspecialized = -111,
124     vmprefix_vm_long_only_option_dump_jitter_version = -112,
125     vmprefix_vm_long_only_option_slow_only = -113
126   };
127 
128 /* Update our option state with the information from a single command-line
129    option. */
130 static error_t
parse_opt(int key,char * arg,struct argp_state * state)131 parse_opt (int key, char *arg, struct argp_state *state)
132 {
133   struct vmprefix_main_command_line *cl = state->input;
134   switch (key)
135     {
136       /* FIXME: within the case I could use state->arg_num to get the current
137          non-option argument index, if needed. */
138     case ARGP_KEY_INIT:
139       /* Set reasonable default values. */
140       cl->debug = false;
141       cl->progress_on_stderr = false;
142       cl->print_locations = false;
143       cl->profile_specialized = false;
144       cl->profile_unspecialized = false;
145       cl->print_routine = false;
146       cl->disassemble_routine = false;
147       cl->run_routine = true;
148       cl->slow_literals_only = false;
149       cl->slow_registers_only = false;
150       cl->optimization_rewriting = true;
151       cl->input_file = NULL;
152       cl->objdump_name = JITTER_OBJDUMP;
153       cl->objdump_name_overridden = false;
154       cl->objdump_options = NULL;
155 #ifdef JITTER_HAVE_ALARM
156       cl->wall_clock_run_time_limit = 0;
157 #endif // #ifdef JITTER_HAVE_ALARM
158 #ifdef JITTER_HAVE_SETRLIMIT
159       cl->cpu_time_limit = RLIM_INFINITY;
160 #endif // #ifdef JITTER_HAVE_SETRLIMIT
161       break;
162     case 't':
163       {
164         jitter_long_long limit;
165         if (jitter_string_to_long_long_inconvenient (arg, & limit) != 0)
166           argp_error (state, "--time-limit: invalid integer %s", arg);
167 #ifdef JITTER_HAVE_ALARM
168         if (limit < 0)
169           argp_error (state, "--time-limit: negative time %s", arg);
170         else if (limit > UINT_MAX)
171           argp_error (state, "--time-limit: integer %s out of range", arg);
172         else if (limit > 0)
173           cl->wall_clock_run_time_limit = limit;
174 #else
175         fprintf (stderr, "warning: alarm is disabled\n");
176 #endif // #ifdef JITTER_HAVE_ALARM
177         }
178       break;
179     case 'c':
180       {
181         jitter_long_long limit;
182         if (jitter_string_to_long_long_inconvenient (arg, & limit) != 0)
183           argp_error (state, "--cpu-time-limit: invalid integer %s", arg);
184 #ifdef JITTER_HAVE_SETRLIMIT
185         if (limit < 0)
186           argp_error (state, "--cpu-time-limit: negative time %" JITTER_PRIill,
187                       limit);
188         else if (limit > 0)
189           cl->cpu_time_limit = limit;
190 #else
191         fprintf (stderr, "warning: setrlimit is disabled\n");
192 #endif // #ifdef JITTER_HAVE_SETRLIMIT
193         }
194       break;
195     case 'd':
196       cl->debug = true;
197       break;
198     case vmprefix_vm_long_only_option_dump_jitter_version:
199       printf ("%s\n", JITTER_PACKAGE_VERSION);
200       exit (EXIT_SUCCESS);
201     case vmprefix_vm_negative_option_no_debug:
202       cl->debug = false;
203       break;
204     case 'e':
205       cl->progress_on_stderr = true;
206       break;
207     case vmprefix_vm_negative_option_no_progress_on_stderr:
208       cl->progress_on_stderr = false;
209       break;
210     case vmprefix_vm_long_only_option_print_locations:
211       cl->print_locations = true;
212       break;
213     case vmprefix_vm_long_only_option_profile_specialized:
214       cl->profile_specialized = true;
215       break;
216     case vmprefix_vm_long_only_option_profile_unspecialized:
217       cl->profile_unspecialized = true;
218       break;
219     case 'p':
220       cl->print_routine = true;
221       break;
222     case vmprefix_vm_negative_option_no_print_locations:
223       cl->print_locations = false;
224       break;
225     case vmprefix_vm_negative_option_no_print_routine:
226       cl->print_routine = false;
227       break;
228     case vmprefix_vm_negative_option_no_profile_specialized:
229       cl->profile_specialized = false;
230       break;
231     case vmprefix_vm_negative_option_no_profile_unspecialized:
232       cl->profile_unspecialized = false;
233       break;
234     case 'b':
235       cl->objdump_name = arg;
236       cl->objdump_name_overridden = true;
237       break;
238     case 'B':
239       cl->objdump_options = arg;
240       break;
241     case 'D':
242       cl->disassemble_routine = true;
243       if (! cl->objdump_name_overridden)
244         cl->objdump_name = (arg != NULL) ? arg : JITTER_OBJDUMP;
245       break;
246     case vmprefix_vm_negative_option_no_disassemble:
247     case vmprefix_vm_negative_option_no_cross_disassemble:
248       cl->disassemble_routine = false;
249       break;
250     case 'C':
251       cl->disassemble_routine = true;
252 #if defined(JITTER_CROSS_COMPILING) && defined (JITTER_CROSS_OBJDUMP)
253       if (! cl->objdump_name_overridden)
254         cl->objdump_name = JITTER_CROSS_OBJDUMP;
255 #else
256       if (! cl->objdump_name_overridden)
257         cl->objdump_name = JITTER_OBJDUMP;
258 #endif // #if defined(JITTER_CROSS_COMPILING) && defined (JITTER_CROSS_OBJDUMP)
259       break;
260     case 'n':
261       cl->run_routine = false;
262       break;
263     case vmprefix_vm_negative_option_no_dry_run:
264       cl->run_routine = true;
265       break;
266     case 'L':
267       cl->slow_literals_only = true;
268       break;
269     case 'R':
270       cl->slow_registers_only = true;
271       break;
272     case vmprefix_vm_long_only_option_slow_only:
273       cl->slow_literals_only = true;
274       cl->slow_registers_only = true;
275       break;
276     case vmprefix_vm_negative_option_no_slow_literals_only:
277       cl->slow_literals_only = false;
278       break;
279     case vmprefix_vm_negative_option_no_slow_registers_only:
280       cl->slow_registers_only = false;
281       break;
282     case vmprefix_vm_negative_option_no_slow_only:
283       cl->slow_literals_only = false;
284       cl->slow_registers_only = false;
285       break;
286     case 'r':
287       cl->optimization_rewriting = false; /* The default is true. */
288       break;
289     case vmprefix_vm_negative_option_optimization_rewriting:
290       cl->optimization_rewriting = true;
291       break;
292 
293     case ARGP_KEY_ARG:
294       cl->input_file = arg;
295       break;
296 
297     /* case ARGP_KEY_NO_ARGS: /\* If this case is omitted, the default is sensible. *\/ */
298     /*   argp_error (state, "you have to supply the input file\n"); */
299     /*   break; */
300 
301     /* case ARGP_KEY_SUCCESS: /\* If this case is omitted, the default is sensible. *\/ */
302     /*   break; */
303 
304     case ARGP_KEY_END:
305       if (state->arg_num != 1)
306         argp_error (state, "you gave %i input files instead of one.",
307                     (int)state->arg_num);
308       break;
309 
310     /* case ARGP_KEY_FINI: /\* If this case is omitted, the default is sensible. *\/ */
311     /*   break; */
312 
313     default:
314       return ARGP_ERR_UNKNOWN;
315     }
316   return 0;
317 }
318 
319 /* Command-line option specification. */
320 static struct argp_option vmprefix_main_option_specification[] =
321   {/* Most frequently used options. */
322    {NULL, '\0', NULL, OPTION_DOC, "Frequently used options:", 10},
323    {"print-routine", 'p', NULL, 0,
324     "Print back the parsed routine"},
325    {"dry-run", 'n', NULL, 0,
326     "Do not actually run the routine"},
327    {"no-run", '\0', NULL, OPTION_ALIAS },
328    /* Most frequently used negative options. */
329    {NULL, '\0', NULL, OPTION_DOC, "", 11},
330    {"no-dry-run", vmprefix_vm_negative_option_no_dry_run, NULL, 0,
331     "Actually run the parsed routine (default)"},
332    {"no-print-routine", vmprefix_vm_negative_option_no_print_routine, NULL, 0,
333     "Don't print back the parsed routine (default)"},
334 
335    /* Disassembly options. */
336    {NULL, '\0', NULL, OPTION_DOC, "Disassembly options:", 20},
337    {"objdump", 'b', "OBJDUMP", 0,
338     "If disassemblying use the given objdump program, overriding the default"},
339    {"objdump-options", 'B', "OPTS", 0,
340     "If disassemblying use the given objdump options, overriding the default"
341     " (" JITTER_OBJDUMP_OPTIONS
342     ").  Options for raw dumping and for setting the correct endianness are "
343     " provided in any case, but user options take precedence"},
344    {"disassemble", 'D', "OBJDUMP", OPTION_ARG_OPTIONAL,
345     "Disassemble native " JITTER_HOST_TRIPLET " code using the given objdump"
346     " program (default: " JITTER_OBJDUMP
347     ") with, unless overridden, the default options"},
348    {"cross-disassemble", 'C', NULL, 0,
349 #if defined(JITTER_CROSS_COMPILING) && defined (JITTER_CROSS_OBJDUMP)
350     "Cross-disassemble " JITTER_HOST_TRIPLET " code (presumably through"
351     " an emulator running on " JITTER_BUILD_TRIPLET
352     " , on which this program was compiled) using "
353     JITTER_CROSS_OBJDUMP " by default"
354 #else
355     "Disassemble native " JITTER_HOST_TRIPLET " code, using " JITTER_OBJDUMP
356     " by default with, unless overridden, the default options"
357     " (this option exists for compatibility with cross-compiled builds)"
358 #endif // #if defined(JITTER_CROSS_COMPILING) && defined (JITTER_CROSS_OBJDUMP)
359    },
360    {"print-locations", vmprefix_vm_long_only_option_print_locations, NULL, 0,
361     "Print data-location information, mapping VM structures to hardware "
362     "resources"},
363    /* Disassembly negative options. */
364    {NULL, '\0', NULL, OPTION_DOC, "", 21},
365    {"no-disassemble", vmprefix_vm_negative_option_no_disassemble, NULL, 0,
366     "Don't disassemble the parsed routine (default)"},
367    {"no-cross-disassemble", vmprefix_vm_negative_option_no_cross_disassemble,
368     NULL, 0,
369     "Don't cross-disassemble the parsed routine (default)"},
370    {"no-print-locations", vmprefix_vm_negative_option_no_print_locations, NULL, 0,
371     "Don't print data location information (default)"},
372 
373    /* Debugging, testing and benchmarking options. */
374    {NULL, '\0', NULL, OPTION_DOC,
375     "Debugging, testing and benchmarking options:", 30},
376    {"progress-on-stderr", 'e', NULL, 0,
377     "Show progress information on stderr instead of stdout"},
378    {"debug", 'd', NULL, 0, "Enable debugging" },
379    {"profile-specialized", vmprefix_vm_long_only_option_profile_specialized,
380     NULL, 0,
381     "Print VM specialised instruction profiling information, if configured in"},
382    {"profile-unspecialized", vmprefix_vm_long_only_option_profile_unspecialized,
383     NULL, 0,
384     "Print VM unspecialised  instruction profiling information, if configured "
385     "in"},
386    {"slow-literals-only", 'L', NULL, 0,
387     "Use slow literals even where fast literals would be available"
388     " (this is mostly useful to measure the speedup introduced by fast"
389     " literals, or possibly to benchmark a worst-case scenario)"},
390    {"slow-registers-only", 'R', NULL, 0,
391     "Use slow registers even when fast registers would be available"
392     " (this is mostly useful to measure the speedup introduced by fast"
393     " registers, or to benchmark a worst-case scenario)"},
394    {"slow-only", vmprefix_vm_long_only_option_slow_only, NULL, 0,
395     "Equivalent to passing both --slow-literals-only and"
396     " --slow-registers-only"},
397    {"dump-jitter-version", vmprefix_vm_long_only_option_dump_jitter_version,
398     NULL, 0,
399     "Print the Jitter version only, without any surrounding text; this "
400     "is convenient for scripts" },
401    {"dump-version", '\0', NULL, OPTION_ALIAS },
402    {"no-optimization-rewriting", 'r', NULL, 0,
403     "Disable optimization rewriting (this is mostly useful for debugging "
404     "rewrite rules and for measuring the speedup they introduce)" },
405    /* Debugging, testing and benchmarking negative options. */
406    {NULL, '\0', NULL, OPTION_DOC, "", 31},
407    {"no-progress-on-stderr", vmprefix_vm_negative_option_no_progress_on_stderr,
408     NULL, 0, "Show progress information on stdout (default)"},
409    {"no-debug", vmprefix_vm_negative_option_no_debug,
410     NULL, 0, "Disable debugging (default)"},
411    {"no-profile-specialized", vmprefix_vm_negative_option_no_profile_specialized,
412     NULL, 0, "Disable specialized instruction profiling (default)"},
413    {"no-profile-unspecialized", vmprefix_vm_negative_option_no_profile_unspecialized,
414     NULL, 0, "Disable unspecialized instruction profiling (default)"},
415    {"no-slow-literals-only", vmprefix_vm_negative_option_no_slow_literals_only,
416     NULL, 0, "Use fast literals when possible (default)"},
417    {"no-slow-registers-only", vmprefix_vm_negative_option_no_slow_registers_only,
418     NULL, 0, "Use fast registers when possible (default)"},
419    {"no-slow-only", vmprefix_vm_negative_option_no_slow_only, NULL, 0,
420     "Equivalent to passing both --no-slow-literals-only and"
421     " --no-slow-registers-only (default)"},
422    {"optimization-rewriting", vmprefix_vm_negative_option_optimization_rewriting,
423     NULL, 0, "Enable optimization rewriting (default)"},
424 
425    /* Test suite options. */
426    {NULL, '\0', NULL, OPTION_DOC, "Options mostly useful for test suites:", 40},
427    {"time-limit", 't', "S", 0,
428     "Fail if wall-clock run time exceeds S seconds (0 for no limit)"
429 #ifndef JITTER_HOST_OS_IS_GNU
430     "; this uses the alarm function, which may interfere with sleep on"
431     " non-GNU systems where sleep is implemented with SIGALRM"
432 #endif // #ifndef JITTER_HOST_OS_IS_GNU
433 #ifndef JITTER_HAVE_ALARM
434     "  (Ignored on this configuration.)"
435 #endif // #ifndef JITTER_HAVE_SETRLIMIT
436    },
437    {"cpu-time-limit", 'c', "S", 0,
438     "Fail if CPU time exceeds S seconds (0 for no limit)"
439 #ifndef JITTER_HAVE_SETRLIMIT
440     "  (Ignored on this configuration.)"
441 #endif // #ifndef JITTER_HAVE_SETRLIMIT
442    },
443 
444    /* Common GNU-style options. */
445    {NULL, '\0', NULL, OPTION_DOC, "Common GNU-style options:", -1},
446    /* These are automatically generated. */
447 
448    /* Option terminator. */
449    { 0 }};
450 
451 /* Customised text text to print on --help and --version . */
452 static void
the_argp_program_version_hook(FILE * restrict stream,struct argp_state * s)453 the_argp_program_version_hook (FILE * restrict stream, struct argp_state *s)
454 {
455   const struct jitter_vm_configuration *c = vmprefix_vm_configuration;
456 
457   const char *instrumentation
458     = jitter_vm_instrumentation_to_string (c->instrumentation);
459   fprintf (stream,
460            "VM driver for %s, %s%s%s dispatch "
461            "(" JITTER_PACKAGE_NAME ") " JITTER_PACKAGE_VERSION "\n",
462            c->lower_case_prefix,
463            instrumentation,
464            (strlen (instrumentation) > 0 ? ", " : ""),
465            c->dispatch_human_readable);
466   fprintf
467      (stream,
468       "Copyright (C) 2021 Luca Saiu.\n"
469       "Jitter comes with ABSOLUTELY NO WARRANTY.\n"
470       "You may redistribute copies of Jitter under the terms of the GNU\n"
471       "General Public License, version 3 or any later version published\n"
472       "by the Free Software Foundation.  For more information see the\n"
473       "file named COPYING.\n"
474       "\n"
475       "Written by Luca Saiu <http://ageinghacker.net> (Jitter, its runtime,\n"
476       "this driver program).\n");
477 }
478 void (*argp_program_version_hook) (FILE * restrict stream, struct argp_state *s)
479   = the_argp_program_version_hook;
480 const char *argp_program_bug_address = JITTER_PACKAGE_BUGREPORT;
481 
482 /* The parser main data structure. */
483 static struct argp argp =
484   {
485     vmprefix_main_option_specification,
486     parse_opt,
487     "FILE.vm",
488     "Run a routine encoded as a text file on the " VMPREFIX_VM_NAME
489     " VM, using " JITTER_DISPATCH_NAME_STRING " dispatch."
490   };
491 
492 
493 
494 
495 /* Main function.
496  * ************************************************************************** */
497 
498 int
main(int argc,char ** argv)499 main (int argc, char **argv)
500 {
501   /* Parse our arguments; every option seen by 'parse_opt' will
502      be reflected in 'arguments'. */
503   struct vmprefix_main_command_line cl;
504   argp_parse (&argp, argc, argv,
505               0,//ARGP_IN_ORDER,
506               0, &cl);
507 
508   /* Initialise the GNU Libtextstyle wrapper, if used. */
509 #ifdef JITTER_WITH_LIBTEXTSTYLE
510   jitter_print_libtextstyle_initialize ();
511 
512   /* FIXME: this should be less crude, but is enough for checking that the
513      libtextstyle wrapper works. */
514   char *style_file_name = "vmprefix-style.css";
515   styled_ostream_t ostream
516     = styled_ostream_create (STDOUT_FILENO, "(stdout)", TTYCTL_AUTO,
517                              style_file_name);
518 #endif // #ifdef JITTER_WITH_LIBTEXTSTYLE
519 
520   /* Make a print context, using the Libtextstyle wrapper if possible. */
521   jitter_print_context ctx
522 #ifdef JITTER_WITH_LIBTEXTSTYLE
523     = jitter_print_context_make_libtextstyle (ostream);
524 #else
525     = jitter_print_context_make_file_star (stdout);
526 #endif // #ifdef JITTER_WITH_LIBTEXTSTYLE
527 
528   FILE *progress;
529   if (cl.progress_on_stderr)
530     progress = stderr;
531   else
532     progress = stdout;
533 
534 #ifdef JITTER_HAVE_ALARM
535   /* Set a limit to the wall-clock run time, if so requested on the command
536      line. */
537   if (cl.wall_clock_run_time_limit != 0)
538     alarm (cl.wall_clock_run_time_limit);
539 #endif // #ifdef JITTER_HAVE_ALARM
540 
541 #ifdef JITTER_HAVE_SETRLIMIT
542   /* Set a limit to the CPU time, if so requested on the command line. */
543   if (cl.cpu_time_limit != RLIM_INFINITY)
544     {
545       if (cl.debug)
546         fprintf (progress, "Setting resource limits...\n");
547       struct rlimit limit;
548       if (getrlimit (RLIMIT_CPU, & limit) != 0)
549         jitter_fatal ("getrlimit failed");
550       limit.rlim_cur = cl.cpu_time_limit;
551       if (setrlimit (RLIMIT_CPU, & limit) != 0)
552         jitter_fatal ("setrlimit failed");
553     }
554 #endif // #ifdef JITTER_HAVE_SETRLIMIT
555 
556   if (cl.debug)
557     fprintf (progress, "Initializing...\n");
558   vmprefix_initialize ();
559 
560   /* Make an empty VM routine, and set options as requested by the user. */
561   struct vmprefix_mutable_routine *r = vmprefix_make_mutable_routine ();
562   if (cl.debug)
563     fprintf (progress,
564              "Options:\n"
565              "* slow literals only: %s\n"
566              "* slow registers only: %s\n"
567              "* optimization rewriting: %s\n",
568              cl.slow_literals_only ? "yes" : "no",
569              cl.slow_registers_only ? "yes" : "no",
570              cl.optimization_rewriting ? "yes" : "no");
571   vmprefix_set_mutable_routine_option_slow_literals_only
572      (r, cl.slow_literals_only);
573   vmprefix_set_mutable_routine_option_slow_registers_only
574      (r, cl.slow_registers_only);
575   vmprefix_set_mutable_routine_option_optimization_rewriting
576      (r, cl.optimization_rewriting);
577 
578   /* Print the VM configuration if in debugging mode. */
579   if (cl.debug)
580     vmprefix_print_vm_configuration (progress, vmprefix_vm_configuration);
581 
582   if (cl.debug)
583     fprintf (progress, "Parsing...\n");
584   if (! strcmp (cl.input_file, "-"))
585     vmprefix_parse_mutable_routine_from_file_star (stdin, r);
586   else
587     vmprefix_parse_mutable_routine_from_file (cl.input_file, r);
588   if (cl.debug)
589     fprintf (progress, "The requried slow register number is %li per class.\n",
590              (long) r->slow_register_per_class_no);
591 
592   /* Make an executable jittery routine. */
593   if (cl.debug)
594     fprintf (progress, "Making executable...\n");
595   struct vmprefix_executable_routine *er
596     = vmprefix_make_executable_routine (r);
597 
598   if (cl.print_routine)
599     {
600       if (cl.debug)
601         fprintf (progress, "Printing back the routine...\n");
602       vmprefix_mutable_routine_print (ctx, r);
603     }
604 
605   if (cl.print_locations)
606     {
607       if (cl.debug)
608         fprintf (progress, "Printing data location information...\n");
609       vmprefix_dump_data_locations (ctx);
610     }
611 
612   if (cl.disassemble_routine)
613     {
614       if (cl.debug)
615         fprintf (progress, "Disassembling...\n");
616       vmprefix_executable_routine_disassemble (ctx, er, true, cl.objdump_name,
617                                                cl.objdump_options);
618     }
619 
620   /* If we dumped data locations or printed back or disassembled the routine,
621      this run is not performance critical and we afford a couple more syscalls.
622      Flush the output buffer, so that the routine is visible before running, and
623      possibly crashing. */
624   if (cl.print_locations || cl.print_routine || cl.disassemble_routine)
625     {
626       jitter_print_flush (ctx);
627       fflush (stdout);
628       fflush (stderr);
629     }
630 
631   if (cl.run_routine)
632     {
633       if (cl.debug)
634         fprintf (progress, "Initializing VM state...\n");
635       struct vmprefix_state s;
636       vmprefix_state_initialize (& s);
637 
638       if (cl.debug)
639         fprintf (progress, "Interpreting...\n");
640       vmprefix_execute_executable_routine (er, & s);
641 
642       if (cl.profile_specialized)
643         {
644           if (cl.debug)
645             fprintf (progress, "Printing specialised profile...\n");
646           struct vmprefix_profile_runtime *pr
647             = vmprefix_state_profile_runtime (& s);
648           vmprefix_profile_runtime_print_specialized (ctx, pr);
649         }
650 
651       if (cl.profile_unspecialized)
652         {
653           if (cl.debug)
654             fprintf (progress, "Printing unspecialised profile...\n");
655           struct vmprefix_profile_runtime *pr
656             = vmprefix_state_profile_runtime (& s);
657           vmprefix_profile_runtime_print_unspecialized (ctx, pr);
658         }
659 
660       if (cl.debug)
661         fprintf (progress, "Finalizing VM state...\n");
662       vmprefix_state_finalize (& s);
663     }
664 
665   if (cl.debug)
666     fprintf (progress, "Destroying the routine data structure...\n");
667   /* Destroy the Jittery routine in both its versions, executable and
668      non-executable. */
669   vmprefix_destroy_executable_routine (er);
670   vmprefix_destroy_mutable_routine (r);
671 
672   if (cl.debug)
673     fprintf (progress, "Finalizing...\n");
674   vmprefix_finalize ();
675 
676   /* Destroy the print context. */
677   jitter_print_context_destroy (ctx);
678 
679   /* End the ostream and finalise the GNU Libtextstyle wrapper, if used. */
680 #ifdef JITTER_WITH_LIBTEXTSTYLE
681   styled_ostream_free (ostream);
682   jitter_print_libtextstyle_finalize ();
683 #endif // #ifdef JITTER_WITH_LIBTEXTSTYLE
684 
685   if (cl.debug)
686     fprintf (progress, "Still alive at exit.\n");
687   return 0;
688 }
689