blob: 25902f1809c57b3b7a516c501685b6498df4f61b [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 Gampe85f1c572018-11-21 13:52:48 -080027#include "android-base/logging.h"
Andreas Gampe9186ced2016-12-12 14:28:21 -080028#include "android-base/strings.h"
29
Igor Murashkinaaebaa02015-01-26 10:55:53 -080030// Includes for the types that are being specialized
31#include <string>
Vladimir Marko88b2b802015-12-04 14:19:04 +000032#include "base/time_utils.h"
Alex Lightfc588092020-01-23 15:39:08 -080033#include "base/logging.h"
Vladimir Marko88b2b802015-12-04 14:19:04 +000034#include "experimental_flags.h"
Igor Murashkinaaebaa02015-01-26 10:55:53 -080035#include "gc/collector_type.h"
36#include "gc/space/large_object_space.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"
Alex Lightfbf96702017-12-14 13:27:13 -080077 "Example: -XjdwpProvider:adbconnection for adb connection mediated jdwp implementation\n"
Alex Light2183d4d2018-01-26 14:24:54 -080078 "Example: -XjdwpProvider:default for the default jdwp implementation\n");
79 } else if (option == "default") {
80 return Result::Success(JdwpProvider::kDefaultJdwpProvider);
Alex Light4650d4a2018-01-24 00:33:49 +000081 } else if (option == "adbconnection") {
Alex Lightfbf96702017-12-14 13:27:13 -080082 return Result::Success(JdwpProvider::kAdbConnection);
Alex Light40320712017-12-14 11:52:04 -080083 } else if (option == "none") {
84 return Result::Success(JdwpProvider::kNone);
Igor Murashkinaaebaa02015-01-26 10:55:53 -080085 } else {
Alex Light40320712017-12-14 11:52:04 -080086 return Result::Failure(std::string("not a valid jdwp provider: ") + option);
Igor Murashkinaaebaa02015-01-26 10:55:53 -080087 }
Igor Murashkinaaebaa02015-01-26 10:55:53 -080088 }
Alex Light40320712017-12-14 11:52:04 -080089 static const char* Name() { return "JdwpProvider"; }
Igor Murashkinaaebaa02015-01-26 10:55:53 -080090};
91
92template <size_t Divisor>
93struct CmdlineType<Memory<Divisor>> : CmdlineTypeParser<Memory<Divisor>> {
94 using typename CmdlineTypeParser<Memory<Divisor>>::Result;
95
Vladimir Marko5c657fe2016-11-03 15:12:29 +000096 Result Parse(const std::string& arg) {
Igor Murashkinaaebaa02015-01-26 10:55:53 -080097 CMDLINE_DEBUG_LOG << "Parsing memory: " << arg << std::endl;
98 size_t val = ParseMemoryOption(arg.c_str(), Divisor);
99 CMDLINE_DEBUG_LOG << "Memory parsed to size_t value: " << val << std::endl;
100
101 if (val == 0) {
102 return Result::Failure(std::string("not a valid memory value, or not divisible by ")
103 + std::to_string(Divisor));
104 }
105
106 return Result::Success(Memory<Divisor>(val));
107 }
108
109 // Parse a string of the form /[0-9]+[kKmMgG]?/, which is used to specify
110 // memory sizes. [kK] indicates kilobytes, [mM] megabytes, and
111 // [gG] gigabytes.
112 //
113 // "s" should point just past the "-Xm?" part of the string.
114 // "div" specifies a divisor, e.g. 1024 if the value must be a multiple
115 // of 1024.
116 //
117 // The spec says the -Xmx and -Xms options must be multiples of 1024. It
118 // doesn't say anything about -Xss.
119 //
120 // Returns 0 (a useless size) if "s" is malformed or specifies a low or
121 // non-evenly-divisible value.
122 //
123 static size_t ParseMemoryOption(const char* s, size_t div) {
124 // strtoul accepts a leading [+-], which we don't want,
125 // so make sure our string starts with a decimal digit.
126 if (isdigit(*s)) {
127 char* s2;
128 size_t val = strtoul(s, &s2, 10);
129 if (s2 != s) {
130 // s2 should be pointing just after the number.
131 // If this is the end of the string, the user
132 // has specified a number of bytes. Otherwise,
133 // there should be exactly one more character
134 // that specifies a multiplier.
135 if (*s2 != '\0') {
136 // The remainder of the string is either a single multiplier
137 // character, or nothing to indicate that the value is in
138 // bytes.
139 char c = *s2++;
140 if (*s2 == '\0') {
141 size_t mul;
142 if (c == '\0') {
143 mul = 1;
144 } else if (c == 'k' || c == 'K') {
145 mul = KB;
146 } else if (c == 'm' || c == 'M') {
147 mul = MB;
148 } else if (c == 'g' || c == 'G') {
149 mul = GB;
150 } else {
151 // Unknown multiplier character.
152 return 0;
153 }
154
155 if (val <= std::numeric_limits<size_t>::max() / mul) {
156 val *= mul;
157 } else {
158 // Clamp to a multiple of 1024.
159 val = std::numeric_limits<size_t>::max() & ~(1024-1);
160 }
161 } else {
162 // There's more than one character after the numeric part.
163 return 0;
164 }
165 }
166 // The man page says that a -Xm value must be a multiple of 1024.
167 if (val % div == 0) {
168 return val;
169 }
170 }
171 }
172 return 0;
173 }
174
175 static const char* Name() { return Memory<Divisor>::Name(); }
176};
177
178template <>
179struct CmdlineType<double> : CmdlineTypeParser<double> {
180 Result Parse(const std::string& str) {
181 char* end = nullptr;
182 errno = 0;
183 double value = strtod(str.c_str(), &end);
184
185 if (*end != '\0') {
186 return Result::Failure("Failed to parse double from " + str);
187 }
188 if (errno == ERANGE) {
189 return Result::OutOfRange(
190 "Failed to parse double from " + str + "; overflow/underflow occurred");
191 }
192
193 return Result::Success(value);
194 }
195
196 static const char* Name() { return "double"; }
197};
198
Andreas Gampe097f34c2017-08-23 08:57:51 -0700199template <typename T>
200static inline CmdlineParseResult<T> ParseNumeric(const std::string& str) {
201 static_assert(sizeof(T) < sizeof(long long int), // NOLINT [runtime/int] [4]
202 "Current support is restricted.");
203
204 const char* begin = str.c_str();
205 char* end;
206
207 // Parse into a larger type (long long) because we can't use strtoul
208 // since it silently converts negative values into unsigned long and doesn't set errno.
209 errno = 0;
210 long long int result = strtoll(begin, &end, 10); // NOLINT [runtime/int] [4]
211 if (begin == end || *end != '\0' || errno == EINVAL) {
212 return CmdlineParseResult<T>::Failure("Failed to parse integer from " + str);
213 } else if ((errno == ERANGE) || // NOLINT [runtime/int] [4]
214 result < std::numeric_limits<T>::min() || result > std::numeric_limits<T>::max()) {
215 return CmdlineParseResult<T>::OutOfRange(
216 "Failed to parse integer from " + str + "; out of range");
217 }
218
219 return CmdlineParseResult<T>::Success(static_cast<T>(result));
220}
221
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800222template <>
223struct CmdlineType<unsigned int> : CmdlineTypeParser<unsigned int> {
224 Result Parse(const std::string& str) {
Andreas Gampe097f34c2017-08-23 08:57:51 -0700225 return ParseNumeric<unsigned int>(str);
226 }
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800227
Andreas Gampe097f34c2017-08-23 08:57:51 -0700228 static const char* Name() { return "unsigned integer"; }
229};
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800230
Andreas Gampe097f34c2017-08-23 08:57:51 -0700231template <>
232struct CmdlineType<int> : CmdlineTypeParser<int> {
233 Result Parse(const std::string& str) {
234 return ParseNumeric<int>(str);
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800235 }
236
Hans Boehmb2155572019-03-27 14:25:53 -0700237 static const char* Name() { return "integer"; }
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800238};
239
240// Lightweight nanosecond value type. Allows parser to convert user-input from milliseconds
241// to nanoseconds automatically after parsing.
242//
243// All implicit conversion from uint64_t uses nanoseconds.
244struct MillisecondsToNanoseconds {
245 // Create from nanoseconds.
246 MillisecondsToNanoseconds(uint64_t nanoseconds) : nanoseconds_(nanoseconds) { // NOLINT [runtime/explicit] [5]
247 }
248
249 // Create from milliseconds.
250 static MillisecondsToNanoseconds FromMilliseconds(unsigned int milliseconds) {
251 return MillisecondsToNanoseconds(MsToNs(milliseconds));
252 }
253
254 // Get the underlying nanoseconds value.
255 uint64_t GetNanoseconds() const {
256 return nanoseconds_;
257 }
258
259 // Get the milliseconds value [via a conversion]. Loss of precision will occur.
260 uint64_t GetMilliseconds() const {
261 return NsToMs(nanoseconds_);
262 }
263
264 // Get the underlying nanoseconds value.
265 operator uint64_t() const {
266 return GetNanoseconds();
267 }
268
269 // Default constructors/copy-constructors.
270 MillisecondsToNanoseconds() : nanoseconds_(0ul) {}
Andreas Gampec801f0d2015-02-24 20:55:16 -0800271 MillisecondsToNanoseconds(const MillisecondsToNanoseconds&) = default;
272 MillisecondsToNanoseconds(MillisecondsToNanoseconds&&) = default;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800273
274 private:
275 uint64_t nanoseconds_;
276};
277
278template <>
279struct CmdlineType<MillisecondsToNanoseconds> : CmdlineTypeParser<MillisecondsToNanoseconds> {
280 Result Parse(const std::string& str) {
281 CmdlineType<unsigned int> uint_parser;
282 CmdlineParseResult<unsigned int> res = uint_parser.Parse(str);
283
284 if (res.IsSuccess()) {
285 return Result::Success(MillisecondsToNanoseconds::FromMilliseconds(res.GetValue()));
286 } else {
287 return Result::CastError(res);
288 }
289 }
290
291 static const char* Name() { return "MillisecondsToNanoseconds"; }
292};
293
294template <>
295struct CmdlineType<std::string> : CmdlineTypeParser<std::string> {
296 Result Parse(const std::string& args) {
297 return Result::Success(args);
298 }
299
300 Result ParseAndAppend(const std::string& args,
301 std::string& existing_value) {
302 if (existing_value.empty()) {
303 existing_value = args;
304 } else {
305 existing_value += ' ';
306 existing_value += args;
307 }
308 return Result::SuccessNoValue();
309 }
310};
311
312template <>
Alex Light185d1342016-08-11 10:48:03 -0700313struct CmdlineType<std::vector<Plugin>> : CmdlineTypeParser<std::vector<Plugin>> {
314 Result Parse(const std::string& args) {
315 assert(false && "Use AppendValues() for a Plugin vector type");
316 return Result::Failure("Unconditional failure: Plugin vector must be appended: " + args);
317 }
318
319 Result ParseAndAppend(const std::string& args,
320 std::vector<Plugin>& existing_value) {
321 existing_value.push_back(Plugin::Create(args));
322 return Result::SuccessNoValue();
323 }
324
325 static const char* Name() { return "std::vector<Plugin>"; }
326};
327
328template <>
Andreas Gampeaadcbc62017-12-28 14:05:42 -0800329struct CmdlineType<std::list<ti::AgentSpec>> : CmdlineTypeParser<std::list<ti::AgentSpec>> {
Alex Light7233c7e2016-07-28 10:07:45 -0700330 Result Parse(const std::string& args) {
Alex Light4b812fa2017-03-29 10:40:15 -0700331 assert(false && "Use AppendValues() for an Agent list type");
332 return Result::Failure("Unconditional failure: Agent list must be appended: " + args);
Alex Light7233c7e2016-07-28 10:07:45 -0700333 }
334
335 Result ParseAndAppend(const std::string& args,
Andreas Gampeaadcbc62017-12-28 14:05:42 -0800336 std::list<ti::AgentSpec>& existing_value) {
Leonard Mosescueb842212016-10-06 17:26:36 -0700337 existing_value.emplace_back(args);
Alex Light7233c7e2016-07-28 10:07:45 -0700338 return Result::SuccessNoValue();
339 }
340
Andreas Gampeaadcbc62017-12-28 14:05:42 -0800341 static const char* Name() { return "std::list<ti::AgentSpec>"; }
Alex Light7233c7e2016-07-28 10:07:45 -0700342};
343
344template <>
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800345struct CmdlineType<std::vector<std::string>> : CmdlineTypeParser<std::vector<std::string>> {
346 Result Parse(const std::string& args) {
347 assert(false && "Use AppendValues() for a string vector type");
348 return Result::Failure("Unconditional failure: string vector must be appended: " + args);
349 }
350
351 Result ParseAndAppend(const std::string& args,
352 std::vector<std::string>& existing_value) {
353 existing_value.push_back(args);
354 return Result::SuccessNoValue();
355 }
356
357 static const char* Name() { return "std::vector<std::string>"; }
358};
359
360template <char Separator>
361struct ParseStringList {
362 explicit ParseStringList(std::vector<std::string>&& list) : list_(list) {}
363
364 operator std::vector<std::string>() const {
365 return list_;
366 }
367
368 operator std::vector<std::string>&&() && {
369 return std::move(list_);
370 }
371
372 size_t Size() const {
373 return list_.size();
374 }
375
376 std::string Join() const {
Andreas Gampe9186ced2016-12-12 14:28:21 -0800377 return android::base::Join(list_, Separator);
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800378 }
379
380 static ParseStringList<Separator> Split(const std::string& str) {
381 std::vector<std::string> list;
382 art::Split(str, Separator, &list);
383 return ParseStringList<Separator>(std::move(list));
384 }
385
386 ParseStringList() = default;
Andreas Gampec801f0d2015-02-24 20:55:16 -0800387 ParseStringList(const ParseStringList&) = default;
388 ParseStringList(ParseStringList&&) = default;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800389
390 private:
391 std::vector<std::string> list_;
392};
393
394template <char Separator>
395struct CmdlineType<ParseStringList<Separator>> : CmdlineTypeParser<ParseStringList<Separator>> {
396 using Result = CmdlineParseResult<ParseStringList<Separator>>;
397
398 Result Parse(const std::string& args) {
399 return Result::Success(ParseStringList<Separator>::Split(args));
400 }
401
402 static const char* Name() { return "ParseStringList<Separator>"; }
403};
404
Orion Hodsonffc791c2019-11-14 19:19:28 +0000405template <>
406struct CmdlineType<std::vector<int32_t>> : CmdlineTypeParser<std::vector<int32_t>> {
407 using Result = CmdlineParseResult<std::vector<int32_t>>;
408
409 Result Parse(const std::string& args) {
410 std::vector<int32_t> list;
411 const char* pos = args.c_str();
412 errno = 0;
413
414 while (true) {
415 char* end = nullptr;
416 int64_t value = strtol(pos, &end, 10);
417 if (pos == end || errno == EINVAL) {
418 return Result::Failure("Failed to parse integer from " + args);
419 } else if ((errno == ERANGE) || // NOLINT [runtime/int] [4]
420 value < std::numeric_limits<int32_t>::min() ||
421 value > std::numeric_limits<int32_t>::max()) {
422 return Result::OutOfRange("Failed to parse integer from " + args + "; out of range");
423 }
424 list.push_back(static_cast<int32_t>(value));
425 if (*end == '\0') {
426 break;
427 } else if (*end != ',') {
428 return Result::Failure(std::string("Unexpected character: ") + *end);
429 }
430 pos = end + 1;
431 }
432 return Result::Success(std::move(list));
433 }
434
435 static const char* Name() { return "std::vector<int32_t>"; }
436};
437
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800438static gc::CollectorType ParseCollectorType(const std::string& option) {
439 if (option == "MS" || option == "nonconcurrent") {
440 return gc::kCollectorTypeMS;
441 } else if (option == "CMS" || option == "concurrent") {
442 return gc::kCollectorTypeCMS;
443 } else if (option == "SS") {
444 return gc::kCollectorTypeSS;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800445 } else if (option == "CC") {
446 return gc::kCollectorTypeCC;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800447 } else {
448 return gc::kCollectorTypeNone;
449 }
450}
451
452struct XGcOption {
453 // These defaults are used when the command line arguments for -Xgc:
454 // are either omitted completely or partially.
Hiroshi Yamauchi1b0adbf2016-11-14 17:35:12 -0800455 gc::CollectorType collector_type_ = gc::kCollectorTypeDefault;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800456 bool verify_pre_gc_heap_ = false;
457 bool verify_pre_sweeping_heap_ = kIsDebugBuild;
Albert Mingkun Yang0b4d1462018-11-29 13:25:35 +0000458 bool generational_cc = kEnableGenerationalCCByDefault;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800459 bool verify_post_gc_heap_ = false;
460 bool verify_pre_gc_rosalloc_ = kIsDebugBuild;
461 bool verify_pre_sweeping_rosalloc_ = false;
462 bool verify_post_gc_rosalloc_ = false;
Hiroshi Yamauchia9b296c2016-10-07 17:07:03 -0700463 // Do no measurements for kUseTableLookupReadBarrier to avoid test timeouts. b/31679493
464 bool measure_ = kIsDebugBuild && !kUseTableLookupReadBarrier;
Mathieu Chartier31000802015-06-14 14:14:37 -0700465 bool gcstress_ = false;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800466};
467
468template <>
469struct CmdlineType<XGcOption> : CmdlineTypeParser<XGcOption> {
470 Result Parse(const std::string& option) { // -Xgc: already stripped
Igor Murashkin5573c372017-11-16 13:34:30 -0800471 XGcOption xgc{};
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800472
473 std::vector<std::string> gc_options;
474 Split(option, ',', &gc_options);
475 for (const std::string& gc_option : gc_options) {
476 gc::CollectorType collector_type = ParseCollectorType(gc_option);
477 if (collector_type != gc::kCollectorTypeNone) {
478 xgc.collector_type_ = collector_type;
479 } else if (gc_option == "preverify") {
480 xgc.verify_pre_gc_heap_ = true;
481 } else if (gc_option == "nopreverify") {
482 xgc.verify_pre_gc_heap_ = false;
483 } else if (gc_option == "presweepingverify") {
484 xgc.verify_pre_sweeping_heap_ = true;
485 } else if (gc_option == "nopresweepingverify") {
486 xgc.verify_pre_sweeping_heap_ = false;
Albert Mingkun Yang0b4d1462018-11-29 13:25:35 +0000487 } else if (gc_option == "generational_cc") {
Roland Levillainb52cd382019-02-20 10:50:50 +0000488 // Note: Option "-Xgc:generational_cc" can be passed directly by
489 // app_process/zygote (see `android::AndroidRuntime::startVm`). If this
490 // option is ever deprecated, it should still be accepted (but ignored)
491 // for compatibility reasons (this should not prevent the runtime from
492 // starting up).
Albert Mingkun Yang0b4d1462018-11-29 13:25:35 +0000493 xgc.generational_cc = true;
494 } else if (gc_option == "nogenerational_cc") {
Roland Levillainb52cd382019-02-20 10:50:50 +0000495 // Note: Option "-Xgc:nogenerational_cc" can be passed directly by
496 // app_process/zygote (see `android::AndroidRuntime::startVm`). If this
497 // option is ever deprecated, it should still be accepted (but ignored)
498 // for compatibility reasons (this should not prevent the runtime from
499 // starting up).
Albert Mingkun Yang0b4d1462018-11-29 13:25:35 +0000500 xgc.generational_cc = false;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800501 } else if (gc_option == "postverify") {
502 xgc.verify_post_gc_heap_ = true;
503 } else if (gc_option == "nopostverify") {
504 xgc.verify_post_gc_heap_ = false;
505 } else if (gc_option == "preverify_rosalloc") {
506 xgc.verify_pre_gc_rosalloc_ = true;
507 } else if (gc_option == "nopreverify_rosalloc") {
508 xgc.verify_pre_gc_rosalloc_ = false;
509 } else if (gc_option == "presweepingverify_rosalloc") {
510 xgc.verify_pre_sweeping_rosalloc_ = true;
511 } else if (gc_option == "nopresweepingverify_rosalloc") {
512 xgc.verify_pre_sweeping_rosalloc_ = false;
513 } else if (gc_option == "postverify_rosalloc") {
514 xgc.verify_post_gc_rosalloc_ = true;
515 } else if (gc_option == "nopostverify_rosalloc") {
516 xgc.verify_post_gc_rosalloc_ = false;
Mathieu Chartier31000802015-06-14 14:14:37 -0700517 } else if (gc_option == "gcstress") {
518 xgc.gcstress_ = true;
519 } else if (gc_option == "nogcstress") {
520 xgc.gcstress_ = false;
Mathieu Chartier56fe2582016-07-14 13:30:03 -0700521 } else if (gc_option == "measure") {
522 xgc.measure_ = true;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800523 } else if ((gc_option == "precise") ||
524 (gc_option == "noprecise") ||
525 (gc_option == "verifycardtable") ||
526 (gc_option == "noverifycardtable")) {
527 // Ignored for backwards compatibility.
528 } else {
529 return Result::Usage(std::string("Unknown -Xgc option ") + gc_option);
530 }
531 }
532
533 return Result::Success(std::move(xgc));
534 }
535
536 static const char* Name() { return "XgcOption"; }
537};
538
539struct BackgroundGcOption {
540 // If background_collector_type_ is kCollectorTypeNone, it defaults to the
541 // XGcOption::collector_type_ after parsing options. If you set this to
542 // kCollectorTypeHSpaceCompact then we will do an hspace compaction when
543 // we transition to background instead of a normal collector transition.
544 gc::CollectorType background_collector_type_;
545
546 BackgroundGcOption(gc::CollectorType background_collector_type) // NOLINT [runtime/explicit] [5]
547 : background_collector_type_(background_collector_type) {}
548 BackgroundGcOption()
549 : background_collector_type_(gc::kCollectorTypeNone) {
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800550 }
551
552 operator gc::CollectorType() const { return background_collector_type_; }
553};
554
555template<>
556struct CmdlineType<BackgroundGcOption>
557 : CmdlineTypeParser<BackgroundGcOption>, private BackgroundGcOption {
558 Result Parse(const std::string& substring) {
559 // Special handling for HSpaceCompact since this is only valid as a background GC type.
560 if (substring == "HSpaceCompact") {
561 background_collector_type_ = gc::kCollectorTypeHomogeneousSpaceCompact;
562 } else {
563 gc::CollectorType collector_type = ParseCollectorType(substring);
564 if (collector_type != gc::kCollectorTypeNone) {
565 background_collector_type_ = collector_type;
566 } else {
567 return Result::Failure();
568 }
569 }
570
571 BackgroundGcOption res = *this;
572 return Result::Success(res);
573 }
574
575 static const char* Name() { return "BackgroundGcOption"; }
576};
577
578template <>
579struct CmdlineType<LogVerbosity> : CmdlineTypeParser<LogVerbosity> {
580 Result Parse(const std::string& options) {
581 LogVerbosity log_verbosity = LogVerbosity();
582
583 std::vector<std::string> verbose_options;
584 Split(options, ',', &verbose_options);
585 for (size_t j = 0; j < verbose_options.size(); ++j) {
586 if (verbose_options[j] == "class") {
587 log_verbosity.class_linker = true;
Mathieu Chartier66a55392016-02-19 10:25:39 -0800588 } else if (verbose_options[j] == "collector") {
589 log_verbosity.collector = true;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800590 } else if (verbose_options[j] == "compiler") {
591 log_verbosity.compiler = true;
Andreas Gampef3d1f942015-05-18 21:41:13 -0700592 } else if (verbose_options[j] == "deopt") {
593 log_verbosity.deopt = true;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800594 } else if (verbose_options[j] == "gc") {
595 log_verbosity.gc = true;
596 } else if (verbose_options[j] == "heap") {
597 log_verbosity.heap = true;
Mathieu Chartier765b2a02019-05-02 11:04:13 -0700598 } else if (verbose_options[j] == "interpreter") {
599 log_verbosity.interpreter = true;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800600 } else if (verbose_options[j] == "jdwp") {
601 log_verbosity.jdwp = true;
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800602 } else if (verbose_options[j] == "jit") {
603 log_verbosity.jit = true;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800604 } else if (verbose_options[j] == "jni") {
605 log_verbosity.jni = true;
606 } else if (verbose_options[j] == "monitor") {
607 log_verbosity.monitor = true;
Richard Uhler66d874d2015-01-15 09:37:19 -0800608 } else if (verbose_options[j] == "oat") {
609 log_verbosity.oat = true;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800610 } else if (verbose_options[j] == "profiler") {
611 log_verbosity.profiler = true;
612 } else if (verbose_options[j] == "signals") {
613 log_verbosity.signals = true;
Phil Wang751beff2015-08-28 15:17:15 +0800614 } else if (verbose_options[j] == "simulator") {
615 log_verbosity.simulator = true;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800616 } else if (verbose_options[j] == "startup") {
617 log_verbosity.startup = true;
618 } else if (verbose_options[j] == "third-party-jni") {
619 log_verbosity.third_party_jni = true;
620 } else if (verbose_options[j] == "threads") {
621 log_verbosity.threads = true;
622 } else if (verbose_options[j] == "verifier") {
623 log_verbosity.verifier = true;
Andreas Gampe92d77202017-12-06 20:49:00 -0800624 } else if (verbose_options[j] == "verifier-debug") {
625 log_verbosity.verifier_debug = true;
Mathieu Chartierfbc31082016-01-24 11:59:56 -0800626 } else if (verbose_options[j] == "image") {
627 log_verbosity.image = true;
Andreas Gampec7ed09b2016-04-25 20:08:55 -0700628 } else if (verbose_options[j] == "systrace-locks") {
629 log_verbosity.systrace_lock_logging = true;
Nicolas Geoffray4ac0e152019-09-18 06:14:50 +0000630 } else if (verbose_options[j] == "plugin") {
631 log_verbosity.plugin = true;
Alex Light7233c7e2016-07-28 10:07:45 -0700632 } else if (verbose_options[j] == "agents") {
633 log_verbosity.agents = true;
Andreas Gampebec07a02017-04-11 13:48:37 -0700634 } else if (verbose_options[j] == "dex") {
635 log_verbosity.dex = true;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800636 } else {
637 return Result::Usage(std::string("Unknown -verbose option ") + verbose_options[j]);
638 }
639 }
640
641 return Result::Success(log_verbosity);
642 }
643
644 static const char* Name() { return "LogVerbosity"; }
645};
646
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800647template <>
Calin Juravle138dbff2016-06-28 19:36:58 +0100648struct CmdlineType<ProfileSaverOptions> : CmdlineTypeParser<ProfileSaverOptions> {
649 using Result = CmdlineParseResult<ProfileSaverOptions>;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800650
651 private:
652 using StringResult = CmdlineParseResult<std::string>;
653 using DoubleResult = CmdlineParseResult<double>;
654
655 template <typename T>
Calin Juravle138dbff2016-06-28 19:36:58 +0100656 static Result ParseInto(ProfileSaverOptions& options,
657 T ProfileSaverOptions::*pField,
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800658 CmdlineParseResult<T>&& result) {
659 assert(pField != nullptr);
660
661 if (result.IsSuccess()) {
662 options.*pField = result.ReleaseValue();
663 return Result::SuccessNoValue();
664 }
665
666 return Result::CastError(result);
667 }
668
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800669 static std::string RemovePrefix(const std::string& source) {
Andreas Gampeca620d72016-11-08 08:09:33 -0800670 size_t prefix_idx = source.find(':');
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800671
672 if (prefix_idx == std::string::npos) {
673 return "";
674 }
675
676 return source.substr(prefix_idx + 1);
677 }
678
679 public:
Calin Juravle138dbff2016-06-28 19:36:58 +0100680 Result ParseAndAppend(const std::string& option, ProfileSaverOptions& existing) {
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800681 // Special case which doesn't include a wildcard argument definition.
682 // We pass-it through as-is.
Calin Juravle138dbff2016-06-28 19:36:58 +0100683 if (option == "-Xjitsaveprofilinginfo") {
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800684 existing.enabled_ = true;
685 return Result::SuccessNoValue();
686 }
687
Mathieu Chartier885a7132017-06-10 14:35:11 -0700688 if (option == "profile-boot-class-path") {
689 existing.profile_boot_class_path_ = true;
690 return Result::SuccessNoValue();
691 }
692
Calin Juravleb3d1eee2018-05-03 22:28:03 -0700693 if (option == "profile-aot-code") {
694 existing.profile_aot_code_ = true;
695 return Result::SuccessNoValue();
696 }
697
698 if (option == "save-without-jit-notifications") {
699 existing.wait_for_jit_notifications_to_save_ = false;
700 return Result::SuccessNoValue();
701 }
702
Calin Juravle138dbff2016-06-28 19:36:58 +0100703 // The rest of these options are always the wildcard from '-Xps-*'
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800704 std::string suffix = RemovePrefix(option);
705
Andreas Gampe9186ced2016-12-12 14:28:21 -0800706 if (android::base::StartsWith(option, "min-save-period-ms:")) {
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800707 CmdlineType<unsigned int> type_parser;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800708 return ParseInto(existing,
Calin Juravle138dbff2016-06-28 19:36:58 +0100709 &ProfileSaverOptions::min_save_period_ms_,
710 type_parser.Parse(suffix));
711 }
Andreas Gampe9186ced2016-12-12 14:28:21 -0800712 if (android::base::StartsWith(option, "save-resolved-classes-delay-ms:")) {
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800713 CmdlineType<unsigned int> type_parser;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800714 return ParseInto(existing,
Calin Juravle138dbff2016-06-28 19:36:58 +0100715 &ProfileSaverOptions::save_resolved_classes_delay_ms_,
716 type_parser.Parse(suffix));
717 }
Mathieu Chartier7b135c82017-06-05 12:54:01 -0700718 if (android::base::StartsWith(option, "hot-startup-method-samples:")) {
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800719 CmdlineType<unsigned int> type_parser;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800720 return ParseInto(existing,
Mathieu Chartier7b135c82017-06-05 12:54:01 -0700721 &ProfileSaverOptions::hot_startup_method_samples_,
Calin Juravle138dbff2016-06-28 19:36:58 +0100722 type_parser.Parse(suffix));
723 }
Andreas Gampe9186ced2016-12-12 14:28:21 -0800724 if (android::base::StartsWith(option, "min-methods-to-save:")) {
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800725 CmdlineType<unsigned int> type_parser;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800726 return ParseInto(existing,
Calin Juravle138dbff2016-06-28 19:36:58 +0100727 &ProfileSaverOptions::min_methods_to_save_,
728 type_parser.Parse(suffix));
729 }
Andreas Gampe9186ced2016-12-12 14:28:21 -0800730 if (android::base::StartsWith(option, "min-classes-to-save:")) {
Calin Juravle138dbff2016-06-28 19:36:58 +0100731 CmdlineType<unsigned int> type_parser;
732 return ParseInto(existing,
733 &ProfileSaverOptions::min_classes_to_save_,
734 type_parser.Parse(suffix));
735 }
Andreas Gampe9186ced2016-12-12 14:28:21 -0800736 if (android::base::StartsWith(option, "min-notification-before-wake:")) {
Calin Juravle138dbff2016-06-28 19:36:58 +0100737 CmdlineType<unsigned int> type_parser;
738 return ParseInto(existing,
739 &ProfileSaverOptions::min_notification_before_wake_,
740 type_parser.Parse(suffix));
741 }
Andreas Gampe9186ced2016-12-12 14:28:21 -0800742 if (android::base::StartsWith(option, "max-notification-before-wake:")) {
Calin Juravle138dbff2016-06-28 19:36:58 +0100743 CmdlineType<unsigned int> type_parser;
744 return ParseInto(existing,
745 &ProfileSaverOptions::max_notification_before_wake_,
746 type_parser.Parse(suffix));
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800747 }
Calin Juravle9545f6d2017-03-16 19:05:09 -0700748 if (android::base::StartsWith(option, "profile-path:")) {
749 existing.profile_path_ = suffix;
750 return Result::SuccessNoValue();
751 }
752
753 return Result::Failure(std::string("Invalid suboption '") + option + "'");
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800754 }
755
Calin Juravle138dbff2016-06-28 19:36:58 +0100756 static const char* Name() { return "ProfileSaverOptions"; }
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800757 static constexpr bool kCanParseBlankless = true;
758};
759
Alex Lighteb7c1442015-08-31 13:17:42 -0700760template<>
761struct CmdlineType<ExperimentalFlags> : CmdlineTypeParser<ExperimentalFlags> {
762 Result ParseAndAppend(const std::string& option, ExperimentalFlags& existing) {
763 if (option == "none") {
Neil Fuller9724c632016-01-07 15:42:47 +0000764 existing = ExperimentalFlags::kNone;
Alex Lighteb7c1442015-08-31 13:17:42 -0700765 } else {
766 return Result::Failure(std::string("Unknown option '") + option + "'");
767 }
768 return Result::SuccessNoValue();
769 }
770
771 static const char* Name() { return "ExperimentalFlags"; }
772};
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800773} // namespace art
774#endif // ART_CMDLINE_CMDLINE_TYPES_H_