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