Chromium Code Reviews| Index: runtime/vm/flags.cc |
| diff --git a/runtime/vm/flags.cc b/runtime/vm/flags.cc |
| index fdca04e1286b142abd1ba988e11955f60410846e..e9359ebff52a4b1f6fc68b43c19b1e18071d87b3 100644 |
| --- a/runtime/vm/flags.cc |
| +++ b/runtime/vm/flags.cc |
| @@ -5,6 +5,7 @@ |
| #include "vm/flags.h" |
| #include "platform/assert.h" |
| +#include "vm/json_stream.h" |
| #include "vm/os.h" |
| namespace dart { |
| @@ -13,11 +14,13 @@ DEFINE_FLAG(bool, print_flags, false, "Print flags as they are being parsed."); |
| DEFINE_FLAG(bool, ignore_unrecognized_flags, false, |
| "Ignore unrecognized flags."); |
| -// List of registered flags. |
| -Flag* Flags::flags_ = NULL; |
| - |
| bool Flags::initialized_ = false; |
| +// List of registered flags. |
| +Flag** Flags::flags_ = NULL; |
| +intptr_t Flags::capacity_ = 0; |
| +intptr_t Flags::num_flags_ = 0; |
| + |
| class Flag { |
| public: |
| enum FlagType { |
| @@ -72,7 +75,6 @@ class Flag { |
| return (type_ == kBoolean) && (bool_ptr_ == NULL); |
| } |
| - Flag* next_; |
| const char* name_; |
| const char* comment_; |
| union { |
| @@ -83,21 +85,42 @@ class Flag { |
| FlagHandler handler_; |
| }; |
| FlagType type_; |
| + bool changed_; |
| }; |
| Flag* Flags::Lookup(const char* name) { |
| - Flag* cur = Flags::flags_; |
| - while (cur != NULL) { |
| - if (strcmp(cur->name_, name) == 0) { |
| - return cur; |
| + for (intptr_t i = 0; i < num_flags_; i++) { |
| + Flag* flag = flags_[i]; |
| + if (strcmp(flag->name_, name) == 0) { |
| + return flag; |
| } |
| - cur = cur->next_; |
| } |
| return NULL; |
| } |
| +void Flags::AddFlag(Flag* flag) { |
| + ASSERT(!initialized_); |
| + if (num_flags_ == capacity_) { |
| + if (flags_ == NULL) { |
| + capacity_ = 256; |
| + flags_ = new Flag*[capacity_]; |
|
Cutch
2014/05/26 05:48:33
My preference would be for calloc / realloc.
|
| + } else { |
| + intptr_t new_capacity = capacity_ * 2; |
| + Flag** new_flags = new Flag*[new_capacity]; |
|
Cutch
2014/05/26 05:48:33
realloc instead
|
| + for (intptr_t i = 0; i < num_flags_; i++) { |
| + new_flags[i] = flags_[i]; |
| + } |
| + 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'
|
| + flags_ = new_flags; |
| + capacity_ = new_capacity; |
| + } |
| + } |
| + flags_[num_flags_++] = flag; |
| +} |
| + |
| + |
| bool Flags::Register_bool(bool* addr, |
| const char* name, |
| bool default_value, |
| @@ -108,9 +131,7 @@ bool Flags::Register_bool(bool* addr, |
| return default_value; |
| } |
| flag = new Flag(name, comment, addr, Flag::kBoolean); |
| - flag->next_ = Flags::flags_; |
| - Flags::flags_ = flag; |
| - |
| + AddFlag(flag); |
| return default_value; |
| } |
| @@ -122,8 +143,7 @@ int Flags::Register_int(int* addr, |
| ASSERT(Lookup(name) == NULL); |
| Flag* flag = new Flag(name, comment, addr, Flag::kInteger); |
| - flag->next_ = Flags::flags_; |
| - Flags::flags_ = flag; |
| + AddFlag(flag); |
| return default_value; |
| } |
| @@ -135,8 +155,7 @@ const char* Flags::Register_charp(charp* addr, |
| const char* comment) { |
| ASSERT(Lookup(name) == NULL); |
| Flag* flag = new Flag(name, comment, addr, Flag::kString); |
| - flag->next_ = Flags::flags_; |
| - Flags::flags_ = flag; |
| + AddFlag(flag); |
| return default_value; |
| } |
| @@ -146,8 +165,7 @@ bool Flags::Register_func(FlagHandler handler, |
| const char* comment) { |
| ASSERT(Lookup(name) == NULL); |
| Flag* flag = new Flag(name, comment, handler); |
| - flag->next_ = Flags::flags_; |
| - Flags::flags_ = flag; |
| + AddFlag(flag); |
| return false; |
| } |
| @@ -162,6 +180,51 @@ static void Normalize(char* s) { |
| } |
| +bool Flags::SetFlagFromString(Flag* flag, const char* argument) { |
| + ASSERT(!flag->IsUnrecognized()); |
| + switch (flag->type_) { |
| + case Flag::kBoolean: { |
| + if (strcmp(argument, "true") == 0) { |
| + *flag->bool_ptr_ = true; |
| + } else if (strcmp(argument, "false") == 0) { |
| + *flag->bool_ptr_ = false; |
| + } else { |
| + return false; |
| + } |
| + break; |
| + } |
| + case Flag::kString: { |
| + *flag->charp_ptr_ = argument == NULL ? NULL : strdup(argument); |
| + break; |
| + } |
| + case Flag::kInteger: { |
| + char* endptr = NULL; |
| + int val = strtol(argument, &endptr, 10); |
| + if (endptr != argument) { |
| + *flag->int_ptr_ = val; |
| + } |
| + break; |
| + } |
| + case Flag::kFunc: { |
| + if (strcmp(argument, "true") == 0) { |
| + (flag->handler_)(true); |
| + } else if (strcmp(argument, "false") == 0) { |
| + (flag->handler_)(false); |
| + } else { |
| + return false; |
| + } |
| + break; |
| + } |
| + default: { |
| + UNREACHABLE(); |
| + return false; |
| + } |
| + } |
| + flag->changed_ = true; |
| + return true; |
| +} |
| + |
| + |
| void Flags::Parse(const char* option) { |
| // Find the beginning of the option argument, if it exists. |
| const char* equals = option; |
| @@ -211,43 +274,9 @@ void Flags::Parse(const char* option) { |
| // Only set values for recognized flags, skip collected |
| // unrecognized flags. |
| if (!flag->IsUnrecognized()) { |
| - switch (flag->type_) { |
| - case Flag::kBoolean: { |
| - if (strcmp(argument, "true") == 0) { |
| - *flag->bool_ptr_ = true; |
| - } else if (strcmp(argument, "false") == 0) { |
| - *flag->bool_ptr_ = false; |
| - } else { |
| - OS::Print("Ignoring flag: %s is a bool flag.\n", name); |
| - } |
| - break; |
| - } |
| - case Flag::kString: { |
| - *flag->charp_ptr_ = argument == NULL ? NULL : strdup(argument); |
| - break; |
| - } |
| - case Flag::kInteger: { |
| - char* endptr = NULL; |
| - int val = strtol(argument, &endptr, 10); |
| - if (endptr != argument) { |
| - *flag->int_ptr_ = val; |
| - } |
| - break; |
| - } |
| - case Flag::kFunc: { |
| - if (strcmp(argument, "true") == 0) { |
| - (flag->handler_)(true); |
| - } else if (strcmp(argument, "false") == 0) { |
| - (flag->handler_)(false); |
| - } else { |
| - OS::Print("Ignoring flag: %s is a bool flag.\n", name); |
| - } |
| - break; |
| - } |
| - default: { |
| - UNREACHABLE(); |
| - break; |
| - } |
| + if (!SetFlagFromString(flag, argument)) { |
| + OS::Print("Ignoring flag: %s is an invalid value for flag %s\n", |
| + argument, name); |
| } |
| } |
| } |
| @@ -265,6 +294,13 @@ static bool IsValidFlag(const char* name, |
| } |
| +int Flags::CompareFlagNames(const void* left, const void* right) { |
| + const Flag* left_flag = *reinterpret_cast<const Flag* const *>(left); |
| + const Flag* right_flag = *reinterpret_cast<const Flag* const *>(right); |
| + return strcmp(left_flag->name_, right_flag->name_); |
| +} |
| + |
| + |
| bool Flags::ProcessCommandLineFlags(int number_of_vm_flags, |
| const char** vm_flags) { |
| if (initialized_) { |
| @@ -272,6 +308,7 @@ bool Flags::ProcessCommandLineFlags(int number_of_vm_flags, |
| } |
| initialized_ = true; |
| + qsort(flags_, num_flags_, sizeof flags_[0], CompareFlagNames); |
| const char* kPrefix = "--"; |
| const intptr_t kPrefixLen = strlen(kPrefix); |
| @@ -286,8 +323,8 @@ bool Flags::ProcessCommandLineFlags(int number_of_vm_flags, |
| if (!FLAG_ignore_unrecognized_flags) { |
| int unrecognized_count = 0; |
| - Flag* flag = Flags::flags_; |
| - while (flag != NULL) { |
| + for (intptr_t j = 0; j < num_flags_; j++) { |
| + Flag* flag = flags_[j]; |
| if (flag->IsUnrecognized()) { |
| if (unrecognized_count == 0) { |
| OS::PrintErr("Unrecognized flags: %s", flag->name_); |
| @@ -296,7 +333,6 @@ bool Flags::ProcessCommandLineFlags(int number_of_vm_flags, |
| } |
| unrecognized_count++; |
| } |
| - flag = flag->next_; |
| } |
| if (unrecognized_count > 0) { |
| OS::PrintErr("\n"); |
| @@ -309,33 +345,88 @@ bool Flags::ProcessCommandLineFlags(int number_of_vm_flags, |
| return true; |
| } |
| - |
| -int Flags::CompareFlagNames(const void* left, const void* right) { |
| - const Flag* left_flag = *reinterpret_cast<const Flag* const *>(left); |
| - const Flag* right_flag = *reinterpret_cast<const Flag* const *>(right); |
| - return strcmp(left_flag->name_, right_flag->name_); |
| +bool Flags::SetFlag(const char* name, |
| + const char* value, |
| + const char** error) { |
| + Flag* flag = Lookup(name); |
| + if (flag == NULL) { |
| + *error = "Cannot set flag: flag not found"; |
| + return false; |
| + } |
| + if (!SetFlagFromString(flag, value)) { |
| + *error = "Cannot set flag: invalid value"; |
| + return false; |
| + } |
| + return true; |
| } |
| void Flags::PrintFlags() { |
| - OS::Print("Flag settings:\n"); |
| - Flag* flag = Flags::flags_; |
| - int num_flags = 0; |
| - while (flag != NULL) { |
| - num_flags++; |
| - flag = flag->next_; |
| + OS::Print("Flag settings:\n"); |
| + for (intptr_t i = 0; i < num_flags_; ++i) { |
| + flags_[i]->Print(); |
| + } |
| +} |
| + |
| + |
| +void Flags::PrintFlagToJSONArray(JSONArray* jsarr, const Flag* flag) { |
| + if (flag->IsUnrecognized() || flag->type_ == Flag::kFunc) { |
| + return; |
| + } |
| + JSONObject jsflag(jsarr); |
| + jsflag.AddProperty("name", flag->name_); |
| + jsflag.AddProperty("comment", flag->comment_); |
| + switch (flag->type_) { |
| + case Flag::kBoolean: { |
| + jsflag.AddProperty("flagType", "bool"); |
| + jsflag.AddProperty("valueAsString", |
| + (*flag->bool_ptr_ ? "true" : "false")); |
| + break; |
| + } |
| + case Flag::kInteger: { |
| + jsflag.AddProperty("flagType", "int"); |
| + jsflag.AddPropertyF("valueAsString", "%d", *flag->int_ptr_); |
| + break; |
| } |
| - Flag** flag_array = new Flag*[num_flags]; |
| - flag = Flags::flags_; |
| - for (int i = 0; i < num_flags; ++i, flag = flag->next_) { |
| - flag_array[i] = flag; |
| + case Flag::kString: { |
| + jsflag.AddProperty("flagType", "string"); |
| + if (flag->charp_ptr_ != NULL) { |
| + jsflag.AddPropertyF("valueAsString", "%s", *flag->charp_ptr_); |
| + } else { |
| + // valueAsString missing means NULL. |
| + } |
| + break; |
| } |
| + default: |
| + UNREACHABLE(); |
| + break; |
| + } |
| +} |
| + |
| - qsort(flag_array, num_flags, sizeof flag_array[0], CompareFlagNames); |
| +void Flags::PrintJSON(JSONStream* js) { |
| + JSONObject jsobj(js); |
| + jsobj.AddProperty("type", "FlagList"); |
| + jsobj.AddProperty("id", "flags"); |
| - for (int i = 0; i < num_flags; ++i) { |
| - flag_array[i]->Print(); |
| + { |
| + JSONArray jsarr(&jsobj, "unmodifiedFlags"); |
| + for (intptr_t i = 0; i < num_flags_; ++i) { |
| + Flag* flag = flags_[i]; |
| + if (!flag->changed_) { |
| + PrintFlagToJSONArray(&jsarr, flag); |
| + } |
| + } |
| + } |
| + { |
| + JSONArray jsarr(&jsobj, "modifiedFlags"); |
| + for (intptr_t i = 0; i < num_flags_; ++i) { |
| + Flag* flag = flags_[i]; |
| + if (flag->changed_) { |
| + PrintFlagToJSONArray(&jsarr, flag); |
| + } |
| } |
| - delete[] flag_array; |
| } |
| +} |
| + |
| } // namespace dart |