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