Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/flags.h" | 5 #include "vm/flags.h" |
| 6 | 6 |
| 7 #include "platform/assert.h" | 7 #include "platform/assert.h" |
| 8 #include "vm/json_stream.h" | |
| 8 #include "vm/os.h" | 9 #include "vm/os.h" |
| 9 | 10 |
| 10 namespace dart { | 11 namespace dart { |
| 11 | 12 |
| 12 DEFINE_FLAG(bool, print_flags, false, "Print flags as they are being parsed."); | 13 DEFINE_FLAG(bool, print_flags, false, "Print flags as they are being parsed."); |
| 13 DEFINE_FLAG(bool, ignore_unrecognized_flags, false, | 14 DEFINE_FLAG(bool, ignore_unrecognized_flags, false, |
| 14 "Ignore unrecognized flags."); | 15 "Ignore unrecognized flags."); |
| 15 | 16 |
| 17 bool Flags::initialized_ = false; | |
| 18 | |
| 16 // List of registered flags. | 19 // List of registered flags. |
| 17 Flag* Flags::flags_ = NULL; | 20 Flag** Flags::flags_ = NULL; |
| 18 | 21 intptr_t Flags::capacity_ = 0; |
| 19 bool Flags::initialized_ = false; | 22 intptr_t Flags::num_flags_ = 0; |
| 20 | 23 |
| 21 class Flag { | 24 class Flag { |
| 22 public: | 25 public: |
| 23 enum FlagType { | 26 enum FlagType { |
| 24 kBoolean, | 27 kBoolean, |
| 25 kInteger, | 28 kInteger, |
| 26 kString, | 29 kString, |
| 27 kFunc, | 30 kFunc, |
| 28 kNumFlagTypes | 31 kNumFlagTypes |
| 29 }; | 32 }; |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 65 default: | 68 default: |
| 66 UNREACHABLE(); | 69 UNREACHABLE(); |
| 67 break; | 70 break; |
| 68 } | 71 } |
| 69 } | 72 } |
| 70 | 73 |
| 71 bool IsUnrecognized() const { | 74 bool IsUnrecognized() const { |
| 72 return (type_ == kBoolean) && (bool_ptr_ == NULL); | 75 return (type_ == kBoolean) && (bool_ptr_ == NULL); |
| 73 } | 76 } |
| 74 | 77 |
| 75 Flag* next_; | |
| 76 const char* name_; | 78 const char* name_; |
| 77 const char* comment_; | 79 const char* comment_; |
| 78 union { | 80 union { |
| 79 void* addr_; | 81 void* addr_; |
| 80 bool* bool_ptr_; | 82 bool* bool_ptr_; |
| 81 int* int_ptr_; | 83 int* int_ptr_; |
| 82 charp* charp_ptr_; | 84 charp* charp_ptr_; |
| 83 FlagHandler handler_; | 85 FlagHandler handler_; |
| 84 }; | 86 }; |
| 85 FlagType type_; | 87 FlagType type_; |
| 88 bool changed_; | |
| 86 }; | 89 }; |
| 87 | 90 |
| 88 | 91 |
| 89 Flag* Flags::Lookup(const char* name) { | 92 Flag* Flags::Lookup(const char* name) { |
| 90 Flag* cur = Flags::flags_; | 93 for (intptr_t i = 0; i < num_flags_; i++) { |
| 91 while (cur != NULL) { | 94 Flag* flag = flags_[i]; |
| 92 if (strcmp(cur->name_, name) == 0) { | 95 if (strcmp(flag->name_, name) == 0) { |
| 93 return cur; | 96 return flag; |
| 94 } | 97 } |
| 95 cur = cur->next_; | |
| 96 } | 98 } |
| 97 return NULL; | 99 return NULL; |
| 98 } | 100 } |
| 99 | 101 |
| 100 | 102 |
| 103 void Flags::AddFlag(Flag* flag) { | |
| 104 ASSERT(!initialized_); | |
| 105 if (num_flags_ == capacity_) { | |
| 106 if (flags_ == NULL) { | |
| 107 capacity_ = 256; | |
| 108 flags_ = new Flag*[capacity_]; | |
|
Cutch
2014/05/26 05:48:33
My preference would be for calloc / realloc.
| |
| 109 } else { | |
| 110 intptr_t new_capacity = capacity_ * 2; | |
| 111 Flag** new_flags = new Flag*[new_capacity]; | |
|
Cutch
2014/05/26 05:48:33
realloc instead
| |
| 112 for (intptr_t i = 0; i < num_flags_; i++) { | |
| 113 new_flags[i] = flags_[i]; | |
| 114 } | |
| 115 delete flags_; | |
|
Cutch
2014/05/26 05:48:33
if you stick with new, this must be array delete:
turnidge
2014/05/27 21:26:00
Fixed delete.
Didn't go to realloc because I don'
| |
| 116 flags_ = new_flags; | |
| 117 capacity_ = new_capacity; | |
| 118 } | |
| 119 } | |
| 120 flags_[num_flags_++] = flag; | |
| 121 } | |
| 122 | |
| 123 | |
| 101 bool Flags::Register_bool(bool* addr, | 124 bool Flags::Register_bool(bool* addr, |
| 102 const char* name, | 125 const char* name, |
| 103 bool default_value, | 126 bool default_value, |
| 104 const char* comment) { | 127 const char* comment) { |
| 105 Flag* flag = Lookup(name); | 128 Flag* flag = Lookup(name); |
| 106 if (flag != NULL) { | 129 if (flag != NULL) { |
| 107 ASSERT(flag->IsUnrecognized()); | 130 ASSERT(flag->IsUnrecognized()); |
| 108 return default_value; | 131 return default_value; |
| 109 } | 132 } |
| 110 flag = new Flag(name, comment, addr, Flag::kBoolean); | 133 flag = new Flag(name, comment, addr, Flag::kBoolean); |
| 111 flag->next_ = Flags::flags_; | 134 AddFlag(flag); |
| 112 Flags::flags_ = flag; | |
| 113 | |
| 114 return default_value; | 135 return default_value; |
| 115 } | 136 } |
| 116 | 137 |
| 117 | 138 |
| 118 int Flags::Register_int(int* addr, | 139 int Flags::Register_int(int* addr, |
| 119 const char* name, | 140 const char* name, |
| 120 int default_value, | 141 int default_value, |
| 121 const char* comment) { | 142 const char* comment) { |
| 122 ASSERT(Lookup(name) == NULL); | 143 ASSERT(Lookup(name) == NULL); |
| 123 | 144 |
| 124 Flag* flag = new Flag(name, comment, addr, Flag::kInteger); | 145 Flag* flag = new Flag(name, comment, addr, Flag::kInteger); |
| 125 flag->next_ = Flags::flags_; | 146 AddFlag(flag); |
| 126 Flags::flags_ = flag; | |
| 127 | 147 |
| 128 return default_value; | 148 return default_value; |
| 129 } | 149 } |
| 130 | 150 |
| 131 | 151 |
| 132 const char* Flags::Register_charp(charp* addr, | 152 const char* Flags::Register_charp(charp* addr, |
| 133 const char* name, | 153 const char* name, |
| 134 const char* default_value, | 154 const char* default_value, |
| 135 const char* comment) { | 155 const char* comment) { |
| 136 ASSERT(Lookup(name) == NULL); | 156 ASSERT(Lookup(name) == NULL); |
| 137 Flag* flag = new Flag(name, comment, addr, Flag::kString); | 157 Flag* flag = new Flag(name, comment, addr, Flag::kString); |
| 138 flag->next_ = Flags::flags_; | 158 AddFlag(flag); |
| 139 Flags::flags_ = flag; | |
| 140 return default_value; | 159 return default_value; |
| 141 } | 160 } |
| 142 | 161 |
| 143 | 162 |
| 144 bool Flags::Register_func(FlagHandler handler, | 163 bool Flags::Register_func(FlagHandler handler, |
| 145 const char* name, | 164 const char* name, |
| 146 const char* comment) { | 165 const char* comment) { |
| 147 ASSERT(Lookup(name) == NULL); | 166 ASSERT(Lookup(name) == NULL); |
| 148 Flag* flag = new Flag(name, comment, handler); | 167 Flag* flag = new Flag(name, comment, handler); |
| 149 flag->next_ = Flags::flags_; | 168 AddFlag(flag); |
| 150 Flags::flags_ = flag; | |
| 151 return false; | 169 return false; |
| 152 } | 170 } |
| 153 | 171 |
| 154 | 172 |
| 155 static void Normalize(char* s) { | 173 static void Normalize(char* s) { |
| 156 intptr_t len = strlen(s); | 174 intptr_t len = strlen(s); |
| 157 for (intptr_t i = 0; i < len; i++) { | 175 for (intptr_t i = 0; i < len; i++) { |
| 158 if (s[i] == '-') { | 176 if (s[i] == '-') { |
| 159 s[i] = '_'; | 177 s[i] = '_'; |
| 160 } | 178 } |
| 161 } | 179 } |
| 162 } | 180 } |
| 163 | 181 |
| 164 | 182 |
| 183 bool Flags::SetFlagFromString(Flag* flag, const char* argument) { | |
| 184 ASSERT(!flag->IsUnrecognized()); | |
| 185 switch (flag->type_) { | |
| 186 case Flag::kBoolean: { | |
| 187 if (strcmp(argument, "true") == 0) { | |
| 188 *flag->bool_ptr_ = true; | |
| 189 } else if (strcmp(argument, "false") == 0) { | |
| 190 *flag->bool_ptr_ = false; | |
| 191 } else { | |
| 192 return false; | |
| 193 } | |
| 194 break; | |
| 195 } | |
| 196 case Flag::kString: { | |
| 197 *flag->charp_ptr_ = argument == NULL ? NULL : strdup(argument); | |
| 198 break; | |
| 199 } | |
| 200 case Flag::kInteger: { | |
| 201 char* endptr = NULL; | |
| 202 int val = strtol(argument, &endptr, 10); | |
| 203 if (endptr != argument) { | |
| 204 *flag->int_ptr_ = val; | |
| 205 } | |
| 206 break; | |
| 207 } | |
| 208 case Flag::kFunc: { | |
| 209 if (strcmp(argument, "true") == 0) { | |
| 210 (flag->handler_)(true); | |
| 211 } else if (strcmp(argument, "false") == 0) { | |
| 212 (flag->handler_)(false); | |
| 213 } else { | |
| 214 return false; | |
| 215 } | |
| 216 break; | |
| 217 } | |
| 218 default: { | |
| 219 UNREACHABLE(); | |
| 220 return false; | |
| 221 } | |
| 222 } | |
| 223 flag->changed_ = true; | |
| 224 return true; | |
| 225 } | |
| 226 | |
| 227 | |
| 165 void Flags::Parse(const char* option) { | 228 void Flags::Parse(const char* option) { |
| 166 // Find the beginning of the option argument, if it exists. | 229 // Find the beginning of the option argument, if it exists. |
| 167 const char* equals = option; | 230 const char* equals = option; |
| 168 while ((*equals != '\0') && (*equals != '=')) { | 231 while ((*equals != '\0') && (*equals != '=')) { |
| 169 equals++; | 232 equals++; |
| 170 } | 233 } |
| 171 | 234 |
| 172 const char* argument = NULL; | 235 const char* argument = NULL; |
| 173 | 236 |
| 174 // Determine if this is an option argument. | 237 // Determine if this is an option argument. |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 204 if (flag == NULL) { | 267 if (flag == NULL) { |
| 205 // Collect unrecognized flags. | 268 // Collect unrecognized flags. |
| 206 char* new_flag = new char[name_len + 1]; | 269 char* new_flag = new char[name_len + 1]; |
| 207 strncpy(new_flag, option, name_len); | 270 strncpy(new_flag, option, name_len); |
| 208 new_flag[name_len] = '\0'; | 271 new_flag[name_len] = '\0'; |
| 209 Flags::Register_bool(NULL, new_flag, true, NULL); | 272 Flags::Register_bool(NULL, new_flag, true, NULL); |
| 210 } else { | 273 } else { |
| 211 // Only set values for recognized flags, skip collected | 274 // Only set values for recognized flags, skip collected |
| 212 // unrecognized flags. | 275 // unrecognized flags. |
| 213 if (!flag->IsUnrecognized()) { | 276 if (!flag->IsUnrecognized()) { |
| 214 switch (flag->type_) { | 277 if (!SetFlagFromString(flag, argument)) { |
| 215 case Flag::kBoolean: { | 278 OS::Print("Ignoring flag: %s is an invalid value for flag %s\n", |
| 216 if (strcmp(argument, "true") == 0) { | 279 argument, name); |
| 217 *flag->bool_ptr_ = true; | |
| 218 } else if (strcmp(argument, "false") == 0) { | |
| 219 *flag->bool_ptr_ = false; | |
| 220 } else { | |
| 221 OS::Print("Ignoring flag: %s is a bool flag.\n", name); | |
| 222 } | |
| 223 break; | |
| 224 } | |
| 225 case Flag::kString: { | |
| 226 *flag->charp_ptr_ = argument == NULL ? NULL : strdup(argument); | |
| 227 break; | |
| 228 } | |
| 229 case Flag::kInteger: { | |
| 230 char* endptr = NULL; | |
| 231 int val = strtol(argument, &endptr, 10); | |
| 232 if (endptr != argument) { | |
| 233 *flag->int_ptr_ = val; | |
| 234 } | |
| 235 break; | |
| 236 } | |
| 237 case Flag::kFunc: { | |
| 238 if (strcmp(argument, "true") == 0) { | |
| 239 (flag->handler_)(true); | |
| 240 } else if (strcmp(argument, "false") == 0) { | |
| 241 (flag->handler_)(false); | |
| 242 } else { | |
| 243 OS::Print("Ignoring flag: %s is a bool flag.\n", name); | |
| 244 } | |
| 245 break; | |
| 246 } | |
| 247 default: { | |
| 248 UNREACHABLE(); | |
| 249 break; | |
| 250 } | |
| 251 } | 280 } |
| 252 } | 281 } |
| 253 } | 282 } |
| 254 | 283 |
| 255 delete[] name; | 284 delete[] name; |
| 256 } | 285 } |
| 257 | 286 |
| 258 | 287 |
| 259 static bool IsValidFlag(const char* name, | 288 static bool IsValidFlag(const char* name, |
| 260 const char* prefix, | 289 const char* prefix, |
| 261 intptr_t prefix_length) { | 290 intptr_t prefix_length) { |
| 262 intptr_t name_length = strlen(name); | 291 intptr_t name_length = strlen(name); |
| 263 return ((name_length > prefix_length) && | 292 return ((name_length > prefix_length) && |
| 264 (strncmp(name, prefix, prefix_length) == 0)); | 293 (strncmp(name, prefix, prefix_length) == 0)); |
| 265 } | 294 } |
| 266 | 295 |
| 267 | 296 |
| 297 int Flags::CompareFlagNames(const void* left, const void* right) { | |
| 298 const Flag* left_flag = *reinterpret_cast<const Flag* const *>(left); | |
| 299 const Flag* right_flag = *reinterpret_cast<const Flag* const *>(right); | |
| 300 return strcmp(left_flag->name_, right_flag->name_); | |
| 301 } | |
| 302 | |
| 303 | |
| 268 bool Flags::ProcessCommandLineFlags(int number_of_vm_flags, | 304 bool Flags::ProcessCommandLineFlags(int number_of_vm_flags, |
| 269 const char** vm_flags) { | 305 const char** vm_flags) { |
| 270 if (initialized_) { | 306 if (initialized_) { |
| 271 return false; | 307 return false; |
| 272 } | 308 } |
| 273 | 309 |
| 274 initialized_ = true; | 310 initialized_ = true; |
| 311 qsort(flags_, num_flags_, sizeof flags_[0], CompareFlagNames); | |
| 275 | 312 |
| 276 const char* kPrefix = "--"; | 313 const char* kPrefix = "--"; |
| 277 const intptr_t kPrefixLen = strlen(kPrefix); | 314 const intptr_t kPrefixLen = strlen(kPrefix); |
| 278 | 315 |
| 279 int i = 0; | 316 int i = 0; |
| 280 while ((i < number_of_vm_flags) && | 317 while ((i < number_of_vm_flags) && |
| 281 IsValidFlag(vm_flags[i], kPrefix, kPrefixLen)) { | 318 IsValidFlag(vm_flags[i], kPrefix, kPrefixLen)) { |
| 282 const char* option = vm_flags[i] + kPrefixLen; | 319 const char* option = vm_flags[i] + kPrefixLen; |
| 283 Parse(option); | 320 Parse(option); |
| 284 i++; | 321 i++; |
| 285 } | 322 } |
| 286 | 323 |
| 287 if (!FLAG_ignore_unrecognized_flags) { | 324 if (!FLAG_ignore_unrecognized_flags) { |
| 288 int unrecognized_count = 0; | 325 int unrecognized_count = 0; |
| 289 Flag* flag = Flags::flags_; | 326 for (intptr_t j = 0; j < num_flags_; j++) { |
| 290 while (flag != NULL) { | 327 Flag* flag = flags_[j]; |
| 291 if (flag->IsUnrecognized()) { | 328 if (flag->IsUnrecognized()) { |
| 292 if (unrecognized_count == 0) { | 329 if (unrecognized_count == 0) { |
| 293 OS::PrintErr("Unrecognized flags: %s", flag->name_); | 330 OS::PrintErr("Unrecognized flags: %s", flag->name_); |
| 294 } else { | 331 } else { |
| 295 OS::PrintErr(", %s", flag->name_); | 332 OS::PrintErr(", %s", flag->name_); |
| 296 } | 333 } |
| 297 unrecognized_count++; | 334 unrecognized_count++; |
| 298 } | 335 } |
| 299 flag = flag->next_; | |
| 300 } | 336 } |
| 301 if (unrecognized_count > 0) { | 337 if (unrecognized_count > 0) { |
| 302 OS::PrintErr("\n"); | 338 OS::PrintErr("\n"); |
| 303 exit(255); | 339 exit(255); |
| 304 } | 340 } |
| 305 } | 341 } |
| 306 if (FLAG_print_flags) { | 342 if (FLAG_print_flags) { |
| 307 PrintFlags(); | 343 PrintFlags(); |
| 308 } | 344 } |
| 309 return true; | 345 return true; |
| 310 } | 346 } |
| 311 | 347 |
| 348 bool Flags::SetFlag(const char* name, | |
| 349 const char* value, | |
| 350 const char** error) { | |
| 351 Flag* flag = Lookup(name); | |
| 352 if (flag == NULL) { | |
| 353 *error = "Cannot set flag: flag not found"; | |
| 354 return false; | |
| 355 } | |
| 356 if (!SetFlagFromString(flag, value)) { | |
| 357 *error = "Cannot set flag: invalid value"; | |
| 358 return false; | |
| 359 } | |
| 360 return true; | |
| 361 } | |
| 362 | |
| 312 | 363 |
| 313 int Flags::CompareFlagNames(const void* left, const void* right) { | 364 void Flags::PrintFlags() { |
| 314 const Flag* left_flag = *reinterpret_cast<const Flag* const *>(left); | 365 OS::Print("Flag settings:\n"); |
| 315 const Flag* right_flag = *reinterpret_cast<const Flag* const *>(right); | 366 for (intptr_t i = 0; i < num_flags_; ++i) { |
| 316 return strcmp(left_flag->name_, right_flag->name_); | 367 flags_[i]->Print(); |
| 368 } | |
| 317 } | 369 } |
| 318 | 370 |
| 319 | 371 |
| 320 void Flags::PrintFlags() { | 372 void Flags::PrintFlagToJSONArray(JSONArray* jsarr, const Flag* flag) { |
| 321 OS::Print("Flag settings:\n"); | 373 if (flag->IsUnrecognized() || flag->type_ == Flag::kFunc) { |
| 322 Flag* flag = Flags::flags_; | 374 return; |
| 323 int num_flags = 0; | 375 } |
| 324 while (flag != NULL) { | 376 JSONObject jsflag(jsarr); |
| 325 num_flags++; | 377 jsflag.AddProperty("name", flag->name_); |
| 326 flag = flag->next_; | 378 jsflag.AddProperty("comment", flag->comment_); |
| 379 switch (flag->type_) { | |
| 380 case Flag::kBoolean: { | |
| 381 jsflag.AddProperty("flagType", "bool"); | |
| 382 jsflag.AddProperty("valueAsString", | |
| 383 (*flag->bool_ptr_ ? "true" : "false")); | |
| 384 break; | |
| 327 } | 385 } |
| 328 Flag** flag_array = new Flag*[num_flags]; | 386 case Flag::kInteger: { |
| 329 flag = Flags::flags_; | 387 jsflag.AddProperty("flagType", "int"); |
| 330 for (int i = 0; i < num_flags; ++i, flag = flag->next_) { | 388 jsflag.AddPropertyF("valueAsString", "%d", *flag->int_ptr_); |
| 331 flag_array[i] = flag; | 389 break; |
| 332 } | 390 } |
| 391 case Flag::kString: { | |
| 392 jsflag.AddProperty("flagType", "string"); | |
| 393 if (flag->charp_ptr_ != NULL) { | |
| 394 jsflag.AddPropertyF("valueAsString", "%s", *flag->charp_ptr_); | |
| 395 } else { | |
| 396 // valueAsString missing means NULL. | |
| 397 } | |
| 398 break; | |
| 399 } | |
| 400 default: | |
| 401 UNREACHABLE(); | |
| 402 break; | |
| 403 } | |
| 404 } | |
| 333 | 405 |
| 334 qsort(flag_array, num_flags, sizeof flag_array[0], CompareFlagNames); | |
| 335 | 406 |
| 336 for (int i = 0; i < num_flags; ++i) { | 407 void Flags::PrintJSON(JSONStream* js) { |
| 337 flag_array[i]->Print(); | 408 JSONObject jsobj(js); |
| 409 jsobj.AddProperty("type", "FlagList"); | |
| 410 jsobj.AddProperty("id", "flags"); | |
| 411 | |
| 412 { | |
| 413 JSONArray jsarr(&jsobj, "unmodifiedFlags"); | |
| 414 for (intptr_t i = 0; i < num_flags_; ++i) { | |
| 415 Flag* flag = flags_[i]; | |
| 416 if (!flag->changed_) { | |
| 417 PrintFlagToJSONArray(&jsarr, flag); | |
| 418 } | |
| 338 } | 419 } |
| 339 delete[] flag_array; | |
| 340 } | 420 } |
| 421 { | |
| 422 JSONArray jsarr(&jsobj, "modifiedFlags"); | |
| 423 for (intptr_t i = 0; i < num_flags_; ++i) { | |
| 424 Flag* flag = flags_[i]; | |
| 425 if (flag->changed_) { | |
| 426 PrintFlagToJSONArray(&jsarr, flag); | |
| 427 } | |
| 428 } | |
| 429 } | |
| 430 } | |
| 431 | |
| 341 } // namespace dart | 432 } // namespace dart |
| OLD | NEW |