Flutter Engine
The Flutter Engine
flags.cc
Go to the documentation of this 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
3// BSD-style license that can be found in the LICENSE file.
4
5#include "vm/flags.h"
6
7#include "platform/assert.h"
8#include "vm/isolate.h"
9#include "vm/json_stream.h"
10#include "vm/os.h"
11
12namespace dart {
13
14DEFINE_FLAG(bool, print_flags, false, "Print flags as they are being parsed.");
16 ignore_unrecognized_flags,
17 false,
18 "Ignore unrecognized flags.");
19
20#define PRODUCT_FLAG_MACRO(name, type, default_value, comment) \
21 type FLAG_##name = \
22 Flags::Register_##type(&FLAG_##name, #name, default_value, comment);
23
24#if defined(DEBUG)
25#define DEBUG_FLAG_MACRO(name, type, default_value, comment) \
26 type FLAG_##name = \
27 Flags::Register_##type(&FLAG_##name, #name, default_value, comment);
28#else // defined(DEBUG)
29#define DEBUG_FLAG_MACRO(name, type, default_value, comment)
30#endif // defined(DEBUG)
31
32#if defined(PRODUCT) && defined(DART_PRECOMPILED_RUNTIME)
33// Nothing to be done for the product flag definitions.
34#define RELEASE_FLAG_MACRO(name, product_value, type, default_value, comment)
35// Nothing to be done for the precompilation flag definitions.
36#define PRECOMPILE_FLAG_MACRO(name, pre_value, product_value, type, \
37 default_value, comment)
38
39#elif defined(PRODUCT) // !PRECOMPILED
40// Nothing to be done for the product flag definitions.
41#define RELEASE_FLAG_MACRO(name, product_value, type, default_value, comment)
42// Nothing to be done for the precompilation flag definitions.
43#define PRECOMPILE_FLAG_MACRO(name, pre_value, product_value, type, \
44 default_value, comment)
45
46#elif defined(DART_PRECOMPILED_RUNTIME) // !PRODUCT
47#define RELEASE_FLAG_MACRO(name, product_value, type, default_value, comment) \
48 type FLAG_##name = \
49 Flags::Register_##type(&FLAG_##name, #name, default_value, comment);
50// Nothing to be done for the precompilation flag definitions.
51#define PRECOMPILE_FLAG_MACRO(name, pre_value, product_value, type, \
52 default_value, comment)
53
54#else // !PRODUCT && !PRECOMPILED
55#define RELEASE_FLAG_MACRO(name, product_value, type, default_value, comment) \
56 type FLAG_##name = \
57 Flags::Register_##type(&FLAG_##name, #name, default_value, comment);
58#define PRECOMPILE_FLAG_MACRO(name, pre_value, product_value, type, \
59 default_value, comment) \
60 type FLAG_##name = \
61 Flags::Register_##type(&FLAG_##name, #name, default_value, comment);
62#endif
63
64// Define all of the non-product flags here.
69
70#undef PRODUCT_FLAG_MACRO
71#undef RELEASE_FLAG_MACRO
72#undef PRECOMPILE_FLAG_MACRO
73#undef DEBUG_FLAG_MACRO
74
75#if defined(DART_PRECOMPILER)
76#if defined(TARGET_USES_THREAD_SANITIZER)
77constexpr bool kDefaultTargetThreadSanitizer = true;
78#else
79constexpr bool kDefaultTargetThreadSanitizer = false;
80#endif
81DEFINE_FLAG(bool,
82 target_thread_sanitizer,
83 kDefaultTargetThreadSanitizer,
84 "Generate Dart code compatible with Thread Sanitizer");
85#if defined(TARGET_USES_MEMORY_SANITIZER)
86constexpr bool kDefaultTargetMemorySanitizer = true;
87#else
88constexpr bool kDefaultTargetMemorySanitizer = false;
89#endif
90DEFINE_FLAG(bool,
91 target_memory_sanitizer,
92 kDefaultTargetMemorySanitizer,
93 "Generate Dart code compatible with Memory Sanitizer");
94#endif
95
96bool Flags::initialized_ = false;
97
98// List of registered flags.
99Flag** Flags::flags_ = nullptr;
100intptr_t Flags::capacity_ = 0;
101intptr_t Flags::num_flags_ = 0;
102
103class Flag {
104 public:
105 enum FlagType {
113 };
114
115 Flag(const char* name, const char* comment, void* addr, FlagType type)
116 : name_(name), comment_(comment), addr_(addr), type_(type) {}
117 Flag(const char* name, const char* comment, FlagHandler handler)
118 : name_(name),
119 comment_(comment),
120 flag_handler_(handler),
122 Flag(const char* name, const char* comment, OptionHandler handler)
123 : name_(name),
124 comment_(comment),
125 option_handler_(handler),
127
128 void Print() {
129 if (IsUnrecognized()) {
130 OS::PrintErr("%s: unrecognized\n", name_);
131 return;
132 }
133 switch (type_) {
134 case kBoolean: {
135 OS::Print("%s: %s (%s)\n", name_, *this->bool_ptr_ ? "true" : "false",
136 comment_);
137 break;
138 }
139 case kInteger: {
140 OS::Print("%s: %d (%s)\n", name_, *this->int_ptr_, comment_);
141 break;
142 }
143 case kUint64: {
144 OS::Print("%s: %" Pu64 " (%s)\n", name_, *this->uint64_ptr_, comment_);
145 break;
146 }
147 case kString: {
148 if (*this->charp_ptr_ != nullptr) {
149 OS::Print("%s: '%s' (%s)\n", name_, *this->charp_ptr_, comment_);
150 } else {
151 OS::Print("%s: (null) (%s)\n", name_, comment_);
152 }
153 break;
154 }
155 case kOptionHandler:
156 case kFlagHandler: {
157 OS::Print("%s: (%s)\n", name_, comment_);
158 break;
159 }
160 default:
161 UNREACHABLE();
162 break;
163 }
164 }
165
166 bool IsUnrecognized() const {
167 return (type_ == kBoolean) && (bool_ptr_ == nullptr);
168 }
169
170 const char* name_;
171 const char* comment_;
172
173 // For kString, kOptionHandler, kFlagHandler flags this stores the copy
174 // of the original flag value passed to SetFlagFromString
176 union {
177 void* addr_;
180 uint64_t* uint64_ptr_;
184 };
186 bool changed_ = false;
187};
188
189Flag* Flags::Lookup(const char* name) {
190 for (intptr_t i = 0; i < num_flags_; i++) {
191 Flag* flag = flags_[i];
192 if (strcmp(flag->name_, name) == 0) {
193 return flag;
194 }
195 }
196 return nullptr;
197}
198
199bool Flags::IsSet(const char* name) {
200 Flag* flag = Lookup(name);
201 return (flag != nullptr) && (flag->type_ == Flag::kBoolean) &&
202 (flag->bool_ptr_ != nullptr) && (*flag->bool_ptr_ == true);
203}
204
205void Flags::Cleanup() {
206 ASSERT(initialized_);
207 initialized_ = false;
208}
209
210void Flags::AddFlag(Flag* flag) {
211 ASSERT(!initialized_);
212 if (num_flags_ == capacity_) {
213 if (flags_ == nullptr) {
214 capacity_ = 256;
215 flags_ = new Flag*[capacity_];
216 } else {
217 intptr_t new_capacity = capacity_ * 2;
218 Flag** new_flags = new Flag*[new_capacity];
219 for (intptr_t i = 0; i < num_flags_; i++) {
220 new_flags[i] = flags_[i];
221 }
222 delete[] flags_;
223 flags_ = new_flags;
224 capacity_ = new_capacity;
225 }
226 }
227 flags_[num_flags_++] = flag;
228}
229
230bool Flags::Register_bool(bool* addr,
231 const char* name,
232 bool default_value,
233 const char* comment) {
234 Flag* flag = Lookup(name);
235 if (flag != nullptr) {
236 ASSERT(flag->IsUnrecognized());
237 return default_value;
238 }
239 flag = new Flag(name, comment, addr, Flag::kBoolean);
240 AddFlag(flag);
241 return default_value;
242}
243
245 const char* name,
246 int default_value,
247 const char* comment) {
248 ASSERT(Lookup(name) == nullptr);
249
250 Flag* flag = new Flag(name, comment, addr, Flag::kInteger);
251 AddFlag(flag);
252
253 return default_value;
254}
255
256uint64_t Flags::Register_uint64_t(uint64_t* addr,
257 const char* name,
258 uint64_t default_value,
259 const char* comment) {
260 ASSERT(Lookup(name) == nullptr);
261
262 Flag* flag = new Flag(name, comment, addr, Flag::kUint64);
263 AddFlag(flag);
264
265 return default_value;
266}
267
268const char* Flags::Register_charp(charp* addr,
269 const char* name,
270 const char* default_value,
271 const char* comment) {
272 ASSERT(Lookup(name) == nullptr);
273 Flag* flag = new Flag(name, comment, addr, Flag::kString);
274 AddFlag(flag);
275 return default_value;
276}
277
279 const char* name,
280 const char* comment) {
281 ASSERT(Lookup(name) == nullptr);
282 Flag* flag = new Flag(name, comment, handler);
283 AddFlag(flag);
284 return false;
285}
286
288 const char* name,
289 const char* comment) {
290 ASSERT(Lookup(name) == nullptr);
291 Flag* flag = new Flag(name, comment, handler);
292 AddFlag(flag);
293 return false;
294}
295
296static void Normalize(char* s) {
297 intptr_t len = strlen(s);
298 for (intptr_t i = 0; i < len; i++) {
299 if (s[i] == '-') {
300 s[i] = '_';
301 }
302 }
303}
304
305bool Flags::SetFlagFromString(Flag* flag, const char* argument) {
306 ASSERT(!flag->IsUnrecognized());
307 switch (flag->type_) {
308 case Flag::kBoolean: {
309 if (strcmp(argument, "true") == 0) {
310 *flag->bool_ptr_ = true;
311 } else if (strcmp(argument, "false") == 0) {
312 *flag->bool_ptr_ = false;
313 } else {
314 return false;
315 }
316 break;
317 }
318 case Flag::kString: {
319 flag->string_value_.reset(argument == nullptr ? nullptr
320 : Utils::StrDup(argument));
321 *flag->charp_ptr_ = flag->string_value_.get();
322 break;
323 }
324 case Flag::kInteger: {
325 char* endptr = nullptr;
326 const intptr_t len = strlen(argument);
327 int base = 10;
328 if ((len > 2) && (argument[0] == '0') && (argument[1] == 'x')) {
329 base = 16;
330 }
331 int val = strtol(argument, &endptr, base);
332 if (endptr == argument + len) {
333 *flag->int_ptr_ = val;
334 } else {
335 return false;
336 }
337 break;
338 }
339 case Flag::kUint64: {
340 char* endptr = nullptr;
341 const intptr_t len = strlen(argument);
342 int base = 10;
343 if ((len > 2) && (argument[0] == '0') && (argument[1] == 'x')) {
344 base = 16;
345 }
346 int64_t val = strtoll(argument, &endptr, base);
347 if (endptr == argument + len) {
348 *flag->uint64_ptr_ = static_cast<uint64_t>(val);
349 } else {
350 return false;
351 }
352 break;
353 }
354 case Flag::kFlagHandler: {
355 if (strcmp(argument, "true") == 0) {
356 (flag->flag_handler_)(true);
357 } else if (strcmp(argument, "false") == 0) {
358 (flag->flag_handler_)(false);
359 } else {
360 return false;
361 }
362 flag->string_value_.reset(Utils::StrDup(argument));
363 break;
364 }
366 flag->string_value_.reset(Utils::StrDup(argument));
367 (flag->option_handler_)(argument);
368 break;
369 }
370 default: {
371 UNREACHABLE();
372 return false;
373 }
374 }
375 flag->changed_ = true;
376 return true;
377}
378
379void Flags::Parse(const char* option) {
380 // Find the beginning of the option argument, if it exists.
381 const char* equals = option;
382 while ((*equals != '\0') && (*equals != '=')) {
383 equals++;
384 }
385
386 const char* argument = nullptr;
387
388 // Determine if this is an option argument.
389 if (*equals != '=') {
390 // No explicit option argument. Determine if there is a "no_" prefix
391 // preceding the name.
392 const char* const kNo1Prefix = "no_";
393 const char* const kNo2Prefix = "no-";
394 const intptr_t kNo1PrefixLen = strlen(kNo1Prefix);
395 const intptr_t kNo2PrefixLen = strlen(kNo2Prefix);
396 if (strncmp(option, kNo1Prefix, kNo1PrefixLen) == 0) {
397 option += kNo1PrefixLen; // Skip the "no_" when looking up the name.
398 argument = "false";
399 } else if (strncmp(option, kNo2Prefix, kNo2PrefixLen) == 0) {
400 option += kNo2PrefixLen; // Skip the "no-" when looking up the name.
401 argument = "false";
402 } else {
403 argument = "true";
404 }
405 } else {
406 // The argument for the option starts right after the equals sign.
407 argument = equals + 1;
408 }
409
410 // Initialize the flag name.
411 intptr_t name_len = equals - option;
412 char* name = new char[name_len + 1];
413 strncpy(name, option, name_len);
414 name[name_len] = '\0';
416
417 Flag* flag = Flags::Lookup(name);
418 if (flag == nullptr) {
419 // Collect unrecognized flags.
420 char* new_flag = new char[name_len + 1];
421 strncpy(new_flag, option, name_len);
422 new_flag[name_len] = '\0';
423 Normalize(new_flag); // Or a later lookup may fail.
424 Flags::Register_bool(nullptr, new_flag, true, nullptr);
425 } else {
426 // Only set values for recognized flags, skip collected
427 // unrecognized flags.
428 if (!flag->IsUnrecognized()) {
429 if (!SetFlagFromString(flag, argument)) {
430 OS::PrintErr("Ignoring flag: %s is an invalid value for flag %s\n",
431 argument, name);
432 }
433 }
434 }
435
436 delete[] name;
437}
438
439static bool IsValidFlag(const char* name,
440 const char* prefix,
441 intptr_t prefix_length) {
442 intptr_t name_length = strlen(name);
443 return ((name_length > prefix_length) &&
444 (strncmp(name, prefix, prefix_length) == 0));
445}
446
447int Flags::CompareFlagNames(const void* left, const void* right) {
448 const Flag* left_flag = *reinterpret_cast<const Flag* const*>(left);
449 const Flag* right_flag = *reinterpret_cast<const Flag* const*>(right);
450 return strcmp(left_flag->name_, right_flag->name_);
451}
452
453char* Flags::ProcessCommandLineFlags(int number_of_vm_flags,
454 const char** vm_flags) {
455 if (initialized_) {
456 return Utils::StrDup("Flags already set");
457 }
458
459 qsort(flags_, num_flags_, sizeof flags_[0], CompareFlagNames);
460
461 const char* const kPrefix = "--";
462 const intptr_t kPrefixLen = strlen(kPrefix);
463
464 int i = 0;
465 while ((i < number_of_vm_flags) &&
466 IsValidFlag(vm_flags[i], kPrefix, kPrefixLen)) {
467 const char* option = vm_flags[i] + kPrefixLen;
468 Parse(option);
469 i++;
470 }
471
472 if (!FLAG_ignore_unrecognized_flags) {
473 int unrecognized_count = 0;
474 TextBuffer error(64);
475 for (intptr_t j = 0; j < num_flags_; j++) {
476 Flag* flag = flags_[j];
477 if (flag->IsUnrecognized()) {
478 if (unrecognized_count == 0) {
479 error.Printf("Unrecognized flags: %s", flag->name_);
480 } else {
481 error.Printf(", %s", flag->name_);
482 }
483 unrecognized_count++;
484 }
485 }
486 if (unrecognized_count > 0) {
487 return error.Steal();
488 }
489 }
490 if (FLAG_print_flags) {
491 PrintFlags();
492 }
493
494 initialized_ = true;
495 return nullptr;
496}
497
498bool Flags::SetFlag(const char* name, const char* value, const char** error) {
499 Flag* flag = Lookup(name);
500 if (flag == nullptr) {
501 *error = "Cannot set flag: flag not found";
502 return false;
503 }
504 if (!SetFlagFromString(flag, value)) {
505 *error = "Cannot set flag: invalid value";
506 return false;
507 }
508 return true;
509}
510
511void Flags::PrintFlags() {
512 OS::Print("Flag settings:\n");
513 for (intptr_t i = 0; i < num_flags_; ++i) {
514 flags_[i]->Print();
515 }
516}
517
518#ifndef PRODUCT
519void Flags::PrintFlagToJSONArray(JSONArray* jsarr, const Flag* flag) {
520 if (flag->IsUnrecognized()) {
521 return;
522 }
523 JSONObject jsflag(jsarr);
524 jsflag.AddProperty("name", flag->name_);
525 jsflag.AddProperty("comment", flag->comment_);
526 jsflag.AddProperty("modified", flag->changed_);
527 switch (flag->type_) {
528 case Flag::kBoolean: {
529 jsflag.AddProperty("_flagType", "Bool");
530 jsflag.AddProperty("valueAsString",
531 (*flag->bool_ptr_ ? "true" : "false"));
532 break;
533 }
534 case Flag::kInteger: {
535 jsflag.AddProperty("_flagType", "Int");
536 jsflag.AddPropertyF("valueAsString", "%d", *flag->int_ptr_);
537 break;
538 }
539 case Flag::kUint64: {
540 jsflag.AddProperty("_flagType", "UInt64");
541 jsflag.AddPropertyF("valueAsString", "%" Pu64, *flag->uint64_ptr_);
542 break;
543 }
544 case Flag::kString: {
545 jsflag.AddProperty("_flagType", "String");
546 if (flag->charp_ptr_ != nullptr) {
547 jsflag.AddPropertyF("valueAsString", "%s", *flag->charp_ptr_);
548 } else {
549 // valueAsString missing means nullptr.
550 }
551 break;
552 }
553 case Flag::kFlagHandler: {
554 jsflag.AddProperty("_flagType", "Bool");
555 const char* value = flag->string_value_.get();
556 jsflag.AddProperty("valueAsString", value == nullptr ? "false" : value);
557 break;
558 }
560 jsflag.AddProperty("_flagType", "String");
561 if (flag->string_value_ != nullptr) {
562 jsflag.AddProperty("valueAsString", flag->string_value_.get());
563 } else {
564 // valueAsString missing means nullptr.
565 }
566 break;
567 }
568 default:
569 UNREACHABLE();
570 break;
571 }
572}
573
574void Flags::PrintJSON(JSONStream* js) {
575 JSONObject jsobj(js);
576 jsobj.AddProperty("type", "FlagList");
577 JSONArray jsarr(&jsobj, "flags");
578 for (intptr_t i = 0; i < num_flags_; ++i) {
579 PrintFlagToJSONArray(&jsarr, flags_[i]);
580 }
581}
582#endif // !PRODUCT
583
584} // namespace dart
bool equals(SkDrawable *a, SkDrawable *b)
#define UNREACHABLE()
Definition: assert.h:248
GLenum type
int * int_ptr_
Definition: flags.cc:179
uint64_t * uint64_ptr_
Definition: flags.cc:180
FlagHandler flag_handler_
Definition: flags.cc:182
const char * name_
Definition: flags.cc:170
bool changed_
Definition: flags.cc:186
CStringUniquePtr string_value_
Definition: flags.cc:175
Flag(const char *name, const char *comment, OptionHandler handler)
Definition: flags.cc:122
void * addr_
Definition: flags.cc:177
charp * charp_ptr_
Definition: flags.cc:181
Flag(const char *name, const char *comment, void *addr, FlagType type)
Definition: flags.cc:115
OptionHandler option_handler_
Definition: flags.cc:183
const FlagType type_
Definition: flags.cc:185
@ kUint64
Definition: flags.cc:108
@ kNumFlagTypes
Definition: flags.cc:112
@ kBoolean
Definition: flags.cc:106
@ kFlagHandler
Definition: flags.cc:110
@ kOptionHandler
Definition: flags.cc:111
@ kString
Definition: flags.cc:109
@ kInteger
Definition: flags.cc:107
bool IsUnrecognized() const
Definition: flags.cc:166
bool * bool_ptr_
Definition: flags.cc:178
Flag(const char *name, const char *comment, FlagHandler handler)
Definition: flags.cc:117
void Print()
Definition: flags.cc:128
const char * comment_
Definition: flags.cc:171
static bool IsSet(const char *name)
static void Cleanup()
static char * ProcessCommandLineFlags(int argc, const char **argv)
static uint64_t Register_uint64_t(uint64_t *addr, const char *name, uint64_t default_value, const char *comment)
static bool Register_bool(bool *addr, const char *name, bool default_value, const char *comment)
static const char * Register_charp(charp *addr, const char *name, const char *default_value, const char *comment)
static bool SetFlag(const char *name, const char *value, const char **error)
static bool RegisterFlagHandler(FlagHandler handler, const char *name, const char *comment)
static int Register_int(int *addr, const char *name, int default_value, const char *comment)
static bool RegisterOptionHandler(OptionHandler handler, const char *name, const char *comment)
static void PrintJSON(JSONStream *js)
static Flag * Lookup(const char *name)
static void static void PrintErr(const char *format,...) PRINTF_ATTRIBUTE(1
static void Print(const char *format,...) PRINTF_ATTRIBUTE(1
static char * StrDup(const char *s)
#define ASSERT(E)
struct MyStruct s
FlutterSemanticsFlag flag
const uint8_t uint32_t uint32_t GError ** error
uint8_t value
#define DEBUG_FLAG_MACRO(name, type, default_value, comment)
Definition: flags.cc:29
#define PRECOMPILE_FLAG_MACRO(name, pre_value, product_value, type, default_value, comment)
Definition: flags.cc:58
#define RELEASE_FLAG_MACRO(name, product_value, type, default_value, comment)
Definition: flags.cc:55
#define PRODUCT_FLAG_MACRO(name, type, default_value, comment)
Definition: flags.cc:20
const char * charp
Definition: flags.h:12
Definition: dart_vm.cc:33
const char *const name
void(* FlagHandler)(bool value)
Definition: flags.h:28
void(* OptionHandler)(const char *value)
Definition: flags.h:29
FLAG_LIST(PRODUCT_FLAG_MACRO, RELEASE_FLAG_MACRO, PRECOMPILE_FLAG_MACRO, DEBUG_FLAG_MACRO) const expr bool FLAG_target_thread_sanitizer
static void Normalize(char *s)
Definition: flags.cc:296
DEFINE_FLAG(bool, print_cluster_information, false, "Print information about clusters written to snapshot")
static bool IsValidFlag(const char *name, const char *prefix, intptr_t prefix_length)
Definition: flags.cc:439
#define Pu64
Definition: globals.h:417