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