blob: 185a0e403ed74dddf1b057e2bac9e89d686f2fd5 [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
Vladimir Marko88b2b802015-12-04 14:19:04 +000023#include "memory_representation.h"
24#include "detail/cmdline_debug_detail.h"
Igor Murashkinaaebaa02015-01-26 10:55:53 -080025#include "cmdline_type_parser.h"
26
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"
Calin Juravle138dbff2016-06-28 19:36:58 +010037#include "jit/profile_saver_options.h"
Alex Light185d1342016-08-11 10:48:03 -070038#include "plugin.h"
Alex Light7233c7e2016-07-28 10:07:45 -070039#include "ti/agent.h"
40#include "unit.h"
Igor Murashkinaaebaa02015-01-26 10:55:53 -080041
42namespace art {
43
44// The default specialization will always fail parsing the type from a string.
45// Provide your own specialization that inherits from CmdlineTypeParser<T>
46// and implements either Parse or ParseAndAppend
47// (only if the argument was defined with ::AppendValues()) but not both.
48template <typename T>
49struct CmdlineType : CmdlineTypeParser<T> {
50};
51
52// Specializations for CmdlineType<T> follow:
53
54// Parse argument definitions for Unit-typed arguments.
55template <>
56struct CmdlineType<Unit> : CmdlineTypeParser<Unit> {
57 Result Parse(const std::string& args) {
58 if (args == "") {
59 return Result::Success(Unit{}); // NOLINT [whitespace/braces] [5]
60 }
61 return Result::Failure("Unexpected extra characters " + args);
62 }
63};
64
65template <>
66struct CmdlineType<JDWP::JdwpOptions> : CmdlineTypeParser<JDWP::JdwpOptions> {
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +010067 /*
68 * Handle one of the JDWP name/value pairs.
69 *
70 * JDWP options are:
71 * help: if specified, show help message and bail
72 * transport: may be dt_socket or dt_shmem
73 * address: for dt_socket, "host:port", or just "port" when listening
74 * server: if "y", wait for debugger to attach; if "n", attach to debugger
75 * timeout: how long to wait for debugger to connect / listen
76 *
77 * Useful with server=n (these aren't supported yet):
78 * onthrow=<exception-name>: connect to debugger when exception thrown
79 * onuncaught=y|n: connect to debugger when uncaught exception thrown
80 * launch=<command-line>: launch the debugger itself
81 *
82 * The "transport" option is required, as is "address" if server=n.
83 */
Igor Murashkinaaebaa02015-01-26 10:55:53 -080084 Result Parse(const std::string& options) {
85 VLOG(jdwp) << "ParseJdwpOptions: " << options;
86
87 if (options == "help") {
88 return Result::Usage(
89 "Example: -Xrunjdwp:transport=dt_socket,address=8000,server=y\n"
90 "Example: -Xrunjdwp:transport=dt_socket,address=localhost:6500,server=n\n");
91 }
92
93 const std::string s;
94
95 std::vector<std::string> pairs;
96 Split(options, ',', &pairs);
97
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +010098 JDWP::JdwpOptions jdwp_options;
Igor Murashkinaaebaa02015-01-26 10:55:53 -080099
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +0100100 for (const std::string& jdwp_option : pairs) {
101 std::string::size_type equals_pos = jdwp_option.find('=');
102 if (equals_pos == std::string::npos) {
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800103 return Result::Failure(s +
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +0100104 "Can't parse JDWP option '" + jdwp_option + "' in '" + options + "'");
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800105 }
106
Sebastien Hertzb3b173b2015-02-06 09:16:32 +0100107 Result parse_attempt = ParseJdwpOption(jdwp_option.substr(0, equals_pos),
108 jdwp_option.substr(equals_pos + 1),
109 &jdwp_options);
110 if (parse_attempt.IsError()) {
111 // We fail to parse this JDWP option.
112 return parse_attempt;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800113 }
114 }
115
116 if (jdwp_options.transport == JDWP::kJdwpTransportUnknown) {
117 return Result::Failure(s + "Must specify JDWP transport: " + options);
118 }
119 if (!jdwp_options.server && (jdwp_options.host.empty() || jdwp_options.port == 0)) {
120 return Result::Failure(s + "Must specify JDWP host and port when server=n: " + options);
121 }
122
123 return Result::Success(std::move(jdwp_options));
124 }
125
Sebastien Hertzb3b173b2015-02-06 09:16:32 +0100126 Result ParseJdwpOption(const std::string& name, const std::string& value,
127 JDWP::JdwpOptions* jdwp_options) {
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800128 if (name == "transport") {
129 if (value == "dt_socket") {
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +0100130 jdwp_options->transport = JDWP::kJdwpTransportSocket;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800131 } else if (value == "dt_android_adb") {
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +0100132 jdwp_options->transport = JDWP::kJdwpTransportAndroidAdb;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800133 } else {
Sebastien Hertzb3b173b2015-02-06 09:16:32 +0100134 return Result::Failure("JDWP transport not supported: " + value);
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800135 }
136 } else if (name == "server") {
137 if (value == "n") {
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +0100138 jdwp_options->server = false;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800139 } else if (value == "y") {
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +0100140 jdwp_options->server = true;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800141 } else {
Sebastien Hertzb3b173b2015-02-06 09:16:32 +0100142 return Result::Failure("JDWP option 'server' must be 'y' or 'n'");
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800143 }
144 } else if (name == "suspend") {
145 if (value == "n") {
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +0100146 jdwp_options->suspend = false;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800147 } else if (value == "y") {
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +0100148 jdwp_options->suspend = true;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800149 } else {
Sebastien Hertzb3b173b2015-02-06 09:16:32 +0100150 return Result::Failure("JDWP option 'suspend' must be 'y' or 'n'");
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800151 }
152 } else if (name == "address") {
153 /* this is either <port> or <host>:<port> */
154 std::string port_string;
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +0100155 jdwp_options->host.clear();
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800156 std::string::size_type colon = value.find(':');
157 if (colon != std::string::npos) {
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +0100158 jdwp_options->host = value.substr(0, colon);
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800159 port_string = value.substr(colon + 1);
160 } else {
161 port_string = value;
162 }
163 if (port_string.empty()) {
Sebastien Hertzb3b173b2015-02-06 09:16:32 +0100164 return Result::Failure("JDWP address missing port: " + value);
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800165 }
166 char* end;
167 uint64_t port = strtoul(port_string.c_str(), &end, 10);
168 if (*end != '\0' || port > 0xffff) {
Sebastien Hertzb3b173b2015-02-06 09:16:32 +0100169 return Result::Failure("JDWP address has junk in port field: " + value);
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800170 }
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +0100171 jdwp_options->port = port;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800172 } else if (name == "launch" || name == "onthrow" || name == "oncaught" || name == "timeout") {
173 /* valid but unsupported */
174 LOG(INFO) << "Ignoring JDWP option '" << name << "'='" << value << "'";
175 } else {
176 LOG(INFO) << "Ignoring unrecognized JDWP option '" << name << "'='" << value << "'";
177 }
178
Sebastien Hertzb3b173b2015-02-06 09:16:32 +0100179 return Result::SuccessNoValue();
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800180 }
181
182 static const char* Name() { return "JdwpOptions"; }
183};
184
185template <size_t Divisor>
186struct CmdlineType<Memory<Divisor>> : CmdlineTypeParser<Memory<Divisor>> {
187 using typename CmdlineTypeParser<Memory<Divisor>>::Result;
188
Vladimir Marko5c657fe2016-11-03 15:12:29 +0000189 Result Parse(const std::string& arg) {
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800190 CMDLINE_DEBUG_LOG << "Parsing memory: " << arg << std::endl;
191 size_t val = ParseMemoryOption(arg.c_str(), Divisor);
192 CMDLINE_DEBUG_LOG << "Memory parsed to size_t value: " << val << std::endl;
193
194 if (val == 0) {
195 return Result::Failure(std::string("not a valid memory value, or not divisible by ")
196 + std::to_string(Divisor));
197 }
198
199 return Result::Success(Memory<Divisor>(val));
200 }
201
202 // Parse a string of the form /[0-9]+[kKmMgG]?/, which is used to specify
203 // memory sizes. [kK] indicates kilobytes, [mM] megabytes, and
204 // [gG] gigabytes.
205 //
206 // "s" should point just past the "-Xm?" part of the string.
207 // "div" specifies a divisor, e.g. 1024 if the value must be a multiple
208 // of 1024.
209 //
210 // The spec says the -Xmx and -Xms options must be multiples of 1024. It
211 // doesn't say anything about -Xss.
212 //
213 // Returns 0 (a useless size) if "s" is malformed or specifies a low or
214 // non-evenly-divisible value.
215 //
216 static size_t ParseMemoryOption(const char* s, size_t div) {
217 // strtoul accepts a leading [+-], which we don't want,
218 // so make sure our string starts with a decimal digit.
219 if (isdigit(*s)) {
220 char* s2;
221 size_t val = strtoul(s, &s2, 10);
222 if (s2 != s) {
223 // s2 should be pointing just after the number.
224 // If this is the end of the string, the user
225 // has specified a number of bytes. Otherwise,
226 // there should be exactly one more character
227 // that specifies a multiplier.
228 if (*s2 != '\0') {
229 // The remainder of the string is either a single multiplier
230 // character, or nothing to indicate that the value is in
231 // bytes.
232 char c = *s2++;
233 if (*s2 == '\0') {
234 size_t mul;
235 if (c == '\0') {
236 mul = 1;
237 } else if (c == 'k' || c == 'K') {
238 mul = KB;
239 } else if (c == 'm' || c == 'M') {
240 mul = MB;
241 } else if (c == 'g' || c == 'G') {
242 mul = GB;
243 } else {
244 // Unknown multiplier character.
245 return 0;
246 }
247
248 if (val <= std::numeric_limits<size_t>::max() / mul) {
249 val *= mul;
250 } else {
251 // Clamp to a multiple of 1024.
252 val = std::numeric_limits<size_t>::max() & ~(1024-1);
253 }
254 } else {
255 // There's more than one character after the numeric part.
256 return 0;
257 }
258 }
259 // The man page says that a -Xm value must be a multiple of 1024.
260 if (val % div == 0) {
261 return val;
262 }
263 }
264 }
265 return 0;
266 }
267
268 static const char* Name() { return Memory<Divisor>::Name(); }
269};
270
271template <>
272struct CmdlineType<double> : CmdlineTypeParser<double> {
273 Result Parse(const std::string& str) {
274 char* end = nullptr;
275 errno = 0;
276 double value = strtod(str.c_str(), &end);
277
278 if (*end != '\0') {
279 return Result::Failure("Failed to parse double from " + str);
280 }
281 if (errno == ERANGE) {
282 return Result::OutOfRange(
283 "Failed to parse double from " + str + "; overflow/underflow occurred");
284 }
285
286 return Result::Success(value);
287 }
288
289 static const char* Name() { return "double"; }
290};
291
292template <>
293struct CmdlineType<unsigned int> : CmdlineTypeParser<unsigned int> {
294 Result Parse(const std::string& str) {
295 const char* begin = str.c_str();
296 char* end;
297
298 // Parse into a larger type (long long) because we can't use strtoul
299 // since it silently converts negative values into unsigned long and doesn't set errno.
300 errno = 0;
301 long long int result = strtoll(begin, &end, 10); // NOLINT [runtime/int] [4]
302 if (begin == end || *end != '\0' || errno == EINVAL) {
303 return Result::Failure("Failed to parse integer from " + str);
304 } else if ((errno == ERANGE) || // NOLINT [runtime/int] [4]
305 result < std::numeric_limits<int>::min()
306 || result > std::numeric_limits<unsigned int>::max() || result < 0) {
307 return Result::OutOfRange(
308 "Failed to parse integer from " + str + "; out of unsigned int range");
309 }
310
311 return Result::Success(static_cast<unsigned int>(result));
312 }
313
314 static const char* Name() { return "unsigned integer"; }
315};
316
317// Lightweight nanosecond value type. Allows parser to convert user-input from milliseconds
318// to nanoseconds automatically after parsing.
319//
320// All implicit conversion from uint64_t uses nanoseconds.
321struct MillisecondsToNanoseconds {
322 // Create from nanoseconds.
323 MillisecondsToNanoseconds(uint64_t nanoseconds) : nanoseconds_(nanoseconds) { // NOLINT [runtime/explicit] [5]
324 }
325
326 // Create from milliseconds.
327 static MillisecondsToNanoseconds FromMilliseconds(unsigned int milliseconds) {
328 return MillisecondsToNanoseconds(MsToNs(milliseconds));
329 }
330
331 // Get the underlying nanoseconds value.
332 uint64_t GetNanoseconds() const {
333 return nanoseconds_;
334 }
335
336 // Get the milliseconds value [via a conversion]. Loss of precision will occur.
337 uint64_t GetMilliseconds() const {
338 return NsToMs(nanoseconds_);
339 }
340
341 // Get the underlying nanoseconds value.
342 operator uint64_t() const {
343 return GetNanoseconds();
344 }
345
346 // Default constructors/copy-constructors.
347 MillisecondsToNanoseconds() : nanoseconds_(0ul) {}
Andreas Gampec801f0d2015-02-24 20:55:16 -0800348 MillisecondsToNanoseconds(const MillisecondsToNanoseconds&) = default;
349 MillisecondsToNanoseconds(MillisecondsToNanoseconds&&) = default;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800350
351 private:
352 uint64_t nanoseconds_;
353};
354
355template <>
356struct CmdlineType<MillisecondsToNanoseconds> : CmdlineTypeParser<MillisecondsToNanoseconds> {
357 Result Parse(const std::string& str) {
358 CmdlineType<unsigned int> uint_parser;
359 CmdlineParseResult<unsigned int> res = uint_parser.Parse(str);
360
361 if (res.IsSuccess()) {
362 return Result::Success(MillisecondsToNanoseconds::FromMilliseconds(res.GetValue()));
363 } else {
364 return Result::CastError(res);
365 }
366 }
367
368 static const char* Name() { return "MillisecondsToNanoseconds"; }
369};
370
371template <>
372struct CmdlineType<std::string> : CmdlineTypeParser<std::string> {
373 Result Parse(const std::string& args) {
374 return Result::Success(args);
375 }
376
377 Result ParseAndAppend(const std::string& args,
378 std::string& existing_value) {
379 if (existing_value.empty()) {
380 existing_value = args;
381 } else {
382 existing_value += ' ';
383 existing_value += args;
384 }
385 return Result::SuccessNoValue();
386 }
387};
388
389template <>
Alex Light185d1342016-08-11 10:48:03 -0700390struct CmdlineType<std::vector<Plugin>> : CmdlineTypeParser<std::vector<Plugin>> {
391 Result Parse(const std::string& args) {
392 assert(false && "Use AppendValues() for a Plugin vector type");
393 return Result::Failure("Unconditional failure: Plugin vector must be appended: " + args);
394 }
395
396 Result ParseAndAppend(const std::string& args,
397 std::vector<Plugin>& existing_value) {
398 existing_value.push_back(Plugin::Create(args));
399 return Result::SuccessNoValue();
400 }
401
402 static const char* Name() { return "std::vector<Plugin>"; }
403};
404
405template <>
Alex Light4b812fa2017-03-29 10:40:15 -0700406struct CmdlineType<std::list<ti::Agent>> : CmdlineTypeParser<std::list<ti::Agent>> {
Alex Light7233c7e2016-07-28 10:07:45 -0700407 Result Parse(const std::string& args) {
Alex Light4b812fa2017-03-29 10:40:15 -0700408 assert(false && "Use AppendValues() for an Agent list type");
409 return Result::Failure("Unconditional failure: Agent list must be appended: " + args);
Alex Light7233c7e2016-07-28 10:07:45 -0700410 }
411
412 Result ParseAndAppend(const std::string& args,
Alex Light4b812fa2017-03-29 10:40:15 -0700413 std::list<ti::Agent>& existing_value) {
Leonard Mosescueb842212016-10-06 17:26:36 -0700414 existing_value.emplace_back(args);
Alex Light7233c7e2016-07-28 10:07:45 -0700415 return Result::SuccessNoValue();
416 }
417
Alex Light4b812fa2017-03-29 10:40:15 -0700418 static const char* Name() { return "std::list<ti::Agent>"; }
Alex Light7233c7e2016-07-28 10:07:45 -0700419};
420
421template <>
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800422struct CmdlineType<std::vector<std::string>> : CmdlineTypeParser<std::vector<std::string>> {
423 Result Parse(const std::string& args) {
424 assert(false && "Use AppendValues() for a string vector type");
425 return Result::Failure("Unconditional failure: string vector must be appended: " + args);
426 }
427
428 Result ParseAndAppend(const std::string& args,
429 std::vector<std::string>& existing_value) {
430 existing_value.push_back(args);
431 return Result::SuccessNoValue();
432 }
433
434 static const char* Name() { return "std::vector<std::string>"; }
435};
436
437template <char Separator>
438struct ParseStringList {
439 explicit ParseStringList(std::vector<std::string>&& list) : list_(list) {}
440
441 operator std::vector<std::string>() const {
442 return list_;
443 }
444
445 operator std::vector<std::string>&&() && {
446 return std::move(list_);
447 }
448
449 size_t Size() const {
450 return list_.size();
451 }
452
453 std::string Join() const {
Andreas Gampe9186ced2016-12-12 14:28:21 -0800454 return android::base::Join(list_, Separator);
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800455 }
456
457 static ParseStringList<Separator> Split(const std::string& str) {
458 std::vector<std::string> list;
459 art::Split(str, Separator, &list);
460 return ParseStringList<Separator>(std::move(list));
461 }
462
463 ParseStringList() = default;
Andreas Gampec801f0d2015-02-24 20:55:16 -0800464 ParseStringList(const ParseStringList&) = default;
465 ParseStringList(ParseStringList&&) = default;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800466
467 private:
468 std::vector<std::string> list_;
469};
470
471template <char Separator>
472struct CmdlineType<ParseStringList<Separator>> : CmdlineTypeParser<ParseStringList<Separator>> {
473 using Result = CmdlineParseResult<ParseStringList<Separator>>;
474
475 Result Parse(const std::string& args) {
476 return Result::Success(ParseStringList<Separator>::Split(args));
477 }
478
479 static const char* Name() { return "ParseStringList<Separator>"; }
480};
481
482static gc::CollectorType ParseCollectorType(const std::string& option) {
483 if (option == "MS" || option == "nonconcurrent") {
484 return gc::kCollectorTypeMS;
485 } else if (option == "CMS" || option == "concurrent") {
486 return gc::kCollectorTypeCMS;
487 } else if (option == "SS") {
488 return gc::kCollectorTypeSS;
489 } else if (option == "GSS") {
490 return gc::kCollectorTypeGSS;
491 } else if (option == "CC") {
492 return gc::kCollectorTypeCC;
493 } else if (option == "MC") {
494 return gc::kCollectorTypeMC;
495 } else {
496 return gc::kCollectorTypeNone;
497 }
498}
499
500struct XGcOption {
501 // These defaults are used when the command line arguments for -Xgc:
502 // are either omitted completely or partially.
Hiroshi Yamauchi1b0adbf2016-11-14 17:35:12 -0800503 gc::CollectorType collector_type_ = gc::kCollectorTypeDefault;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800504 bool verify_pre_gc_heap_ = false;
505 bool verify_pre_sweeping_heap_ = kIsDebugBuild;
506 bool verify_post_gc_heap_ = false;
507 bool verify_pre_gc_rosalloc_ = kIsDebugBuild;
508 bool verify_pre_sweeping_rosalloc_ = false;
509 bool verify_post_gc_rosalloc_ = false;
Hiroshi Yamauchia9b296c2016-10-07 17:07:03 -0700510 // Do no measurements for kUseTableLookupReadBarrier to avoid test timeouts. b/31679493
511 bool measure_ = kIsDebugBuild && !kUseTableLookupReadBarrier;
Mathieu Chartier31000802015-06-14 14:14:37 -0700512 bool gcstress_ = false;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800513};
514
515template <>
516struct CmdlineType<XGcOption> : CmdlineTypeParser<XGcOption> {
517 Result Parse(const std::string& option) { // -Xgc: already stripped
518 XGcOption xgc{}; // NOLINT [readability/braces] [4]
519
520 std::vector<std::string> gc_options;
521 Split(option, ',', &gc_options);
522 for (const std::string& gc_option : gc_options) {
523 gc::CollectorType collector_type = ParseCollectorType(gc_option);
524 if (collector_type != gc::kCollectorTypeNone) {
525 xgc.collector_type_ = collector_type;
526 } else if (gc_option == "preverify") {
527 xgc.verify_pre_gc_heap_ = true;
528 } else if (gc_option == "nopreverify") {
529 xgc.verify_pre_gc_heap_ = false;
530 } else if (gc_option == "presweepingverify") {
531 xgc.verify_pre_sweeping_heap_ = true;
532 } else if (gc_option == "nopresweepingverify") {
533 xgc.verify_pre_sweeping_heap_ = false;
534 } else if (gc_option == "postverify") {
535 xgc.verify_post_gc_heap_ = true;
536 } else if (gc_option == "nopostverify") {
537 xgc.verify_post_gc_heap_ = false;
538 } else if (gc_option == "preverify_rosalloc") {
539 xgc.verify_pre_gc_rosalloc_ = true;
540 } else if (gc_option == "nopreverify_rosalloc") {
541 xgc.verify_pre_gc_rosalloc_ = false;
542 } else if (gc_option == "presweepingverify_rosalloc") {
543 xgc.verify_pre_sweeping_rosalloc_ = true;
544 } else if (gc_option == "nopresweepingverify_rosalloc") {
545 xgc.verify_pre_sweeping_rosalloc_ = false;
546 } else if (gc_option == "postverify_rosalloc") {
547 xgc.verify_post_gc_rosalloc_ = true;
548 } else if (gc_option == "nopostverify_rosalloc") {
549 xgc.verify_post_gc_rosalloc_ = false;
Mathieu Chartier31000802015-06-14 14:14:37 -0700550 } else if (gc_option == "gcstress") {
551 xgc.gcstress_ = true;
552 } else if (gc_option == "nogcstress") {
553 xgc.gcstress_ = false;
Mathieu Chartier56fe2582016-07-14 13:30:03 -0700554 } else if (gc_option == "measure") {
555 xgc.measure_ = true;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800556 } else if ((gc_option == "precise") ||
557 (gc_option == "noprecise") ||
558 (gc_option == "verifycardtable") ||
559 (gc_option == "noverifycardtable")) {
560 // Ignored for backwards compatibility.
561 } else {
562 return Result::Usage(std::string("Unknown -Xgc option ") + gc_option);
563 }
564 }
565
566 return Result::Success(std::move(xgc));
567 }
568
569 static const char* Name() { return "XgcOption"; }
570};
571
572struct BackgroundGcOption {
573 // If background_collector_type_ is kCollectorTypeNone, it defaults to the
574 // XGcOption::collector_type_ after parsing options. If you set this to
575 // kCollectorTypeHSpaceCompact then we will do an hspace compaction when
576 // we transition to background instead of a normal collector transition.
577 gc::CollectorType background_collector_type_;
578
579 BackgroundGcOption(gc::CollectorType background_collector_type) // NOLINT [runtime/explicit] [5]
580 : background_collector_type_(background_collector_type) {}
581 BackgroundGcOption()
582 : background_collector_type_(gc::kCollectorTypeNone) {
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800583 }
584
585 operator gc::CollectorType() const { return background_collector_type_; }
586};
587
588template<>
589struct CmdlineType<BackgroundGcOption>
590 : CmdlineTypeParser<BackgroundGcOption>, private BackgroundGcOption {
591 Result Parse(const std::string& substring) {
592 // Special handling for HSpaceCompact since this is only valid as a background GC type.
593 if (substring == "HSpaceCompact") {
594 background_collector_type_ = gc::kCollectorTypeHomogeneousSpaceCompact;
595 } else {
596 gc::CollectorType collector_type = ParseCollectorType(substring);
597 if (collector_type != gc::kCollectorTypeNone) {
598 background_collector_type_ = collector_type;
599 } else {
600 return Result::Failure();
601 }
602 }
603
604 BackgroundGcOption res = *this;
605 return Result::Success(res);
606 }
607
608 static const char* Name() { return "BackgroundGcOption"; }
609};
610
611template <>
612struct CmdlineType<LogVerbosity> : CmdlineTypeParser<LogVerbosity> {
613 Result Parse(const std::string& options) {
614 LogVerbosity log_verbosity = LogVerbosity();
615
616 std::vector<std::string> verbose_options;
617 Split(options, ',', &verbose_options);
618 for (size_t j = 0; j < verbose_options.size(); ++j) {
619 if (verbose_options[j] == "class") {
620 log_verbosity.class_linker = true;
Mathieu Chartier66a55392016-02-19 10:25:39 -0800621 } else if (verbose_options[j] == "collector") {
622 log_verbosity.collector = true;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800623 } else if (verbose_options[j] == "compiler") {
624 log_verbosity.compiler = true;
Andreas Gampef3d1f942015-05-18 21:41:13 -0700625 } else if (verbose_options[j] == "deopt") {
626 log_verbosity.deopt = true;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800627 } else if (verbose_options[j] == "gc") {
628 log_verbosity.gc = true;
629 } else if (verbose_options[j] == "heap") {
630 log_verbosity.heap = true;
631 } else if (verbose_options[j] == "jdwp") {
632 log_verbosity.jdwp = true;
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800633 } else if (verbose_options[j] == "jit") {
634 log_verbosity.jit = true;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800635 } else if (verbose_options[j] == "jni") {
636 log_verbosity.jni = true;
637 } else if (verbose_options[j] == "monitor") {
638 log_verbosity.monitor = true;
Richard Uhler66d874d2015-01-15 09:37:19 -0800639 } else if (verbose_options[j] == "oat") {
640 log_verbosity.oat = true;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800641 } else if (verbose_options[j] == "profiler") {
642 log_verbosity.profiler = true;
643 } else if (verbose_options[j] == "signals") {
644 log_verbosity.signals = true;
Phil Wang751beff2015-08-28 15:17:15 +0800645 } else if (verbose_options[j] == "simulator") {
646 log_verbosity.simulator = true;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800647 } else if (verbose_options[j] == "startup") {
648 log_verbosity.startup = true;
649 } else if (verbose_options[j] == "third-party-jni") {
650 log_verbosity.third_party_jni = true;
651 } else if (verbose_options[j] == "threads") {
652 log_verbosity.threads = true;
653 } else if (verbose_options[j] == "verifier") {
654 log_verbosity.verifier = true;
Mathieu Chartierfbc31082016-01-24 11:59:56 -0800655 } else if (verbose_options[j] == "image") {
656 log_verbosity.image = true;
Andreas Gampec7ed09b2016-04-25 20:08:55 -0700657 } else if (verbose_options[j] == "systrace-locks") {
658 log_verbosity.systrace_lock_logging = true;
Alex Light7233c7e2016-07-28 10:07:45 -0700659 } else if (verbose_options[j] == "agents") {
660 log_verbosity.agents = true;
Andreas Gampebec07a02017-04-11 13:48:37 -0700661 } else if (verbose_options[j] == "dex") {
662 log_verbosity.dex = true;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800663 } else {
664 return Result::Usage(std::string("Unknown -verbose option ") + verbose_options[j]);
665 }
666 }
667
668 return Result::Success(log_verbosity);
669 }
670
671 static const char* Name() { return "LogVerbosity"; }
672};
673
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800674template <>
Calin Juravle138dbff2016-06-28 19:36:58 +0100675struct CmdlineType<ProfileSaverOptions> : CmdlineTypeParser<ProfileSaverOptions> {
676 using Result = CmdlineParseResult<ProfileSaverOptions>;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800677
678 private:
679 using StringResult = CmdlineParseResult<std::string>;
680 using DoubleResult = CmdlineParseResult<double>;
681
682 template <typename T>
Calin Juravle138dbff2016-06-28 19:36:58 +0100683 static Result ParseInto(ProfileSaverOptions& options,
684 T ProfileSaverOptions::*pField,
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800685 CmdlineParseResult<T>&& result) {
686 assert(pField != nullptr);
687
688 if (result.IsSuccess()) {
689 options.*pField = result.ReleaseValue();
690 return Result::SuccessNoValue();
691 }
692
693 return Result::CastError(result);
694 }
695
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800696 static std::string RemovePrefix(const std::string& source) {
Andreas Gampeca620d72016-11-08 08:09:33 -0800697 size_t prefix_idx = source.find(':');
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800698
699 if (prefix_idx == std::string::npos) {
700 return "";
701 }
702
703 return source.substr(prefix_idx + 1);
704 }
705
706 public:
Calin Juravle138dbff2016-06-28 19:36:58 +0100707 Result ParseAndAppend(const std::string& option, ProfileSaverOptions& existing) {
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800708 // Special case which doesn't include a wildcard argument definition.
709 // We pass-it through as-is.
Calin Juravle138dbff2016-06-28 19:36:58 +0100710 if (option == "-Xjitsaveprofilinginfo") {
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800711 existing.enabled_ = true;
712 return Result::SuccessNoValue();
713 }
714
Calin Juravle138dbff2016-06-28 19:36:58 +0100715 // The rest of these options are always the wildcard from '-Xps-*'
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800716 std::string suffix = RemovePrefix(option);
717
Andreas Gampe9186ced2016-12-12 14:28:21 -0800718 if (android::base::StartsWith(option, "min-save-period-ms:")) {
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800719 CmdlineType<unsigned int> type_parser;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800720 return ParseInto(existing,
Calin Juravle138dbff2016-06-28 19:36:58 +0100721 &ProfileSaverOptions::min_save_period_ms_,
722 type_parser.Parse(suffix));
723 }
Andreas Gampe9186ced2016-12-12 14:28:21 -0800724 if (android::base::StartsWith(option, "save-resolved-classes-delay-ms:")) {
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::save_resolved_classes_delay_ms_,
728 type_parser.Parse(suffix));
729 }
Mathieu Chartier7b135c82017-06-05 12:54:01 -0700730 if (android::base::StartsWith(option, "hot-startup-method-samples:")) {
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800731 CmdlineType<unsigned int> type_parser;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800732 return ParseInto(existing,
Mathieu Chartier7b135c82017-06-05 12:54:01 -0700733 &ProfileSaverOptions::hot_startup_method_samples_,
Calin Juravle138dbff2016-06-28 19:36:58 +0100734 type_parser.Parse(suffix));
735 }
Andreas Gampe9186ced2016-12-12 14:28:21 -0800736 if (android::base::StartsWith(option, "min-methods-to-save:")) {
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800737 CmdlineType<unsigned int> type_parser;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800738 return ParseInto(existing,
Calin Juravle138dbff2016-06-28 19:36:58 +0100739 &ProfileSaverOptions::min_methods_to_save_,
740 type_parser.Parse(suffix));
741 }
Andreas Gampe9186ced2016-12-12 14:28:21 -0800742 if (android::base::StartsWith(option, "min-classes-to-save:")) {
Calin Juravle138dbff2016-06-28 19:36:58 +0100743 CmdlineType<unsigned int> type_parser;
744 return ParseInto(existing,
745 &ProfileSaverOptions::min_classes_to_save_,
746 type_parser.Parse(suffix));
747 }
Andreas Gampe9186ced2016-12-12 14:28:21 -0800748 if (android::base::StartsWith(option, "min-notification-before-wake:")) {
Calin Juravle138dbff2016-06-28 19:36:58 +0100749 CmdlineType<unsigned int> type_parser;
750 return ParseInto(existing,
751 &ProfileSaverOptions::min_notification_before_wake_,
752 type_parser.Parse(suffix));
753 }
Andreas Gampe9186ced2016-12-12 14:28:21 -0800754 if (android::base::StartsWith(option, "max-notification-before-wake:")) {
Calin Juravle138dbff2016-06-28 19:36:58 +0100755 CmdlineType<unsigned int> type_parser;
756 return ParseInto(existing,
757 &ProfileSaverOptions::max_notification_before_wake_,
758 type_parser.Parse(suffix));
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800759 }
Calin Juravle9545f6d2017-03-16 19:05:09 -0700760 if (android::base::StartsWith(option, "profile-path:")) {
761 existing.profile_path_ = suffix;
762 return Result::SuccessNoValue();
763 }
764
765 return Result::Failure(std::string("Invalid suboption '") + option + "'");
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800766 }
767
Calin Juravle138dbff2016-06-28 19:36:58 +0100768 static const char* Name() { return "ProfileSaverOptions"; }
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800769 static constexpr bool kCanParseBlankless = true;
770};
771
Alex Lighteb7c1442015-08-31 13:17:42 -0700772template<>
773struct CmdlineType<ExperimentalFlags> : CmdlineTypeParser<ExperimentalFlags> {
774 Result ParseAndAppend(const std::string& option, ExperimentalFlags& existing) {
775 if (option == "none") {
Neil Fuller9724c632016-01-07 15:42:47 +0000776 existing = ExperimentalFlags::kNone;
Alex Lighteb7c1442015-08-31 13:17:42 -0700777 } else {
778 return Result::Failure(std::string("Unknown option '") + option + "'");
779 }
780 return Result::SuccessNoValue();
781 }
782
783 static const char* Name() { return "ExperimentalFlags"; }
784};
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800785} // namespace art
786#endif // ART_CMDLINE_CMDLINE_TYPES_H_