• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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