| Index: src/flags.cc
|
| diff --git a/src/flags.cc b/src/flags.cc
|
| index b8a9e99d87d722c6a3530244ed7a9dbec286565f..886824704299a306a7524933cbd28fc727ce1ea6 100644
|
| --- a/src/flags.cc
|
| +++ b/src/flags.cc
|
| @@ -34,125 +34,155 @@
|
|
|
| namespace v8 { namespace internal {
|
|
|
| -// -----------------------------------------------------------------------------
|
| -// Helpers
|
| +// Define all of our flags.
|
| +#define FLAG_MODE_DEFINE
|
| +#include "flags.defs"
|
|
|
| -static inline char NormalizeChar(char ch) {
|
| - return ch == '_' ? '-' : ch;
|
| -}
|
| +// Define all of our flags default values.
|
| +#define FLAG_MODE_DEFINE_DEFAULTS
|
| +#include "flags.defs"
|
| +
|
| +namespace {
|
| +
|
| +// This structure represents a single entry in the flag system, with a pointer
|
| +// to the actual flag, default value, comment, etc. This is designed to be POD
|
| +// initialized as to avoid requiring static constructors.
|
| +struct Flag {
|
| + enum FlagType { TYPE_BOOL, TYPE_INT, TYPE_FLOAT, TYPE_STRING };
|
| +
|
| + FlagType type_; // What type of flag, bool, int, or string.
|
| + const char* name_; // Name of the flag, ex "my_flag".
|
| + void* valptr_; // Pointer to the global flag variable.
|
| + const void* defptr_; // Pointer to the default value.
|
| + const char* cmt_; // A comment about the flags purpose.
|
| +
|
| + FlagType type() const { return type_; }
|
|
|
| + const char* name() const { return name_; }
|
|
|
| -static const char* NormalizeName(const char* name) {
|
| - int len = strlen(name);
|
| - char* result = NewArray<char>(len + 1);
|
| - for (int i = 0; i <= len; i++) {
|
| - result[i] = NormalizeChar(name[i]);
|
| + const char* comment() const { return cmt_; }
|
| +
|
| + bool* bool_variable() const {
|
| + ASSERT(type_ == TYPE_BOOL);
|
| + return reinterpret_cast<bool*>(valptr_);
|
| }
|
| - return const_cast<const char*>(result);
|
| -}
|
|
|
| + int* int_variable() const {
|
| + ASSERT(type_ == TYPE_INT);
|
| + return reinterpret_cast<int*>(valptr_);
|
| + }
|
|
|
| -static bool EqualNames(const char* a, const char* b) {
|
| - for (int i = 0; NormalizeChar(a[i]) == NormalizeChar(b[i]); i++) {
|
| - if (a[i] == '\0') {
|
| - return true;
|
| - }
|
| + double* float_variable() const {
|
| + ASSERT(type_ == TYPE_FLOAT);
|
| + return reinterpret_cast<double*>(valptr_);
|
| }
|
| - return false;
|
| -}
|
|
|
| + const char** string_variable() const {
|
| + ASSERT(type_ == TYPE_STRING);
|
| + return reinterpret_cast<const char**>(valptr_);
|
| + }
|
|
|
| -// -----------------------------------------------------------------------------
|
| -// Implementation of Flag
|
| + bool bool_default() const {
|
| + ASSERT(type_ == TYPE_BOOL);
|
| + return *reinterpret_cast<const bool*>(defptr_);
|
| + }
|
|
|
| -Flag::Flag(const char* file, const char* name, const char* comment,
|
| - Type type, void* variable, FlagValue default_) {
|
| - file_ = file;
|
| - name_ = NormalizeName(name);
|
| - comment_ = comment;
|
| - type_ = type;
|
| - variable_ = reinterpret_cast<FlagValue*>(variable);
|
| - this->default_ = default_;
|
| - FlagList::Register(this);
|
| -}
|
| + int int_default() const {
|
| + ASSERT(type_ == TYPE_INT);
|
| + return *reinterpret_cast<const int*>(defptr_);
|
| + }
|
|
|
| + double float_default() const {
|
| + ASSERT(type_ == TYPE_FLOAT);
|
| + return *reinterpret_cast<const double*>(defptr_);
|
| + }
|
|
|
| -void Flag::SetToDefault() {
|
| - // Note that we cannot simply do '*variable_ = default_;' since
|
| - // flag variables are not really of type FlagValue and thus may
|
| - // be smaller! The FlagValue union is simply 'overlayed' on top
|
| - // of a flag variable for convenient access. Since union members
|
| - // are guarantee to be aligned at the beginning, this works.
|
| - switch (type_) {
|
| - case Flag::BOOL:
|
| - variable_->b = default_.b;
|
| - return;
|
| - case Flag::INT:
|
| - variable_->i = default_.i;
|
| - return;
|
| - case Flag::FLOAT:
|
| - variable_->f = default_.f;
|
| - return;
|
| - case Flag::STRING:
|
| - variable_->s = default_.s;
|
| - return;
|
| + const char* string_default() const {
|
| + ASSERT(type_ == TYPE_STRING);
|
| + return *reinterpret_cast<const char* const *>(defptr_);
|
| }
|
| - UNREACHABLE();
|
| -}
|
|
|
| + // Compare this flag's current value against the default.
|
| + bool IsDefault() const {
|
| + switch (type_) {
|
| + case TYPE_BOOL:
|
| + return *bool_variable() == bool_default();
|
| + case TYPE_INT:
|
| + return *int_variable() == int_default();
|
| + case TYPE_FLOAT:
|
| + return *float_variable() == float_default();
|
| + case TYPE_STRING:
|
| + const char* str1 = *string_variable();
|
| + const char* str2 = string_default();
|
| + if (str2 == NULL) return str1 == NULL;
|
| + if (str1 == NULL) return str2 == NULL;
|
| + return strcmp(str1, str2) == 0;
|
| + }
|
| + return true; // NOTREACHED
|
| + }
|
|
|
| -bool Flag::IsDefault() const {
|
| - switch (type_) {
|
| - case Flag::BOOL:
|
| - return variable_->b == default_.b;
|
| - case Flag::INT:
|
| - return variable_->i == default_.i;
|
| - case Flag::FLOAT:
|
| - return variable_->f == default_.f;
|
| - case Flag::STRING:
|
| - if (variable_->s && default_.s) {
|
| - return strcmp(variable_->s, default_.s) == 0;
|
| - } else {
|
| - return variable_->s == default_.s;
|
| - }
|
| + // Set a flag back to it's default value.
|
| + void Reset() {
|
| + switch (type_) {
|
| + case TYPE_BOOL:
|
| + *bool_variable() = bool_default();
|
| + break;
|
| + case TYPE_INT:
|
| + *int_variable() = int_default();
|
| + break;
|
| + case TYPE_FLOAT:
|
| + *float_variable() = float_default();
|
| + break;
|
| + case TYPE_STRING:
|
| + *string_variable() = string_default();
|
| + break;
|
| + }
|
| }
|
| - UNREACHABLE();
|
| - return false;
|
| -}
|
| +};
|
| +
|
| +Flag flags[] = {
|
| +#define FLAG_MODE_META
|
| +#include "flags.defs"
|
| +};
|
| +
|
| +const size_t num_flags = sizeof(flags) / sizeof(*flags);
|
| +
|
| +} // namespace
|
|
|
|
|
| -static const char* Type2String(Flag::Type type) {
|
| +static const char* Type2String(Flag::FlagType type) {
|
| switch (type) {
|
| - case Flag::BOOL: return "bool";
|
| - case Flag::INT: return "int";
|
| - case Flag::FLOAT: return "float";
|
| - case Flag::STRING: return "string";
|
| + case Flag::TYPE_BOOL: return "bool";
|
| + case Flag::TYPE_INT: return "int";
|
| + case Flag::TYPE_FLOAT: return "float";
|
| + case Flag::TYPE_STRING: return "string";
|
| }
|
| UNREACHABLE();
|
| return NULL;
|
| }
|
|
|
|
|
| -static char* ToString(Flag::Type type, FlagValue* variable) {
|
| +static char* ToString(Flag* flag) {
|
| Vector<char> value;
|
| - switch (type) {
|
| - case Flag::BOOL:
|
| + switch (flag->type()) {
|
| + case Flag::TYPE_BOOL:
|
| value = Vector<char>::New(6);
|
| - OS::SNPrintF(value, "%s", (variable->b ? "true" : "false"));
|
| + OS::SNPrintF(value, "%s", (*flag->bool_variable() ? "true" : "false"));
|
| break;
|
| - case Flag::INT:
|
| + case Flag::TYPE_INT:
|
| value = Vector<char>::New(12);
|
| - OS::SNPrintF(value, "%d", variable->i);
|
| + OS::SNPrintF(value, "%d", *flag->int_variable());
|
| break;
|
| - case Flag::FLOAT:
|
| + case Flag::TYPE_FLOAT:
|
| value = Vector<char>::New(20);
|
| - OS::SNPrintF(value, "%f", variable->f);
|
| + OS::SNPrintF(value, "%f", *flag->float_variable());
|
| break;
|
| - case Flag::STRING:
|
| - if (variable->s) {
|
| - int length = strlen(variable->s) + 1;
|
| + case Flag::TYPE_STRING:
|
| + const char* str = *flag->string_variable();
|
| + if (str) {
|
| + int length = strlen(str) + 1;
|
| value = Vector<char>::New(length);
|
| - OS::SNPrintF(value, "%s", variable->s);
|
| + OS::SNPrintF(value, "%s", str);
|
| } else {
|
| value = Vector<char>::New(5);
|
| OS::SNPrintF(value, "NULL");
|
| @@ -164,42 +194,14 @@ static char* ToString(Flag::Type type, FlagValue* variable) {
|
| }
|
|
|
|
|
| -static void PrintFlagValue(Flag::Type type, FlagValue* variable) {
|
| - char* value = ToString(type, variable);
|
| - printf("%s", value);
|
| - DeleteArray(value);
|
| -}
|
| -
|
| -
|
| -char* Flag::StringValue() const {
|
| - return ToString(type_, variable_);
|
| -}
|
| -
|
| -
|
| -void Flag::Print(bool print_current_value) {
|
| - printf(" --%s (%s) type: %s default: ", name_, comment_,
|
| - Type2String(type_));
|
| - PrintFlagValue(type_, &default_);
|
| - if (print_current_value) {
|
| - printf(" current value: ");
|
| - PrintFlagValue(type_, variable_);
|
| - }
|
| - printf("\n");
|
| -}
|
| -
|
| -
|
| -// -----------------------------------------------------------------------------
|
| -// Implementation of FlagList
|
| -
|
| -Flag* FlagList::list_ = NULL;
|
| -
|
| -
|
| +// static
|
| List<char *>* FlagList::argv() {
|
| List<char *>* args = new List<char*>(8);
|
| - for (Flag* f = list_; f != NULL; f = f->next()) {
|
| + for (size_t i = 0; i < num_flags; ++i) {
|
| + Flag* f = &flags[i];
|
| if (!f->IsDefault()) {
|
| Vector<char> cmdline_flag;
|
| - if (f->type() != Flag::BOOL || *(f->bool_variable())) {
|
| + if (f->type() != Flag::TYPE_BOOL || *(f->bool_variable())) {
|
| int length = strlen(f->name()) + 2 + 1;
|
| cmdline_flag = Vector<char>::New(length);
|
| OS::SNPrintF(cmdline_flag, "--%s", f->name());
|
| @@ -209,45 +211,26 @@ List<char *>* FlagList::argv() {
|
| OS::SNPrintF(cmdline_flag, "--no%s", f->name());
|
| }
|
| args->Add(cmdline_flag.start());
|
| - if (f->type() != Flag::BOOL) {
|
| - args->Add(f->StringValue());
|
| - }
|
| - }
|
| - }
|
| - return args;
|
| -}
|
| -
|
| -
|
| -void FlagList::Print(const char* file, bool print_current_value) {
|
| - // Since flag registration is likely by file (= C++ file),
|
| - // we don't need to sort by file and still get grouped output.
|
| - const char* current = NULL;
|
| - for (Flag* f = list_; f != NULL; f = f->next()) {
|
| - if (file == NULL || file == f->file()) {
|
| - if (current != f->file()) {
|
| - printf("Flags from %s:\n", f->file());
|
| - current = f->file();
|
| + if (f->type() != Flag::TYPE_BOOL) {
|
| + args->Add(ToString(f));
|
| }
|
| - f->Print(print_current_value);
|
| }
|
| }
|
| -}
|
|
|
| -
|
| -Flag* FlagList::Lookup(const char* name) {
|
| - Flag* f = list_;
|
| - while (f != NULL && !EqualNames(name, f->name()))
|
| - f = f->next();
|
| - return f;
|
| + return args;
|
| }
|
|
|
|
|
| -void FlagList::SplitArgument(const char* arg,
|
| - char* buffer,
|
| - int buffer_size,
|
| - const char** name,
|
| - const char** value,
|
| - bool* is_bool) {
|
| +// Helper function to parse flags: Takes an argument arg and splits it into
|
| +// a flag name and flag value (or NULL if they are missing). is_bool is set
|
| +// if the arg started with "-no" or "--no". The buffer may be used to NUL-
|
| +// terminate the name, it must be large enough to hold any possible name.
|
| +static void SplitArgument(const char* arg,
|
| + char* buffer,
|
| + int buffer_size,
|
| + const char** name,
|
| + const char** value,
|
| + bool* is_bool) {
|
| *name = NULL;
|
| *value = NULL;
|
| *is_bool = false;
|
| @@ -282,6 +265,31 @@ void FlagList::SplitArgument(const char* arg,
|
| }
|
|
|
|
|
| +inline char NormalizeChar(char ch) {
|
| + return ch == '_' ? '-' : ch;
|
| +}
|
| +
|
| +
|
| +static bool EqualNames(const char* a, const char* b) {
|
| + for (int i = 0; NormalizeChar(a[i]) == NormalizeChar(b[i]); i++) {
|
| + if (a[i] == '\0') {
|
| + return true;
|
| + }
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +
|
| +static Flag* FindFlag(const char* name) {
|
| + for (size_t i = 0; i < num_flags; ++i) {
|
| + if (EqualNames(name, flags[i].name()))
|
| + return &flags[i];
|
| + }
|
| + return NULL;
|
| +}
|
| +
|
| +
|
| +// static
|
| int FlagList::SetFlagsFromCommandLine(int* argc,
|
| char** argv,
|
| bool remove_flags) {
|
| @@ -299,7 +307,7 @@ int FlagList::SetFlagsFromCommandLine(int* argc,
|
|
|
| if (name != NULL) {
|
| // lookup the flag
|
| - Flag* flag = Lookup(name);
|
| + Flag* flag = FindFlag(name);
|
| if (flag == NULL) {
|
| if (remove_flags) {
|
| // We don't recognize this flag but since we're removing
|
| @@ -314,7 +322,7 @@ int FlagList::SetFlagsFromCommandLine(int* argc,
|
| }
|
|
|
| // if we still need a flag value, use the next argument if available
|
| - if (flag->type() != Flag::BOOL && value == NULL) {
|
| + if (flag->type() != Flag::TYPE_BOOL && value == NULL) {
|
| if (i < *argc) {
|
| value = argv[i++];
|
| } else {
|
| @@ -327,23 +335,23 @@ int FlagList::SetFlagsFromCommandLine(int* argc,
|
| // set the flag
|
| char* endp = const_cast<char*>(""); // *endp is only read
|
| switch (flag->type()) {
|
| - case Flag::BOOL:
|
| + case Flag::TYPE_BOOL:
|
| *flag->bool_variable() = !is_bool;
|
| break;
|
| - case Flag::INT:
|
| + case Flag::TYPE_INT:
|
| *flag->int_variable() = strtol(value, &endp, 10); // NOLINT
|
| break;
|
| - case Flag::FLOAT:
|
| + case Flag::TYPE_FLOAT:
|
| *flag->float_variable() = strtod(value, &endp);
|
| break;
|
| - case Flag::STRING:
|
| + case Flag::TYPE_STRING:
|
| *flag->string_variable() = value;
|
| break;
|
| }
|
|
|
| // handle errors
|
| - if ((flag->type() == Flag::BOOL && value != NULL) ||
|
| - (flag->type() != Flag::BOOL && is_bool) ||
|
| + if ((flag->type() == Flag::TYPE_BOOL && value != NULL) ||
|
| + (flag->type() != Flag::TYPE_BOOL && is_bool) ||
|
| *endp != '\0') {
|
| fprintf(stderr, "Error: illegal value for flag %s of type %s\n",
|
| arg, Type2String(flag->type()));
|
| @@ -384,6 +392,7 @@ static char* SkipBlackSpace(char* p) {
|
| }
|
|
|
|
|
| +// static
|
| int FlagList::SetFlagsFromString(const char* str, int len) {
|
| // make a 0-terminated copy of str
|
| char* copy0 = NewArray<char>(len + 1);
|
| @@ -427,12 +436,23 @@ int FlagList::SetFlagsFromString(const char* str, int len) {
|
| }
|
|
|
|
|
| -void FlagList::Register(Flag* flag) {
|
| - ASSERT(flag != NULL && strlen(flag->name()) > 0);
|
| - if (Lookup(flag->name()) != NULL)
|
| - V8_Fatal(flag->file(), 0, "flag %s declared twice", flag->name());
|
| - flag->next_ = list_;
|
| - list_ = flag;
|
| +// static
|
| +void FlagList::ResetAllFlags() {
|
| + for (size_t i = 0; i < num_flags; ++i) {
|
| + flags[i].Reset();
|
| + }
|
| +}
|
| +
|
| +
|
| +// static
|
| +void FlagList::PrintHelp() {
|
| + for (size_t i = 0; i < num_flags; ++i) {
|
| + Flag* f = &flags[i];
|
| + char* value = ToString(f);
|
| + printf(" --%s (%s) type: %s default: %s\n",
|
| + f->name(), f->comment(), Type2String(f->type()), value);
|
| + DeleteArray(value);
|
| + }
|
| }
|
|
|
| } } // namespace v8::internal
|
|
|