| 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 |
| 101 bool Flags::IsSet(const char* name) { | 103 bool Flags::IsSet(const char* name) { |
| 102 Flag* flag = Lookup(name); | 104 Flag* flag = Lookup(name); |
| 103 return (flag != NULL) && | 105 return (flag != NULL) && |
| 104 (flag->type_ == Flag::kBoolean) && | 106 (flag->type_ == Flag::kBoolean) && |
| 105 (flag->bool_ptr_ != NULL) && | 107 (flag->bool_ptr_ != NULL) && |
| 106 (*flag->bool_ptr_ == true); | 108 (*flag->bool_ptr_ == true); |
| 107 } | 109 } |
| 108 | 110 |
| 109 | 111 |
| 112 void Flags::AddFlag(Flag* flag) { |
| 113 ASSERT(!initialized_); |
| 114 if (num_flags_ == capacity_) { |
| 115 if (flags_ == NULL) { |
| 116 capacity_ = 256; |
| 117 flags_ = new Flag*[capacity_]; |
| 118 } else { |
| 119 intptr_t new_capacity = capacity_ * 2; |
| 120 Flag** new_flags = new Flag*[new_capacity]; |
| 121 for (intptr_t i = 0; i < num_flags_; i++) { |
| 122 new_flags[i] = flags_[i]; |
| 123 } |
| 124 delete [] flags_; |
| 125 flags_ = new_flags; |
| 126 capacity_ = new_capacity; |
| 127 } |
| 128 } |
| 129 flags_[num_flags_++] = flag; |
| 130 } |
| 131 |
| 132 |
| 110 bool Flags::Register_bool(bool* addr, | 133 bool Flags::Register_bool(bool* addr, |
| 111 const char* name, | 134 const char* name, |
| 112 bool default_value, | 135 bool default_value, |
| 113 const char* comment) { | 136 const char* comment) { |
| 114 Flag* flag = Lookup(name); | 137 Flag* flag = Lookup(name); |
| 115 if (flag != NULL) { | 138 if (flag != NULL) { |
| 116 ASSERT(flag->IsUnrecognized()); | 139 ASSERT(flag->IsUnrecognized()); |
| 117 return default_value; | 140 return default_value; |
| 118 } | 141 } |
| 119 flag = new Flag(name, comment, addr, Flag::kBoolean); | 142 flag = new Flag(name, comment, addr, Flag::kBoolean); |
| 120 flag->next_ = Flags::flags_; | 143 AddFlag(flag); |
| 121 Flags::flags_ = flag; | |
| 122 | |
| 123 return default_value; | 144 return default_value; |
| 124 } | 145 } |
| 125 | 146 |
| 126 | 147 |
| 127 int Flags::Register_int(int* addr, | 148 int Flags::Register_int(int* addr, |
| 128 const char* name, | 149 const char* name, |
| 129 int default_value, | 150 int default_value, |
| 130 const char* comment) { | 151 const char* comment) { |
| 131 ASSERT(Lookup(name) == NULL); | 152 ASSERT(Lookup(name) == NULL); |
| 132 | 153 |
| 133 Flag* flag = new Flag(name, comment, addr, Flag::kInteger); | 154 Flag* flag = new Flag(name, comment, addr, Flag::kInteger); |
| 134 flag->next_ = Flags::flags_; | 155 AddFlag(flag); |
| 135 Flags::flags_ = flag; | |
| 136 | 156 |
| 137 return default_value; | 157 return default_value; |
| 138 } | 158 } |
| 139 | 159 |
| 140 | 160 |
| 141 const char* Flags::Register_charp(charp* addr, | 161 const char* Flags::Register_charp(charp* addr, |
| 142 const char* name, | 162 const char* name, |
| 143 const char* default_value, | 163 const char* default_value, |
| 144 const char* comment) { | 164 const char* comment) { |
| 145 ASSERT(Lookup(name) == NULL); | 165 ASSERT(Lookup(name) == NULL); |
| 146 Flag* flag = new Flag(name, comment, addr, Flag::kString); | 166 Flag* flag = new Flag(name, comment, addr, Flag::kString); |
| 147 flag->next_ = Flags::flags_; | 167 AddFlag(flag); |
| 148 Flags::flags_ = flag; | |
| 149 return default_value; | 168 return default_value; |
| 150 } | 169 } |
| 151 | 170 |
| 152 | 171 |
| 153 bool Flags::Register_func(FlagHandler handler, | 172 bool Flags::Register_func(FlagHandler handler, |
| 154 const char* name, | 173 const char* name, |
| 155 const char* comment) { | 174 const char* comment) { |
| 156 ASSERT(Lookup(name) == NULL); | 175 ASSERT(Lookup(name) == NULL); |
| 157 Flag* flag = new Flag(name, comment, handler); | 176 Flag* flag = new Flag(name, comment, handler); |
| 158 flag->next_ = Flags::flags_; | 177 AddFlag(flag); |
| 159 Flags::flags_ = flag; | |
| 160 return false; | 178 return false; |
| 161 } | 179 } |
| 162 | 180 |
| 163 | 181 |
| 164 static void Normalize(char* s) { | 182 static void Normalize(char* s) { |
| 165 intptr_t len = strlen(s); | 183 intptr_t len = strlen(s); |
| 166 for (intptr_t i = 0; i < len; i++) { | 184 for (intptr_t i = 0; i < len; i++) { |
| 167 if (s[i] == '-') { | 185 if (s[i] == '-') { |
| 168 s[i] = '_'; | 186 s[i] = '_'; |
| 169 } | 187 } |
| 170 } | 188 } |
| 171 } | 189 } |
| 172 | 190 |
| 173 | 191 |
| 192 bool Flags::SetFlagFromString(Flag* flag, const char* argument) { |
| 193 ASSERT(!flag->IsUnrecognized()); |
| 194 switch (flag->type_) { |
| 195 case Flag::kBoolean: { |
| 196 if (strcmp(argument, "true") == 0) { |
| 197 *flag->bool_ptr_ = true; |
| 198 } else if (strcmp(argument, "false") == 0) { |
| 199 *flag->bool_ptr_ = false; |
| 200 } else { |
| 201 return false; |
| 202 } |
| 203 break; |
| 204 } |
| 205 case Flag::kString: { |
| 206 *flag->charp_ptr_ = argument == NULL ? NULL : strdup(argument); |
| 207 break; |
| 208 } |
| 209 case Flag::kInteger: { |
| 210 char* endptr = NULL; |
| 211 int val = strtol(argument, &endptr, 10); |
| 212 if (endptr != argument) { |
| 213 *flag->int_ptr_ = val; |
| 214 } |
| 215 break; |
| 216 } |
| 217 case Flag::kFunc: { |
| 218 if (strcmp(argument, "true") == 0) { |
| 219 (flag->handler_)(true); |
| 220 } else if (strcmp(argument, "false") == 0) { |
| 221 (flag->handler_)(false); |
| 222 } else { |
| 223 return false; |
| 224 } |
| 225 break; |
| 226 } |
| 227 default: { |
| 228 UNREACHABLE(); |
| 229 return false; |
| 230 } |
| 231 } |
| 232 flag->changed_ = true; |
| 233 return true; |
| 234 } |
| 235 |
| 236 |
| 174 void Flags::Parse(const char* option) { | 237 void Flags::Parse(const char* option) { |
| 175 // Find the beginning of the option argument, if it exists. | 238 // Find the beginning of the option argument, if it exists. |
| 176 const char* equals = option; | 239 const char* equals = option; |
| 177 while ((*equals != '\0') && (*equals != '=')) { | 240 while ((*equals != '\0') && (*equals != '=')) { |
| 178 equals++; | 241 equals++; |
| 179 } | 242 } |
| 180 | 243 |
| 181 const char* argument = NULL; | 244 const char* argument = NULL; |
| 182 | 245 |
| 183 // Determine if this is an option argument. | 246 // Determine if this is an option argument. |
| (...skipping 29 matching lines...) Expand all Loading... |
| 213 if (flag == NULL) { | 276 if (flag == NULL) { |
| 214 // Collect unrecognized flags. | 277 // Collect unrecognized flags. |
| 215 char* new_flag = new char[name_len + 1]; | 278 char* new_flag = new char[name_len + 1]; |
| 216 strncpy(new_flag, option, name_len); | 279 strncpy(new_flag, option, name_len); |
| 217 new_flag[name_len] = '\0'; | 280 new_flag[name_len] = '\0'; |
| 218 Flags::Register_bool(NULL, new_flag, true, NULL); | 281 Flags::Register_bool(NULL, new_flag, true, NULL); |
| 219 } else { | 282 } else { |
| 220 // Only set values for recognized flags, skip collected | 283 // Only set values for recognized flags, skip collected |
| 221 // unrecognized flags. | 284 // unrecognized flags. |
| 222 if (!flag->IsUnrecognized()) { | 285 if (!flag->IsUnrecognized()) { |
| 223 switch (flag->type_) { | 286 if (!SetFlagFromString(flag, argument)) { |
| 224 case Flag::kBoolean: { | 287 OS::Print("Ignoring flag: %s is an invalid value for flag %s\n", |
| 225 if (strcmp(argument, "true") == 0) { | 288 argument, name); |
| 226 *flag->bool_ptr_ = true; | |
| 227 } else if (strcmp(argument, "false") == 0) { | |
| 228 *flag->bool_ptr_ = false; | |
| 229 } else { | |
| 230 OS::Print("Ignoring flag: %s is a bool flag.\n", name); | |
| 231 } | |
| 232 break; | |
| 233 } | |
| 234 case Flag::kString: { | |
| 235 *flag->charp_ptr_ = argument == NULL ? NULL : strdup(argument); | |
| 236 break; | |
| 237 } | |
| 238 case Flag::kInteger: { | |
| 239 char* endptr = NULL; | |
| 240 int val = strtol(argument, &endptr, 10); | |
| 241 if (endptr != argument) { | |
| 242 *flag->int_ptr_ = val; | |
| 243 } | |
| 244 break; | |
| 245 } | |
| 246 case Flag::kFunc: { | |
| 247 if (strcmp(argument, "true") == 0) { | |
| 248 (flag->handler_)(true); | |
| 249 } else if (strcmp(argument, "false") == 0) { | |
| 250 (flag->handler_)(false); | |
| 251 } else { | |
| 252 OS::Print("Ignoring flag: %s is a bool flag.\n", name); | |
| 253 } | |
| 254 break; | |
| 255 } | |
| 256 default: { | |
| 257 UNREACHABLE(); | |
| 258 break; | |
| 259 } | |
| 260 } | 289 } |
| 261 } | 290 } |
| 262 } | 291 } |
| 263 | 292 |
| 264 delete[] name; | 293 delete[] name; |
| 265 } | 294 } |
| 266 | 295 |
| 267 | 296 |
| 268 static bool IsValidFlag(const char* name, | 297 static bool IsValidFlag(const char* name, |
| 269 const char* prefix, | 298 const char* prefix, |
| 270 intptr_t prefix_length) { | 299 intptr_t prefix_length) { |
| 271 intptr_t name_length = strlen(name); | 300 intptr_t name_length = strlen(name); |
| 272 return ((name_length > prefix_length) && | 301 return ((name_length > prefix_length) && |
| 273 (strncmp(name, prefix, prefix_length) == 0)); | 302 (strncmp(name, prefix, prefix_length) == 0)); |
| 274 } | 303 } |
| 275 | 304 |
| 276 | 305 |
| 306 int Flags::CompareFlagNames(const void* left, const void* right) { |
| 307 const Flag* left_flag = *reinterpret_cast<const Flag* const *>(left); |
| 308 const Flag* right_flag = *reinterpret_cast<const Flag* const *>(right); |
| 309 return strcmp(left_flag->name_, right_flag->name_); |
| 310 } |
| 311 |
| 312 |
| 277 bool Flags::ProcessCommandLineFlags(int number_of_vm_flags, | 313 bool Flags::ProcessCommandLineFlags(int number_of_vm_flags, |
| 278 const char** vm_flags) { | 314 const char** vm_flags) { |
| 279 if (initialized_) { | 315 if (initialized_) { |
| 280 return false; | 316 return false; |
| 281 } | 317 } |
| 282 | 318 |
| 283 initialized_ = true; | 319 qsort(flags_, num_flags_, sizeof flags_[0], CompareFlagNames); |
| 284 | 320 |
| 285 const char* kPrefix = "--"; | 321 const char* kPrefix = "--"; |
| 286 const intptr_t kPrefixLen = strlen(kPrefix); | 322 const intptr_t kPrefixLen = strlen(kPrefix); |
| 287 | 323 |
| 288 int i = 0; | 324 int i = 0; |
| 289 while ((i < number_of_vm_flags) && | 325 while ((i < number_of_vm_flags) && |
| 290 IsValidFlag(vm_flags[i], kPrefix, kPrefixLen)) { | 326 IsValidFlag(vm_flags[i], kPrefix, kPrefixLen)) { |
| 291 const char* option = vm_flags[i] + kPrefixLen; | 327 const char* option = vm_flags[i] + kPrefixLen; |
| 292 Parse(option); | 328 Parse(option); |
| 293 i++; | 329 i++; |
| 294 } | 330 } |
| 295 | 331 |
| 296 if (!FLAG_ignore_unrecognized_flags) { | 332 if (!FLAG_ignore_unrecognized_flags) { |
| 297 int unrecognized_count = 0; | 333 int unrecognized_count = 0; |
| 298 Flag* flag = Flags::flags_; | 334 for (intptr_t j = 0; j < num_flags_; j++) { |
| 299 while (flag != NULL) { | 335 Flag* flag = flags_[j]; |
| 300 if (flag->IsUnrecognized()) { | 336 if (flag->IsUnrecognized()) { |
| 301 if (unrecognized_count == 0) { | 337 if (unrecognized_count == 0) { |
| 302 OS::PrintErr("Unrecognized flags: %s", flag->name_); | 338 OS::PrintErr("Unrecognized flags: %s", flag->name_); |
| 303 } else { | 339 } else { |
| 304 OS::PrintErr(", %s", flag->name_); | 340 OS::PrintErr(", %s", flag->name_); |
| 305 } | 341 } |
| 306 unrecognized_count++; | 342 unrecognized_count++; |
| 307 } | 343 } |
| 308 flag = flag->next_; | |
| 309 } | 344 } |
| 310 if (unrecognized_count > 0) { | 345 if (unrecognized_count > 0) { |
| 311 OS::PrintErr("\n"); | 346 OS::PrintErr("\n"); |
| 312 exit(255); | 347 exit(255); |
| 313 } | 348 } |
| 314 } | 349 } |
| 315 if (FLAG_print_flags) { | 350 if (FLAG_print_flags) { |
| 316 PrintFlags(); | 351 PrintFlags(); |
| 317 } | 352 } |
| 353 |
| 354 initialized_ = true; |
| 355 return true; |
| 356 } |
| 357 |
| 358 bool Flags::SetFlag(const char* name, |
| 359 const char* value, |
| 360 const char** error) { |
| 361 Flag* flag = Lookup(name); |
| 362 if (flag == NULL) { |
| 363 *error = "Cannot set flag: flag not found"; |
| 364 return false; |
| 365 } |
| 366 if (!SetFlagFromString(flag, value)) { |
| 367 *error = "Cannot set flag: invalid value"; |
| 368 return false; |
| 369 } |
| 318 return true; | 370 return true; |
| 319 } | 371 } |
| 320 | 372 |
| 321 | 373 |
| 322 int Flags::CompareFlagNames(const void* left, const void* right) { | 374 void Flags::PrintFlags() { |
| 323 const Flag* left_flag = *reinterpret_cast<const Flag* const *>(left); | 375 OS::Print("Flag settings:\n"); |
| 324 const Flag* right_flag = *reinterpret_cast<const Flag* const *>(right); | 376 for (intptr_t i = 0; i < num_flags_; ++i) { |
| 325 return strcmp(left_flag->name_, right_flag->name_); | 377 flags_[i]->Print(); |
| 378 } |
| 326 } | 379 } |
| 327 | 380 |
| 328 | 381 |
| 329 void Flags::PrintFlags() { | 382 void Flags::PrintFlagToJSONArray(JSONArray* jsarr, const Flag* flag) { |
| 330 OS::Print("Flag settings:\n"); | 383 if (flag->IsUnrecognized() || flag->type_ == Flag::kFunc) { |
| 331 Flag* flag = Flags::flags_; | 384 return; |
| 332 int num_flags = 0; | 385 } |
| 333 while (flag != NULL) { | 386 JSONObject jsflag(jsarr); |
| 334 num_flags++; | 387 jsflag.AddProperty("name", flag->name_); |
| 335 flag = flag->next_; | 388 jsflag.AddProperty("comment", flag->comment_); |
| 389 switch (flag->type_) { |
| 390 case Flag::kBoolean: { |
| 391 jsflag.AddProperty("flagType", "bool"); |
| 392 jsflag.AddProperty("valueAsString", |
| 393 (*flag->bool_ptr_ ? "true" : "false")); |
| 394 break; |
| 336 } | 395 } |
| 337 Flag** flag_array = new Flag*[num_flags]; | 396 case Flag::kInteger: { |
| 338 flag = Flags::flags_; | 397 jsflag.AddProperty("flagType", "int"); |
| 339 for (int i = 0; i < num_flags; ++i, flag = flag->next_) { | 398 jsflag.AddPropertyF("valueAsString", "%d", *flag->int_ptr_); |
| 340 flag_array[i] = flag; | 399 break; |
| 341 } | 400 } |
| 401 case Flag::kString: { |
| 402 jsflag.AddProperty("flagType", "string"); |
| 403 if (flag->charp_ptr_ != NULL) { |
| 404 jsflag.AddPropertyF("valueAsString", "%s", *flag->charp_ptr_); |
| 405 } else { |
| 406 // valueAsString missing means NULL. |
| 407 } |
| 408 break; |
| 409 } |
| 410 default: |
| 411 UNREACHABLE(); |
| 412 break; |
| 413 } |
| 414 } |
| 342 | 415 |
| 343 qsort(flag_array, num_flags, sizeof flag_array[0], CompareFlagNames); | |
| 344 | 416 |
| 345 for (int i = 0; i < num_flags; ++i) { | 417 void Flags::PrintJSON(JSONStream* js) { |
| 346 flag_array[i]->Print(); | 418 JSONObject jsobj(js); |
| 419 jsobj.AddProperty("type", "FlagList"); |
| 420 jsobj.AddProperty("id", "flags"); |
| 421 |
| 422 { |
| 423 JSONArray jsarr(&jsobj, "unmodifiedFlags"); |
| 424 for (intptr_t i = 0; i < num_flags_; ++i) { |
| 425 Flag* flag = flags_[i]; |
| 426 if (!flag->changed_) { |
| 427 PrintFlagToJSONArray(&jsarr, flag); |
| 428 } |
| 347 } | 429 } |
| 348 delete[] flag_array; | |
| 349 } | 430 } |
| 431 { |
| 432 JSONArray jsarr(&jsobj, "modifiedFlags"); |
| 433 for (intptr_t i = 0; i < num_flags_; ++i) { |
| 434 Flag* flag = flags_[i]; |
| 435 if (flag->changed_) { |
| 436 PrintFlagToJSONArray(&jsarr, flag); |
| 437 } |
| 438 } |
| 439 } |
| 440 } |
| 441 |
| 350 } // namespace dart | 442 } // namespace dart |
| OLD | NEW |