1 // Copyright 2006-2008 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <ctype.h>
6 #include <stdlib.h>
7
8 #include "src/v8.h"
9
10 #include "src/assembler.h"
11 #include "src/platform.h"
12 #include "src/smart-pointers.h"
13 #include "src/string-stream.h"
14
15 namespace v8 {
16 namespace internal {
17
18 // Define all of our flags.
19 #define FLAG_MODE_DEFINE
20 #include "src/flag-definitions.h"
21
22 // Define all of our flags default values.
23 #define FLAG_MODE_DEFINE_DEFAULTS
24 #include "src/flag-definitions.h"
25
26 namespace {
27
28 // This structure represents a single entry in the flag system, with a pointer
29 // to the actual flag, default value, comment, etc. This is designed to be POD
30 // initialized as to avoid requiring static constructors.
31 struct Flag {
32 enum FlagType { TYPE_BOOL, TYPE_MAYBE_BOOL, TYPE_INT, TYPE_FLOAT,
33 TYPE_STRING, TYPE_ARGS };
34
35 FlagType type_; // What type of flag, bool, int, or string.
36 const char* name_; // Name of the flag, ex "my_flag".
37 void* valptr_; // Pointer to the global flag variable.
38 const void* defptr_; // Pointer to the default value.
39 const char* cmt_; // A comment about the flags purpose.
40 bool owns_ptr_; // Does the flag own its string value?
41
typev8::internal::__anon048e2e640111::Flag42 FlagType type() const { return type_; }
43
namev8::internal::__anon048e2e640111::Flag44 const char* name() const { return name_; }
45
commentv8::internal::__anon048e2e640111::Flag46 const char* comment() const { return cmt_; }
47
bool_variablev8::internal::__anon048e2e640111::Flag48 bool* bool_variable() const {
49 ASSERT(type_ == TYPE_BOOL);
50 return reinterpret_cast<bool*>(valptr_);
51 }
52
maybe_bool_variablev8::internal::__anon048e2e640111::Flag53 MaybeBoolFlag* maybe_bool_variable() const {
54 ASSERT(type_ == TYPE_MAYBE_BOOL);
55 return reinterpret_cast<MaybeBoolFlag*>(valptr_);
56 }
57
int_variablev8::internal::__anon048e2e640111::Flag58 int* int_variable() const {
59 ASSERT(type_ == TYPE_INT);
60 return reinterpret_cast<int*>(valptr_);
61 }
62
float_variablev8::internal::__anon048e2e640111::Flag63 double* float_variable() const {
64 ASSERT(type_ == TYPE_FLOAT);
65 return reinterpret_cast<double*>(valptr_);
66 }
67
string_valuev8::internal::__anon048e2e640111::Flag68 const char* string_value() const {
69 ASSERT(type_ == TYPE_STRING);
70 return *reinterpret_cast<const char**>(valptr_);
71 }
72
set_string_valuev8::internal::__anon048e2e640111::Flag73 void set_string_value(const char* value, bool owns_ptr) {
74 ASSERT(type_ == TYPE_STRING);
75 const char** ptr = reinterpret_cast<const char**>(valptr_);
76 if (owns_ptr_ && *ptr != NULL) DeleteArray(*ptr);
77 *ptr = value;
78 owns_ptr_ = owns_ptr;
79 }
80
args_variablev8::internal::__anon048e2e640111::Flag81 JSArguments* args_variable() const {
82 ASSERT(type_ == TYPE_ARGS);
83 return reinterpret_cast<JSArguments*>(valptr_);
84 }
85
bool_defaultv8::internal::__anon048e2e640111::Flag86 bool bool_default() const {
87 ASSERT(type_ == TYPE_BOOL);
88 return *reinterpret_cast<const bool*>(defptr_);
89 }
90
int_defaultv8::internal::__anon048e2e640111::Flag91 int int_default() const {
92 ASSERT(type_ == TYPE_INT);
93 return *reinterpret_cast<const int*>(defptr_);
94 }
95
float_defaultv8::internal::__anon048e2e640111::Flag96 double float_default() const {
97 ASSERT(type_ == TYPE_FLOAT);
98 return *reinterpret_cast<const double*>(defptr_);
99 }
100
string_defaultv8::internal::__anon048e2e640111::Flag101 const char* string_default() const {
102 ASSERT(type_ == TYPE_STRING);
103 return *reinterpret_cast<const char* const *>(defptr_);
104 }
105
args_defaultv8::internal::__anon048e2e640111::Flag106 JSArguments args_default() const {
107 ASSERT(type_ == TYPE_ARGS);
108 return *reinterpret_cast<const JSArguments*>(defptr_);
109 }
110
111 // Compare this flag's current value against the default.
IsDefaultv8::internal::__anon048e2e640111::Flag112 bool IsDefault() const {
113 switch (type_) {
114 case TYPE_BOOL:
115 return *bool_variable() == bool_default();
116 case TYPE_MAYBE_BOOL:
117 return maybe_bool_variable()->has_value == false;
118 case TYPE_INT:
119 return *int_variable() == int_default();
120 case TYPE_FLOAT:
121 return *float_variable() == float_default();
122 case TYPE_STRING: {
123 const char* str1 = string_value();
124 const char* str2 = string_default();
125 if (str2 == NULL) return str1 == NULL;
126 if (str1 == NULL) return str2 == NULL;
127 return strcmp(str1, str2) == 0;
128 }
129 case TYPE_ARGS:
130 return args_variable()->argc == 0;
131 }
132 UNREACHABLE();
133 return true;
134 }
135
136 // Set a flag back to it's default value.
Resetv8::internal::__anon048e2e640111::Flag137 void Reset() {
138 switch (type_) {
139 case TYPE_BOOL:
140 *bool_variable() = bool_default();
141 break;
142 case TYPE_MAYBE_BOOL:
143 *maybe_bool_variable() = MaybeBoolFlag::Create(false, false);
144 break;
145 case TYPE_INT:
146 *int_variable() = int_default();
147 break;
148 case TYPE_FLOAT:
149 *float_variable() = float_default();
150 break;
151 case TYPE_STRING:
152 set_string_value(string_default(), false);
153 break;
154 case TYPE_ARGS:
155 *args_variable() = args_default();
156 break;
157 }
158 }
159 };
160
161 Flag flags[] = {
162 #define FLAG_MODE_META
163 #include "src/flag-definitions.h"
164 };
165
166 const size_t num_flags = sizeof(flags) / sizeof(*flags);
167
168 } // namespace
169
170
Type2String(Flag::FlagType type)171 static const char* Type2String(Flag::FlagType type) {
172 switch (type) {
173 case Flag::TYPE_BOOL: return "bool";
174 case Flag::TYPE_MAYBE_BOOL: return "maybe_bool";
175 case Flag::TYPE_INT: return "int";
176 case Flag::TYPE_FLOAT: return "float";
177 case Flag::TYPE_STRING: return "string";
178 case Flag::TYPE_ARGS: return "arguments";
179 }
180 UNREACHABLE();
181 return NULL;
182 }
183
184
ToString(Flag * flag)185 static SmartArrayPointer<const char> ToString(Flag* flag) {
186 HeapStringAllocator string_allocator;
187 StringStream buffer(&string_allocator);
188 switch (flag->type()) {
189 case Flag::TYPE_BOOL:
190 buffer.Add("%s", (*flag->bool_variable() ? "true" : "false"));
191 break;
192 case Flag::TYPE_MAYBE_BOOL:
193 buffer.Add("%s", flag->maybe_bool_variable()->has_value
194 ? (flag->maybe_bool_variable()->value ? "true" : "false")
195 : "unset");
196 break;
197 case Flag::TYPE_INT:
198 buffer.Add("%d", *flag->int_variable());
199 break;
200 case Flag::TYPE_FLOAT:
201 buffer.Add("%f", FmtElm(*flag->float_variable()));
202 break;
203 case Flag::TYPE_STRING: {
204 const char* str = flag->string_value();
205 buffer.Add("%s", str ? str : "NULL");
206 break;
207 }
208 case Flag::TYPE_ARGS: {
209 JSArguments args = *flag->args_variable();
210 if (args.argc > 0) {
211 buffer.Add("%s", args[0]);
212 for (int i = 1; i < args.argc; i++) {
213 buffer.Add(" %s", args[i]);
214 }
215 }
216 break;
217 }
218 }
219 return buffer.ToCString();
220 }
221
222
223 // static
argv()224 List<const char*>* FlagList::argv() {
225 List<const char*>* args = new List<const char*>(8);
226 Flag* args_flag = NULL;
227 for (size_t i = 0; i < num_flags; ++i) {
228 Flag* f = &flags[i];
229 if (!f->IsDefault()) {
230 if (f->type() == Flag::TYPE_ARGS) {
231 ASSERT(args_flag == NULL);
232 args_flag = f; // Must be last in arguments.
233 continue;
234 }
235 HeapStringAllocator string_allocator;
236 StringStream buffer(&string_allocator);
237 if (f->type() != Flag::TYPE_BOOL || *(f->bool_variable())) {
238 buffer.Add("--%s", f->name());
239 } else {
240 buffer.Add("--no%s", f->name());
241 }
242 args->Add(buffer.ToCString().Detach());
243 if (f->type() != Flag::TYPE_BOOL) {
244 args->Add(ToString(f).Detach());
245 }
246 }
247 }
248 if (args_flag != NULL) {
249 HeapStringAllocator string_allocator;
250 StringStream buffer(&string_allocator);
251 buffer.Add("--%s", args_flag->name());
252 args->Add(buffer.ToCString().Detach());
253 JSArguments jsargs = *args_flag->args_variable();
254 for (int j = 0; j < jsargs.argc; j++) {
255 args->Add(StrDup(jsargs[j]));
256 }
257 }
258 return args;
259 }
260
261
NormalizeChar(char ch)262 inline char NormalizeChar(char ch) {
263 return ch == '_' ? '-' : ch;
264 }
265
266
267 // Helper function to parse flags: Takes an argument arg and splits it into
268 // a flag name and flag value (or NULL if they are missing). is_bool is set
269 // if the arg started with "-no" or "--no". The buffer may be used to NUL-
270 // terminate the name, it must be large enough to hold any possible name.
SplitArgument(const char * arg,char * buffer,int buffer_size,const char ** name,const char ** value,bool * is_bool)271 static void SplitArgument(const char* arg,
272 char* buffer,
273 int buffer_size,
274 const char** name,
275 const char** value,
276 bool* is_bool) {
277 *name = NULL;
278 *value = NULL;
279 *is_bool = false;
280
281 if (arg != NULL && *arg == '-') {
282 // find the begin of the flag name
283 arg++; // remove 1st '-'
284 if (*arg == '-') {
285 arg++; // remove 2nd '-'
286 if (arg[0] == '\0') {
287 const char* kJSArgumentsFlagName = "js_arguments";
288 *name = kJSArgumentsFlagName;
289 return;
290 }
291 }
292 if (arg[0] == 'n' && arg[1] == 'o') {
293 arg += 2; // remove "no"
294 if (NormalizeChar(arg[0]) == '-') arg++; // remove dash after "no".
295 *is_bool = true;
296 }
297 *name = arg;
298
299 // find the end of the flag name
300 while (*arg != '\0' && *arg != '=')
301 arg++;
302
303 // get the value if any
304 if (*arg == '=') {
305 // make a copy so we can NUL-terminate flag name
306 size_t n = arg - *name;
307 CHECK(n < static_cast<size_t>(buffer_size)); // buffer is too small
308 MemCopy(buffer, *name, n);
309 buffer[n] = '\0';
310 *name = buffer;
311 // get the value
312 *value = arg + 1;
313 }
314 }
315 }
316
317
EqualNames(const char * a,const char * b)318 static bool EqualNames(const char* a, const char* b) {
319 for (int i = 0; NormalizeChar(a[i]) == NormalizeChar(b[i]); i++) {
320 if (a[i] == '\0') {
321 return true;
322 }
323 }
324 return false;
325 }
326
327
FindFlag(const char * name)328 static Flag* FindFlag(const char* name) {
329 for (size_t i = 0; i < num_flags; ++i) {
330 if (EqualNames(name, flags[i].name()))
331 return &flags[i];
332 }
333 return NULL;
334 }
335
336
337 // static
SetFlagsFromCommandLine(int * argc,char ** argv,bool remove_flags)338 int FlagList::SetFlagsFromCommandLine(int* argc,
339 char** argv,
340 bool remove_flags) {
341 int return_code = 0;
342 // parse arguments
343 for (int i = 1; i < *argc;) {
344 int j = i; // j > 0
345 const char* arg = argv[i++];
346
347 // split arg into flag components
348 char buffer[1*KB];
349 const char* name;
350 const char* value;
351 bool is_bool;
352 SplitArgument(arg, buffer, sizeof buffer, &name, &value, &is_bool);
353
354 if (name != NULL) {
355 // lookup the flag
356 Flag* flag = FindFlag(name);
357 if (flag == NULL) {
358 if (remove_flags) {
359 // We don't recognize this flag but since we're removing
360 // the flags we recognize we assume that the remaining flags
361 // will be processed somewhere else so this flag might make
362 // sense there.
363 continue;
364 } else {
365 PrintF(stderr, "Error: unrecognized flag %s\n"
366 "Try --help for options\n", arg);
367 return_code = j;
368 break;
369 }
370 }
371
372 // if we still need a flag value, use the next argument if available
373 if (flag->type() != Flag::TYPE_BOOL &&
374 flag->type() != Flag::TYPE_MAYBE_BOOL &&
375 flag->type() != Flag::TYPE_ARGS &&
376 value == NULL) {
377 if (i < *argc) {
378 value = argv[i++];
379 } else {
380 PrintF(stderr, "Error: missing value for flag %s of type %s\n"
381 "Try --help for options\n",
382 arg, Type2String(flag->type()));
383 return_code = j;
384 break;
385 }
386 }
387
388 // set the flag
389 char* endp = const_cast<char*>(""); // *endp is only read
390 switch (flag->type()) {
391 case Flag::TYPE_BOOL:
392 *flag->bool_variable() = !is_bool;
393 break;
394 case Flag::TYPE_MAYBE_BOOL:
395 *flag->maybe_bool_variable() = MaybeBoolFlag::Create(true, !is_bool);
396 break;
397 case Flag::TYPE_INT:
398 *flag->int_variable() = strtol(value, &endp, 10); // NOLINT
399 break;
400 case Flag::TYPE_FLOAT:
401 *flag->float_variable() = strtod(value, &endp);
402 break;
403 case Flag::TYPE_STRING:
404 flag->set_string_value(value ? StrDup(value) : NULL, true);
405 break;
406 case Flag::TYPE_ARGS: {
407 int start_pos = (value == NULL) ? i : i - 1;
408 int js_argc = *argc - start_pos;
409 const char** js_argv = NewArray<const char*>(js_argc);
410 if (value != NULL) {
411 js_argv[0] = StrDup(value);
412 }
413 for (int k = i; k < *argc; k++) {
414 js_argv[k - start_pos] = StrDup(argv[k]);
415 }
416 *flag->args_variable() = JSArguments::Create(js_argc, js_argv);
417 i = *argc; // Consume all arguments
418 break;
419 }
420 }
421
422 // handle errors
423 bool is_bool_type = flag->type() == Flag::TYPE_BOOL ||
424 flag->type() == Flag::TYPE_MAYBE_BOOL;
425 if ((is_bool_type && value != NULL) || (!is_bool_type && is_bool) ||
426 *endp != '\0') {
427 PrintF(stderr, "Error: illegal value for flag %s of type %s\n"
428 "Try --help for options\n",
429 arg, Type2String(flag->type()));
430 return_code = j;
431 break;
432 }
433
434 // remove the flag & value from the command
435 if (remove_flags) {
436 while (j < i) {
437 argv[j++] = NULL;
438 }
439 }
440 }
441 }
442
443 // shrink the argument list
444 if (remove_flags) {
445 int j = 1;
446 for (int i = 1; i < *argc; i++) {
447 if (argv[i] != NULL)
448 argv[j++] = argv[i];
449 }
450 *argc = j;
451 }
452
453 if (FLAG_help) {
454 PrintHelp();
455 exit(0);
456 }
457 // parsed all flags successfully
458 return return_code;
459 }
460
461
SkipWhiteSpace(char * p)462 static char* SkipWhiteSpace(char* p) {
463 while (*p != '\0' && isspace(*p) != 0) p++;
464 return p;
465 }
466
467
SkipBlackSpace(char * p)468 static char* SkipBlackSpace(char* p) {
469 while (*p != '\0' && isspace(*p) == 0) p++;
470 return p;
471 }
472
473
474 // static
SetFlagsFromString(const char * str,int len)475 int FlagList::SetFlagsFromString(const char* str, int len) {
476 // make a 0-terminated copy of str
477 ScopedVector<char> copy0(len + 1);
478 MemCopy(copy0.start(), str, len);
479 copy0[len] = '\0';
480
481 // strip leading white space
482 char* copy = SkipWhiteSpace(copy0.start());
483
484 // count the number of 'arguments'
485 int argc = 1; // be compatible with SetFlagsFromCommandLine()
486 for (char* p = copy; *p != '\0'; argc++) {
487 p = SkipBlackSpace(p);
488 p = SkipWhiteSpace(p);
489 }
490
491 // allocate argument array
492 ScopedVector<char*> argv(argc);
493
494 // split the flags string into arguments
495 argc = 1; // be compatible with SetFlagsFromCommandLine()
496 for (char* p = copy; *p != '\0'; argc++) {
497 argv[argc] = p;
498 p = SkipBlackSpace(p);
499 if (*p != '\0') *p++ = '\0'; // 0-terminate argument
500 p = SkipWhiteSpace(p);
501 }
502
503 // set the flags
504 int result = SetFlagsFromCommandLine(&argc, argv.start(), false);
505
506 return result;
507 }
508
509
510 // static
ResetAllFlags()511 void FlagList::ResetAllFlags() {
512 for (size_t i = 0; i < num_flags; ++i) {
513 flags[i].Reset();
514 }
515 }
516
517
518 // static
PrintHelp()519 void FlagList::PrintHelp() {
520 CpuFeatures::PrintTarget();
521 CpuFeatures::PrintFeatures();
522
523 printf("Usage:\n");
524 printf(" shell [options] -e string\n");
525 printf(" execute string in V8\n");
526 printf(" shell [options] file1 file2 ... filek\n");
527 printf(" run JavaScript scripts in file1, file2, ..., filek\n");
528 printf(" shell [options]\n");
529 printf(" shell [options] --shell [file1 file2 ... filek]\n");
530 printf(" run an interactive JavaScript shell\n");
531 printf(" d8 [options] file1 file2 ... filek\n");
532 printf(" d8 [options]\n");
533 printf(" d8 [options] --shell [file1 file2 ... filek]\n");
534 printf(" run the new debugging shell\n\n");
535 printf("Options:\n");
536 for (size_t i = 0; i < num_flags; ++i) {
537 Flag* f = &flags[i];
538 SmartArrayPointer<const char> value = ToString(f);
539 printf(" --%s (%s)\n type: %s default: %s\n",
540 f->name(), f->comment(), Type2String(f->type()), value.get());
541 }
542 }
543
544
545 // static
EnforceFlagImplications()546 void FlagList::EnforceFlagImplications() {
547 #define FLAG_MODE_DEFINE_IMPLICATIONS
548 #include "src/flag-definitions.h"
549 #undef FLAG_MODE_DEFINE_IMPLICATIONS
550 }
551
552 } } // namespace v8::internal
553