blob: a5bb117509593c35c2357d68adf347de325402ab [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
25// Includes for the types that are being specialized
26#include <string>
Vladimir Marko88b2b802015-12-04 14:19:04 +000027#include "base/logging.h"
28#include "base/time_utils.h"
29#include "experimental_flags.h"
Igor Murashkinaaebaa02015-01-26 10:55:53 -080030#include "gc/collector_type.h"
31#include "gc/space/large_object_space.h"
Alex Light7233c7e2016-07-28 10:07:45 -070032#include "jdwp/jdwp.h"
Calin Juravle138dbff2016-06-28 19:36:58 +010033#include "jit/profile_saver_options.h"
Alex Light185d1342016-08-11 10:48:03 -070034#include "plugin.h"
Alex Light7233c7e2016-07-28 10:07:45 -070035#include "ti/agent.h"
36#include "unit.h"
Igor Murashkinaaebaa02015-01-26 10:55:53 -080037
38namespace art {
39
40// The default specialization will always fail parsing the type from a string.
41// Provide your own specialization that inherits from CmdlineTypeParser<T>
42// and implements either Parse or ParseAndAppend
43// (only if the argument was defined with ::AppendValues()) but not both.
44template <typename T>
45struct CmdlineType : CmdlineTypeParser<T> {
46};
47
48// Specializations for CmdlineType<T> follow:
49
50// Parse argument definitions for Unit-typed arguments.
51template <>
52struct CmdlineType<Unit> : CmdlineTypeParser<Unit> {
53 Result Parse(const std::string& args) {
54 if (args == "") {
55 return Result::Success(Unit{}); // NOLINT [whitespace/braces] [5]
56 }
57 return Result::Failure("Unexpected extra characters " + args);
58 }
59};
60
61template <>
62struct CmdlineType<JDWP::JdwpOptions> : CmdlineTypeParser<JDWP::JdwpOptions> {
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +010063 /*
64 * Handle one of the JDWP name/value pairs.
65 *
66 * JDWP options are:
67 * help: if specified, show help message and bail
68 * transport: may be dt_socket or dt_shmem
69 * address: for dt_socket, "host:port", or just "port" when listening
70 * server: if "y", wait for debugger to attach; if "n", attach to debugger
71 * timeout: how long to wait for debugger to connect / listen
72 *
73 * Useful with server=n (these aren't supported yet):
74 * onthrow=<exception-name>: connect to debugger when exception thrown
75 * onuncaught=y|n: connect to debugger when uncaught exception thrown
76 * launch=<command-line>: launch the debugger itself
77 *
78 * The "transport" option is required, as is "address" if server=n.
79 */
Igor Murashkinaaebaa02015-01-26 10:55:53 -080080 Result Parse(const std::string& options) {
81 VLOG(jdwp) << "ParseJdwpOptions: " << options;
82
83 if (options == "help") {
84 return Result::Usage(
85 "Example: -Xrunjdwp:transport=dt_socket,address=8000,server=y\n"
86 "Example: -Xrunjdwp:transport=dt_socket,address=localhost:6500,server=n\n");
87 }
88
89 const std::string s;
90
91 std::vector<std::string> pairs;
92 Split(options, ',', &pairs);
93
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +010094 JDWP::JdwpOptions jdwp_options;
Igor Murashkinaaebaa02015-01-26 10:55:53 -080095
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +010096 for (const std::string& jdwp_option : pairs) {
97 std::string::size_type equals_pos = jdwp_option.find('=');
98 if (equals_pos == std::string::npos) {
Igor Murashkinaaebaa02015-01-26 10:55:53 -080099 return Result::Failure(s +
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +0100100 "Can't parse JDWP option '" + jdwp_option + "' in '" + options + "'");
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800101 }
102
Sebastien Hertzb3b173b2015-02-06 09:16:32 +0100103 Result parse_attempt = ParseJdwpOption(jdwp_option.substr(0, equals_pos),
104 jdwp_option.substr(equals_pos + 1),
105 &jdwp_options);
106 if (parse_attempt.IsError()) {
107 // We fail to parse this JDWP option.
108 return parse_attempt;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800109 }
110 }
111
112 if (jdwp_options.transport == JDWP::kJdwpTransportUnknown) {
113 return Result::Failure(s + "Must specify JDWP transport: " + options);
114 }
115 if (!jdwp_options.server && (jdwp_options.host.empty() || jdwp_options.port == 0)) {
116 return Result::Failure(s + "Must specify JDWP host and port when server=n: " + options);
117 }
118
119 return Result::Success(std::move(jdwp_options));
120 }
121
Sebastien Hertzb3b173b2015-02-06 09:16:32 +0100122 Result ParseJdwpOption(const std::string& name, const std::string& value,
123 JDWP::JdwpOptions* jdwp_options) {
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800124 if (name == "transport") {
125 if (value == "dt_socket") {
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +0100126 jdwp_options->transport = JDWP::kJdwpTransportSocket;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800127 } else if (value == "dt_android_adb") {
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +0100128 jdwp_options->transport = JDWP::kJdwpTransportAndroidAdb;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800129 } else {
Sebastien Hertzb3b173b2015-02-06 09:16:32 +0100130 return Result::Failure("JDWP transport not supported: " + value);
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800131 }
132 } else if (name == "server") {
133 if (value == "n") {
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +0100134 jdwp_options->server = false;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800135 } else if (value == "y") {
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +0100136 jdwp_options->server = true;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800137 } else {
Sebastien Hertzb3b173b2015-02-06 09:16:32 +0100138 return Result::Failure("JDWP option 'server' must be 'y' or 'n'");
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800139 }
140 } else if (name == "suspend") {
141 if (value == "n") {
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +0100142 jdwp_options->suspend = false;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800143 } else if (value == "y") {
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +0100144 jdwp_options->suspend = true;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800145 } else {
Sebastien Hertzb3b173b2015-02-06 09:16:32 +0100146 return Result::Failure("JDWP option 'suspend' must be 'y' or 'n'");
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800147 }
148 } else if (name == "address") {
149 /* this is either <port> or <host>:<port> */
150 std::string port_string;
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +0100151 jdwp_options->host.clear();
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800152 std::string::size_type colon = value.find(':');
153 if (colon != std::string::npos) {
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +0100154 jdwp_options->host = value.substr(0, colon);
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800155 port_string = value.substr(colon + 1);
156 } else {
157 port_string = value;
158 }
159 if (port_string.empty()) {
Sebastien Hertzb3b173b2015-02-06 09:16:32 +0100160 return Result::Failure("JDWP address missing port: " + value);
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800161 }
162 char* end;
163 uint64_t port = strtoul(port_string.c_str(), &end, 10);
164 if (*end != '\0' || port > 0xffff) {
Sebastien Hertzb3b173b2015-02-06 09:16:32 +0100165 return Result::Failure("JDWP address has junk in port field: " + value);
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800166 }
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +0100167 jdwp_options->port = port;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800168 } else if (name == "launch" || name == "onthrow" || name == "oncaught" || name == "timeout") {
169 /* valid but unsupported */
170 LOG(INFO) << "Ignoring JDWP option '" << name << "'='" << value << "'";
171 } else {
172 LOG(INFO) << "Ignoring unrecognized JDWP option '" << name << "'='" << value << "'";
173 }
174
Sebastien Hertzb3b173b2015-02-06 09:16:32 +0100175 return Result::SuccessNoValue();
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800176 }
177
178 static const char* Name() { return "JdwpOptions"; }
179};
180
181template <size_t Divisor>
182struct CmdlineType<Memory<Divisor>> : CmdlineTypeParser<Memory<Divisor>> {
183 using typename CmdlineTypeParser<Memory<Divisor>>::Result;
184
Vladimir Marko5c657fe2016-11-03 15:12:29 +0000185 Result Parse(const std::string& arg) {
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800186 CMDLINE_DEBUG_LOG << "Parsing memory: " << arg << std::endl;
187 size_t val = ParseMemoryOption(arg.c_str(), Divisor);
188 CMDLINE_DEBUG_LOG << "Memory parsed to size_t value: " << val << std::endl;
189
190 if (val == 0) {
191 return Result::Failure(std::string("not a valid memory value, or not divisible by ")
192 + std::to_string(Divisor));
193 }
194
195 return Result::Success(Memory<Divisor>(val));
196 }
197
198 // Parse a string of the form /[0-9]+[kKmMgG]?/, which is used to specify
199 // memory sizes. [kK] indicates kilobytes, [mM] megabytes, and
200 // [gG] gigabytes.
201 //
202 // "s" should point just past the "-Xm?" part of the string.
203 // "div" specifies a divisor, e.g. 1024 if the value must be a multiple
204 // of 1024.
205 //
206 // The spec says the -Xmx and -Xms options must be multiples of 1024. It
207 // doesn't say anything about -Xss.
208 //
209 // Returns 0 (a useless size) if "s" is malformed or specifies a low or
210 // non-evenly-divisible value.
211 //
212 static size_t ParseMemoryOption(const char* s, size_t div) {
213 // strtoul accepts a leading [+-], which we don't want,
214 // so make sure our string starts with a decimal digit.
215 if (isdigit(*s)) {
216 char* s2;
217 size_t val = strtoul(s, &s2, 10);
218 if (s2 != s) {
219 // s2 should be pointing just after the number.
220 // If this is the end of the string, the user
221 // has specified a number of bytes. Otherwise,
222 // there should be exactly one more character
223 // that specifies a multiplier.
224 if (*s2 != '\0') {
225 // The remainder of the string is either a single multiplier
226 // character, or nothing to indicate that the value is in
227 // bytes.
228 char c = *s2++;
229 if (*s2 == '\0') {
230 size_t mul;
231 if (c == '\0') {
232 mul = 1;
233 } else if (c == 'k' || c == 'K') {
234 mul = KB;
235 } else if (c == 'm' || c == 'M') {
236 mul = MB;
237 } else if (c == 'g' || c == 'G') {
238 mul = GB;
239 } else {
240 // Unknown multiplier character.
241 return 0;
242 }
243
244 if (val <= std::numeric_limits<size_t>::max() / mul) {
245 val *= mul;
246 } else {
247 // Clamp to a multiple of 1024.
248 val = std::numeric_limits<size_t>::max() & ~(1024-1);
249 }
250 } else {
251 // There's more than one character after the numeric part.
252 return 0;
253 }
254 }
255 // The man page says that a -Xm value must be a multiple of 1024.
256 if (val % div == 0) {
257 return val;
258 }
259 }
260 }
261 return 0;
262 }
263
264 static const char* Name() { return Memory<Divisor>::Name(); }
265};
266
267template <>
268struct CmdlineType<double> : CmdlineTypeParser<double> {
269 Result Parse(const std::string& str) {
270 char* end = nullptr;
271 errno = 0;
272 double value = strtod(str.c_str(), &end);
273
274 if (*end != '\0') {
275 return Result::Failure("Failed to parse double from " + str);
276 }
277 if (errno == ERANGE) {
278 return Result::OutOfRange(
279 "Failed to parse double from " + str + "; overflow/underflow occurred");
280 }
281
282 return Result::Success(value);
283 }
284
285 static const char* Name() { return "double"; }
286};
287
288template <>
289struct CmdlineType<unsigned int> : CmdlineTypeParser<unsigned int> {
290 Result Parse(const std::string& str) {
291 const char* begin = str.c_str();
292 char* end;
293
294 // Parse into a larger type (long long) because we can't use strtoul
295 // since it silently converts negative values into unsigned long and doesn't set errno.
296 errno = 0;
297 long long int result = strtoll(begin, &end, 10); // NOLINT [runtime/int] [4]
298 if (begin == end || *end != '\0' || errno == EINVAL) {
299 return Result::Failure("Failed to parse integer from " + str);
300 } else if ((errno == ERANGE) || // NOLINT [runtime/int] [4]
301 result < std::numeric_limits<int>::min()
302 || result > std::numeric_limits<unsigned int>::max() || result < 0) {
303 return Result::OutOfRange(
304 "Failed to parse integer from " + str + "; out of unsigned int range");
305 }
306
307 return Result::Success(static_cast<unsigned int>(result));
308 }
309
310 static const char* Name() { return "unsigned integer"; }
311};
312
313// Lightweight nanosecond value type. Allows parser to convert user-input from milliseconds
314// to nanoseconds automatically after parsing.
315//
316// All implicit conversion from uint64_t uses nanoseconds.
317struct MillisecondsToNanoseconds {
318 // Create from nanoseconds.
319 MillisecondsToNanoseconds(uint64_t nanoseconds) : nanoseconds_(nanoseconds) { // NOLINT [runtime/explicit] [5]
320 }
321
322 // Create from milliseconds.
323 static MillisecondsToNanoseconds FromMilliseconds(unsigned int milliseconds) {
324 return MillisecondsToNanoseconds(MsToNs(milliseconds));
325 }
326
327 // Get the underlying nanoseconds value.
328 uint64_t GetNanoseconds() const {
329 return nanoseconds_;
330 }
331
332 // Get the milliseconds value [via a conversion]. Loss of precision will occur.
333 uint64_t GetMilliseconds() const {
334 return NsToMs(nanoseconds_);
335 }
336
337 // Get the underlying nanoseconds value.
338 operator uint64_t() const {
339 return GetNanoseconds();
340 }
341
342 // Default constructors/copy-constructors.
343 MillisecondsToNanoseconds() : nanoseconds_(0ul) {}
Andreas Gampec801f0d2015-02-24 20:55:16 -0800344 MillisecondsToNanoseconds(const MillisecondsToNanoseconds&) = default;
345 MillisecondsToNanoseconds(MillisecondsToNanoseconds&&) = default;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800346
347 private:
348 uint64_t nanoseconds_;
349};
350
351template <>
352struct CmdlineType<MillisecondsToNanoseconds> : CmdlineTypeParser<MillisecondsToNanoseconds> {
353 Result Parse(const std::string& str) {
354 CmdlineType<unsigned int> uint_parser;
355 CmdlineParseResult<unsigned int> res = uint_parser.Parse(str);
356
357 if (res.IsSuccess()) {
358 return Result::Success(MillisecondsToNanoseconds::FromMilliseconds(res.GetValue()));
359 } else {
360 return Result::CastError(res);
361 }
362 }
363
364 static const char* Name() { return "MillisecondsToNanoseconds"; }
365};
366
367template <>
368struct CmdlineType<std::string> : CmdlineTypeParser<std::string> {
369 Result Parse(const std::string& args) {
370 return Result::Success(args);
371 }
372
373 Result ParseAndAppend(const std::string& args,
374 std::string& existing_value) {
375 if (existing_value.empty()) {
376 existing_value = args;
377 } else {
378 existing_value += ' ';
379 existing_value += args;
380 }
381 return Result::SuccessNoValue();
382 }
383};
384
385template <>
Alex Light185d1342016-08-11 10:48:03 -0700386struct CmdlineType<std::vector<Plugin>> : CmdlineTypeParser<std::vector<Plugin>> {
387 Result Parse(const std::string& args) {
388 assert(false && "Use AppendValues() for a Plugin vector type");
389 return Result::Failure("Unconditional failure: Plugin vector must be appended: " + args);
390 }
391
392 Result ParseAndAppend(const std::string& args,
393 std::vector<Plugin>& existing_value) {
394 existing_value.push_back(Plugin::Create(args));
395 return Result::SuccessNoValue();
396 }
397
398 static const char* Name() { return "std::vector<Plugin>"; }
399};
400
401template <>
Alex Light7233c7e2016-07-28 10:07:45 -0700402struct CmdlineType<std::vector<ti::Agent>> : CmdlineTypeParser<std::vector<ti::Agent>> {
403 Result Parse(const std::string& args) {
404 assert(false && "Use AppendValues() for an Agent vector type");
405 return Result::Failure("Unconditional failure: Agent vector must be appended: " + args);
406 }
407
408 Result ParseAndAppend(const std::string& args,
409 std::vector<ti::Agent>& existing_value) {
Leonard Mosescueb842212016-10-06 17:26:36 -0700410 existing_value.emplace_back(args);
Alex Light7233c7e2016-07-28 10:07:45 -0700411 return Result::SuccessNoValue();
412 }
413
414 static const char* Name() { return "std::vector<ti::Agent>"; }
415};
416
417template <>
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800418struct CmdlineType<std::vector<std::string>> : CmdlineTypeParser<std::vector<std::string>> {
419 Result Parse(const std::string& args) {
420 assert(false && "Use AppendValues() for a string vector type");
421 return Result::Failure("Unconditional failure: string vector must be appended: " + args);
422 }
423
424 Result ParseAndAppend(const std::string& args,
425 std::vector<std::string>& existing_value) {
426 existing_value.push_back(args);
427 return Result::SuccessNoValue();
428 }
429
430 static const char* Name() { return "std::vector<std::string>"; }
431};
432
433template <char Separator>
434struct ParseStringList {
435 explicit ParseStringList(std::vector<std::string>&& list) : list_(list) {}
436
437 operator std::vector<std::string>() const {
438 return list_;
439 }
440
441 operator std::vector<std::string>&&() && {
442 return std::move(list_);
443 }
444
445 size_t Size() const {
446 return list_.size();
447 }
448
449 std::string Join() const {
450 return art::Join(list_, Separator);
451 }
452
453 static ParseStringList<Separator> Split(const std::string& str) {
454 std::vector<std::string> list;
455 art::Split(str, Separator, &list);
456 return ParseStringList<Separator>(std::move(list));
457 }
458
459 ParseStringList() = default;
Andreas Gampec801f0d2015-02-24 20:55:16 -0800460 ParseStringList(const ParseStringList&) = default;
461 ParseStringList(ParseStringList&&) = default;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800462
463 private:
464 std::vector<std::string> list_;
465};
466
467template <char Separator>
468struct CmdlineType<ParseStringList<Separator>> : CmdlineTypeParser<ParseStringList<Separator>> {
469 using Result = CmdlineParseResult<ParseStringList<Separator>>;
470
471 Result Parse(const std::string& args) {
472 return Result::Success(ParseStringList<Separator>::Split(args));
473 }
474
475 static const char* Name() { return "ParseStringList<Separator>"; }
476};
477
478static gc::CollectorType ParseCollectorType(const std::string& option) {
479 if (option == "MS" || option == "nonconcurrent") {
480 return gc::kCollectorTypeMS;
481 } else if (option == "CMS" || option == "concurrent") {
482 return gc::kCollectorTypeCMS;
483 } else if (option == "SS") {
484 return gc::kCollectorTypeSS;
485 } else if (option == "GSS") {
486 return gc::kCollectorTypeGSS;
487 } else if (option == "CC") {
488 return gc::kCollectorTypeCC;
489 } else if (option == "MC") {
490 return gc::kCollectorTypeMC;
491 } else {
492 return gc::kCollectorTypeNone;
493 }
494}
495
496struct XGcOption {
497 // These defaults are used when the command line arguments for -Xgc:
498 // are either omitted completely or partially.
Mathieu Chartier56fe2582016-07-14 13:30:03 -0700499 gc::CollectorType collector_type_ = kUseReadBarrier ?
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800500 // If RB is enabled (currently a build-time decision),
501 // use CC as the default GC.
502 gc::kCollectorTypeCC :
503 gc::kCollectorTypeDefault;
504 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) {
583
584 if (kUseReadBarrier) {
Hiroshi Yamauchi60985b72016-08-24 13:53:12 -0700585 background_collector_type_ = gc::kCollectorTypeCCBackground; // Background compaction for CC.
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800586 }
587 }
588
589 operator gc::CollectorType() const { return background_collector_type_; }
590};
591
592template<>
593struct CmdlineType<BackgroundGcOption>
594 : CmdlineTypeParser<BackgroundGcOption>, private BackgroundGcOption {
595 Result Parse(const std::string& substring) {
596 // Special handling for HSpaceCompact since this is only valid as a background GC type.
597 if (substring == "HSpaceCompact") {
598 background_collector_type_ = gc::kCollectorTypeHomogeneousSpaceCompact;
599 } else {
600 gc::CollectorType collector_type = ParseCollectorType(substring);
601 if (collector_type != gc::kCollectorTypeNone) {
602 background_collector_type_ = collector_type;
603 } else {
604 return Result::Failure();
605 }
606 }
607
608 BackgroundGcOption res = *this;
609 return Result::Success(res);
610 }
611
612 static const char* Name() { return "BackgroundGcOption"; }
613};
614
615template <>
616struct CmdlineType<LogVerbosity> : CmdlineTypeParser<LogVerbosity> {
617 Result Parse(const std::string& options) {
618 LogVerbosity log_verbosity = LogVerbosity();
619
620 std::vector<std::string> verbose_options;
621 Split(options, ',', &verbose_options);
622 for (size_t j = 0; j < verbose_options.size(); ++j) {
623 if (verbose_options[j] == "class") {
624 log_verbosity.class_linker = true;
Mathieu Chartier66a55392016-02-19 10:25:39 -0800625 } else if (verbose_options[j] == "collector") {
626 log_verbosity.collector = true;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800627 } else if (verbose_options[j] == "compiler") {
628 log_verbosity.compiler = true;
Andreas Gampef3d1f942015-05-18 21:41:13 -0700629 } else if (verbose_options[j] == "deopt") {
630 log_verbosity.deopt = true;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800631 } else if (verbose_options[j] == "gc") {
632 log_verbosity.gc = true;
633 } else if (verbose_options[j] == "heap") {
634 log_verbosity.heap = true;
635 } else if (verbose_options[j] == "jdwp") {
636 log_verbosity.jdwp = true;
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800637 } else if (verbose_options[j] == "jit") {
638 log_verbosity.jit = true;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800639 } else if (verbose_options[j] == "jni") {
640 log_verbosity.jni = true;
641 } else if (verbose_options[j] == "monitor") {
642 log_verbosity.monitor = true;
Richard Uhler66d874d2015-01-15 09:37:19 -0800643 } else if (verbose_options[j] == "oat") {
644 log_verbosity.oat = true;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800645 } else if (verbose_options[j] == "profiler") {
646 log_verbosity.profiler = true;
647 } else if (verbose_options[j] == "signals") {
648 log_verbosity.signals = true;
Phil Wang751beff2015-08-28 15:17:15 +0800649 } else if (verbose_options[j] == "simulator") {
650 log_verbosity.simulator = true;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800651 } else if (verbose_options[j] == "startup") {
652 log_verbosity.startup = true;
653 } else if (verbose_options[j] == "third-party-jni") {
654 log_verbosity.third_party_jni = true;
655 } else if (verbose_options[j] == "threads") {
656 log_verbosity.threads = true;
657 } else if (verbose_options[j] == "verifier") {
658 log_verbosity.verifier = true;
Mathieu Chartierfbc31082016-01-24 11:59:56 -0800659 } else if (verbose_options[j] == "image") {
660 log_verbosity.image = true;
Andreas Gampec7ed09b2016-04-25 20:08:55 -0700661 } else if (verbose_options[j] == "systrace-locks") {
662 log_verbosity.systrace_lock_logging = true;
Alex Light7233c7e2016-07-28 10:07:45 -0700663 } else if (verbose_options[j] == "agents") {
664 log_verbosity.agents = true;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800665 } else {
666 return Result::Usage(std::string("Unknown -verbose option ") + verbose_options[j]);
667 }
668 }
669
670 return Result::Success(log_verbosity);
671 }
672
673 static const char* Name() { return "LogVerbosity"; }
674};
675
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800676template <>
Calin Juravle138dbff2016-06-28 19:36:58 +0100677struct CmdlineType<ProfileSaverOptions> : CmdlineTypeParser<ProfileSaverOptions> {
678 using Result = CmdlineParseResult<ProfileSaverOptions>;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800679
680 private:
681 using StringResult = CmdlineParseResult<std::string>;
682 using DoubleResult = CmdlineParseResult<double>;
683
684 template <typename T>
Calin Juravle138dbff2016-06-28 19:36:58 +0100685 static Result ParseInto(ProfileSaverOptions& options,
686 T ProfileSaverOptions::*pField,
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800687 CmdlineParseResult<T>&& result) {
688 assert(pField != nullptr);
689
690 if (result.IsSuccess()) {
691 options.*pField = result.ReleaseValue();
692 return Result::SuccessNoValue();
693 }
694
695 return Result::CastError(result);
696 }
697
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800698 static std::string RemovePrefix(const std::string& source) {
699 size_t prefix_idx = source.find(":");
700
701 if (prefix_idx == std::string::npos) {
702 return "";
703 }
704
705 return source.substr(prefix_idx + 1);
706 }
707
708 public:
Calin Juravle138dbff2016-06-28 19:36:58 +0100709 Result ParseAndAppend(const std::string& option, ProfileSaverOptions& existing) {
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800710 // Special case which doesn't include a wildcard argument definition.
711 // We pass-it through as-is.
Calin Juravle138dbff2016-06-28 19:36:58 +0100712 if (option == "-Xjitsaveprofilinginfo") {
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800713 existing.enabled_ = true;
714 return Result::SuccessNoValue();
715 }
716
Calin Juravle138dbff2016-06-28 19:36:58 +0100717 // The rest of these options are always the wildcard from '-Xps-*'
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800718 std::string suffix = RemovePrefix(option);
719
Calin Juravle138dbff2016-06-28 19:36:58 +0100720 if (StartsWith(option, "min-save-period-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::min_save_period_ms_,
724 type_parser.Parse(suffix));
725 }
726 if (StartsWith(option, "save-resolved-classes-delay-ms:")) {
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::save_resolved_classes_delay_ms_,
730 type_parser.Parse(suffix));
731 }
732 if (StartsWith(option, "startup-method-samples:")) {
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::startup_method_samples_,
736 type_parser.Parse(suffix));
737 }
738 if (StartsWith(option, "min-methods-to-save:")) {
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800739 CmdlineType<unsigned int> type_parser;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800740 return ParseInto(existing,
Calin Juravle138dbff2016-06-28 19:36:58 +0100741 &ProfileSaverOptions::min_methods_to_save_,
742 type_parser.Parse(suffix));
743 }
744 if (StartsWith(option, "min-classes-to-save:")) {
745 CmdlineType<unsigned int> type_parser;
746 return ParseInto(existing,
747 &ProfileSaverOptions::min_classes_to_save_,
748 type_parser.Parse(suffix));
749 }
750 if (StartsWith(option, "min-notification-before-wake:")) {
751 CmdlineType<unsigned int> type_parser;
752 return ParseInto(existing,
753 &ProfileSaverOptions::min_notification_before_wake_,
754 type_parser.Parse(suffix));
755 }
756 if (StartsWith(option, "max-notification-before-wake:")) {
757 CmdlineType<unsigned int> type_parser;
758 return ParseInto(existing,
759 &ProfileSaverOptions::max_notification_before_wake_,
760 type_parser.Parse(suffix));
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800761 } else {
762 return Result::Failure(std::string("Invalid suboption '") + option + "'");
763 }
764 }
765
Calin Juravle138dbff2016-06-28 19:36:58 +0100766 static const char* Name() { return "ProfileSaverOptions"; }
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800767 static constexpr bool kCanParseBlankless = true;
768};
769
Alex Lighteb7c1442015-08-31 13:17:42 -0700770template<>
771struct CmdlineType<ExperimentalFlags> : CmdlineTypeParser<ExperimentalFlags> {
772 Result ParseAndAppend(const std::string& option, ExperimentalFlags& existing) {
773 if (option == "none") {
Neil Fuller9724c632016-01-07 15:42:47 +0000774 existing = ExperimentalFlags::kNone;
Alex Light7233c7e2016-07-28 10:07:45 -0700775 } else if (option == "agents") {
776 existing = existing | ExperimentalFlags::kAgents;
Alex Light185d1342016-08-11 10:48:03 -0700777 } else if (option == "runtime-plugins") {
778 existing = existing | ExperimentalFlags::kRuntimePlugins;
Narayan Kamath25352fc2016-08-03 12:46:58 +0100779 } else if (option == "method-handles") {
780 existing = existing | ExperimentalFlags::kMethodHandles;
Alex Lighteb7c1442015-08-31 13:17:42 -0700781 } else {
782 return Result::Failure(std::string("Unknown option '") + option + "'");
783 }
784 return Result::SuccessNoValue();
785 }
786
787 static const char* Name() { return "ExperimentalFlags"; }
788};
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800789
790} // namespace art
791#endif // ART_CMDLINE_CMDLINE_TYPES_H_