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 |