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.
11 #include "src/assembler.h"
12 #include "src/base/platform/platform.h"
13 #include "src/ostreams.h"
18 // Define all of our flags.
19 #define FLAG_MODE_DEFINE
20 #include "src/flag-definitions.h" // NOLINT
22 // Define all of our flags default values.
23 #define FLAG_MODE_DEFINE_DEFAULTS
24 #include "src/flag-definitions.h" // NOLINT
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.
32 enum FlagType { TYPE_BOOL, TYPE_MAYBE_BOOL, TYPE_INT, TYPE_FLOAT,
33 TYPE_STRING, TYPE_ARGS };
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?
42 FlagType type() const { return type_; }
44 const char* name() const { return name_; }
46 const char* comment() const { return cmt_; }
48 bool* bool_variable() const {
49 DCHECK(type_ == TYPE_BOOL);
50 return reinterpret_cast<bool*>(valptr_);
53 MaybeBoolFlag* maybe_bool_variable() const {
54 DCHECK(type_ == TYPE_MAYBE_BOOL);
55 return reinterpret_cast<MaybeBoolFlag*>(valptr_);
58 int* int_variable() const {
59 DCHECK(type_ == TYPE_INT);
60 return reinterpret_cast<int*>(valptr_);
63 double* float_variable() const {
64 DCHECK(type_ == TYPE_FLOAT);
65 return reinterpret_cast<double*>(valptr_);
68 const char* string_value() const {
69 DCHECK(type_ == TYPE_STRING);
70 return *reinterpret_cast<const char**>(valptr_);
73 void set_string_value(const char* value, bool owns_ptr) {
74 DCHECK(type_ == TYPE_STRING);
75 const char** ptr = reinterpret_cast<const char**>(valptr_);
76 if (owns_ptr_ && *ptr != NULL) DeleteArray(*ptr);
81 JSArguments* args_variable() const {
82 DCHECK(type_ == TYPE_ARGS);
83 return reinterpret_cast<JSArguments*>(valptr_);
86 bool bool_default() const {
87 DCHECK(type_ == TYPE_BOOL);
88 return *reinterpret_cast<const bool*>(defptr_);
91 int int_default() const {
92 DCHECK(type_ == TYPE_INT);
93 return *reinterpret_cast<const int*>(defptr_);
96 double float_default() const {
97 DCHECK(type_ == TYPE_FLOAT);
98 return *reinterpret_cast<const double*>(defptr_);
101 const char* string_default() const {
102 DCHECK(type_ == TYPE_STRING);
103 return *reinterpret_cast<const char* const *>(defptr_);
106 JSArguments args_default() const {
107 DCHECK(type_ == TYPE_ARGS);
108 return *reinterpret_cast<const JSArguments*>(defptr_);
111 // Compare this flag's current value against the default.
112 bool IsDefault() const {
115 return *bool_variable() == bool_default();
116 case TYPE_MAYBE_BOOL:
117 return maybe_bool_variable()->has_value == false;
119 return *int_variable() == int_default();
121 return *float_variable() == float_default();
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;
130 return args_variable()->argc == 0;
136 // Set a flag back to it's default value.
140 *bool_variable() = bool_default();
142 case TYPE_MAYBE_BOOL:
143 *maybe_bool_variable() = MaybeBoolFlag::Create(false, false);
146 *int_variable() = int_default();
149 *float_variable() = float_default();
152 set_string_value(string_default(), false);
155 *args_variable() = args_default();
162 #define FLAG_MODE_META
163 #include "src/flag-definitions.h"
166 const size_t num_flags = sizeof(flags) / sizeof(*flags);
171 static const char* Type2String(Flag::FlagType 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";
185 std::ostream& operator<<(std::ostream& os, const Flag& flag) { // NOLINT
186 switch (flag.type()) {
187 case Flag::TYPE_BOOL:
188 os << (*flag.bool_variable() ? "true" : "false");
190 case Flag::TYPE_MAYBE_BOOL:
191 os << (flag.maybe_bool_variable()->has_value
192 ? (flag.maybe_bool_variable()->value ? "true" : "false")
196 os << *flag.int_variable();
198 case Flag::TYPE_FLOAT:
199 os << *flag.float_variable();
201 case Flag::TYPE_STRING: {
202 const char* str = flag.string_value();
203 os << (str ? str : "NULL");
206 case Flag::TYPE_ARGS: {
207 JSArguments args = *flag.args_variable();
210 for (int i = 1; i < args.argc; i++) {
222 List<const char*>* FlagList::argv() {
223 List<const char*>* args = new List<const char*>(8);
224 Flag* args_flag = NULL;
225 for (size_t i = 0; i < num_flags; ++i) {
227 if (!f->IsDefault()) {
228 if (f->type() == Flag::TYPE_ARGS) {
229 DCHECK(args_flag == NULL);
230 args_flag = f; // Must be last in arguments.
234 bool disabled = f->type() == Flag::TYPE_BOOL && !*f->bool_variable();
235 std::ostringstream os;
236 os << (disabled ? "--no" : "--") << f->name();
237 args->Add(StrDup(os.str().c_str()));
239 if (f->type() != Flag::TYPE_BOOL) {
240 std::ostringstream os;
242 args->Add(StrDup(os.str().c_str()));
246 if (args_flag != NULL) {
247 std::ostringstream os;
248 os << "--" << args_flag->name();
249 args->Add(StrDup(os.str().c_str()));
250 JSArguments jsargs = *args_flag->args_variable();
251 for (int j = 0; j < jsargs.argc; j++) {
252 args->Add(StrDup(jsargs[j]));
259 inline char NormalizeChar(char ch) {
260 return ch == '_' ? '-' : ch;
264 // Helper function to parse flags: Takes an argument arg and splits it into
265 // a flag name and flag value (or NULL if they are missing). is_bool is set
266 // if the arg started with "-no" or "--no". The buffer may be used to NUL-
267 // terminate the name, it must be large enough to hold any possible name.
268 static void SplitArgument(const char* arg,
278 if (arg != NULL && *arg == '-') {
279 // find the begin of the flag name
280 arg++; // remove 1st '-'
282 arg++; // remove 2nd '-'
283 if (arg[0] == '\0') {
284 const char* kJSArgumentsFlagName = "js_arguments";
285 *name = kJSArgumentsFlagName;
289 if (arg[0] == 'n' && arg[1] == 'o') {
290 arg += 2; // remove "no"
291 if (NormalizeChar(arg[0]) == '-') arg++; // remove dash after "no".
296 // find the end of the flag name
297 while (*arg != '\0' && *arg != '=')
300 // get the value if any
302 // make a copy so we can NUL-terminate flag name
303 size_t n = arg - *name;
304 CHECK(n < static_cast<size_t>(buffer_size)); // buffer is too small
305 MemCopy(buffer, *name, n);
315 static bool EqualNames(const char* a, const char* b) {
316 for (int i = 0; NormalizeChar(a[i]) == NormalizeChar(b[i]); i++) {
325 static Flag* FindFlag(const char* name) {
326 for (size_t i = 0; i < num_flags; ++i) {
327 if (EqualNames(name, flags[i].name()))
335 int FlagList::SetFlagsFromCommandLine(int* argc,
340 for (int i = 1; i < *argc;) {
342 const char* arg = argv[i++];
344 // split arg into flag components
349 SplitArgument(arg, buffer, sizeof buffer, &name, &value, &is_bool);
353 Flag* flag = FindFlag(name);
356 // We don't recognize this flag but since we're removing
357 // the flags we recognize we assume that the remaining flags
358 // will be processed somewhere else so this flag might make
362 PrintF(stderr, "Error: unrecognized flag %s\n"
363 "Try --help for options\n", arg);
369 // if we still need a flag value, use the next argument if available
370 if (flag->type() != Flag::TYPE_BOOL &&
371 flag->type() != Flag::TYPE_MAYBE_BOOL &&
372 flag->type() != Flag::TYPE_ARGS &&
378 PrintF(stderr, "Error: missing value for flag %s of type %s\n"
379 "Try --help for options\n",
380 arg, Type2String(flag->type()));
387 char* endp = const_cast<char*>(""); // *endp is only read
388 switch (flag->type()) {
389 case Flag::TYPE_BOOL:
390 *flag->bool_variable() = !is_bool;
392 case Flag::TYPE_MAYBE_BOOL:
393 *flag->maybe_bool_variable() = MaybeBoolFlag::Create(true, !is_bool);
396 *flag->int_variable() = strtol(value, &endp, 10); // NOLINT
398 case Flag::TYPE_FLOAT:
399 *flag->float_variable() = strtod(value, &endp);
401 case Flag::TYPE_STRING:
402 flag->set_string_value(value ? StrDup(value) : NULL, true);
404 case Flag::TYPE_ARGS: {
405 int start_pos = (value == NULL) ? i : i - 1;
406 int js_argc = *argc - start_pos;
407 const char** js_argv = NewArray<const char*>(js_argc);
409 js_argv[0] = StrDup(value);
411 for (int k = i; k < *argc; k++) {
412 js_argv[k - start_pos] = StrDup(argv[k]);
414 *flag->args_variable() = JSArguments::Create(js_argc, js_argv);
415 i = *argc; // Consume all arguments
421 bool is_bool_type = flag->type() == Flag::TYPE_BOOL ||
422 flag->type() == Flag::TYPE_MAYBE_BOOL;
423 if ((is_bool_type && value != NULL) || (!is_bool_type && is_bool) ||
425 PrintF(stderr, "Error: illegal value for flag %s of type %s\n"
426 "Try --help for options\n",
427 arg, Type2String(flag->type()));
432 // remove the flag & value from the command
441 // shrink the argument list
444 for (int i = 1; i < *argc; i++) {
455 // parsed all flags successfully
460 static char* SkipWhiteSpace(char* p) {
461 while (*p != '\0' && isspace(*p) != 0) p++;
466 static char* SkipBlackSpace(char* p) {
467 while (*p != '\0' && isspace(*p) == 0) p++;
473 int FlagList::SetFlagsFromString(const char* str, int len) {
474 // make a 0-terminated copy of str
475 ScopedVector<char> copy0(len + 1);
476 MemCopy(copy0.start(), str, len);
479 // strip leading white space
480 char* copy = SkipWhiteSpace(copy0.start());
482 // count the number of 'arguments'
483 int argc = 1; // be compatible with SetFlagsFromCommandLine()
484 for (char* p = copy; *p != '\0'; argc++) {
485 p = SkipBlackSpace(p);
486 p = SkipWhiteSpace(p);
489 // allocate argument array
490 ScopedVector<char*> argv(argc);
492 // split the flags string into arguments
493 argc = 1; // be compatible with SetFlagsFromCommandLine()
494 for (char* p = copy; *p != '\0'; argc++) {
496 p = SkipBlackSpace(p);
497 if (*p != '\0') *p++ = '\0'; // 0-terminate argument
498 p = SkipWhiteSpace(p);
502 int result = SetFlagsFromCommandLine(&argc, argv.start(), false);
509 void FlagList::ResetAllFlags() {
510 for (size_t i = 0; i < num_flags; ++i) {
517 void FlagList::PrintHelp() {
518 CpuFeatures::Probe(false);
519 CpuFeatures::PrintTarget();
520 CpuFeatures::PrintFeatures();
524 << " shell [options] -e string\n"
525 << " execute string in V8\n"
526 << " shell [options] file1 file2 ... filek\n"
527 << " run JavaScript scripts in file1, file2, ..., filek\n"
528 << " shell [options]\n"
529 << " shell [options] --shell [file1 file2 ... filek]\n"
530 << " run an interactive JavaScript shell\n"
531 << " d8 [options] file1 file2 ... filek\n"
533 << " d8 [options] --shell [file1 file2 ... filek]\n"
534 << " run the new debugging shell\n\n"
536 for (size_t i = 0; i < num_flags; ++i) {
538 os << " --" << f->name() << " (" << f->comment() << ")\n"
539 << " type: " << Type2String(f->type()) << " default: " << *f
546 void FlagList::EnforceFlagImplications() {
547 #define FLAG_MODE_DEFINE_IMPLICATIONS
548 #include "src/flag-definitions.h"
549 #undef FLAG_MODE_DEFINE_IMPLICATIONS
552 } } // namespace v8::internal