• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #ifndef ART_CMDLINE_CMDLINE_TYPES_H_
17 #define ART_CMDLINE_CMDLINE_TYPES_H_
18 
19 #define CMDLINE_NDEBUG 1  // Do not output any debugging information for parsing.
20 
21 #include <list>
22 #include <ostream>
23 
24 #include "android-base/parsebool.h"
25 #include "android-base/stringprintf.h"
26 #include "cmdline_type_parser.h"
27 #include "detail/cmdline_debug_detail.h"
28 #include "memory_representation.h"
29 
30 #include "android-base/logging.h"
31 #include "android-base/strings.h"
32 
33 // Includes for the types that are being specialized
34 #include <string>
35 #include "base/time_utils.h"
36 #include "base/logging.h"
37 #include "experimental_flags.h"
38 #include "gc/collector_type.h"
39 #include "gc/space/large_object_space.h"
40 #include "jdwp_provider.h"
41 #include "jit/profile_saver_options.h"
42 #include "plugin.h"
43 #include "read_barrier_config.h"
44 #include "ti/agent.h"
45 #include "unit.h"
46 
47 namespace art {
48 
49 // The default specialization will always fail parsing the type from a string.
50 // Provide your own specialization that inherits from CmdlineTypeParser<T>
51 // and implements either Parse or ParseAndAppend
52 // (only if the argument was defined with ::AppendValues()) but not both.
53 template <typename T>
54 struct CmdlineType : CmdlineTypeParser<T> {
55 };
56 
57 // Specializations for CmdlineType<T> follow:
58 
59 // Parse argument definitions for Unit-typed arguments.
60 template <>
61 struct CmdlineType<Unit> : CmdlineTypeParser<Unit> {
62   Result Parse(const std::string& args) {
63     if (args == "") {
64       return Result::Success(Unit{});
65     }
66     return Result::Failure("Unexpected extra characters " + args);
67   }
68 };
69 
70 template <>
71 struct CmdlineType<bool> : CmdlineTypeParser<bool> {
72   Result Parse(const std::string& args) {
73     switch (::android::base::ParseBool(args)) {
74       case ::android::base::ParseBoolResult::kError:
75         return Result::Failure("Could not parse '" + args + "' as boolean");
76       case ::android::base::ParseBoolResult::kTrue:
77         return Result::Success(true);
78       case ::android::base::ParseBoolResult::kFalse:
79         return Result::Success(false);
80     }
81   }
82 
83   static const char* DescribeType() { return "true|false|1|0|y|n|yes|no|on|off"; }
84 };
85 
86 template <>
87 struct CmdlineType<JdwpProvider> : CmdlineTypeParser<JdwpProvider> {
88   /*
89    * Handle a single JDWP provider name. Must be either 'internal', 'default', or the file name of
90    * an agent. A plugin will make use of this and the jdwpOptions to set up jdwp when appropriate.
91    */
92   Result Parse(const std::string& option) {
93     if (option == "help") {
94       return Result::Usage(
95           "Example: -XjdwpProvider:none to disable JDWP\n"
96           "Example: -XjdwpProvider:adbconnection for adb connection mediated jdwp implementation\n"
97           "Example: -XjdwpProvider:default for the default jdwp implementation\n");
98     } else if (option == "default") {
99       return Result::Success(JdwpProvider::kDefaultJdwpProvider);
100     } else if (option == "adbconnection") {
101       return Result::Success(JdwpProvider::kAdbConnection);
102     } else if (option == "none") {
103       return Result::Success(JdwpProvider::kNone);
104     } else {
105       return Result::Failure(std::string("not a valid jdwp provider: ") + option);
106     }
107   }
108   static const char* Name() { return "JdwpProvider"; }
109   static const char* DescribeType() { return "none|adbconnection|default"; }
110 };
111 
112 template <size_t Divisor>
113 struct CmdlineType<Memory<Divisor>> : CmdlineTypeParser<Memory<Divisor>> {
114   using typename CmdlineTypeParser<Memory<Divisor>>::Result;
115 
116   Result Parse(const std::string& arg) {
117     CMDLINE_DEBUG_LOG << "Parsing memory: " << arg << std::endl;
118     size_t val = ParseMemoryOption(arg.c_str(), Divisor);
119     CMDLINE_DEBUG_LOG << "Memory parsed to size_t value: " << val << std::endl;
120 
121     if (val == 0) {
122       return Result::Failure(std::string("not a valid memory value, or not divisible by ")
123                              + std::to_string(Divisor));
124     }
125 
126     return Result::Success(Memory<Divisor>(val));
127   }
128 
129   // Parse a string of the form /[0-9]+[kKmMgG]?/, which is used to specify
130   // memory sizes.  [kK] indicates kilobytes, [mM] megabytes, and
131   // [gG] gigabytes.
132   //
133   // "s" should point just past the "-Xm?" part of the string.
134   // "div" specifies a divisor, e.g. 1024 if the value must be a multiple
135   // of 1024.
136   //
137   // The spec says the -Xmx and -Xms options must be multiples of 1024.  It
138   // doesn't say anything about -Xss.
139   //
140   // Returns 0 (a useless size) if "s" is malformed or specifies a low or
141   // non-evenly-divisible value.
142   //
143   static size_t ParseMemoryOption(const char* s, size_t div) {
144     // strtoul accepts a leading [+-], which we don't want,
145     // so make sure our string starts with a decimal digit.
146     if (isdigit(*s)) {
147       char* s2;
148       size_t val = strtoul(s, &s2, 10);
149       if (s2 != s) {
150         // s2 should be pointing just after the number.
151         // If this is the end of the string, the user
152         // has specified a number of bytes.  Otherwise,
153         // there should be exactly one more character
154         // that specifies a multiplier.
155         if (*s2 != '\0') {
156           // The remainder of the string is either a single multiplier
157           // character, or nothing to indicate that the value is in
158           // bytes.
159           char c = *s2++;
160           if (*s2 == '\0') {
161             size_t mul;
162             if (c == '\0') {
163               mul = 1;
164             } else if (c == 'k' || c == 'K') {
165               mul = KB;
166             } else if (c == 'm' || c == 'M') {
167               mul = MB;
168             } else if (c == 'g' || c == 'G') {
169               mul = GB;
170             } else {
171               // Unknown multiplier character.
172               return 0;
173             }
174 
175             if (val <= std::numeric_limits<size_t>::max() / mul) {
176               val *= mul;
177             } else {
178               // Clamp to a multiple of 1024.
179               val = std::numeric_limits<size_t>::max() & ~(1024-1);
180             }
181           } else {
182             // There's more than one character after the numeric part.
183             return 0;
184           }
185         }
186         // The man page says that a -Xm value must be a multiple of 1024.
187         if (val % div == 0) {
188           return val;
189         }
190       }
191     }
192     return 0;
193   }
194 
195   static const char* Name() { return Memory<Divisor>::Name(); }
196   static const char* DescribeType() {
197     static std::string str;
198     if (str.empty()) {
199       str = "Memory with granularity of " + std::to_string(Divisor) + " bytes";
200     }
201     return str.c_str();
202   }
203 };
204 
205 template <>
206 struct CmdlineType<double> : CmdlineTypeParser<double> {
207   Result Parse(const std::string& str) {
208     char* end = nullptr;
209     errno = 0;
210     double value = strtod(str.c_str(), &end);
211 
212     if (*end != '\0') {
213       return Result::Failure("Failed to parse double from " + str);
214     }
215     if (errno == ERANGE) {
216       return Result::OutOfRange(
217           "Failed to parse double from " + str + "; overflow/underflow occurred");
218     }
219 
220     return Result::Success(value);
221   }
222 
223   static const char* Name() { return "double"; }
224   static const char* DescribeType() { return "double value"; }
225 };
226 
227 template <typename T>
228 static inline CmdlineParseResult<T> ParseNumeric(const std::string& str) {
229   static_assert(sizeof(T) < sizeof(long long int),  // NOLINT [runtime/int] [4]
230                 "Current support is restricted.");
231 
232   const char* begin = str.c_str();
233   char* end;
234 
235   // Parse into a larger type (long long) because we can't use strtoul
236   // since it silently converts negative values into unsigned long and doesn't set errno.
237   errno = 0;
238   long long int result = strtoll(begin, &end, 10);  // NOLINT [runtime/int] [4]
239   if (begin == end || *end != '\0' || errno == EINVAL) {
240     return CmdlineParseResult<T>::Failure("Failed to parse integer from " + str);
241   } else if ((errno == ERANGE) ||  // NOLINT [runtime/int] [4]
242       result < std::numeric_limits<T>::min() || result > std::numeric_limits<T>::max()) {
243     return CmdlineParseResult<T>::OutOfRange(
244         "Failed to parse integer from " + str + "; out of range");
245   }
246 
247   return CmdlineParseResult<T>::Success(static_cast<T>(result));
248 }
249 
250 template <>
251 struct CmdlineType<unsigned int> : CmdlineTypeParser<unsigned int> {
252   Result Parse(const std::string& str) {
253     return ParseNumeric<unsigned int>(str);
254   }
255 
256   static const char* Name() { return "unsigned integer"; }
257   static const char* DescribeType() { return "unsigned integer value"; }
258 };
259 
260 template <>
261 struct CmdlineType<int> : CmdlineTypeParser<int> {
262   Result Parse(const std::string& str) {
263     return ParseNumeric<int>(str);
264   }
265 
266   static const char* Name() { return "integer"; }
267   static const char* DescribeType() { return "integer value"; }
268 };
269 
270 // Lightweight nanosecond value type. Allows parser to convert user-input from milliseconds
271 // to nanoseconds automatically after parsing.
272 //
273 // All implicit conversion from uint64_t uses nanoseconds.
274 struct MillisecondsToNanoseconds {
275   // Create from nanoseconds.
276   MillisecondsToNanoseconds(uint64_t nanoseconds) : nanoseconds_(nanoseconds) {  // NOLINT [runtime/explicit] [5]
277   }
278 
279   // Create from milliseconds.
280   static MillisecondsToNanoseconds FromMilliseconds(unsigned int milliseconds) {
281     return MillisecondsToNanoseconds(MsToNs(milliseconds));
282   }
283 
284   // Get the underlying nanoseconds value.
285   uint64_t GetNanoseconds() const {
286     return nanoseconds_;
287   }
288 
289   // Get the milliseconds value [via a conversion]. Loss of precision will occur.
290   uint64_t GetMilliseconds() const {
291     return NsToMs(nanoseconds_);
292   }
293 
294   // Get the underlying nanoseconds value.
295   operator uint64_t() const {
296     return GetNanoseconds();
297   }
298 
299   // Default constructors/copy-constructors.
300   MillisecondsToNanoseconds() : nanoseconds_(0ul) {}
301   MillisecondsToNanoseconds(const MillisecondsToNanoseconds&) = default;
302   MillisecondsToNanoseconds(MillisecondsToNanoseconds&&) = default;
303 
304  private:
305   uint64_t nanoseconds_;
306 };
307 
308 template <>
309 struct CmdlineType<MillisecondsToNanoseconds> : CmdlineTypeParser<MillisecondsToNanoseconds> {
310   Result Parse(const std::string& str) {
311     CmdlineType<unsigned int> uint_parser;
312     CmdlineParseResult<unsigned int> res = uint_parser.Parse(str);
313 
314     if (res.IsSuccess()) {
315       return Result::Success(MillisecondsToNanoseconds::FromMilliseconds(res.GetValue()));
316     } else {
317       return Result::CastError(res);
318     }
319   }
320 
321   static const char* Name() { return "MillisecondsToNanoseconds"; }
322   static const char* DescribeType() { return "millisecond value"; }
323 };
324 
325 template <>
326 struct CmdlineType<std::string> : CmdlineTypeParser<std::string> {
327   Result Parse(const std::string& args) {
328     return Result::Success(args);
329   }
330 
331   Result ParseAndAppend(const std::string& args,
332                         std::string& existing_value) {
333     if (existing_value.empty()) {
334       existing_value = args;
335     } else {
336       existing_value += ' ';
337       existing_value += args;
338     }
339     return Result::SuccessNoValue();
340   }
341   static const char* DescribeType() { return "string value"; }
342 };
343 
344 template <>
345 struct CmdlineType<std::vector<Plugin>> : CmdlineTypeParser<std::vector<Plugin>> {
346   Result Parse(const std::string& args) {
347     assert(false && "Use AppendValues() for a Plugin vector type");
348     return Result::Failure("Unconditional failure: Plugin vector must be appended: " + args);
349   }
350 
351   Result ParseAndAppend(const std::string& args,
352                         std::vector<Plugin>& existing_value) {
353     existing_value.push_back(Plugin::Create(args));
354     return Result::SuccessNoValue();
355   }
356 
357   static const char* Name() { return "std::vector<Plugin>"; }
358   static const char* DescribeType() { return "/path/to/libplugin.so"; }
359 };
360 
361 template <>
362 struct CmdlineType<std::list<ti::AgentSpec>> : CmdlineTypeParser<std::list<ti::AgentSpec>> {
363   Result Parse(const std::string& args) {
364     assert(false && "Use AppendValues() for an Agent list type");
365     return Result::Failure("Unconditional failure: Agent list must be appended: " + args);
366   }
367 
368   Result ParseAndAppend(const std::string& args,
369                         std::list<ti::AgentSpec>& existing_value) {
370     existing_value.emplace_back(args);
371     return Result::SuccessNoValue();
372   }
373 
374   static const char* Name() { return "std::list<ti::AgentSpec>"; }
375   static const char* DescribeType() { return "/path/to/libagent.so=options"; }
376 };
377 
378 template <>
379 struct CmdlineType<std::vector<std::string>> : CmdlineTypeParser<std::vector<std::string>> {
380   Result Parse(const std::string& args) {
381     assert(false && "Use AppendValues() for a string vector type");
382     return Result::Failure("Unconditional failure: string vector must be appended: " + args);
383   }
384 
385   Result ParseAndAppend(const std::string& args,
386                         std::vector<std::string>& existing_value) {
387     existing_value.push_back(args);
388     return Result::SuccessNoValue();
389   }
390 
391   static const char* Name() { return "std::vector<std::string>"; }
392   static const char* DescribeType() { return "string value"; }
393 };
394 
395 template <>
396 struct CmdlineType<std::vector<int>> : CmdlineTypeParser<std::vector<int>> {
397   Result Parse(const std::string& args) {
398     assert(false && "Use AppendValues() for a int vector type");
399     return Result::Failure("Unconditional failure: string vector must be appended: " + args);
400   }
401 
402   Result ParseAndAppend(const std::string& args,
403                         std::vector<int>& existing_value) {
404     auto result = ParseNumeric<int>(args);
405     if (result.IsSuccess()) {
406       existing_value.push_back(result.GetValue());
407     } else {
408       return Result::CastError(result);
409     }
410     return Result::SuccessNoValue();
411   }
412 
413   static const char* Name() { return "std::vector<int>"; }
414   static const char* DescribeType() { return "int values"; }
415 };
416 
417 template <typename ArgType, char Separator>
418 struct ParseList {
419   explicit ParseList(std::vector<ArgType>&& list) : list_(list) {}
420 
421   operator std::vector<ArgType>() const {
422     return list_;
423   }
424 
425   operator std::vector<ArgType>&&() && {
426     return std::move(list_);
427   }
428 
429   size_t Size() const {
430     return list_.size();
431   }
432 
433   std::string Join() const {
434     return android::base::Join(list_, Separator);
435   }
436 
437   ParseList() = default;
438   ParseList(const ParseList&) = default;
439   ParseList(ParseList&&) noexcept = default;
440 
441  private:
442   std::vector<ArgType> list_;
443 };
444 
445 template <char Separator>
446 using ParseIntList = ParseList<int, Separator>;
447 
448 template <char Separator>
449 struct ParseStringList : public ParseList<std::string, Separator> {
450   explicit ParseStringList(std::vector<std::string>&& list) : ParseList<std::string, Separator>(std::move(list)) {}
451 
452   static ParseStringList<Separator> Split(const std::string& str) {
453     std::vector<std::string> list;
454     art::Split(str, Separator, &list);
455     return ParseStringList<Separator>(std::move(list));
456   }
457 
458   ParseStringList() = default;
459   ParseStringList(const ParseStringList&) = default;
460   ParseStringList(ParseStringList&&) noexcept = default;
461 };
462 
463 template <char Separator>
464 struct CmdlineType<ParseStringList<Separator>> : CmdlineTypeParser<ParseStringList<Separator>> {
465   using Result = CmdlineParseResult<ParseStringList<Separator>>;
466 
467   Result Parse(const std::string& args) {
468     return Result::Success(ParseStringList<Separator>::Split(args));
469   }
470 
471   static const char* Name() { return "ParseStringList<Separator>"; }
472   static const char* DescribeType() {
473     static std::string str;
474     if (str.empty()) {
475       str = android::base::StringPrintf("list separated by '%c'", Separator);
476     }
477     return str.c_str();
478   }
479 };
480 
481 template <char Separator>
482 struct CmdlineType<ParseIntList<Separator>> : CmdlineTypeParser<ParseIntList<Separator>> {
483   using Result = CmdlineParseResult<ParseIntList<Separator>>;
484 
485   Result Parse(const std::string& args) {
486     std::vector<int> list;
487     const char* pos = args.c_str();
488     errno = 0;
489 
490     while (true) {
491       char* end = nullptr;
492       int64_t value = strtol(pos, &end, 10);
493       if (pos == end ||  errno == EINVAL) {
494         return Result::Failure("Failed to parse integer from " + args);
495       } else if ((errno == ERANGE) ||  // NOLINT [runtime/int] [4]
496                  value < std::numeric_limits<int>::min() ||
497                  value > std::numeric_limits<int>::max()) {
498         return Result::OutOfRange("Failed to parse integer from " + args + "; out of range");
499       }
500       list.push_back(static_cast<int>(value));
501       if (*end == '\0') {
502         break;
503       } else if (*end != Separator) {
504         return Result::Failure(std::string("Unexpected character: ") + *end);
505       }
506       pos = end + 1;
507     }
508     return Result::Success(ParseIntList<Separator>(std::move(list)));
509   }
510 
511   static const char* Name() { return "ParseIntList<Separator>"; }
512   static const char* DescribeType() {
513     static std::string str;
514     if (str.empty()) {
515       str = android::base::StringPrintf("integer list separated by '%c'", Separator);
516     }
517     return str.c_str();
518   }
519 };
520 
521 static gc::CollectorType ParseCollectorType(const std::string& option) {
522   if (option == "MS" || option == "nonconcurrent") {
523     return gc::kCollectorTypeMS;
524   } else if (option == "CMS" || option == "concurrent") {
525     return gc::kCollectorTypeCMS;
526   } else if (option == "SS") {
527     return gc::kCollectorTypeSS;
528   } else if (option == "CC") {
529     return gc::kCollectorTypeCC;
530   } else {
531     return gc::kCollectorTypeNone;
532   }
533 }
534 
535 struct XGcOption {
536   // These defaults are used when the command line arguments for -Xgc:
537   // are either omitted completely or partially.
538   gc::CollectorType collector_type_ = gc::kCollectorTypeDefault;
539   bool verify_pre_gc_heap_ = false;
540   bool verify_pre_sweeping_heap_ = kIsDebugBuild;
541   bool generational_cc = kEnableGenerationalCCByDefault;
542   bool verify_post_gc_heap_ = false;
543   bool verify_pre_gc_rosalloc_ = kIsDebugBuild;
544   bool verify_pre_sweeping_rosalloc_ = false;
545   bool verify_post_gc_rosalloc_ = false;
546   // Do no measurements for kUseTableLookupReadBarrier to avoid test timeouts. b/31679493
547   bool measure_ = kIsDebugBuild && !kUseTableLookupReadBarrier;
548   bool gcstress_ = false;
549 };
550 
551 template <>
552 struct CmdlineType<XGcOption> : CmdlineTypeParser<XGcOption> {
553   Result Parse(const std::string& option) {  // -Xgc: already stripped
554     XGcOption xgc{};
555 
556     std::vector<std::string> gc_options;
557     Split(option, ',', &gc_options);
558     for (const std::string& gc_option : gc_options) {
559       gc::CollectorType collector_type = ParseCollectorType(gc_option);
560       if (collector_type != gc::kCollectorTypeNone) {
561         xgc.collector_type_ = collector_type;
562       } else if (gc_option == "preverify") {
563         xgc.verify_pre_gc_heap_ = true;
564       } else if (gc_option == "nopreverify") {
565         xgc.verify_pre_gc_heap_ = false;
566       }  else if (gc_option == "presweepingverify") {
567         xgc.verify_pre_sweeping_heap_ = true;
568       } else if (gc_option == "nopresweepingverify") {
569         xgc.verify_pre_sweeping_heap_ = false;
570       } else if (gc_option == "generational_cc") {
571         // Note: Option "-Xgc:generational_cc" can be passed directly by
572         // app_process/zygote (see `android::AndroidRuntime::startVm`). If this
573         // option is ever deprecated, it should still be accepted (but ignored)
574         // for compatibility reasons (this should not prevent the runtime from
575         // starting up).
576         xgc.generational_cc = true;
577       } else if (gc_option == "nogenerational_cc") {
578         // Note: Option "-Xgc:nogenerational_cc" can be passed directly by
579         // app_process/zygote (see `android::AndroidRuntime::startVm`). If this
580         // option is ever deprecated, it should still be accepted (but ignored)
581         // for compatibility reasons (this should not prevent the runtime from
582         // starting up).
583         xgc.generational_cc = false;
584       } else if (gc_option == "postverify") {
585         xgc.verify_post_gc_heap_ = true;
586       } else if (gc_option == "nopostverify") {
587         xgc.verify_post_gc_heap_ = false;
588       } else if (gc_option == "preverify_rosalloc") {
589         xgc.verify_pre_gc_rosalloc_ = true;
590       } else if (gc_option == "nopreverify_rosalloc") {
591         xgc.verify_pre_gc_rosalloc_ = false;
592       } else if (gc_option == "presweepingverify_rosalloc") {
593         xgc.verify_pre_sweeping_rosalloc_ = true;
594       } else if (gc_option == "nopresweepingverify_rosalloc") {
595         xgc.verify_pre_sweeping_rosalloc_ = false;
596       } else if (gc_option == "postverify_rosalloc") {
597         xgc.verify_post_gc_rosalloc_ = true;
598       } else if (gc_option == "nopostverify_rosalloc") {
599         xgc.verify_post_gc_rosalloc_ = false;
600       } else if (gc_option == "gcstress") {
601         xgc.gcstress_ = true;
602       } else if (gc_option == "nogcstress") {
603         xgc.gcstress_ = false;
604       } else if (gc_option == "measure") {
605         xgc.measure_ = true;
606       } else if ((gc_option == "precise") ||
607                  (gc_option == "noprecise") ||
608                  (gc_option == "verifycardtable") ||
609                  (gc_option == "noverifycardtable")) {
610         // Ignored for backwards compatibility.
611       } else {
612         return Result::Usage(std::string("Unknown -Xgc option ") + gc_option);
613       }
614     }
615 
616     return Result::Success(std::move(xgc));
617   }
618 
619   static const char* Name() { return "XgcOption"; }
620   static const char* DescribeType() {
621     return "MS|nonconccurent|concurrent|CMS|SS|CC|[no]preverify[_rosalloc]|"
622            "[no]presweepingverify[_rosalloc]|[no]generation_cc|[no]postverify[_rosalloc]|"
623            "[no]gcstress|measure|[no]precisce|[no]verifycardtable";
624   }
625 };
626 
627 struct BackgroundGcOption {
628   // If background_collector_type_ is kCollectorTypeNone, it defaults to the
629   // XGcOption::collector_type_ after parsing options. If you set this to
630   // kCollectorTypeHSpaceCompact then we will do an hspace compaction when
631   // we transition to background instead of a normal collector transition.
632   gc::CollectorType background_collector_type_;
633 
634   BackgroundGcOption(gc::CollectorType background_collector_type)  // NOLINT [runtime/explicit] [5]
635     : background_collector_type_(background_collector_type) {}
636   BackgroundGcOption()
637     : background_collector_type_(gc::kCollectorTypeNone) {
638   }
639 
640   operator gc::CollectorType() const { return background_collector_type_; }
641 };
642 
643 template<>
644 struct CmdlineType<BackgroundGcOption>
645   : CmdlineTypeParser<BackgroundGcOption>, private BackgroundGcOption {
646   Result Parse(const std::string& substring) {
647     // Special handling for HSpaceCompact since this is only valid as a background GC type.
648     if (substring == "HSpaceCompact") {
649       background_collector_type_ = gc::kCollectorTypeHomogeneousSpaceCompact;
650     } else {
651       gc::CollectorType collector_type = ParseCollectorType(substring);
652       if (collector_type != gc::kCollectorTypeNone) {
653         background_collector_type_ = collector_type;
654       } else {
655         return Result::Failure();
656       }
657     }
658 
659     BackgroundGcOption res = *this;
660     return Result::Success(res);
661   }
662 
663   static const char* Name() { return "BackgroundGcOption"; }
664   static const char* DescribeType() {
665     return "HSpaceCompact|MS|nonconccurent|CMS|concurrent|SS|CC";
666   }
667 };
668 
669 template <>
670 struct CmdlineType<LogVerbosity> : CmdlineTypeParser<LogVerbosity> {
671   Result Parse(const std::string& options) {
672     LogVerbosity log_verbosity = LogVerbosity();
673 
674     std::vector<std::string> verbose_options;
675     Split(options, ',', &verbose_options);
676     for (size_t j = 0; j < verbose_options.size(); ++j) {
677       if (verbose_options[j] == "class") {
678         log_verbosity.class_linker = true;
679       } else if (verbose_options[j] == "collector") {
680         log_verbosity.collector = true;
681       } else if (verbose_options[j] == "compiler") {
682         log_verbosity.compiler = true;
683       } else if (verbose_options[j] == "deopt") {
684         log_verbosity.deopt = true;
685       } else if (verbose_options[j] == "gc") {
686         log_verbosity.gc = true;
687       } else if (verbose_options[j] == "heap") {
688         log_verbosity.heap = true;
689       } else if (verbose_options[j] == "interpreter") {
690         log_verbosity.interpreter = true;
691       } else if (verbose_options[j] == "jdwp") {
692         log_verbosity.jdwp = true;
693       } else if (verbose_options[j] == "jit") {
694         log_verbosity.jit = true;
695       } else if (verbose_options[j] == "jni") {
696         log_verbosity.jni = true;
697       } else if (verbose_options[j] == "monitor") {
698         log_verbosity.monitor = true;
699       } else if (verbose_options[j] == "oat") {
700         log_verbosity.oat = true;
701       } else if (verbose_options[j] == "profiler") {
702         log_verbosity.profiler = true;
703       } else if (verbose_options[j] == "signals") {
704         log_verbosity.signals = true;
705       } else if (verbose_options[j] == "simulator") {
706         log_verbosity.simulator = true;
707       } else if (verbose_options[j] == "startup") {
708         log_verbosity.startup = true;
709       } else if (verbose_options[j] == "third-party-jni") {
710         log_verbosity.third_party_jni = true;
711       } else if (verbose_options[j] == "threads") {
712         log_verbosity.threads = true;
713       } else if (verbose_options[j] == "verifier") {
714         log_verbosity.verifier = true;
715       } else if (verbose_options[j] == "verifier-debug") {
716         log_verbosity.verifier_debug = true;
717       } else if (verbose_options[j] == "image") {
718         log_verbosity.image = true;
719       } else if (verbose_options[j] == "systrace-locks") {
720         log_verbosity.systrace_lock_logging = true;
721       } else if (verbose_options[j] == "plugin") {
722         log_verbosity.plugin = true;
723       } else if (verbose_options[j] == "agents") {
724         log_verbosity.agents = true;
725       } else if (verbose_options[j] == "dex") {
726         log_verbosity.dex = true;
727       } else {
728         return Result::Usage(std::string("Unknown -verbose option ") + verbose_options[j]);
729       }
730     }
731 
732     return Result::Success(log_verbosity);
733   }
734 
735   static const char* Name() { return "LogVerbosity"; }
736   static const char* DescribeType() {
737     return "class|collector|compiler|deopt|gc|heap|interpreter|jdwp|jit|jni|monitor|oat|profiler|"
738            "signals|simulator|startup|third-party-jni|threads|verifier|verifier-debug|image|"
739            "systrace-locks|plugin|agents|dex";
740   }
741 };
742 
743 template <>
744 struct CmdlineType<ProfileSaverOptions> : CmdlineTypeParser<ProfileSaverOptions> {
745   using Result = CmdlineParseResult<ProfileSaverOptions>;
746 
747  private:
748   using StringResult = CmdlineParseResult<std::string>;
749   using DoubleResult = CmdlineParseResult<double>;
750 
751   template <typename T>
752   static Result ParseInto(ProfileSaverOptions& options,
753                           T ProfileSaverOptions::*pField,
754                           CmdlineParseResult<T>&& result) {
755     assert(pField != nullptr);
756 
757     if (result.IsSuccess()) {
758       options.*pField = result.ReleaseValue();
759       return Result::SuccessNoValue();
760     }
761 
762     return Result::CastError(result);
763   }
764 
765   static std::string RemovePrefix(const std::string& source) {
766     size_t prefix_idx = source.find(':');
767 
768     if (prefix_idx == std::string::npos) {
769       return "";
770     }
771 
772     return source.substr(prefix_idx + 1);
773   }
774 
775  public:
776   Result ParseAndAppend(const std::string& option, ProfileSaverOptions& existing) {
777     // Special case which doesn't include a wildcard argument definition.
778     // We pass-it through as-is.
779     if (option == "-Xjitsaveprofilinginfo") {
780       existing.enabled_ = true;
781       return Result::SuccessNoValue();
782     }
783 
784     if (option == "profile-boot-class-path") {
785       existing.profile_boot_class_path_ = true;
786       return Result::SuccessNoValue();
787     }
788 
789     if (option == "profile-aot-code") {
790       existing.profile_aot_code_ = true;
791       return Result::SuccessNoValue();
792     }
793 
794     if (option == "save-without-jit-notifications") {
795       existing.wait_for_jit_notifications_to_save_ = false;
796       return Result::SuccessNoValue();
797     }
798 
799     // The rest of these options are always the wildcard from '-Xps-*'
800     std::string suffix = RemovePrefix(option);
801 
802     if (android::base::StartsWith(option, "min-save-period-ms:")) {
803       CmdlineType<unsigned int> type_parser;
804       return ParseInto(existing,
805              &ProfileSaverOptions::min_save_period_ms_,
806              type_parser.Parse(suffix));
807     }
808     if (android::base::StartsWith(option, "min-first-save-ms:")) {
809       CmdlineType<unsigned int> type_parser;
810       return ParseInto(existing,
811              &ProfileSaverOptions::min_first_save_ms_,
812              type_parser.Parse(suffix));
813     }
814     if (android::base::StartsWith(option, "save-resolved-classes-delay-ms:")) {
815       CmdlineType<unsigned int> type_parser;
816       return ParseInto(existing,
817              &ProfileSaverOptions::save_resolved_classes_delay_ms_,
818              type_parser.Parse(suffix));
819     }
820     if (android::base::StartsWith(option, "hot-startup-method-samples:")) {
821       CmdlineType<unsigned int> type_parser;
822       return ParseInto(existing,
823              &ProfileSaverOptions::hot_startup_method_samples_,
824              type_parser.Parse(suffix));
825     }
826     if (android::base::StartsWith(option, "min-methods-to-save:")) {
827       CmdlineType<unsigned int> type_parser;
828       return ParseInto(existing,
829              &ProfileSaverOptions::min_methods_to_save_,
830              type_parser.Parse(suffix));
831     }
832     if (android::base::StartsWith(option, "min-classes-to-save:")) {
833       CmdlineType<unsigned int> type_parser;
834       return ParseInto(existing,
835              &ProfileSaverOptions::min_classes_to_save_,
836              type_parser.Parse(suffix));
837     }
838     if (android::base::StartsWith(option, "min-notification-before-wake:")) {
839       CmdlineType<unsigned int> type_parser;
840       return ParseInto(existing,
841              &ProfileSaverOptions::min_notification_before_wake_,
842              type_parser.Parse(suffix));
843     }
844     if (android::base::StartsWith(option, "max-notification-before-wake:")) {
845       CmdlineType<unsigned int> type_parser;
846       return ParseInto(existing,
847              &ProfileSaverOptions::max_notification_before_wake_,
848              type_parser.Parse(suffix));
849     }
850     if (android::base::StartsWith(option, "profile-path:")) {
851       existing.profile_path_ = suffix;
852       return Result::SuccessNoValue();
853     }
854 
855     return Result::Failure(std::string("Invalid suboption '") + option + "'");
856   }
857 
858   static const char* Name() { return "ProfileSaverOptions"; }
859   static const char* DescribeType() { return "string|unsigned integer"; }
860   static constexpr bool kCanParseBlankless = true;
861 };
862 
863 template<>
864 struct CmdlineType<ExperimentalFlags> : CmdlineTypeParser<ExperimentalFlags> {
865   Result ParseAndAppend(const std::string& option, ExperimentalFlags& existing) {
866     if (option == "none") {
867       existing = ExperimentalFlags::kNone;
868     } else {
869       return Result::Failure(std::string("Unknown option '") + option + "'");
870     }
871     return Result::SuccessNoValue();
872   }
873 
874   static const char* Name() { return "ExperimentalFlags"; }
875   static const char* DescribeType() { return "none"; }
876 };
877 }  // namespace art
878 #endif  // ART_CMDLINE_CMDLINE_TYPES_H_
879