Home | History | Annotate | Download | only in src
      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