Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4)

Side by Side Diff: src/flags.cc

Issue 1935: New static flags system (Closed)
Patch Set: Merge, again. Created 12 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/flags.h ('k') | src/flags.defs » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2006-2008 the V8 project authors. All rights reserved. 1 // Copyright 2006-2008 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 16 matching lines...) Expand all
27 27
28 #include <ctype.h> 28 #include <ctype.h>
29 #include <stdlib.h> 29 #include <stdlib.h>
30 30
31 #include "v8.h" 31 #include "v8.h"
32 32
33 #include "platform.h" 33 #include "platform.h"
34 34
35 namespace v8 { namespace internal { 35 namespace v8 { namespace internal {
36 36
37 // ----------------------------------------------------------------------------- 37 // Define all of our flags.
38 // Helpers 38 #define FLAG_MODE_DEFINE
39 #include "flags.defs"
39 40
40 static inline char NormalizeChar(char ch) { 41 // Define all of our flags default values.
41 return ch == '_' ? '-' : ch; 42 #define FLAG_MODE_DEFINE_DEFAULTS
42 } 43 #include "flags.defs"
44
45 namespace {
46
47 // This structure represents a single entry in the flag system, with a pointer
48 // to the actual flag, default value, comment, etc. This is designed to be POD
49 // initialized as to avoid requiring static constructors.
50 struct Flag {
51 enum FlagType { TYPE_BOOL, TYPE_INT, TYPE_FLOAT, TYPE_STRING };
52
53 FlagType type_; // What type of flag, bool, int, or string.
54 const char* name_; // Name of the flag, ex "my_flag".
55 void* valptr_; // Pointer to the global flag variable.
56 const void* defptr_; // Pointer to the default value.
57 const char* cmt_; // A comment about the flags purpose.
58
59 FlagType type() const { return type_; }
60
61 const char* name() const { return name_; }
62
63 const char* comment() const { return cmt_; }
64
65 bool* bool_variable() const {
66 ASSERT(type_ == TYPE_BOOL);
67 return reinterpret_cast<bool*>(valptr_);
68 }
69
70 int* int_variable() const {
71 ASSERT(type_ == TYPE_INT);
72 return reinterpret_cast<int*>(valptr_);
73 }
74
75 double* float_variable() const {
76 ASSERT(type_ == TYPE_FLOAT);
77 return reinterpret_cast<double*>(valptr_);
78 }
79
80 const char** string_variable() const {
81 ASSERT(type_ == TYPE_STRING);
82 return reinterpret_cast<const char**>(valptr_);
83 }
84
85 bool bool_default() const {
86 ASSERT(type_ == TYPE_BOOL);
87 return *reinterpret_cast<const bool*>(defptr_);
88 }
89
90 int int_default() const {
91 ASSERT(type_ == TYPE_INT);
92 return *reinterpret_cast<const int*>(defptr_);
93 }
94
95 double float_default() const {
96 ASSERT(type_ == TYPE_FLOAT);
97 return *reinterpret_cast<const double*>(defptr_);
98 }
99
100 const char* string_default() const {
101 ASSERT(type_ == TYPE_STRING);
102 return *reinterpret_cast<const char* const *>(defptr_);
103 }
104
105 // Compare this flag's current value against the default.
106 bool IsDefault() const {
107 switch (type_) {
108 case TYPE_BOOL:
109 return *bool_variable() == bool_default();
110 case TYPE_INT:
111 return *int_variable() == int_default();
112 case TYPE_FLOAT:
113 return *float_variable() == float_default();
114 case TYPE_STRING:
115 const char* str1 = *string_variable();
116 const char* str2 = string_default();
117 if (str2 == NULL) return str1 == NULL;
118 if (str1 == NULL) return str2 == NULL;
119 return strcmp(str1, str2) == 0;
120 }
121 return true; // NOTREACHED
122 }
123
124 // Set a flag back to it's default value.
125 void Reset() {
126 switch (type_) {
127 case TYPE_BOOL:
128 *bool_variable() = bool_default();
129 break;
130 case TYPE_INT:
131 *int_variable() = int_default();
132 break;
133 case TYPE_FLOAT:
134 *float_variable() = float_default();
135 break;
136 case TYPE_STRING:
137 *string_variable() = string_default();
138 break;
139 }
140 }
141 };
142
143 Flag flags[] = {
144 #define FLAG_MODE_META
145 #include "flags.defs"
146 };
147
148 const size_t num_flags = sizeof(flags) / sizeof(*flags);
149
150 } // namespace
43 151
44 152
45 static const char* NormalizeName(const char* name) { 153 static const char* Type2String(Flag::FlagType type) {
46 int len = strlen(name);
47 char* result = NewArray<char>(len + 1);
48 for (int i = 0; i <= len; i++) {
49 result[i] = NormalizeChar(name[i]);
50 }
51 return const_cast<const char*>(result);
52 }
53
54
55 static bool EqualNames(const char* a, const char* b) {
56 for (int i = 0; NormalizeChar(a[i]) == NormalizeChar(b[i]); i++) {
57 if (a[i] == '\0') {
58 return true;
59 }
60 }
61 return false;
62 }
63
64
65 // -----------------------------------------------------------------------------
66 // Implementation of Flag
67
68 Flag::Flag(const char* file, const char* name, const char* comment,
69 Type type, void* variable, FlagValue default_) {
70 file_ = file;
71 name_ = NormalizeName(name);
72 comment_ = comment;
73 type_ = type;
74 variable_ = reinterpret_cast<FlagValue*>(variable);
75 this->default_ = default_;
76 FlagList::Register(this);
77 }
78
79
80 void Flag::SetToDefault() {
81 // Note that we cannot simply do '*variable_ = default_;' since
82 // flag variables are not really of type FlagValue and thus may
83 // be smaller! The FlagValue union is simply 'overlayed' on top
84 // of a flag variable for convenient access. Since union members
85 // are guarantee to be aligned at the beginning, this works.
86 switch (type_) {
87 case Flag::BOOL:
88 variable_->b = default_.b;
89 return;
90 case Flag::INT:
91 variable_->i = default_.i;
92 return;
93 case Flag::FLOAT:
94 variable_->f = default_.f;
95 return;
96 case Flag::STRING:
97 variable_->s = default_.s;
98 return;
99 }
100 UNREACHABLE();
101 }
102
103
104 bool Flag::IsDefault() const {
105 switch (type_) {
106 case Flag::BOOL:
107 return variable_->b == default_.b;
108 case Flag::INT:
109 return variable_->i == default_.i;
110 case Flag::FLOAT:
111 return variable_->f == default_.f;
112 case Flag::STRING:
113 if (variable_->s && default_.s) {
114 return strcmp(variable_->s, default_.s) == 0;
115 } else {
116 return variable_->s == default_.s;
117 }
118 }
119 UNREACHABLE();
120 return false;
121 }
122
123
124 static const char* Type2String(Flag::Type type) {
125 switch (type) { 154 switch (type) {
126 case Flag::BOOL: return "bool"; 155 case Flag::TYPE_BOOL: return "bool";
127 case Flag::INT: return "int"; 156 case Flag::TYPE_INT: return "int";
128 case Flag::FLOAT: return "float"; 157 case Flag::TYPE_FLOAT: return "float";
129 case Flag::STRING: return "string"; 158 case Flag::TYPE_STRING: return "string";
130 } 159 }
131 UNREACHABLE(); 160 UNREACHABLE();
132 return NULL; 161 return NULL;
133 } 162 }
134 163
135 164
136 static char* ToString(Flag::Type type, FlagValue* variable) { 165 static char* ToString(Flag* flag) {
137 Vector<char> value; 166 Vector<char> value;
138 switch (type) { 167 switch (flag->type()) {
139 case Flag::BOOL: 168 case Flag::TYPE_BOOL:
140 value = Vector<char>::New(6); 169 value = Vector<char>::New(6);
141 OS::SNPrintF(value, "%s", (variable->b ? "true" : "false")); 170 OS::SNPrintF(value, "%s", (*flag->bool_variable() ? "true" : "false"));
142 break; 171 break;
143 case Flag::INT: 172 case Flag::TYPE_INT:
144 value = Vector<char>::New(12); 173 value = Vector<char>::New(12);
145 OS::SNPrintF(value, "%d", variable->i); 174 OS::SNPrintF(value, "%d", *flag->int_variable());
146 break; 175 break;
147 case Flag::FLOAT: 176 case Flag::TYPE_FLOAT:
148 value = Vector<char>::New(20); 177 value = Vector<char>::New(20);
149 OS::SNPrintF(value, "%f", variable->f); 178 OS::SNPrintF(value, "%f", *flag->float_variable());
150 break; 179 break;
151 case Flag::STRING: 180 case Flag::TYPE_STRING:
152 if (variable->s) { 181 const char* str = *flag->string_variable();
153 int length = strlen(variable->s) + 1; 182 if (str) {
183 int length = strlen(str) + 1;
154 value = Vector<char>::New(length); 184 value = Vector<char>::New(length);
155 OS::SNPrintF(value, "%s", variable->s); 185 OS::SNPrintF(value, "%s", str);
156 } else { 186 } else {
157 value = Vector<char>::New(5); 187 value = Vector<char>::New(5);
158 OS::SNPrintF(value, "NULL"); 188 OS::SNPrintF(value, "NULL");
159 } 189 }
160 break; 190 break;
161 } 191 }
162 ASSERT(!value.is_empty()); 192 ASSERT(!value.is_empty());
163 return value.start(); 193 return value.start();
164 } 194 }
165 195
166 196
167 static void PrintFlagValue(Flag::Type type, FlagValue* variable) { 197 // static
168 char* value = ToString(type, variable);
169 printf("%s", value);
170 DeleteArray(value);
171 }
172
173
174 char* Flag::StringValue() const {
175 return ToString(type_, variable_);
176 }
177
178
179 void Flag::Print(bool print_current_value) {
180 printf(" --%s (%s) type: %s default: ", name_, comment_,
181 Type2String(type_));
182 PrintFlagValue(type_, &default_);
183 if (print_current_value) {
184 printf(" current value: ");
185 PrintFlagValue(type_, variable_);
186 }
187 printf("\n");
188 }
189
190
191 // -----------------------------------------------------------------------------
192 // Implementation of FlagList
193
194 Flag* FlagList::list_ = NULL;
195
196
197 List<char *>* FlagList::argv() { 198 List<char *>* FlagList::argv() {
198 List<char *>* args = new List<char*>(8); 199 List<char *>* args = new List<char*>(8);
199 for (Flag* f = list_; f != NULL; f = f->next()) { 200 for (size_t i = 0; i < num_flags; ++i) {
201 Flag* f = &flags[i];
200 if (!f->IsDefault()) { 202 if (!f->IsDefault()) {
201 Vector<char> cmdline_flag; 203 Vector<char> cmdline_flag;
202 if (f->type() != Flag::BOOL || *(f->bool_variable())) { 204 if (f->type() != Flag::TYPE_BOOL || *(f->bool_variable())) {
203 int length = strlen(f->name()) + 2 + 1; 205 int length = strlen(f->name()) + 2 + 1;
204 cmdline_flag = Vector<char>::New(length); 206 cmdline_flag = Vector<char>::New(length);
205 OS::SNPrintF(cmdline_flag, "--%s", f->name()); 207 OS::SNPrintF(cmdline_flag, "--%s", f->name());
206 } else { 208 } else {
207 int length = strlen(f->name()) + 4 + 1; 209 int length = strlen(f->name()) + 4 + 1;
208 cmdline_flag = Vector<char>::New(length); 210 cmdline_flag = Vector<char>::New(length);
209 OS::SNPrintF(cmdline_flag, "--no%s", f->name()); 211 OS::SNPrintF(cmdline_flag, "--no%s", f->name());
210 } 212 }
211 args->Add(cmdline_flag.start()); 213 args->Add(cmdline_flag.start());
212 if (f->type() != Flag::BOOL) { 214 if (f->type() != Flag::TYPE_BOOL) {
213 args->Add(f->StringValue()); 215 args->Add(ToString(f));
214 } 216 }
215 } 217 }
216 } 218 }
219
217 return args; 220 return args;
218 } 221 }
219 222
220 223
221 void FlagList::Print(const char* file, bool print_current_value) { 224 // Helper function to parse flags: Takes an argument arg and splits it into
222 // Since flag registration is likely by file (= C++ file), 225 // a flag name and flag value (or NULL if they are missing). is_bool is set
223 // we don't need to sort by file and still get grouped output. 226 // if the arg started with "-no" or "--no". The buffer may be used to NUL-
224 const char* current = NULL; 227 // terminate the name, it must be large enough to hold any possible name.
225 for (Flag* f = list_; f != NULL; f = f->next()) { 228 static void SplitArgument(const char* arg,
226 if (file == NULL || file == f->file()) { 229 char* buffer,
227 if (current != f->file()) { 230 int buffer_size,
228 printf("Flags from %s:\n", f->file()); 231 const char** name,
229 current = f->file(); 232 const char** value,
230 } 233 bool* is_bool) {
231 f->Print(print_current_value);
232 }
233 }
234 }
235
236
237 Flag* FlagList::Lookup(const char* name) {
238 Flag* f = list_;
239 while (f != NULL && !EqualNames(name, f->name()))
240 f = f->next();
241 return f;
242 }
243
244
245 void FlagList::SplitArgument(const char* arg,
246 char* buffer,
247 int buffer_size,
248 const char** name,
249 const char** value,
250 bool* is_bool) {
251 *name = NULL; 234 *name = NULL;
252 *value = NULL; 235 *value = NULL;
253 *is_bool = false; 236 *is_bool = false;
254 237
255 if (*arg == '-') { 238 if (*arg == '-') {
256 // find the begin of the flag name 239 // find the begin of the flag name
257 arg++; // remove 1st '-' 240 arg++; // remove 1st '-'
258 if (*arg == '-') 241 if (*arg == '-')
259 arg++; // remove 2nd '-' 242 arg++; // remove 2nd '-'
260 if (arg[0] == 'n' && arg[1] == 'o') { 243 if (arg[0] == 'n' && arg[1] == 'o') {
(...skipping 14 matching lines...) Expand all
275 memcpy(buffer, *name, n); 258 memcpy(buffer, *name, n);
276 buffer[n] = '\0'; 259 buffer[n] = '\0';
277 *name = buffer; 260 *name = buffer;
278 // get the value 261 // get the value
279 *value = arg + 1; 262 *value = arg + 1;
280 } 263 }
281 } 264 }
282 } 265 }
283 266
284 267
268 inline char NormalizeChar(char ch) {
269 return ch == '_' ? '-' : ch;
270 }
271
272
273 static bool EqualNames(const char* a, const char* b) {
274 for (int i = 0; NormalizeChar(a[i]) == NormalizeChar(b[i]); i++) {
275 if (a[i] == '\0') {
276 return true;
277 }
278 }
279 return false;
280 }
281
282
283 static Flag* FindFlag(const char* name) {
284 for (size_t i = 0; i < num_flags; ++i) {
285 if (EqualNames(name, flags[i].name()))
286 return &flags[i];
287 }
288 return NULL;
289 }
290
291
292 // static
285 int FlagList::SetFlagsFromCommandLine(int* argc, 293 int FlagList::SetFlagsFromCommandLine(int* argc,
286 char** argv, 294 char** argv,
287 bool remove_flags) { 295 bool remove_flags) {
288 // parse arguments 296 // parse arguments
289 for (int i = 1; i < *argc;) { 297 for (int i = 1; i < *argc;) {
290 int j = i; // j > 0 298 int j = i; // j > 0
291 const char* arg = argv[i++]; 299 const char* arg = argv[i++];
292 300
293 // split arg into flag components 301 // split arg into flag components
294 char buffer[1*KB]; 302 char buffer[1*KB];
295 const char* name; 303 const char* name;
296 const char* value; 304 const char* value;
297 bool is_bool; 305 bool is_bool;
298 SplitArgument(arg, buffer, sizeof buffer, &name, &value, &is_bool); 306 SplitArgument(arg, buffer, sizeof buffer, &name, &value, &is_bool);
299 307
300 if (name != NULL) { 308 if (name != NULL) {
301 // lookup the flag 309 // lookup the flag
302 Flag* flag = Lookup(name); 310 Flag* flag = FindFlag(name);
303 if (flag == NULL) { 311 if (flag == NULL) {
304 if (remove_flags) { 312 if (remove_flags) {
305 // We don't recognize this flag but since we're removing 313 // We don't recognize this flag but since we're removing
306 // the flags we recognize we assume that the remaining flags 314 // the flags we recognize we assume that the remaining flags
307 // will be processed somewhere else so this flag might make 315 // will be processed somewhere else so this flag might make
308 // sense there. 316 // sense there.
309 continue; 317 continue;
310 } else { 318 } else {
311 fprintf(stderr, "Error: unrecognized flag %s\n", arg); 319 fprintf(stderr, "Error: unrecognized flag %s\n", arg);
312 return j; 320 return j;
313 } 321 }
314 } 322 }
315 323
316 // if we still need a flag value, use the next argument if available 324 // if we still need a flag value, use the next argument if available
317 if (flag->type() != Flag::BOOL && value == NULL) { 325 if (flag->type() != Flag::TYPE_BOOL && value == NULL) {
318 if (i < *argc) { 326 if (i < *argc) {
319 value = argv[i++]; 327 value = argv[i++];
320 } else { 328 } else {
321 fprintf(stderr, "Error: missing value for flag %s of type %s\n", 329 fprintf(stderr, "Error: missing value for flag %s of type %s\n",
322 arg, Type2String(flag->type())); 330 arg, Type2String(flag->type()));
323 return j; 331 return j;
324 } 332 }
325 } 333 }
326 334
327 // set the flag 335 // set the flag
328 char* endp = const_cast<char*>(""); // *endp is only read 336 char* endp = const_cast<char*>(""); // *endp is only read
329 switch (flag->type()) { 337 switch (flag->type()) {
330 case Flag::BOOL: 338 case Flag::TYPE_BOOL:
331 *flag->bool_variable() = !is_bool; 339 *flag->bool_variable() = !is_bool;
332 break; 340 break;
333 case Flag::INT: 341 case Flag::TYPE_INT:
334 *flag->int_variable() = strtol(value, &endp, 10); // NOLINT 342 *flag->int_variable() = strtol(value, &endp, 10); // NOLINT
335 break; 343 break;
336 case Flag::FLOAT: 344 case Flag::TYPE_FLOAT:
337 *flag->float_variable() = strtod(value, &endp); 345 *flag->float_variable() = strtod(value, &endp);
338 break; 346 break;
339 case Flag::STRING: 347 case Flag::TYPE_STRING:
340 *flag->string_variable() = value; 348 *flag->string_variable() = value;
341 break; 349 break;
342 } 350 }
343 351
344 // handle errors 352 // handle errors
345 if ((flag->type() == Flag::BOOL && value != NULL) || 353 if ((flag->type() == Flag::TYPE_BOOL && value != NULL) ||
346 (flag->type() != Flag::BOOL && is_bool) || 354 (flag->type() != Flag::TYPE_BOOL && is_bool) ||
347 *endp != '\0') { 355 *endp != '\0') {
348 fprintf(stderr, "Error: illegal value for flag %s of type %s\n", 356 fprintf(stderr, "Error: illegal value for flag %s of type %s\n",
349 arg, Type2String(flag->type())); 357 arg, Type2String(flag->type()));
350 return j; 358 return j;
351 } 359 }
352 360
353 // remove the flag & value from the command 361 // remove the flag & value from the command
354 if (remove_flags) 362 if (remove_flags)
355 while (j < i) 363 while (j < i)
356 argv[j++] = NULL; 364 argv[j++] = NULL;
(...skipping 20 matching lines...) Expand all
377 return p; 385 return p;
378 } 386 }
379 387
380 388
381 static char* SkipBlackSpace(char* p) { 389 static char* SkipBlackSpace(char* p) {
382 while (*p != '\0' && isspace(*p) == 0) p++; 390 while (*p != '\0' && isspace(*p) == 0) p++;
383 return p; 391 return p;
384 } 392 }
385 393
386 394
395 // static
387 int FlagList::SetFlagsFromString(const char* str, int len) { 396 int FlagList::SetFlagsFromString(const char* str, int len) {
388 // make a 0-terminated copy of str 397 // make a 0-terminated copy of str
389 char* copy0 = NewArray<char>(len + 1); 398 char* copy0 = NewArray<char>(len + 1);
390 memcpy(copy0, str, len); 399 memcpy(copy0, str, len);
391 copy0[len] = '\0'; 400 copy0[len] = '\0';
392 401
393 // strip leading white space 402 // strip leading white space
394 char* copy = SkipWhiteSpace(copy0); 403 char* copy = SkipWhiteSpace(copy0);
395 404
396 // count the number of 'arguments' 405 // count the number of 'arguments'
(...skipping 23 matching lines...) Expand all
420 // don't delete copy0 since the substrings 429 // don't delete copy0 since the substrings
421 // may be pointed to by FLAG variables! 430 // may be pointed to by FLAG variables!
422 // (this is a memory leak, but it's minor since this 431 // (this is a memory leak, but it's minor since this
423 // code is only used for debugging, or perhaps once 432 // code is only used for debugging, or perhaps once
424 // during initialization). 433 // during initialization).
425 434
426 return result; 435 return result;
427 } 436 }
428 437
429 438
430 void FlagList::Register(Flag* flag) { 439 // static
431 ASSERT(flag != NULL && strlen(flag->name()) > 0); 440 void FlagList::ResetAllFlags() {
432 if (Lookup(flag->name()) != NULL) 441 for (size_t i = 0; i < num_flags; ++i) {
433 V8_Fatal(flag->file(), 0, "flag %s declared twice", flag->name()); 442 flags[i].Reset();
434 flag->next_ = list_; 443 }
435 list_ = flag; 444 }
445
446
447 // static
448 void FlagList::PrintHelp() {
449 for (size_t i = 0; i < num_flags; ++i) {
450 Flag* f = &flags[i];
451 char* value = ToString(f);
452 printf(" --%s (%s) type: %s default: %s\n",
453 f->name(), f->comment(), Type2String(f->type()), value);
454 DeleteArray(value);
455 }
436 } 456 }
437 457
438 } } // namespace v8::internal 458 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/flags.h ('k') | src/flags.defs » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698