blob: e41d9bde59dd02b60032eed390bdbf9987537a78 [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
Vladimir Marko88b2b802015-12-04 14:19:04 +000021#include "memory_representation.h"
22#include "detail/cmdline_debug_detail.h"
Igor Murashkinaaebaa02015-01-26 10:55:53 -080023#include "cmdline_type_parser.h"
24
Andreas Gampe9186ced2016-12-12 14:28:21 -080025#include "android-base/strings.h"
26
Igor Murashkinaaebaa02015-01-26 10:55:53 -080027// Includes for the types that are being specialized
28#include <string>
Vladimir Marko88b2b802015-12-04 14:19:04 +000029#include "base/logging.h"
30#include "base/time_utils.h"
31#include "experimental_flags.h"
Igor Murashkinaaebaa02015-01-26 10:55:53 -080032#include "gc/collector_type.h"
33#include "gc/space/large_object_space.h"
Alex Light7233c7e2016-07-28 10:07:45 -070034#include "jdwp/jdwp.h"
Calin Juravle138dbff2016-06-28 19:36:58 +010035#include "jit/profile_saver_options.h"
Alex Light185d1342016-08-11 10:48:03 -070036#include "plugin.h"
Alex Light7233c7e2016-07-28 10:07:45 -070037#include "ti/agent.h"
38#include "unit.h"
Igor Murashkinaaebaa02015-01-26 10:55:53 -080039
40namespace art {
41
42// The default specialization will always fail parsing the type from a string.
43// Provide your own specialization that inherits from CmdlineTypeParser<T>
44// and implements either Parse or ParseAndAppend
45// (only if the argument was defined with ::AppendValues()) but not both.
46template <typename T>
47struct CmdlineType : CmdlineTypeParser<T> {
48};
49
50// Specializations for CmdlineType<T> follow:
51
52// Parse argument definitions for Unit-typed arguments.
53template <>
54struct CmdlineType<Unit> : CmdlineTypeParser<Unit> {
55 Result Parse(const std::string& args) {
56 if (args == "") {
57 return Result::Success(Unit{}); // NOLINT [whitespace/braces] [5]
58 }
59 return Result::Failure("Unexpected extra characters " + args);
60 }
61};
62
63template <>
64struct CmdlineType<JDWP::JdwpOptions> : CmdlineTypeParser<JDWP::JdwpOptions> {
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +010065 /*
66 * Handle one of the JDWP name/value pairs.
67 *
68 * JDWP options are:
69 * help: if specified, show help message and bail
70 * transport: may be dt_socket or dt_shmem
71 * address: for dt_socket, "host:port", or just "port" when listening
72 * server: if "y", wait for debugger to attach; if "n", attach to debugger
73 * timeout: how long to wait for debugger to connect / listen
74 *
75 * Useful with server=n (these aren't supported yet):
76 * onthrow=<exception-name>: connect to debugger when exception thrown
77 * onuncaught=y|n: connect to debugger when uncaught exception thrown
78 * launch=<command-line>: launch the debugger itself
79 *
80 * The "transport" option is required, as is "address" if server=n.
81 */
Igor Murashkinaaebaa02015-01-26 10:55:53 -080082 Result Parse(const std::string& options) {
83 VLOG(jdwp) << "ParseJdwpOptions: " << options;
84
85 if (options == "help") {
86 return Result::Usage(
87 "Example: -Xrunjdwp:transport=dt_socket,address=8000,server=y\n"
88 "Example: -Xrunjdwp:transport=dt_socket,address=localhost:6500,server=n\n");
89 }
90
91 const std::string s;
92
93 std::vector<std::string> pairs;
94 Split(options, ',', &pairs);
95
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +010096 JDWP::JdwpOptions jdwp_options;
Igor Murashkinaaebaa02015-01-26 10:55:53 -080097
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +010098 for (const std::string& jdwp_option : pairs) {
99 std::string::size_type equals_pos = jdwp_option.find('=');
100 if (equals_pos == std::string::npos) {
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800101 return Result::Failure(s +
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +0100102 "Can't parse JDWP option '" + jdwp_option + "' in '" + options + "'");
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800103 }
104
Sebastien Hertzb3b173b2015-02-06 09:16:32 +0100105 Result parse_attempt = ParseJdwpOption(jdwp_option.substr(0, equals_pos),
106 jdwp_option.substr(equals_pos + 1),
107 &jdwp_options);
108 if (parse_attempt.IsError()) {
109 // We fail to parse this JDWP option.
110 return parse_attempt;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800111 }
112 }
113
114 if (jdwp_options.transport == JDWP::kJdwpTransportUnknown) {
115 return Result::Failure(s + "Must specify JDWP transport: " + options);
116 }
117 if (!jdwp_options.server && (jdwp_options.host.empty() || jdwp_options.port == 0)) {
118 return Result::Failure(s + "Must specify JDWP host and port when server=n: " + options);
119 }
120
121 return Result::Success(std::move(jdwp_options));
122 }
123
Sebastien Hertzb3b173b2015-02-06 09:16:32 +0100124 Result ParseJdwpOption(const std::string& name, const std::string& value,
125 JDWP::JdwpOptions* jdwp_options) {
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800126 if (name == "transport") {
127 if (value == "dt_socket") {
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +0100128 jdwp_options->transport = JDWP::kJdwpTransportSocket;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800129 } else if (value == "dt_android_adb") {
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +0100130 jdwp_options->transport = JDWP::kJdwpTransportAndroidAdb;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800131 } else {
Sebastien Hertzb3b173b2015-02-06 09:16:32 +0100132 return Result::Failure("JDWP transport not supported: " + value);
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800133 }
134 } else if (name == "server") {
135 if (value == "n") {
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +0100136 jdwp_options->server = false;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800137 } else if (value == "y") {
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +0100138 jdwp_options->server = true;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800139 } else {
Sebastien Hertzb3b173b2015-02-06 09:16:32 +0100140 return Result::Failure("JDWP option 'server' must be 'y' or 'n'");
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800141 }
142 } else if (name == "suspend") {
143 if (value == "n") {
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +0100144 jdwp_options->suspend = false;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800145 } else if (value == "y") {
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +0100146 jdwp_options->suspend = true;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800147 } else {
Sebastien Hertzb3b173b2015-02-06 09:16:32 +0100148 return Result::Failure("JDWP option 'suspend' must be 'y' or 'n'");
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800149 }
150 } else if (name == "address") {
151 /* this is either <port> or <host>:<port> */
152 std::string port_string;
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +0100153 jdwp_options->host.clear();
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800154 std::string::size_type colon = value.find(':');
155 if (colon != std::string::npos) {
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +0100156 jdwp_options->host = value.substr(0, colon);
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800157 port_string = value.substr(colon + 1);
158 } else {
159 port_string = value;
160 }
161 if (port_string.empty()) {
Sebastien Hertzb3b173b2015-02-06 09:16:32 +0100162 return Result::Failure("JDWP address missing port: " + value);
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800163 }
164 char* end;
165 uint64_t port = strtoul(port_string.c_str(), &end, 10);
166 if (*end != '\0' || port > 0xffff) {
Sebastien Hertzb3b173b2015-02-06 09:16:32 +0100167 return Result::Failure("JDWP address has junk in port field: " + value);
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800168 }
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +0100169 jdwp_options->port = port;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800170 } else if (name == "launch" || name == "onthrow" || name == "oncaught" || name == "timeout") {
171 /* valid but unsupported */
172 LOG(INFO) << "Ignoring JDWP option '" << name << "'='" << value << "'";
173 } else {
174 LOG(INFO) << "Ignoring unrecognized JDWP option '" << name << "'='" << value << "'";
175 }
176
Sebastien Hertzb3b173b2015-02-06 09:16:32 +0100177 return Result::SuccessNoValue();
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800178 }
179
180 static const char* Name() { return "JdwpOptions"; }
181};
182
183template <size_t Divisor>
184struct CmdlineType<Memory<Divisor>> : CmdlineTypeParser<Memory<Divisor>> {
185 using typename CmdlineTypeParser<Memory<Divisor>>::Result;
186
Vladimir Marko5c657fe2016-11-03 15:12:29 +0000187 Result Parse(const std::string& arg) {
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800188 CMDLINE_DEBUG_LOG << "Parsing memory: " << arg << std::endl;
189 size_t val = ParseMemoryOption(arg.c_str(), Divisor);
190 CMDLINE_DEBUG_LOG << "Memory parsed to size_t value: " << val << std::endl;
191
192 if (val == 0) {
193 return Result::Failure(std::string("not a valid memory value, or not divisible by ")
194 + std::to_string(Divisor));
195 }
196
197 return Result::Success(Memory<Divisor>(val));
198 }
199
200 // Parse a string of the form /[0-9]+[kKmMgG]?/, which is used to specify
201 // memory sizes. [kK] indicates kilobytes, [mM] megabytes, and
202 // [gG] gigabytes.
203 //
204 // "s" should point just past the "-Xm?" part of the string.
205 // "div" specifies a divisor, e.g. 1024 if the value must be a multiple
206 // of 1024.
207 //
208 // The spec says the -Xmx and -Xms options must be multiples of 1024. It
209 // doesn't say anything about -Xss.
210 //
211 // Returns 0 (a useless size) if "s" is malformed or specifies a low or
212 // non-evenly-divisible value.
213 //
214 static size_t ParseMemoryOption(const char* s, size_t div) {
215 // strtoul accepts a leading [+-], which we don't want,
216 // so make sure our string starts with a decimal digit.
217 if (isdigit(*s)) {
218 char* s2;
219 size_t val = strtoul(s, &s2, 10);
220 if (s2 != s) {
221 // s2 should be pointing just after the number.
222 // If this is the end of the string, the user
223 // has specified a number of bytes. Otherwise,
224 // there should be exactly one more character
225 // that specifies a multiplier.
226 if (*s2 != '\0') {
227 // The remainder of the string is either a single multiplier
228 // character, or nothing to indicate that the value is in
229 // bytes.
230 char c = *s2++;
231 if (*s2 == '\0') {
232 size_t mul;
233 if (c == '\0') {
234 mul = 1;
235 } else if (c == 'k' || c == 'K') {
236 mul = KB;
237 } else if (c == 'm' || c == 'M') {
238 mul = MB;
239 } else if (c == 'g' || c == 'G') {
240 mul = GB;
241 } else {
242 // Unknown multiplier character.
243 return 0;
244 }
245
246 if (val <= std::numeric_limits<size_t>::max() / mul) {
247 val *= mul;
248 } else {
249 // Clamp to a multiple of 1024.
250 val = std::numeric_limits<size_t>::max() & ~(1024-1);
251 }
252 } else {
253 // There's more than one character after the numeric part.
254 return 0;
255 }
256 }
257 // The man page says that a -Xm value must be a multiple of 1024.
258 if (val % div == 0) {
259 return val;
260 }
261 }
262 }
263 return 0;
264 }
265
266 static const char* Name() { return Memory<Divisor>::Name(); }
267};
268
269template <>
270struct CmdlineType<double> : CmdlineTypeParser<double> {
271 Result Parse(const std::string& str) {
272 char* end = nullptr;
273 errno = 0;
274 double value = strtod(str.c_str(), &end);
275
276 if (*end != '\0') {
277 return Result::Failure("Failed to parse double from " + str);
278 }
279 if (errno == ERANGE) {
280 return Result::OutOfRange(
281 "Failed to parse double from " + str + "; overflow/underflow occurred");
282 }
283
284 return Result::Success(value);
285 }
286
287 static const char* Name() { return "double"; }
288};
289
290template <>
291struct CmdlineType<unsigned int> : CmdlineTypeParser<unsigned int> {
292 Result Parse(const std::string& str) {
293 const char* begin = str.c_str();
294 char* end;
295
296 // Parse into a larger type (long long) because we can't use strtoul
297 // since it silently converts negative values into unsigned long and doesn't set errno.
298 errno = 0;
299 long long int result = strtoll(begin, &end, 10); // NOLINT [runtime/int] [4]
300 if (begin == end || *end != '\0' || errno == EINVAL) {
301 return Result::Failure("Failed to parse integer from " + str);
302 } else if ((errno == ERANGE) || // NOLINT [runtime/int] [4]
303 result < std::numeric_limits<int>::min()
304 || result > std::numeric_limits<unsigned int>::max() || result < 0) {
305 return Result::OutOfRange(
306 "Failed to parse integer from " + str + "; out of unsigned int range");
307 }
308
309 return Result::Success(static_cast<unsigned int>(result));
310 }
311
312 static const char* Name() { return "unsigned integer"; }
313};
314
315// Lightweight nanosecond value type. Allows parser to convert user-input from milliseconds
316// to nanoseconds automatically after parsing.
317//
318// All implicit conversion from uint64_t uses nanoseconds.
319struct MillisecondsToNanoseconds {
320 // Create from nanoseconds.
321 MillisecondsToNanoseconds(uint64_t nanoseconds) : nanoseconds_(nanoseconds) { // NOLINT [runtime/explicit] [5]
322 }
323
324 // Create from milliseconds.
325 static MillisecondsToNanoseconds FromMilliseconds(unsigned int milliseconds) {
326 return MillisecondsToNanoseconds(MsToNs(milliseconds));
327 }
328
329 // Get the underlying nanoseconds value.
330 uint64_t GetNanoseconds() const {
331 return nanoseconds_;
332 }
333
334 // Get the milliseconds value [via a conversion]. Loss of precision will occur.
335 uint64_t GetMilliseconds() const {
336 return NsToMs(nanoseconds_);
337 }
338
339 // Get the underlying nanoseconds value.
340 operator uint64_t() const {
341 return GetNanoseconds();
342 }
343
344 // Default constructors/copy-constructors.
345 MillisecondsToNanoseconds() : nanoseconds_(0ul) {}
Andreas Gampec801f0d2015-02-24 20:55:16 -0800346 MillisecondsToNanoseconds(const MillisecondsToNanoseconds&) = default;
347 MillisecondsToNanoseconds(MillisecondsToNanoseconds&&) = default;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800348
349 private:
350 uint64_t nanoseconds_;
351};
352
353template <>
354struct CmdlineType<MillisecondsToNanoseconds> : CmdlineTypeParser<MillisecondsToNanoseconds> {
355 Result Parse(const std::string& str) {
356 CmdlineType<unsigned int> uint_parser;
357 CmdlineParseResult<unsigned int> res = uint_parser.Parse(str);
358
359 if (res.IsSuccess()) {
360 return Result::Success(MillisecondsToNanoseconds::FromMilliseconds(res.GetValue()));
361 } else {
362 return Result::CastError(res);
363 }
364 }
365
366 static const char* Name() { return "MillisecondsToNanoseconds"; }
367};
368
369template <>
370struct CmdlineType<std::string> : CmdlineTypeParser<std::string> {
371 Result Parse(const std::string& args) {
372 return Result::Success(args);
373 }
374
375 Result ParseAndAppend(const std::string& args,
376 std::string& existing_value) {
377 if (existing_value.empty()) {
378 existing_value = args;
379 } else {
380 existing_value += ' ';
381 existing_value += args;
382 }
383 return Result::SuccessNoValue();
384 }
385};
386
387template <>
Alex Light185d1342016-08-11 10:48:03 -0700388struct CmdlineType<std::vector<Plugin>> : CmdlineTypeParser<std::vector<Plugin>> {
389 Result Parse(const std::string& args) {
390 assert(false && "Use AppendValues() for a Plugin vector type");
391 return Result::Failure("Unconditional failure: Plugin vector must be appended: " + args);
392 }
393
394 Result ParseAndAppend(const std::string& args,
395 std::vector<Plugin>& existing_value) {
396 existing_value.push_back(Plugin::Create(args));
397 return Result::SuccessNoValue();
398 }
399
400 static const char* Name() { return "std::vector<Plugin>"; }
401};
402
403template <>
Alex Light7233c7e2016-07-28 10:07:45 -0700404struct CmdlineType<std::vector<ti::Agent>> : CmdlineTypeParser<std::vector<ti::Agent>> {
405 Result Parse(const std::string& args) {
406 assert(false && "Use AppendValues() for an Agent vector type");
407 return Result::Failure("Unconditional failure: Agent vector must be appended: " + args);
408 }
409
410 Result ParseAndAppend(const std::string& args,
411 std::vector<ti::Agent>& existing_value) {
Leonard Mosescueb842212016-10-06 17:26:36 -0700412 existing_value.emplace_back(args);
Alex Light7233c7e2016-07-28 10:07:45 -0700413 return Result::SuccessNoValue();
414 }
415
416 static const char* Name() { return "std::vector<ti::Agent>"; }
417};
418
419template <>
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800420struct CmdlineType<std::vector<std::string>> : CmdlineTypeParser<std::vector<std::string>> {
421 Result Parse(const std::string& args) {
422 assert(false && "Use AppendValues() for a string vector type");
423 return Result::Failure("Unconditional failure: string vector must be appended: " + args);
424 }
425
426 Result ParseAndAppend(const std::string& args,
427 std::vector<std::string>& existing_value) {
428 existing_value.push_back(args);
429 return Result::SuccessNoValue();
430 }
431
432 static const char* Name() { return "std::vector<std::string>"; }
433};
434
435template <char Separator>
436struct ParseStringList {
437 explicit ParseStringList(std::vector<std::string>&& list) : list_(list) {}
438
439 operator std::vector<std::string>() const {
440 return list_;
441 }
442
443 operator std::vector<std::string>&&() && {
444 return std::move(list_);
445 }
446
447 size_t Size() const {
448 return list_.size();
449 }
450
451 std::string Join() const {
Andreas Gampe9186ced2016-12-12 14:28:21 -0800452 return android::base::Join(list_, Separator);
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800453 }
454
455 static ParseStringList<Separator> Split(const std::string& str) {
456 std::vector<std::string> list;
457 art::Split(str, Separator, &list);
458 return ParseStringList<Separator>(std::move(list));
459 }
460
461 ParseStringList() = default;
Andreas Gampec801f0d2015-02-24 20:55:16 -0800462 ParseStringList(const ParseStringList&) = default;
463 ParseStringList(ParseStringList&&) = default;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800464
465 private:
466 std::vector<std::string> list_;
467};
468
469template <char Separator>
470struct CmdlineType<ParseStringList<Separator>> : CmdlineTypeParser<ParseStringList<Separator>> {
471 using Result = CmdlineParseResult<ParseStringList<Separator>>;
472
473 Result Parse(const std::string& args) {
474 return Result::Success(ParseStringList<Separator>::Split(args));
475 }
476
477 static const char* Name() { return "ParseStringList<Separator>"; }
478};
479
480static gc::CollectorType ParseCollectorType(const std::string& option) {
481 if (option == "MS" || option == "nonconcurrent") {
482 return gc::kCollectorTypeMS;
483 } else if (option == "CMS" || option == "concurrent") {
484 return gc::kCollectorTypeCMS;
485 } else if (option == "SS") {
486 return gc::kCollectorTypeSS;
487 } else if (option == "GSS") {
488 return gc::kCollectorTypeGSS;
489 } else if (option == "CC") {
490 return gc::kCollectorTypeCC;
491 } else if (option == "MC") {
492 return gc::kCollectorTypeMC;
493 } else {
494 return gc::kCollectorTypeNone;
495 }
496}
497
498struct XGcOption {
499 // These defaults are used when the command line arguments for -Xgc:
500 // are either omitted completely or partially.
Hiroshi Yamauchi1b0adbf2016-11-14 17:35:12 -0800501 gc::CollectorType collector_type_ = gc::kCollectorTypeDefault;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800502 bool verify_pre_gc_heap_ = false;
503 bool verify_pre_sweeping_heap_ = kIsDebugBuild;
504 bool verify_post_gc_heap_ = false;
505 bool verify_pre_gc_rosalloc_ = kIsDebugBuild;
506 bool verify_pre_sweeping_rosalloc_ = false;
507 bool verify_post_gc_rosalloc_ = false;
Hiroshi Yamauchia9b296c2016-10-07 17:07:03 -0700508 // Do no measurements for kUseTableLookupReadBarrier to avoid test timeouts. b/31679493
509 bool measure_ = kIsDebugBuild && !kUseTableLookupReadBarrier;
Mathieu Chartier31000802015-06-14 14:14:37 -0700510 bool gcstress_ = false;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800511};
512
513template <>
514struct CmdlineType<XGcOption> : CmdlineTypeParser<XGcOption> {
515 Result Parse(const std::string& option) { // -Xgc: already stripped
516 XGcOption xgc{}; // NOLINT [readability/braces] [4]
517
518 std::vector<std::string> gc_options;
519 Split(option, ',', &gc_options);
520 for (const std::string& gc_option : gc_options) {
521 gc::CollectorType collector_type = ParseCollectorType(gc_option);
522 if (collector_type != gc::kCollectorTypeNone) {
523 xgc.collector_type_ = collector_type;
524 } else if (gc_option == "preverify") {
525 xgc.verify_pre_gc_heap_ = true;
526 } else if (gc_option == "nopreverify") {
527 xgc.verify_pre_gc_heap_ = false;
528 } else if (gc_option == "presweepingverify") {
529 xgc.verify_pre_sweeping_heap_ = true;
530 } else if (gc_option == "nopresweepingverify") {
531 xgc.verify_pre_sweeping_heap_ = false;
532 } else if (gc_option == "postverify") {
533 xgc.verify_post_gc_heap_ = true;
534 } else if (gc_option == "nopostverify") {
535 xgc.verify_post_gc_heap_ = false;
536 } else if (gc_option == "preverify_rosalloc") {
537 xgc.verify_pre_gc_rosalloc_ = true;
538 } else if (gc_option == "nopreverify_rosalloc") {
539 xgc.verify_pre_gc_rosalloc_ = false;
540 } else if (gc_option == "presweepingverify_rosalloc") {
541 xgc.verify_pre_sweeping_rosalloc_ = true;
542 } else if (gc_option == "nopresweepingverify_rosalloc") {
543 xgc.verify_pre_sweeping_rosalloc_ = false;
544 } else if (gc_option == "postverify_rosalloc") {
545 xgc.verify_post_gc_rosalloc_ = true;
546 } else if (gc_option == "nopostverify_rosalloc") {
547 xgc.verify_post_gc_rosalloc_ = false;
Mathieu Chartier31000802015-06-14 14:14:37 -0700548 } else if (gc_option == "gcstress") {
549 xgc.gcstress_ = true;
550 } else if (gc_option == "nogcstress") {
551 xgc.gcstress_ = false;
Mathieu Chartier56fe2582016-07-14 13:30:03 -0700552 } else if (gc_option == "measure") {
553 xgc.measure_ = true;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800554 } else if ((gc_option == "precise") ||
555 (gc_option == "noprecise") ||
556 (gc_option == "verifycardtable") ||
557 (gc_option == "noverifycardtable")) {
558 // Ignored for backwards compatibility.
559 } else {
560 return Result::Usage(std::string("Unknown -Xgc option ") + gc_option);
561 }
562 }
563
564 return Result::Success(std::move(xgc));
565 }
566
567 static const char* Name() { return "XgcOption"; }
568};
569
570struct BackgroundGcOption {
571 // If background_collector_type_ is kCollectorTypeNone, it defaults to the
572 // XGcOption::collector_type_ after parsing options. If you set this to
573 // kCollectorTypeHSpaceCompact then we will do an hspace compaction when
574 // we transition to background instead of a normal collector transition.
575 gc::CollectorType background_collector_type_;
576
577 BackgroundGcOption(gc::CollectorType background_collector_type) // NOLINT [runtime/explicit] [5]
578 : background_collector_type_(background_collector_type) {}
579 BackgroundGcOption()
580 : background_collector_type_(gc::kCollectorTypeNone) {
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800581 }
582
583 operator gc::CollectorType() const { return background_collector_type_; }
584};
585
586template<>
587struct CmdlineType<BackgroundGcOption>
588 : CmdlineTypeParser<BackgroundGcOption>, private BackgroundGcOption {
589 Result Parse(const std::string& substring) {
590 // Special handling for HSpaceCompact since this is only valid as a background GC type.
591 if (substring == "HSpaceCompact") {
592 background_collector_type_ = gc::kCollectorTypeHomogeneousSpaceCompact;
593 } else {
594 gc::CollectorType collector_type = ParseCollectorType(substring);
595 if (collector_type != gc::kCollectorTypeNone) {
596 background_collector_type_ = collector_type;
597 } else {
598 return Result::Failure();
599 }
600 }
601
602 BackgroundGcOption res = *this;
603 return Result::Success(res);
604 }
605
606 static const char* Name() { return "BackgroundGcOption"; }
607};
608
609template <>
610struct CmdlineType<LogVerbosity> : CmdlineTypeParser<LogVerbosity> {
611 Result Parse(const std::string& options) {
612 LogVerbosity log_verbosity = LogVerbosity();
613
614 std::vector<std::string> verbose_options;
615 Split(options, ',', &verbose_options);
616 for (size_t j = 0; j < verbose_options.size(); ++j) {
617 if (verbose_options[j] == "class") {
618 log_verbosity.class_linker = true;
Mathieu Chartier66a55392016-02-19 10:25:39 -0800619 } else if (verbose_options[j] == "collector") {
620 log_verbosity.collector = true;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800621 } else if (verbose_options[j] == "compiler") {
622 log_verbosity.compiler = true;
Andreas Gampef3d1f942015-05-18 21:41:13 -0700623 } else if (verbose_options[j] == "deopt") {
624 log_verbosity.deopt = true;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800625 } else if (verbose_options[j] == "gc") {
626 log_verbosity.gc = true;
627 } else if (verbose_options[j] == "heap") {
628 log_verbosity.heap = true;
629 } else if (verbose_options[j] == "jdwp") {
630 log_verbosity.jdwp = true;
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800631 } else if (verbose_options[j] == "jit") {
632 log_verbosity.jit = true;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800633 } else if (verbose_options[j] == "jni") {
634 log_verbosity.jni = true;
635 } else if (verbose_options[j] == "monitor") {
636 log_verbosity.monitor = true;
Richard Uhler66d874d2015-01-15 09:37:19 -0800637 } else if (verbose_options[j] == "oat") {
638 log_verbosity.oat = true;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800639 } else if (verbose_options[j] == "profiler") {
640 log_verbosity.profiler = true;
641 } else if (verbose_options[j] == "signals") {
642 log_verbosity.signals = true;
Phil Wang751beff2015-08-28 15:17:15 +0800643 } else if (verbose_options[j] == "simulator") {
644 log_verbosity.simulator = true;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800645 } else if (verbose_options[j] == "startup") {
646 log_verbosity.startup = true;
647 } else if (verbose_options[j] == "third-party-jni") {
648 log_verbosity.third_party_jni = true;
649 } else if (verbose_options[j] == "threads") {
650 log_verbosity.threads = true;
651 } else if (verbose_options[j] == "verifier") {
652 log_verbosity.verifier = true;
Mathieu Chartierfbc31082016-01-24 11:59:56 -0800653 } else if (verbose_options[j] == "image") {
654 log_verbosity.image = true;
Andreas Gampec7ed09b2016-04-25 20:08:55 -0700655 } else if (verbose_options[j] == "systrace-locks") {
656 log_verbosity.systrace_lock_logging = true;
Alex Light7233c7e2016-07-28 10:07:45 -0700657 } else if (verbose_options[j] == "agents") {
658 log_verbosity.agents = true;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800659 } else {
660 return Result::Usage(std::string("Unknown -verbose option ") + verbose_options[j]);
661 }
662 }
663
664 return Result::Success(log_verbosity);
665 }
666
667 static const char* Name() { return "LogVerbosity"; }
668};
669
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800670template <>
Calin Juravle138dbff2016-06-28 19:36:58 +0100671struct CmdlineType<ProfileSaverOptions> : CmdlineTypeParser<ProfileSaverOptions> {
672 using Result = CmdlineParseResult<ProfileSaverOptions>;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800673
674 private:
675 using StringResult = CmdlineParseResult<std::string>;
676 using DoubleResult = CmdlineParseResult<double>;
677
678 template <typename T>
Calin Juravle138dbff2016-06-28 19:36:58 +0100679 static Result ParseInto(ProfileSaverOptions& options,
680 T ProfileSaverOptions::*pField,
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800681 CmdlineParseResult<T>&& result) {
682 assert(pField != nullptr);
683
684 if (result.IsSuccess()) {
685 options.*pField = result.ReleaseValue();
686 return Result::SuccessNoValue();
687 }
688
689 return Result::CastError(result);
690 }
691
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800692 static std::string RemovePrefix(const std::string& source) {
Andreas Gampeca620d72016-11-08 08:09:33 -0800693 size_t prefix_idx = source.find(':');
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800694
695 if (prefix_idx == std::string::npos) {
696 return "";
697 }
698
699 return source.substr(prefix_idx + 1);
700 }
701
702 public:
Calin Juravle138dbff2016-06-28 19:36:58 +0100703 Result ParseAndAppend(const std::string& option, ProfileSaverOptions& existing) {
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800704 // Special case which doesn't include a wildcard argument definition.
705 // We pass-it through as-is.
Calin Juravle138dbff2016-06-28 19:36:58 +0100706 if (option == "-Xjitsaveprofilinginfo") {
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800707 existing.enabled_ = true;
708 return Result::SuccessNoValue();
709 }
710
Calin Juravle138dbff2016-06-28 19:36:58 +0100711 // The rest of these options are always the wildcard from '-Xps-*'
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800712 std::string suffix = RemovePrefix(option);
713
Andreas Gampe9186ced2016-12-12 14:28:21 -0800714 if (android::base::StartsWith(option, "min-save-period-ms:")) {
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800715 CmdlineType<unsigned int> type_parser;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800716 return ParseInto(existing,
Calin Juravle138dbff2016-06-28 19:36:58 +0100717 &ProfileSaverOptions::min_save_period_ms_,
718 type_parser.Parse(suffix));
719 }
Andreas Gampe9186ced2016-12-12 14:28:21 -0800720 if (android::base::StartsWith(option, "save-resolved-classes-delay-ms:")) {
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800721 CmdlineType<unsigned int> type_parser;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800722 return ParseInto(existing,
Calin Juravle138dbff2016-06-28 19:36:58 +0100723 &ProfileSaverOptions::save_resolved_classes_delay_ms_,
724 type_parser.Parse(suffix));
725 }
Andreas Gampe9186ced2016-12-12 14:28:21 -0800726 if (android::base::StartsWith(option, "startup-method-samples:")) {
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800727 CmdlineType<unsigned int> type_parser;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800728 return ParseInto(existing,
Calin Juravle138dbff2016-06-28 19:36:58 +0100729 &ProfileSaverOptions::startup_method_samples_,
730 type_parser.Parse(suffix));
731 }
Andreas Gampe9186ced2016-12-12 14:28:21 -0800732 if (android::base::StartsWith(option, "min-methods-to-save:")) {
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800733 CmdlineType<unsigned int> type_parser;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800734 return ParseInto(existing,
Calin Juravle138dbff2016-06-28 19:36:58 +0100735 &ProfileSaverOptions::min_methods_to_save_,
736 type_parser.Parse(suffix));
737 }
Andreas Gampe9186ced2016-12-12 14:28:21 -0800738 if (android::base::StartsWith(option, "min-classes-to-save:")) {
Calin Juravle138dbff2016-06-28 19:36:58 +0100739 CmdlineType<unsigned int> type_parser;
740 return ParseInto(existing,
741 &ProfileSaverOptions::min_classes_to_save_,
742 type_parser.Parse(suffix));
743 }
Andreas Gampe9186ced2016-12-12 14:28:21 -0800744 if (android::base::StartsWith(option, "min-notification-before-wake:")) {
Calin Juravle138dbff2016-06-28 19:36:58 +0100745 CmdlineType<unsigned int> type_parser;
746 return ParseInto(existing,
747 &ProfileSaverOptions::min_notification_before_wake_,
748 type_parser.Parse(suffix));
749 }
Andreas Gampe9186ced2016-12-12 14:28:21 -0800750 if (android::base::StartsWith(option, "max-notification-before-wake:")) {
Calin Juravle138dbff2016-06-28 19:36:58 +0100751 CmdlineType<unsigned int> type_parser;
752 return ParseInto(existing,
753 &ProfileSaverOptions::max_notification_before_wake_,
754 type_parser.Parse(suffix));
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800755 } else {
756 return Result::Failure(std::string("Invalid suboption '") + option + "'");
757 }
758 }
759
Calin Juravle138dbff2016-06-28 19:36:58 +0100760 static const char* Name() { return "ProfileSaverOptions"; }
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800761 static constexpr bool kCanParseBlankless = true;
762};
763
Alex Lighteb7c1442015-08-31 13:17:42 -0700764template<>
765struct CmdlineType<ExperimentalFlags> : CmdlineTypeParser<ExperimentalFlags> {
766 Result ParseAndAppend(const std::string& option, ExperimentalFlags& existing) {
767 if (option == "none") {
Neil Fuller9724c632016-01-07 15:42:47 +0000768 existing = ExperimentalFlags::kNone;
Alex Light7233c7e2016-07-28 10:07:45 -0700769 } else if (option == "agents") {
770 existing = existing | ExperimentalFlags::kAgents;
Alex Light185d1342016-08-11 10:48:03 -0700771 } else if (option == "runtime-plugins") {
772 existing = existing | ExperimentalFlags::kRuntimePlugins;
Narayan Kamath25352fc2016-08-03 12:46:58 +0100773 } else if (option == "method-handles") {
774 existing = existing | ExperimentalFlags::kMethodHandles;
Alex Lighteb7c1442015-08-31 13:17:42 -0700775 } else {
776 return Result::Failure(std::string("Unknown option '") + option + "'");
777 }
778 return Result::SuccessNoValue();
779 }
780
781 static const char* Name() { return "ExperimentalFlags"; }
782};
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800783
784} // namespace art
785#endif // ART_CMDLINE_CMDLINE_TYPES_H_