• 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/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 
typev8::internal::__anon47a5dc570111::Flag41   FlagType type() const { return type_; }
42 
namev8::internal::__anon47a5dc570111::Flag43   const char* name() const { return name_; }
44 
commentv8::internal::__anon47a5dc570111::Flag45   const char* comment() const { return cmt_; }
46 
bool_variablev8::internal::__anon47a5dc570111::Flag47   bool* bool_variable() const {
48     DCHECK(type_ == TYPE_BOOL);
49     return reinterpret_cast<bool*>(valptr_);
50   }
51 
maybe_bool_variablev8::internal::__anon47a5dc570111::Flag52   MaybeBoolFlag* maybe_bool_variable() const {
53     DCHECK(type_ == TYPE_MAYBE_BOOL);
54     return reinterpret_cast<MaybeBoolFlag*>(valptr_);
55   }
56 
int_variablev8::internal::__anon47a5dc570111::Flag57   int* int_variable() const {
58     DCHECK(type_ == TYPE_INT);
59     return reinterpret_cast<int*>(valptr_);
60   }
61 
float_variablev8::internal::__anon47a5dc570111::Flag62   double* float_variable() const {
63     DCHECK(type_ == TYPE_FLOAT);
64     return reinterpret_cast<double*>(valptr_);
65   }
66 
string_valuev8::internal::__anon47a5dc570111::Flag67   const char* string_value() const {
68     DCHECK(type_ == TYPE_STRING);
69     return *reinterpret_cast<const char**>(valptr_);
70   }
71 
set_string_valuev8::internal::__anon47a5dc570111::Flag72   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 
args_variablev8::internal::__anon47a5dc570111::Flag80   JSArguments* args_variable() const {
81     DCHECK(type_ == TYPE_ARGS);
82     return reinterpret_cast<JSArguments*>(valptr_);
83   }
84 
bool_defaultv8::internal::__anon47a5dc570111::Flag85   bool bool_default() const {
86     DCHECK(type_ == TYPE_BOOL);
87     return *reinterpret_cast<const bool*>(defptr_);
88   }
89 
int_defaultv8::internal::__anon47a5dc570111::Flag90   int int_default() const {
91     DCHECK(type_ == TYPE_INT);
92     return *reinterpret_cast<const int*>(defptr_);
93   }
94 
float_defaultv8::internal::__anon47a5dc570111::Flag95   double float_default() const {
96     DCHECK(type_ == TYPE_FLOAT);
97     return *reinterpret_cast<const double*>(defptr_);
98   }
99 
string_defaultv8::internal::__anon47a5dc570111::Flag100   const char* string_default() const {
101     DCHECK(type_ == TYPE_STRING);
102     return *reinterpret_cast<const char* const *>(defptr_);
103   }
104 
args_defaultv8::internal::__anon47a5dc570111::Flag105   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.
IsDefaultv8::internal::__anon47a5dc570111::Flag111   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.
Resetv8::internal::__anon47a5dc570111::Flag136   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 
Type2String(Flag::FlagType type)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 
operator <<(OStream & os,const Flag & flag)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
argv()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 
NormalizeChar(char ch)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.
SplitArgument(const char * arg,char * buffer,int buffer_size,const char ** name,const char ** value,bool * is_bool)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 
EqualNames(const char * a,const char * b)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 
FindFlag(const char * name)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
SetFlagsFromCommandLine(int * argc,char ** argv,bool remove_flags)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 
SkipWhiteSpace(char * p)459 static char* SkipWhiteSpace(char* p) {
460   while (*p != '\0' && isspace(*p) != 0) p++;
461   return p;
462 }
463 
464 
SkipBlackSpace(char * p)465 static char* SkipBlackSpace(char* p) {
466   while (*p != '\0' && isspace(*p) == 0) p++;
467   return p;
468 }
469 
470 
471 // static
SetFlagsFromString(const char * str,int len)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
ResetAllFlags()508 void FlagList::ResetAllFlags() {
509   for (size_t i = 0; i < num_flags; ++i) {
510     flags[i].Reset();
511   }
512 }
513 
514 
515 // static
PrintHelp()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
EnforceFlagImplications()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