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