blob: cb3140a091d9acb5511d0ade8253e202b51068a5 [file] [log] [blame]
Igor Murashkinaaebaa02015-01-26 10:55:53 -08001/*
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
Andreas Gamped482e732017-04-24 17:59:09 -070021#include <list>
22
Igor Murashkinaaebaa02015-01-26 10:55:53 -080023#include "cmdline_type_parser.h"
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070024#include "detail/cmdline_debug_detail.h"
25#include "memory_representation.h"
Igor Murashkinaaebaa02015-01-26 10:55:53 -080026
Andreas Gampe9186ced2016-12-12 14:28:21 -080027#include "android-base/strings.h"
28
Igor Murashkinaaebaa02015-01-26 10:55:53 -080029// Includes for the types that are being specialized
30#include <string>
Vladimir Marko88b2b802015-12-04 14:19:04 +000031#include "base/logging.h"
32#include "base/time_utils.h"
33#include "experimental_flags.h"
Igor Murashkinaaebaa02015-01-26 10:55:53 -080034#include "gc/collector_type.h"
35#include "gc/space/large_object_space.h"
Alex Light7233c7e2016-07-28 10:07:45 -070036#include "jdwp/jdwp.h"
Alex Light40320712017-12-14 11:52:04 -080037#include "jdwp_provider.h"
Calin Juravle138dbff2016-06-28 19:36:58 +010038#include "jit/profile_saver_options.h"
Alex Light185d1342016-08-11 10:48:03 -070039#include "plugin.h"
Andreas Gampe217488a2017-09-18 08:34:42 -070040#include "read_barrier_config.h"
Alex Light7233c7e2016-07-28 10:07:45 -070041#include "ti/agent.h"
42#include "unit.h"
Igor Murashkinaaebaa02015-01-26 10:55:53 -080043
44namespace art {
45
46// The default specialization will always fail parsing the type from a string.
47// Provide your own specialization that inherits from CmdlineTypeParser<T>
48// and implements either Parse or ParseAndAppend
49// (only if the argument was defined with ::AppendValues()) but not both.
50template <typename T>
51struct CmdlineType : CmdlineTypeParser<T> {
52};
53
54// Specializations for CmdlineType<T> follow:
55
56// Parse argument definitions for Unit-typed arguments.
57template <>
58struct CmdlineType<Unit> : CmdlineTypeParser<Unit> {
59 Result Parse(const std::string& args) {
60 if (args == "") {
Igor Murashkin5573c372017-11-16 13:34:30 -080061 return Result::Success(Unit{});
Igor Murashkinaaebaa02015-01-26 10:55:53 -080062 }
63 return Result::Failure("Unexpected extra characters " + args);
64 }
65};
66
67template <>
Alex Light40320712017-12-14 11:52:04 -080068struct CmdlineType<JdwpProvider> : CmdlineTypeParser<JdwpProvider> {
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +010069 /*
Alex Light40320712017-12-14 11:52:04 -080070 * Handle a single JDWP provider name. Must be either 'internal', 'default', or the file name of
71 * an agent. A plugin will make use of this and the jdwpOptions to set up jdwp when appropriate.
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +010072 */
Alex Light40320712017-12-14 11:52:04 -080073 Result Parse(const std::string& option) {
74 if (option == "help") {
Igor Murashkinaaebaa02015-01-26 10:55:53 -080075 return Result::Usage(
Alex Light40320712017-12-14 11:52:04 -080076 "Example: -XjdwpProvider:none to disable JDWP\n"
77 "Example: -XjdwpProvider:internal for internal jdwp implementation\n"
Alex Lightfbf96702017-12-14 13:27:13 -080078 "Example: -XjdwpProvider:adbconnection for adb connection mediated jdwp implementation\n"
Alex Light2183d4d2018-01-26 14:24:54 -080079 "Example: -XjdwpProvider:default for the default jdwp implementation\n");
80 } else if (option == "default") {
81 return Result::Success(JdwpProvider::kDefaultJdwpProvider);
82 } else if (option == "internal") {
Alex Light40320712017-12-14 11:52:04 -080083 return Result::Success(JdwpProvider::kInternal);
Alex Light4650d4a2018-01-24 00:33:49 +000084 } else if (option == "adbconnection") {
Alex Lightfbf96702017-12-14 13:27:13 -080085 return Result::Success(JdwpProvider::kAdbConnection);
Alex Light40320712017-12-14 11:52:04 -080086 } else if (option == "none") {
87 return Result::Success(JdwpProvider::kNone);
Igor Murashkinaaebaa02015-01-26 10:55:53 -080088 } else {
Alex Light40320712017-12-14 11:52:04 -080089 return Result::Failure(std::string("not a valid jdwp provider: ") + option);
Igor Murashkinaaebaa02015-01-26 10:55:53 -080090 }
Igor Murashkinaaebaa02015-01-26 10:55:53 -080091 }
Alex Light40320712017-12-14 11:52:04 -080092 static const char* Name() { return "JdwpProvider"; }
Igor Murashkinaaebaa02015-01-26 10:55:53 -080093};
94
95template <size_t Divisor>
96struct CmdlineType<Memory<Divisor>> : CmdlineTypeParser<Memory<Divisor>> {
97 using typename CmdlineTypeParser<Memory<Divisor>>::Result;
98
Vladimir Marko5c657fe2016-11-03 15:12:29 +000099 Result Parse(const std::string& arg) {
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800100 CMDLINE_DEBUG_LOG << "Parsing memory: " << arg << std::endl;
101 size_t val = ParseMemoryOption(arg.c_str(), Divisor);
102 CMDLINE_DEBUG_LOG << "Memory parsed to size_t value: " << val << std::endl;
103
104 if (val == 0) {
105 return Result::Failure(std::string("not a valid memory value, or not divisible by ")
106 + std::to_string(Divisor));
107 }
108
109 return Result::Success(Memory<Divisor>(val));
110 }
111
112 // Parse a string of the form /[0-9]+[kKmMgG]?/, which is used to specify
113 // memory sizes. [kK] indicates kilobytes, [mM] megabytes, and
114 // [gG] gigabytes.
115 //
116 // "s" should point just past the "-Xm?" part of the string.
117 // "div" specifies a divisor, e.g. 1024 if the value must be a multiple
118 // of 1024.
119 //
120 // The spec says the -Xmx and -Xms options must be multiples of 1024. It
121 // doesn't say anything about -Xss.
122 //
123 // Returns 0 (a useless size) if "s" is malformed or specifies a low or
124 // non-evenly-divisible value.
125 //
126 static size_t ParseMemoryOption(const char* s, size_t div) {
127 // strtoul accepts a leading [+-], which we don't want,
128 // so make sure our string starts with a decimal digit.
129 if (isdigit(*s)) {
130 char* s2;
131 size_t val = strtoul(s, &s2, 10);
132 if (s2 != s) {
133 // s2 should be pointing just after the number.
134 // If this is the end of the string, the user
135 // has specified a number of bytes. Otherwise,
136 // there should be exactly one more character
137 // that specifies a multiplier.
138 if (*s2 != '\0') {
139 // The remainder of the string is either a single multiplier
140 // character, or nothing to indicate that the value is in
141 // bytes.
142 char c = *s2++;
143 if (*s2 == '\0') {
144 size_t mul;
145 if (c == '\0') {
146 mul = 1;
147 } else if (c == 'k' || c == 'K') {
148 mul = KB;
149 } else if (c == 'm' || c == 'M') {
150 mul = MB;
151 } else if (c == 'g' || c == 'G') {
152 mul = GB;
153 } else {
154 // Unknown multiplier character.
155 return 0;
156 }
157
158 if (val <= std::numeric_limits<size_t>::max() / mul) {
159 val *= mul;
160 } else {
161 // Clamp to a multiple of 1024.
162 val = std::numeric_limits<size_t>::max() & ~(1024-1);
163 }
164 } else {
165 // There's more than one character after the numeric part.
166 return 0;
167 }
168 }
169 // The man page says that a -Xm value must be a multiple of 1024.
170 if (val % div == 0) {
171 return val;
172 }
173 }
174 }
175 return 0;
176 }
177
178 static const char* Name() { return Memory<Divisor>::Name(); }
179};
180
181template <>
182struct CmdlineType<double> : CmdlineTypeParser<double> {
183 Result Parse(const std::string& str) {
184 char* end = nullptr;
185 errno = 0;
186 double value = strtod(str.c_str(), &end);
187
188 if (*end != '\0') {
189 return Result::Failure("Failed to parse double from " + str);
190 }
191 if (errno == ERANGE) {
192 return Result::OutOfRange(
193 "Failed to parse double from " + str + "; overflow/underflow occurred");
194 }
195
196 return Result::Success(value);
197 }
198
199 static const char* Name() { return "double"; }
200};
201
Andreas Gampe097f34c2017-08-23 08:57:51 -0700202template <typename T>
203static inline CmdlineParseResult<T> ParseNumeric(const std::string& str) {
204 static_assert(sizeof(T) < sizeof(long long int), // NOLINT [runtime/int] [4]
205 "Current support is restricted.");
206
207 const char* begin = str.c_str();
208 char* end;
209
210 // Parse into a larger type (long long) because we can't use strtoul
211 // since it silently converts negative values into unsigned long and doesn't set errno.
212 errno = 0;
213 long long int result = strtoll(begin, &end, 10); // NOLINT [runtime/int] [4]
214 if (begin == end || *end != '\0' || errno == EINVAL) {
215 return CmdlineParseResult<T>::Failure("Failed to parse integer from " + str);
216 } else if ((errno == ERANGE) || // NOLINT [runtime/int] [4]
217 result < std::numeric_limits<T>::min() || result > std::numeric_limits<T>::max()) {
218 return CmdlineParseResult<T>::OutOfRange(
219 "Failed to parse integer from " + str + "; out of range");
220 }
221
222 return CmdlineParseResult<T>::Success(static_cast<T>(result));
223}
224
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800225template <>
226struct CmdlineType<unsigned int> : CmdlineTypeParser<unsigned int> {
227 Result Parse(const std::string& str) {
Andreas Gampe097f34c2017-08-23 08:57:51 -0700228 return ParseNumeric<unsigned int>(str);
229 }
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800230
Andreas Gampe097f34c2017-08-23 08:57:51 -0700231 static const char* Name() { return "unsigned integer"; }
232};
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800233
Andreas Gampe097f34c2017-08-23 08:57:51 -0700234template <>
235struct CmdlineType<int> : CmdlineTypeParser<int> {
236 Result Parse(const std::string& str) {
237 return ParseNumeric<int>(str);
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800238 }
239
240 static const char* Name() { return "unsigned integer"; }
241};
242
243// Lightweight nanosecond value type. Allows parser to convert user-input from milliseconds
244// to nanoseconds automatically after parsing.
245//
246// All implicit conversion from uint64_t uses nanoseconds.
247struct MillisecondsToNanoseconds {
248 // Create from nanoseconds.
249 MillisecondsToNanoseconds(uint64_t nanoseconds) : nanoseconds_(nanoseconds) { // NOLINT [runtime/explicit] [5]
250 }
251
252 // Create from milliseconds.
253 static MillisecondsToNanoseconds FromMilliseconds(unsigned int milliseconds) {
254 return MillisecondsToNanoseconds(MsToNs(milliseconds));
255 }
256
257 // Get the underlying nanoseconds value.
258 uint64_t GetNanoseconds() const {
259 return nanoseconds_;
260 }
261
262 // Get the milliseconds value [via a conversion]. Loss of precision will occur.
263 uint64_t GetMilliseconds() const {
264 return NsToMs(nanoseconds_);
265 }
266
267 // Get the underlying nanoseconds value.
268 operator uint64_t() const {
269 return GetNanoseconds();
270 }
271
272 // Default constructors/copy-constructors.
273 MillisecondsToNanoseconds() : nanoseconds_(0ul) {}
Andreas Gampec801f0d2015-02-24 20:55:16 -0800274 MillisecondsToNanoseconds(const MillisecondsToNanoseconds&) = default;
275 MillisecondsToNanoseconds(MillisecondsToNanoseconds&&) = default;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800276
277 private:
278 uint64_t nanoseconds_;
279};
280
281template <>
282struct CmdlineType<MillisecondsToNanoseconds> : CmdlineTypeParser<MillisecondsToNanoseconds> {
283 Result Parse(const std::string& str) {
284 CmdlineType<unsigned int> uint_parser;
285 CmdlineParseResult<unsigned int> res = uint_parser.Parse(str);
286
287 if (res.IsSuccess()) {
288 return Result::Success(MillisecondsToNanoseconds::FromMilliseconds(res.GetValue()));
289 } else {
290 return Result::CastError(res);
291 }
292 }
293
294 static const char* Name() { return "MillisecondsToNanoseconds"; }
295};
296
297template <>
298struct CmdlineType<std::string> : CmdlineTypeParser<std::string> {
299 Result Parse(const std::string& args) {
300 return Result::Success(args);
301 }
302
303 Result ParseAndAppend(const std::string& args,
304 std::string& existing_value) {
305 if (existing_value.empty()) {
306 existing_value = args;
307 } else {
308 existing_value += ' ';
309 existing_value += args;
310 }
311 return Result::SuccessNoValue();
312 }
313};
314
315template <>
Alex Light185d1342016-08-11 10:48:03 -0700316struct CmdlineType<std::vector<Plugin>> : CmdlineTypeParser<std::vector<Plugin>> {
317 Result Parse(const std::string& args) {
318 assert(false && "Use AppendValues() for a Plugin vector type");
319 return Result::Failure("Unconditional failure: Plugin vector must be appended: " + args);
320 }
321
322 Result ParseAndAppend(const std::string& args,
323 std::vector<Plugin>& existing_value) {
324 existing_value.push_back(Plugin::Create(args));
325 return Result::SuccessNoValue();
326 }
327
328 static const char* Name() { return "std::vector<Plugin>"; }
329};
330
331template <>
Andreas Gampeaadcbc62017-12-28 14:05:42 -0800332struct CmdlineType<std::list<ti::AgentSpec>> : CmdlineTypeParser<std::list<ti::AgentSpec>> {
Alex Light7233c7e2016-07-28 10:07:45 -0700333 Result Parse(const std::string& args) {
Alex Light4b812fa2017-03-29 10:40:15 -0700334 assert(false && "Use AppendValues() for an Agent list type");
335 return Result::Failure("Unconditional failure: Agent list must be appended: " + args);
Alex Light7233c7e2016-07-28 10:07:45 -0700336 }
337
338 Result ParseAndAppend(const std::string& args,
Andreas Gampeaadcbc62017-12-28 14:05:42 -0800339 std::list<ti::AgentSpec>& existing_value) {
Leonard Mosescueb842212016-10-06 17:26:36 -0700340 existing_value.emplace_back(args);
Alex Light7233c7e2016-07-28 10:07:45 -0700341 return Result::SuccessNoValue();
342 }
343
Andreas Gampeaadcbc62017-12-28 14:05:42 -0800344 static const char* Name() { return "std::list<ti::AgentSpec>"; }
Alex Light7233c7e2016-07-28 10:07:45 -0700345};
346
347template <>
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800348struct CmdlineType<std::vector<std::string>> : CmdlineTypeParser<std::vector<std::string>> {
349 Result Parse(const std::string& args) {
350 assert(false && "Use AppendValues() for a string vector type");
351 return Result::Failure("Unconditional failure: string vector must be appended: " + args);
352 }
353
354 Result ParseAndAppend(const std::string& args,
355 std::vector<std::string>& existing_value) {
356 existing_value.push_back(args);
357 return Result::SuccessNoValue();
358 }
359
360 static const char* Name() { return "std::vector<std::string>"; }
361};
362
363template <char Separator>
364struct ParseStringList {
365 explicit ParseStringList(std::vector<std::string>&& list) : list_(list) {}
366
367 operator std::vector<std::string>() const {
368 return list_;
369 }
370
371 operator std::vector<std::string>&&() && {
372 return std::move(list_);
373 }
374
375 size_t Size() const {
376 return list_.size();
377 }
378
379 std::string Join() const {
Andreas Gampe9186ced2016-12-12 14:28:21 -0800380 return android::base::Join(list_, Separator);
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800381 }
382
383 static ParseStringList<Separator> Split(const std::string& str) {
384 std::vector<std::string> list;
385 art::Split(str, Separator, &list);
386 return ParseStringList<Separator>(std::move(list));
387 }
388
389 ParseStringList() = default;
Andreas Gampec801f0d2015-02-24 20:55:16 -0800390 ParseStringList(const ParseStringList&) = default;
391 ParseStringList(ParseStringList&&) = default;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800392
393 private:
394 std::vector<std::string> list_;
395};
396
397template <char Separator>
398struct CmdlineType<ParseStringList<Separator>> : CmdlineTypeParser<ParseStringList<Separator>> {
399 using Result = CmdlineParseResult<ParseStringList<Separator>>;
400
401 Result Parse(const std::string& args) {
402 return Result::Success(ParseStringList<Separator>::Split(args));
403 }
404
405 static const char* Name() { return "ParseStringList<Separator>"; }
406};
407
408static gc::CollectorType ParseCollectorType(const std::string& option) {
409 if (option == "MS" || option == "nonconcurrent") {
410 return gc::kCollectorTypeMS;
411 } else if (option == "CMS" || option == "concurrent") {
412 return gc::kCollectorTypeCMS;
413 } else if (option == "SS") {
414 return gc::kCollectorTypeSS;
415 } else if (option == "GSS") {
416 return gc::kCollectorTypeGSS;
417 } else if (option == "CC") {
418 return gc::kCollectorTypeCC;
419 } else if (option == "MC") {
420 return gc::kCollectorTypeMC;
421 } else {
422 return gc::kCollectorTypeNone;
423 }
424}
425
426struct XGcOption {
427 // These defaults are used when the command line arguments for -Xgc:
428 // are either omitted completely or partially.
Hiroshi Yamauchi1b0adbf2016-11-14 17:35:12 -0800429 gc::CollectorType collector_type_ = gc::kCollectorTypeDefault;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800430 bool verify_pre_gc_heap_ = false;
431 bool verify_pre_sweeping_heap_ = kIsDebugBuild;
432 bool verify_post_gc_heap_ = false;
433 bool verify_pre_gc_rosalloc_ = kIsDebugBuild;
434 bool verify_pre_sweeping_rosalloc_ = false;
435 bool verify_post_gc_rosalloc_ = false;
Hiroshi Yamauchia9b296c2016-10-07 17:07:03 -0700436 // Do no measurements for kUseTableLookupReadBarrier to avoid test timeouts. b/31679493
437 bool measure_ = kIsDebugBuild && !kUseTableLookupReadBarrier;
Mathieu Chartier31000802015-06-14 14:14:37 -0700438 bool gcstress_ = false;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800439};
440
441template <>
442struct CmdlineType<XGcOption> : CmdlineTypeParser<XGcOption> {
443 Result Parse(const std::string& option) { // -Xgc: already stripped
Igor Murashkin5573c372017-11-16 13:34:30 -0800444 XGcOption xgc{};
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800445
446 std::vector<std::string> gc_options;
447 Split(option, ',', &gc_options);
448 for (const std::string& gc_option : gc_options) {
449 gc::CollectorType collector_type = ParseCollectorType(gc_option);
450 if (collector_type != gc::kCollectorTypeNone) {
451 xgc.collector_type_ = collector_type;
452 } else if (gc_option == "preverify") {
453 xgc.verify_pre_gc_heap_ = true;
454 } else if (gc_option == "nopreverify") {
455 xgc.verify_pre_gc_heap_ = false;
456 } else if (gc_option == "presweepingverify") {
457 xgc.verify_pre_sweeping_heap_ = true;
458 } else if (gc_option == "nopresweepingverify") {
459 xgc.verify_pre_sweeping_heap_ = false;
460 } else if (gc_option == "postverify") {
461 xgc.verify_post_gc_heap_ = true;
462 } else if (gc_option == "nopostverify") {
463 xgc.verify_post_gc_heap_ = false;
464 } else if (gc_option == "preverify_rosalloc") {
465 xgc.verify_pre_gc_rosalloc_ = true;
466 } else if (gc_option == "nopreverify_rosalloc") {
467 xgc.verify_pre_gc_rosalloc_ = false;
468 } else if (gc_option == "presweepingverify_rosalloc") {
469 xgc.verify_pre_sweeping_rosalloc_ = true;
470 } else if (gc_option == "nopresweepingverify_rosalloc") {
471 xgc.verify_pre_sweeping_rosalloc_ = false;
472 } else if (gc_option == "postverify_rosalloc") {
473 xgc.verify_post_gc_rosalloc_ = true;
474 } else if (gc_option == "nopostverify_rosalloc") {
475 xgc.verify_post_gc_rosalloc_ = false;
Mathieu Chartier31000802015-06-14 14:14:37 -0700476 } else if (gc_option == "gcstress") {
477 xgc.gcstress_ = true;
478 } else if (gc_option == "nogcstress") {
479 xgc.gcstress_ = false;
Mathieu Chartier56fe2582016-07-14 13:30:03 -0700480 } else if (gc_option == "measure") {
481 xgc.measure_ = true;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800482 } else if ((gc_option == "precise") ||
483 (gc_option == "noprecise") ||
484 (gc_option == "verifycardtable") ||
485 (gc_option == "noverifycardtable")) {
486 // Ignored for backwards compatibility.
487 } else {
488 return Result::Usage(std::string("Unknown -Xgc option ") + gc_option);
489 }
490 }
491
492 return Result::Success(std::move(xgc));
493 }
494
495 static const char* Name() { return "XgcOption"; }
496};
497
498struct BackgroundGcOption {
499 // If background_collector_type_ is kCollectorTypeNone, it defaults to the
500 // XGcOption::collector_type_ after parsing options. If you set this to
501 // kCollectorTypeHSpaceCompact then we will do an hspace compaction when
502 // we transition to background instead of a normal collector transition.
503 gc::CollectorType background_collector_type_;
504
505 BackgroundGcOption(gc::CollectorType background_collector_type) // NOLINT [runtime/explicit] [5]
506 : background_collector_type_(background_collector_type) {}
507 BackgroundGcOption()
508 : background_collector_type_(gc::kCollectorTypeNone) {
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800509 }
510
511 operator gc::CollectorType() const { return background_collector_type_; }
512};
513
514template<>
515struct CmdlineType<BackgroundGcOption>
516 : CmdlineTypeParser<BackgroundGcOption>, private BackgroundGcOption {
517 Result Parse(const std::string& substring) {
518 // Special handling for HSpaceCompact since this is only valid as a background GC type.
519 if (substring == "HSpaceCompact") {
520 background_collector_type_ = gc::kCollectorTypeHomogeneousSpaceCompact;
521 } else {
522 gc::CollectorType collector_type = ParseCollectorType(substring);
523 if (collector_type != gc::kCollectorTypeNone) {
524 background_collector_type_ = collector_type;
525 } else {
526 return Result::Failure();
527 }
528 }
529
530 BackgroundGcOption res = *this;
531 return Result::Success(res);
532 }
533
534 static const char* Name() { return "BackgroundGcOption"; }
535};
536
537template <>
538struct CmdlineType<LogVerbosity> : CmdlineTypeParser<LogVerbosity> {
539 Result Parse(const std::string& options) {
540 LogVerbosity log_verbosity = LogVerbosity();
541
542 std::vector<std::string> verbose_options;
543 Split(options, ',', &verbose_options);
544 for (size_t j = 0; j < verbose_options.size(); ++j) {
545 if (verbose_options[j] == "class") {
546 log_verbosity.class_linker = true;
Mathieu Chartier66a55392016-02-19 10:25:39 -0800547 } else if (verbose_options[j] == "collector") {
548 log_verbosity.collector = true;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800549 } else if (verbose_options[j] == "compiler") {
550 log_verbosity.compiler = true;
Andreas Gampef3d1f942015-05-18 21:41:13 -0700551 } else if (verbose_options[j] == "deopt") {
552 log_verbosity.deopt = true;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800553 } else if (verbose_options[j] == "gc") {
554 log_verbosity.gc = true;
555 } else if (verbose_options[j] == "heap") {
556 log_verbosity.heap = true;
557 } else if (verbose_options[j] == "jdwp") {
558 log_verbosity.jdwp = true;
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800559 } else if (verbose_options[j] == "jit") {
560 log_verbosity.jit = true;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800561 } else if (verbose_options[j] == "jni") {
562 log_verbosity.jni = true;
563 } else if (verbose_options[j] == "monitor") {
564 log_verbosity.monitor = true;
Richard Uhler66d874d2015-01-15 09:37:19 -0800565 } else if (verbose_options[j] == "oat") {
566 log_verbosity.oat = true;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800567 } else if (verbose_options[j] == "profiler") {
568 log_verbosity.profiler = true;
569 } else if (verbose_options[j] == "signals") {
570 log_verbosity.signals = true;
Phil Wang751beff2015-08-28 15:17:15 +0800571 } else if (verbose_options[j] == "simulator") {
572 log_verbosity.simulator = true;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800573 } else if (verbose_options[j] == "startup") {
574 log_verbosity.startup = true;
575 } else if (verbose_options[j] == "third-party-jni") {
576 log_verbosity.third_party_jni = true;
577 } else if (verbose_options[j] == "threads") {
578 log_verbosity.threads = true;
579 } else if (verbose_options[j] == "verifier") {
580 log_verbosity.verifier = true;
Andreas Gampe92d77202017-12-06 20:49:00 -0800581 } else if (verbose_options[j] == "verifier-debug") {
582 log_verbosity.verifier_debug = true;
Mathieu Chartierfbc31082016-01-24 11:59:56 -0800583 } else if (verbose_options[j] == "image") {
584 log_verbosity.image = true;
Andreas Gampec7ed09b2016-04-25 20:08:55 -0700585 } else if (verbose_options[j] == "systrace-locks") {
586 log_verbosity.systrace_lock_logging = true;
Alex Light7233c7e2016-07-28 10:07:45 -0700587 } else if (verbose_options[j] == "agents") {
588 log_verbosity.agents = true;
Andreas Gampebec07a02017-04-11 13:48:37 -0700589 } else if (verbose_options[j] == "dex") {
590 log_verbosity.dex = true;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800591 } else {
592 return Result::Usage(std::string("Unknown -verbose option ") + verbose_options[j]);
593 }
594 }
595
596 return Result::Success(log_verbosity);
597 }
598
599 static const char* Name() { return "LogVerbosity"; }
600};
601
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800602template <>
Calin Juravle138dbff2016-06-28 19:36:58 +0100603struct CmdlineType<ProfileSaverOptions> : CmdlineTypeParser<ProfileSaverOptions> {
604 using Result = CmdlineParseResult<ProfileSaverOptions>;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800605
606 private:
607 using StringResult = CmdlineParseResult<std::string>;
608 using DoubleResult = CmdlineParseResult<double>;
609
610 template <typename T>
Calin Juravle138dbff2016-06-28 19:36:58 +0100611 static Result ParseInto(ProfileSaverOptions& options,
612 T ProfileSaverOptions::*pField,
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800613 CmdlineParseResult<T>&& result) {
614 assert(pField != nullptr);
615
616 if (result.IsSuccess()) {
617 options.*pField = result.ReleaseValue();
618 return Result::SuccessNoValue();
619 }
620
621 return Result::CastError(result);
622 }
623
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800624 static std::string RemovePrefix(const std::string& source) {
Andreas Gampeca620d72016-11-08 08:09:33 -0800625 size_t prefix_idx = source.find(':');
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800626
627 if (prefix_idx == std::string::npos) {
628 return "";
629 }
630
631 return source.substr(prefix_idx + 1);
632 }
633
634 public:
Calin Juravle138dbff2016-06-28 19:36:58 +0100635 Result ParseAndAppend(const std::string& option, ProfileSaverOptions& existing) {
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800636 // Special case which doesn't include a wildcard argument definition.
637 // We pass-it through as-is.
Calin Juravle138dbff2016-06-28 19:36:58 +0100638 if (option == "-Xjitsaveprofilinginfo") {
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800639 existing.enabled_ = true;
640 return Result::SuccessNoValue();
641 }
642
Mathieu Chartier885a7132017-06-10 14:35:11 -0700643 if (option == "profile-boot-class-path") {
644 existing.profile_boot_class_path_ = true;
645 return Result::SuccessNoValue();
646 }
647
Calin Juravle3105b272018-05-03 22:28:03 -0700648 if (option == "profile-aot-code") {
649 existing.profile_aot_code_ = true;
650 return Result::SuccessNoValue();
651 }
652
653 if (option == "save-without-jit-notifications") {
654 existing.wait_for_jit_notifications_to_save_ = false;
655 return Result::SuccessNoValue();
656 }
657
Calin Juravle138dbff2016-06-28 19:36:58 +0100658 // The rest of these options are always the wildcard from '-Xps-*'
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800659 std::string suffix = RemovePrefix(option);
660
Andreas Gampe9186ced2016-12-12 14:28:21 -0800661 if (android::base::StartsWith(option, "min-save-period-ms:")) {
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800662 CmdlineType<unsigned int> type_parser;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800663 return ParseInto(existing,
Calin Juravle138dbff2016-06-28 19:36:58 +0100664 &ProfileSaverOptions::min_save_period_ms_,
665 type_parser.Parse(suffix));
666 }
Andreas Gampe9186ced2016-12-12 14:28:21 -0800667 if (android::base::StartsWith(option, "save-resolved-classes-delay-ms:")) {
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800668 CmdlineType<unsigned int> type_parser;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800669 return ParseInto(existing,
Calin Juravle138dbff2016-06-28 19:36:58 +0100670 &ProfileSaverOptions::save_resolved_classes_delay_ms_,
671 type_parser.Parse(suffix));
672 }
Mathieu Chartier7b135c82017-06-05 12:54:01 -0700673 if (android::base::StartsWith(option, "hot-startup-method-samples:")) {
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800674 CmdlineType<unsigned int> type_parser;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800675 return ParseInto(existing,
Mathieu Chartier7b135c82017-06-05 12:54:01 -0700676 &ProfileSaverOptions::hot_startup_method_samples_,
Calin Juravle138dbff2016-06-28 19:36:58 +0100677 type_parser.Parse(suffix));
678 }
Andreas Gampe9186ced2016-12-12 14:28:21 -0800679 if (android::base::StartsWith(option, "min-methods-to-save:")) {
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800680 CmdlineType<unsigned int> type_parser;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800681 return ParseInto(existing,
Calin Juravle138dbff2016-06-28 19:36:58 +0100682 &ProfileSaverOptions::min_methods_to_save_,
683 type_parser.Parse(suffix));
684 }
Andreas Gampe9186ced2016-12-12 14:28:21 -0800685 if (android::base::StartsWith(option, "min-classes-to-save:")) {
Calin Juravle138dbff2016-06-28 19:36:58 +0100686 CmdlineType<unsigned int> type_parser;
687 return ParseInto(existing,
688 &ProfileSaverOptions::min_classes_to_save_,
689 type_parser.Parse(suffix));
690 }
Andreas Gampe9186ced2016-12-12 14:28:21 -0800691 if (android::base::StartsWith(option, "min-notification-before-wake:")) {
Calin Juravle138dbff2016-06-28 19:36:58 +0100692 CmdlineType<unsigned int> type_parser;
693 return ParseInto(existing,
694 &ProfileSaverOptions::min_notification_before_wake_,
695 type_parser.Parse(suffix));
696 }
Andreas Gampe9186ced2016-12-12 14:28:21 -0800697 if (android::base::StartsWith(option, "max-notification-before-wake:")) {
Calin Juravle138dbff2016-06-28 19:36:58 +0100698 CmdlineType<unsigned int> type_parser;
699 return ParseInto(existing,
700 &ProfileSaverOptions::max_notification_before_wake_,
701 type_parser.Parse(suffix));
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800702 }
Calin Juravle9545f6d2017-03-16 19:05:09 -0700703 if (android::base::StartsWith(option, "profile-path:")) {
704 existing.profile_path_ = suffix;
705 return Result::SuccessNoValue();
706 }
707
708 return Result::Failure(std::string("Invalid suboption '") + option + "'");
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800709 }
710
Calin Juravle138dbff2016-06-28 19:36:58 +0100711 static const char* Name() { return "ProfileSaverOptions"; }
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800712 static constexpr bool kCanParseBlankless = true;
713};
714
Alex Lighteb7c1442015-08-31 13:17:42 -0700715template<>
716struct CmdlineType<ExperimentalFlags> : CmdlineTypeParser<ExperimentalFlags> {
717 Result ParseAndAppend(const std::string& option, ExperimentalFlags& existing) {
718 if (option == "none") {
Neil Fuller9724c632016-01-07 15:42:47 +0000719 existing = ExperimentalFlags::kNone;
Alex Lighteb7c1442015-08-31 13:17:42 -0700720 } else {
721 return Result::Failure(std::string("Unknown option '") + option + "'");
722 }
723 return Result::SuccessNoValue();
724 }
725
726 static const char* Name() { return "ExperimentalFlags"; }
727};
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800728} // namespace art
729#endif // ART_CMDLINE_CMDLINE_TYPES_H_