/home/travis/build/MoarVM/MoarVM/src/main.c
Line | Count | Source (jump to first uncovered line) |
1 | | #include <stdio.h> |
2 | | #include <stdlib.h> |
3 | | #include <string.h> |
4 | | #include <moar.h> |
5 | | |
6 | | #if MVM_TRACING |
7 | | # define TRACING_OPT "[--tracing] " |
8 | | # define TRACING_USAGE "\n --tracing output a line to stderr on every interpreter instr" |
9 | | #else |
10 | | # define TRACING_OPT "" |
11 | | # define TRACING_USAGE "" |
12 | | #endif |
13 | | |
14 | | #ifndef _WIN32 |
15 | | # include "signal.h" |
16 | | #endif |
17 | | |
18 | | /* flags need to be sorted alphabetically */ |
19 | | |
20 | | enum { |
21 | | NOT_A_FLAG = -2, |
22 | | UNKNOWN_FLAG = -1, |
23 | | |
24 | | FLAG_CRASH, |
25 | | FLAG_DUMP, |
26 | | FLAG_FULL_CLEANUP, |
27 | | FLAG_HELP, |
28 | | FLAG_TRACING, |
29 | | FLAG_VERSION, |
30 | | |
31 | | OPT_EXECNAME, |
32 | | OPT_LIBPATH |
33 | | }; |
34 | | |
35 | | static const char *const FLAGS[] = { |
36 | | "--crash", |
37 | | "--dump", |
38 | | "--full-cleanup", |
39 | | "--help", |
40 | | "--tracing", |
41 | | "--version", |
42 | | }; |
43 | | |
44 | | static const char USAGE[] = "\ |
45 | | USAGE: moar [--crash] [--libpath=...] " TRACING_OPT "input.moarvm [program args]\n\ |
46 | | moar --dump input.moarvm\n\ |
47 | | moar --help\n\ |
48 | | \n\ |
49 | | --help display this message\n\ |
50 | | --dump dump the bytecode to stdout instead of executing\n\ |
51 | | --full-cleanup try to free all memory and exit cleanly\n\ |
52 | | --crash abort instead of exiting on unhandled exception\n\ |
53 | | --libpath specify path loadbytecode should search in\n\ |
54 | | --version show version information" |
55 | | TRACING_USAGE |
56 | | "\n\ |
57 | | \n\ |
58 | | The following environment variables are respected:\n\ |
59 | | \n\ |
60 | | MVM_SPESH_DISABLE Disables all dynamic optimization\n\ |
61 | | MVM_SPESH_NODELAY Run dynamic optimization even for cold frames\n\ |
62 | | MVM_SPESH_INLINE_DISABLE Disables inlining\n\ |
63 | | MVM_SPESH_OSR_DISABLE Disables on-stack replacement\n\ |
64 | | MVM_SPESH_LIMIT Limit the maximum number of specializations\n\ |
65 | | MVM_JIT_DISABLE Disables JITting to machine code\n\ |
66 | | MVM_SPESH_LOG Specifies a dynamic optimizer log file\n\ |
67 | | MVM_JIT_LOG Specifies a JIT-compiler log file\n\ |
68 | | MVM_JIT_BYTECODE_DIR Specifies a directory for JIT bytecode dumps\n\ |
69 | | MVM_CROSS_THREAD_WRITE_LOG Log unprotected cross-thread object writes to stderr\n\ |
70 | | MVM_COVERAGE_LOG Append line-by-line coverage messages to this file\n\ |
71 | | "; |
72 | | |
73 | | static int cmp_flag(const void *key, const void *value) |
74 | 0 | { |
75 | 0 | return strcmp(key, *(char **)value); |
76 | 0 | } |
77 | | |
78 | 0 | static int starts_with(const char *str, const char *want) { |
79 | 0 | size_t str_len = strlen(str); |
80 | 0 | size_t want_len = strlen(want); |
81 | 0 | return str_len < want_len |
82 | 0 | ? 0 |
83 | 0 | : strncmp(str, want, want_len) == 0; |
84 | 0 | } |
85 | | |
86 | | static int parse_flag(const char *arg) |
87 | 130 | { |
88 | 130 | const char *const *found; |
89 | 130 | |
90 | 130 | if (!arg || arg[0] != '-') |
91 | 130 | return NOT_A_FLAG; |
92 | 130 | |
93 | 0 | found = bsearch(arg, FLAGS, sizeof FLAGS / sizeof *FLAGS, sizeof *FLAGS, cmp_flag); |
94 | 0 |
|
95 | 0 | if (found) |
96 | 0 | return (int)(found - FLAGS); |
97 | 0 | else if (starts_with(arg, "--libpath=")) |
98 | 0 | return OPT_LIBPATH; |
99 | 0 | else if (starts_with(arg, "--execname=")) |
100 | 0 | return OPT_EXECNAME; |
101 | 0 | else |
102 | 0 | return UNKNOWN_FLAG; |
103 | 0 | } |
104 | | |
105 | | #ifndef _WIN32 |
106 | | int main(int argc, char *argv[]) |
107 | | #else |
108 | | int wmain(int argc, wchar_t *wargv[]) |
109 | | #endif |
110 | 130 | { |
111 | 130 | MVMInstance *instance; |
112 | 130 | const char *input_file; |
113 | 130 | const char *executable_name = NULL; |
114 | 130 | const char *lib_path[8]; |
115 | 130 | |
116 | 130 | #ifdef _WIN32 |
117 | | char **argv = MVM_UnicodeToUTF8_argv(argc, wargv); |
118 | | #endif |
119 | 130 | |
120 | 130 | int dump = 0; |
121 | 130 | int full_cleanup = 0; |
122 | 130 | int argi = 1; |
123 | 130 | int lib_path_i = 0; |
124 | 130 | int flag; |
125 | 130 | |
126 | 130 | for (; (flag = parse_flag(argv[argi])) != NOT_A_FLAG; ++argi) { |
127 | 0 | switch (flag) { |
128 | 0 | case FLAG_CRASH: |
129 | 0 | MVM_crash_on_error(); |
130 | 0 | continue; |
131 | 0 |
|
132 | 0 | case FLAG_DUMP: |
133 | 0 | dump = 1; |
134 | 0 | continue; |
135 | 0 |
|
136 | 0 | case FLAG_FULL_CLEANUP: |
137 | 0 | full_cleanup = 1; |
138 | 0 | continue; |
139 | 0 |
|
140 | 0 | case FLAG_HELP: |
141 | 0 | puts(USAGE); |
142 | 0 | return EXIT_SUCCESS; |
143 | 0 |
|
144 | 0 | #if MVM_TRACING |
145 | | case FLAG_TRACING: |
146 | | MVM_interp_enable_tracing(); |
147 | | continue; |
148 | | #endif |
149 | 0 |
|
150 | 0 | case OPT_EXECNAME: |
151 | 0 | executable_name = argv[argi] + strlen("--execname="); |
152 | 0 | continue; |
153 | 0 |
|
154 | 0 | case OPT_LIBPATH: |
155 | 0 | if (lib_path_i == 7) { /* 0..7 == 8 */ |
156 | 0 | fprintf(stderr, "ERROR: Only up to eight --libpath options are allowed.\n"); |
157 | 0 | return EXIT_FAILURE; |
158 | 0 | } |
159 | 0 |
|
160 | 0 | lib_path[lib_path_i++] = argv[argi] + strlen("--libpath="); |
161 | 0 | continue; |
162 | 0 |
|
163 | 0 | case FLAG_VERSION: { |
164 | 0 | char *spesh_disable; |
165 | 0 | char *jit_disable; |
166 | 0 |
|
167 | 0 | printf("This is MoarVM version %s", MVM_VERSION); |
168 | 0 | if (MVM_jit_support()) { |
169 | 0 | printf(" built with JIT support"); |
170 | 0 |
|
171 | 0 | spesh_disable = getenv("MVM_SPESH_DISABLE"); |
172 | 0 | jit_disable = getenv("MVM_JIT_DISABLE"); |
173 | 0 | if (spesh_disable && strlen(spesh_disable) != 0) { |
174 | 0 | printf(" (disabled via MVM_SPESH_DISABLE)"); |
175 | 0 | } else if (jit_disable && strlen(jit_disable) != 0) { |
176 | 0 | printf(" (disabled via MVM_JIT_DISABLE)"); |
177 | 0 | } |
178 | 0 | } |
179 | 0 | printf("\n"); |
180 | 0 | return EXIT_SUCCESS; |
181 | 0 | } |
182 | 0 |
|
183 | 0 | default: |
184 | 0 | fprintf(stderr, "ERROR: Unknown flag %s.\n\n%s\n", argv[argi], USAGE); |
185 | 0 | return EXIT_FAILURE; |
186 | 0 | } |
187 | 0 | } |
188 | 130 | |
189 | 130 | lib_path[lib_path_i] = NULL; |
190 | 130 | |
191 | 130 | if (argi >= argc) { |
192 | 0 | fprintf(stderr, "ERROR: Missing input file.\n\n%s\n", USAGE); |
193 | 0 | return EXIT_FAILURE; |
194 | 0 | } |
195 | 130 | |
196 | 130 | instance = MVM_vm_create_instance(); |
197 | 130 | input_file = argv[argi++]; |
198 | 130 | |
199 | 130 | /* stash the rest of the raw command line args in the instance */ |
200 | 130 | MVM_vm_set_clargs(instance, argc - argi, argv + argi); |
201 | 130 | MVM_vm_set_prog_name(instance, input_file); |
202 | 130 | MVM_vm_set_exec_name(instance, executable_name); |
203 | 130 | MVM_vm_set_lib_path(instance, lib_path_i, lib_path); |
204 | 130 | |
205 | 130 | /* Ignore SIGPIPE by default, since we error-check reads/writes. This does |
206 | 130 | * not prevent users from setting up their own signal handler for SIGPIPE, |
207 | 130 | * which will take precedence over this ignore. */ |
208 | 130 | #ifndef _WIN32 |
209 | 130 | signal(SIGPIPE, SIG_IGN); |
210 | 130 | #endif |
211 | 130 | |
212 | 130 | if (dump) MVM_vm_dump_file(instance, input_file); |
213 | 130 | else MVM_vm_run_file(instance, input_file); |
214 | 130 | |
215 | 130 | if (full_cleanup) { |
216 | 0 | MVM_vm_destroy_instance(instance); |
217 | 0 | return EXIT_SUCCESS; |
218 | 0 | } |
219 | 130 | else { |
220 | 130 | MVM_vm_exit(instance); |
221 | 130 | } |
222 | 130 | } |