1 /*
2  * Copyright (C) 2011 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 
17 #include "parsed_options.h"
18 
19 #include <sstream>
20 
21 #include "base/stringpiece.h"
22 #include "debugger.h"
23 #include "gc/heap.h"
24 #include "monitor.h"
25 #include "runtime.h"
26 #include "trace.h"
27 #include "utils.h"
28 
29 #include "cmdline_parser.h"
30 #include "runtime_options.h"
31 
32 namespace art {
33 
34 using MemoryKiB = Memory<1024>;
35 
ParsedOptions()36 ParsedOptions::ParsedOptions()
37   : hook_is_sensitive_thread_(nullptr),
38     hook_vfprintf_(vfprintf),
39     hook_exit_(exit),
40     hook_abort_(nullptr) {                          // We don't call abort(3) by default; see
41                                                     // Runtime::Abort
42 }
43 
Create(const RuntimeOptions & options,bool ignore_unrecognized,RuntimeArgumentMap * runtime_options)44 ParsedOptions* ParsedOptions::Create(const RuntimeOptions& options, bool ignore_unrecognized,
45                                      RuntimeArgumentMap* runtime_options) {
46   CHECK(runtime_options != nullptr);
47 
48   std::unique_ptr<ParsedOptions> parsed(new ParsedOptions());
49   if (parsed->Parse(options, ignore_unrecognized, runtime_options)) {
50     return parsed.release();
51   }
52   return nullptr;
53 }
54 
55 using RuntimeParser = CmdlineParser<RuntimeArgumentMap, RuntimeArgumentMap::Key>;
56 
57 // Yes, the stack frame is huge. But we get called super early on (and just once)
58 // to pass the command line arguments, so we'll probably be ok.
59 // Ideas to avoid suppressing this diagnostic are welcome!
60 #pragma GCC diagnostic push
61 #pragma GCC diagnostic ignored "-Wframe-larger-than="
62 
MakeParser(bool ignore_unrecognized)63 std::unique_ptr<RuntimeParser> ParsedOptions::MakeParser(bool ignore_unrecognized) {
64   using M = RuntimeArgumentMap;
65 
66   std::unique_ptr<RuntimeParser::Builder> parser_builder =
67       std::unique_ptr<RuntimeParser::Builder>(new RuntimeParser::Builder());
68 
69   parser_builder->
70        Define("-Xzygote")
71           .IntoKey(M::Zygote)
72       .Define("-help")
73           .IntoKey(M::Help)
74       .Define("-showversion")
75           .IntoKey(M::ShowVersion)
76       .Define("-Xbootclasspath:_")
77           .WithType<std::string>()
78           .IntoKey(M::BootClassPath)
79       .Define("-Xbootclasspath-locations:_")
80           .WithType<ParseStringList<':'>>()  // std::vector<std::string>, split by :
81           .IntoKey(M::BootClassPathLocations)
82       .Define({"-classpath _", "-cp _"})
83           .WithType<std::string>()
84           .IntoKey(M::ClassPath)
85       .Define("-Ximage:_")
86           .WithType<std::string>()
87           .IntoKey(M::Image)
88       .Define("-Xcheck:jni")
89           .IntoKey(M::CheckJni)
90       .Define("-Xjniopts:forcecopy")
91           .IntoKey(M::JniOptsForceCopy)
92       .Define({"-Xrunjdwp:_", "-agentlib:jdwp=_"})
93           .WithType<JDWP::JdwpOptions>()
94           .IntoKey(M::JdwpOptions)
95       .Define("-Xms_")
96           .WithType<MemoryKiB>()
97           .IntoKey(M::MemoryInitialSize)
98       .Define("-Xmx_")
99           .WithType<MemoryKiB>()
100           .IntoKey(M::MemoryMaximumSize)
101       .Define("-XX:HeapGrowthLimit=_")
102           .WithType<MemoryKiB>()
103           .IntoKey(M::HeapGrowthLimit)
104       .Define("-XX:HeapMinFree=_")
105           .WithType<MemoryKiB>()
106           .IntoKey(M::HeapMinFree)
107       .Define("-XX:HeapMaxFree=_")
108           .WithType<MemoryKiB>()
109           .IntoKey(M::HeapMaxFree)
110       .Define("-XX:NonMovingSpaceCapacity=_")
111           .WithType<MemoryKiB>()
112           .IntoKey(M::NonMovingSpaceCapacity)
113       .Define("-XX:HeapTargetUtilization=_")
114           .WithType<double>().WithRange(0.1, 0.9)
115           .IntoKey(M::HeapTargetUtilization)
116       .Define("-XX:ForegroundHeapGrowthMultiplier=_")
117           .WithType<double>().WithRange(0.1, 1.0)
118           .IntoKey(M::ForegroundHeapGrowthMultiplier)
119       .Define("-XX:ParallelGCThreads=_")
120           .WithType<unsigned int>()
121           .IntoKey(M::ParallelGCThreads)
122       .Define("-XX:ConcGCThreads=_")
123           .WithType<unsigned int>()
124           .IntoKey(M::ConcGCThreads)
125       .Define("-Xss_")
126           .WithType<Memory<1>>()
127           .IntoKey(M::StackSize)
128       .Define("-XX:MaxSpinsBeforeThinLockInflation=_")
129           .WithType<unsigned int>()
130           .IntoKey(M::MaxSpinsBeforeThinLockInflation)
131       .Define("-XX:LongPauseLogThreshold=_")  // in ms
132           .WithType<MillisecondsToNanoseconds>()  // store as ns
133           .IntoKey(M::LongPauseLogThreshold)
134       .Define("-XX:LongGCLogThreshold=_")  // in ms
135           .WithType<MillisecondsToNanoseconds>()  // store as ns
136           .IntoKey(M::LongGCLogThreshold)
137       .Define("-XX:DumpGCPerformanceOnShutdown")
138           .IntoKey(M::DumpGCPerformanceOnShutdown)
139       .Define("-XX:DumpJITInfoOnShutdown")
140           .IntoKey(M::DumpJITInfoOnShutdown)
141       .Define("-XX:IgnoreMaxFootprint")
142           .IntoKey(M::IgnoreMaxFootprint)
143       .Define("-XX:LowMemoryMode")
144           .IntoKey(M::LowMemoryMode)
145       .Define("-XX:UseTLAB")
146           .WithValue(true)
147           .IntoKey(M::UseTLAB)
148       .Define({"-XX:EnableHSpaceCompactForOOM", "-XX:DisableHSpaceCompactForOOM"})
149           .WithValues({true, false})
150           .IntoKey(M::EnableHSpaceCompactForOOM)
151       .Define("-Xusejit:_")
152           .WithType<bool>()
153           .WithValueMap({{"false", false}, {"true", true}})
154           .IntoKey(M::UseJIT)
155       .Define("-Xjitcodecachesize:_")
156           .WithType<MemoryKiB>()
157           .IntoKey(M::JITCodeCacheCapacity)
158       .Define("-Xjitthreshold:_")
159           .WithType<unsigned int>()
160           .IntoKey(M::JITCompileThreshold)
161       .Define("-XX:HspaceCompactForOOMMinIntervalMs=_")  // in ms
162           .WithType<MillisecondsToNanoseconds>()  // store as ns
163           .IntoKey(M::HSpaceCompactForOOMMinIntervalsMs)
164       .Define("-D_")
165           .WithType<std::vector<std::string>>().AppendValues()
166           .IntoKey(M::PropertiesList)
167       .Define("-Xjnitrace:_")
168           .WithType<std::string>()
169           .IntoKey(M::JniTrace)
170       .Define("-Xpatchoat:_")
171           .WithType<std::string>()
172           .IntoKey(M::PatchOat)
173       .Define({"-Xrelocate", "-Xnorelocate"})
174           .WithValues({true, false})
175           .IntoKey(M::Relocate)
176       .Define({"-Xdex2oat", "-Xnodex2oat"})
177           .WithValues({true, false})
178           .IntoKey(M::Dex2Oat)
179       .Define({"-Ximage-dex2oat", "-Xnoimage-dex2oat"})
180           .WithValues({true, false})
181           .IntoKey(M::ImageDex2Oat)
182       .Define("-Xint")
183           .WithValue(true)
184           .IntoKey(M::Interpret)
185       .Define("-Xgc:_")
186           .WithType<XGcOption>()
187           .IntoKey(M::GcOption)
188       .Define("-XX:LargeObjectSpace=_")
189           .WithType<gc::space::LargeObjectSpaceType>()
190           .WithValueMap({{"disabled", gc::space::LargeObjectSpaceType::kDisabled},
191                          {"freelist", gc::space::LargeObjectSpaceType::kFreeList},
192                          {"map",      gc::space::LargeObjectSpaceType::kMap}})
193           .IntoKey(M::LargeObjectSpace)
194       .Define("-XX:LargeObjectThreshold=_")
195           .WithType<Memory<1>>()
196           .IntoKey(M::LargeObjectThreshold)
197       .Define("-XX:BackgroundGC=_")
198           .WithType<BackgroundGcOption>()
199           .IntoKey(M::BackgroundGc)
200       .Define("-XX:+DisableExplicitGC")
201           .IntoKey(M::DisableExplicitGC)
202       .Define("-verbose:_")
203           .WithType<LogVerbosity>()
204           .IntoKey(M::Verbose)
205       .Define("-Xlockprofthreshold:_")
206           .WithType<unsigned int>()
207           .IntoKey(M::LockProfThreshold)
208       .Define("-Xstacktracefile:_")
209           .WithType<std::string>()
210           .IntoKey(M::StackTraceFile)
211       .Define("-Xmethod-trace")
212           .IntoKey(M::MethodTrace)
213       .Define("-Xmethod-trace-file:_")
214           .WithType<std::string>()
215           .IntoKey(M::MethodTraceFile)
216       .Define("-Xmethod-trace-file-size:_")
217           .WithType<unsigned int>()
218           .IntoKey(M::MethodTraceFileSize)
219       .Define("-Xmethod-trace-stream")
220           .IntoKey(M::MethodTraceStreaming)
221       .Define("-Xprofile:_")
222           .WithType<TraceClockSource>()
223           .WithValueMap({{"threadcpuclock", TraceClockSource::kThreadCpu},
224                          {"wallclock",      TraceClockSource::kWall},
225                          {"dualclock",      TraceClockSource::kDual}})
226           .IntoKey(M::ProfileClock)
227       .Define("-Xenable-profiler")
228           .WithType<TestProfilerOptions>()
229           .AppendValues()
230           .IntoKey(M::ProfilerOpts)  // NOTE: Appends into same key as -Xprofile-*
231       .Define("-Xprofile-_")  // -Xprofile-<key>:<value>
232           .WithType<TestProfilerOptions>()
233           .AppendValues()
234           .IntoKey(M::ProfilerOpts)  // NOTE: Appends into same key as -Xenable-profiler
235       .Define("-Xcompiler:_")
236           .WithType<std::string>()
237           .IntoKey(M::Compiler)
238       .Define("-Xcompiler-option _")
239           .WithType<std::vector<std::string>>()
240           .AppendValues()
241           .IntoKey(M::CompilerOptions)
242       .Define("-Ximage-compiler-option _")
243           .WithType<std::vector<std::string>>()
244           .AppendValues()
245           .IntoKey(M::ImageCompilerOptions)
246       .Define("-Xverify:_")
247           .WithType<bool>()
248           .WithValueMap({{"none", false},
249                          {"remote", true},
250                          {"all", true}})
251           .IntoKey(M::Verify)
252       .Define("-XX:NativeBridge=_")
253           .WithType<std::string>()
254           .IntoKey(M::NativeBridge)
255       .Define("-Xzygote-max-boot-retry=_")
256           .WithType<unsigned int>()
257           .IntoKey(M::ZygoteMaxFailedBoots)
258       .Define("-Xno-dex-file-fallback")
259           .IntoKey(M::NoDexFileFallback)
260       .Define("--cpu-abilist=_")
261           .WithType<std::string>()
262           .IntoKey(M::CpuAbiList)
263       .Define("-Xfingerprint:_")
264           .WithType<std::string>()
265           .IntoKey(M::Fingerprint)
266       .Ignore({
267           "-ea", "-da", "-enableassertions", "-disableassertions", "--runtime-arg", "-esa",
268           "-dsa", "-enablesystemassertions", "-disablesystemassertions", "-Xrs", "-Xint:_",
269           "-Xdexopt:_", "-Xnoquithandler", "-Xjnigreflimit:_", "-Xgenregmap", "-Xnogenregmap",
270           "-Xverifyopt:_", "-Xcheckdexsum", "-Xincludeselectedop", "-Xjitop:_",
271           "-Xincludeselectedmethod", "-Xjitthreshold:_",
272           "-Xjitblocking", "-Xjitmethod:_", "-Xjitclass:_", "-Xjitoffset:_",
273           "-Xjitconfig:_", "-Xjitcheckcg", "-Xjitverbose", "-Xjitprofile",
274           "-Xjitdisableopt", "-Xjitsuspendpoll", "-XX:mainThreadStackSize=_"})
275       .IgnoreUnrecognized(ignore_unrecognized);
276 
277   // TODO: Move Usage information into this DSL.
278 
279   return std::unique_ptr<RuntimeParser>(new RuntimeParser(parser_builder->Build()));
280 }
281 
282 #pragma GCC diagnostic pop
283 
284 // Remove all the special options that have something in the void* part of the option.
285 // If runtime_options is not null, put the options in there.
286 // As a side-effect, populate the hooks from options.
ProcessSpecialOptions(const RuntimeOptions & options,RuntimeArgumentMap * runtime_options,std::vector<std::string> * out_options)287 bool ParsedOptions::ProcessSpecialOptions(const RuntimeOptions& options,
288                                           RuntimeArgumentMap* runtime_options,
289                                           std::vector<std::string>* out_options) {
290   using M = RuntimeArgumentMap;
291 
292   // TODO: Move the below loop into JNI
293   // Handle special options that set up hooks
294   for (size_t i = 0; i < options.size(); ++i) {
295     const std::string option(options[i].first);
296       // TODO: support -Djava.class.path
297     if (option == "bootclasspath") {
298       auto boot_class_path
299           = reinterpret_cast<const std::vector<const DexFile*>*>(options[i].second);
300 
301       if (runtime_options != nullptr) {
302         runtime_options->Set(M::BootClassPathDexList, boot_class_path);
303       }
304     } else if (option == "compilercallbacks") {
305       CompilerCallbacks* compiler_callbacks =
306           reinterpret_cast<CompilerCallbacks*>(const_cast<void*>(options[i].second));
307       if (runtime_options != nullptr) {
308         runtime_options->Set(M::CompilerCallbacksPtr, compiler_callbacks);
309       }
310     } else if (option == "imageinstructionset") {
311       const char* isa_str = reinterpret_cast<const char*>(options[i].second);
312       auto&& image_isa = GetInstructionSetFromString(isa_str);
313       if (image_isa == kNone) {
314         Usage("%s is not a valid instruction set.", isa_str);
315         return false;
316       }
317       if (runtime_options != nullptr) {
318         runtime_options->Set(M::ImageInstructionSet, image_isa);
319       }
320     } else if (option == "sensitiveThread") {
321       const void* hook = options[i].second;
322       bool (*hook_is_sensitive_thread)() = reinterpret_cast<bool (*)()>(const_cast<void*>(hook));
323 
324       if (runtime_options != nullptr) {
325         runtime_options->Set(M::HookIsSensitiveThread, hook_is_sensitive_thread);
326       }
327     } else if (option == "vfprintf") {
328       const void* hook = options[i].second;
329       if (hook == nullptr) {
330         Usage("vfprintf argument was nullptr");
331         return false;
332       }
333       int (*hook_vfprintf)(FILE *, const char*, va_list) =
334           reinterpret_cast<int (*)(FILE *, const char*, va_list)>(const_cast<void*>(hook));
335 
336       if (runtime_options != nullptr) {
337         runtime_options->Set(M::HookVfprintf, hook_vfprintf);
338       }
339       hook_vfprintf_ = hook_vfprintf;
340     } else if (option == "exit") {
341       const void* hook = options[i].second;
342       if (hook == nullptr) {
343         Usage("exit argument was nullptr");
344         return false;
345       }
346       void(*hook_exit)(jint) = reinterpret_cast<void(*)(jint)>(const_cast<void*>(hook));
347       if (runtime_options != nullptr) {
348         runtime_options->Set(M::HookExit, hook_exit);
349       }
350       hook_exit_ = hook_exit;
351     } else if (option == "abort") {
352       const void* hook = options[i].second;
353       if (hook == nullptr) {
354         Usage("abort was nullptr\n");
355         return false;
356       }
357       void(*hook_abort)() = reinterpret_cast<void(*)()>(const_cast<void*>(hook));
358       if (runtime_options != nullptr) {
359         runtime_options->Set(M::HookAbort, hook_abort);
360       }
361       hook_abort_ = hook_abort;
362     } else {
363       // It is a regular option, that doesn't have a known 'second' value.
364       // Push it on to the regular options which will be parsed by our parser.
365       if (out_options != nullptr) {
366         out_options->push_back(option);
367       }
368     }
369   }
370 
371   return true;
372 }
373 
Parse(const RuntimeOptions & options,bool ignore_unrecognized,RuntimeArgumentMap * runtime_options)374 bool ParsedOptions::Parse(const RuntimeOptions& options, bool ignore_unrecognized,
375                           RuntimeArgumentMap* runtime_options) {
376   //  gLogVerbosity.class_linker = true;  // TODO: don't check this in!
377   //  gLogVerbosity.compiler = true;  // TODO: don't check this in!
378   //  gLogVerbosity.gc = true;  // TODO: don't check this in!
379   //  gLogVerbosity.heap = true;  // TODO: don't check this in!
380   //  gLogVerbosity.jdwp = true;  // TODO: don't check this in!
381   //  gLogVerbosity.jit = true;  // TODO: don't check this in!
382   //  gLogVerbosity.jni = true;  // TODO: don't check this in!
383   //  gLogVerbosity.monitor = true;  // TODO: don't check this in!
384   //  gLogVerbosity.profiler = true;  // TODO: don't check this in!
385   //  gLogVerbosity.signals = true;  // TODO: don't check this in!
386   //  gLogVerbosity.startup = true;  // TODO: don't check this in!
387   //  gLogVerbosity.third_party_jni = true;  // TODO: don't check this in!
388   //  gLogVerbosity.threads = true;  // TODO: don't check this in!
389   //  gLogVerbosity.verifier = true;  // TODO: don't check this in!
390 
391   for (size_t i = 0; i < options.size(); ++i) {
392     if (true && options[0].first == "-Xzygote") {
393       LOG(INFO) << "option[" << i << "]=" << options[i].first;
394     }
395   }
396 
397   auto parser = MakeParser(ignore_unrecognized);
398 
399   // Convert to a simple string list (without the magic pointer options)
400   std::vector<std::string> argv_list;
401   if (!ProcessSpecialOptions(options, nullptr, &argv_list)) {
402     return false;
403   }
404 
405   CmdlineResult parse_result = parser->Parse(argv_list);
406 
407   // Handle parse errors by displaying the usage and potentially exiting.
408   if (parse_result.IsError()) {
409     if (parse_result.GetStatus() == CmdlineResult::kUsage) {
410       UsageMessage(stdout, "%s\n", parse_result.GetMessage().c_str());
411       Exit(0);
412     } else if (parse_result.GetStatus() == CmdlineResult::kUnknown && !ignore_unrecognized) {
413       Usage("%s\n", parse_result.GetMessage().c_str());
414       return false;
415     } else {
416       Usage("%s\n", parse_result.GetMessage().c_str());
417       Exit(0);
418     }
419 
420     UNREACHABLE();
421   }
422 
423   using M = RuntimeArgumentMap;
424   RuntimeArgumentMap args = parser->ReleaseArgumentsMap();
425 
426   // -help, -showversion, etc.
427   if (args.Exists(M::Help)) {
428     Usage(nullptr);
429     return false;
430   } else if (args.Exists(M::ShowVersion)) {
431     UsageMessage(stdout, "ART version %s\n", Runtime::GetVersion());
432     Exit(0);
433   } else if (args.Exists(M::BootClassPath)) {
434     LOG(INFO) << "setting boot class path to " << *args.Get(M::BootClassPath);
435   }
436 
437   // Set a default boot class path if we didn't get an explicit one via command line.
438   if (getenv("BOOTCLASSPATH") != nullptr) {
439     args.SetIfMissing(M::BootClassPath, std::string(getenv("BOOTCLASSPATH")));
440   }
441 
442   // Set a default class path if we didn't get an explicit one via command line.
443   if (getenv("CLASSPATH") != nullptr) {
444     args.SetIfMissing(M::ClassPath, std::string(getenv("CLASSPATH")));
445   }
446 
447   // Default to number of processors minus one since the main GC thread also does work.
448   args.SetIfMissing(M::ParallelGCThreads, gc::Heap::kDefaultEnableParallelGC ?
449       static_cast<unsigned int>(sysconf(_SC_NPROCESSORS_CONF) - 1u) : 0u);
450 
451   // -Xverbose:
452   {
453     LogVerbosity *log_verbosity = args.Get(M::Verbose);
454     if (log_verbosity != nullptr) {
455       gLogVerbosity = *log_verbosity;
456     }
457   }
458 
459   // -Xprofile:
460   Trace::SetDefaultClockSource(args.GetOrDefault(M::ProfileClock));
461 
462   if (!ProcessSpecialOptions(options, &args, nullptr)) {
463       return false;
464   }
465 
466   {
467     // If not set, background collector type defaults to homogeneous compaction.
468     // If foreground is GSS, use GSS as background collector.
469     // If not low memory mode, semispace otherwise.
470 
471     gc::CollectorType background_collector_type_;
472     gc::CollectorType collector_type_ = (XGcOption{}).collector_type_;  // NOLINT [whitespace/braces] [5]
473     bool low_memory_mode_ = args.Exists(M::LowMemoryMode);
474 
475     background_collector_type_ = args.GetOrDefault(M::BackgroundGc);
476     {
477       XGcOption* xgc = args.Get(M::GcOption);
478       if (xgc != nullptr && xgc->collector_type_ != gc::kCollectorTypeNone) {
479         collector_type_ = xgc->collector_type_;
480       }
481     }
482 
483     if (background_collector_type_ == gc::kCollectorTypeNone) {
484       if (collector_type_ != gc::kCollectorTypeGSS) {
485         background_collector_type_ = low_memory_mode_ ?
486             gc::kCollectorTypeSS : gc::kCollectorTypeHomogeneousSpaceCompact;
487       } else {
488         background_collector_type_ = collector_type_;
489       }
490     }
491 
492     args.Set(M::BackgroundGc, BackgroundGcOption { background_collector_type_ });
493   }
494 
495   // If a reference to the dalvik core.jar snuck in, replace it with
496   // the art specific version. This can happen with on device
497   // boot.art/boot.oat generation by GenerateImage which relies on the
498   // value of BOOTCLASSPATH.
499 #if defined(ART_TARGET)
500   std::string core_jar("/core.jar");
501   std::string core_libart_jar("/core-libart.jar");
502 #else
503   // The host uses hostdex files.
504   std::string core_jar("/core-hostdex.jar");
505   std::string core_libart_jar("/core-libart-hostdex.jar");
506 #endif
507   auto boot_class_path_string = args.GetOrDefault(M::BootClassPath);
508 
509   size_t core_jar_pos = boot_class_path_string.find(core_jar);
510   if (core_jar_pos != std::string::npos) {
511     boot_class_path_string.replace(core_jar_pos, core_jar.size(), core_libart_jar);
512     args.Set(M::BootClassPath, boot_class_path_string);
513   }
514 
515   {
516     auto&& boot_class_path = args.GetOrDefault(M::BootClassPath);
517     auto&& boot_class_path_locations = args.GetOrDefault(M::BootClassPathLocations);
518     if (args.Exists(M::BootClassPathLocations)) {
519       size_t boot_class_path_count = ParseStringList<':'>::Split(boot_class_path).Size();
520 
521       if (boot_class_path_count != boot_class_path_locations.Size()) {
522         Usage("The number of boot class path files does not match"
523             " the number of boot class path locations given\n"
524             "  boot class path files     (%zu): %s\n"
525             "  boot class path locations (%zu): %s\n",
526             boot_class_path.size(), boot_class_path_string.c_str(),
527             boot_class_path_locations.Size(), boot_class_path_locations.Join().c_str());
528         return false;
529       }
530     }
531   }
532 
533   if (!args.Exists(M::CompilerCallbacksPtr) && !args.Exists(M::Image)) {
534     std::string image = GetAndroidRoot();
535     image += "/framework/boot.art";
536     args.Set(M::Image, image);
537   }
538 
539   if (args.GetOrDefault(M::HeapGrowthLimit) == 0u) {  // 0 means no growth limit
540     args.Set(M::HeapGrowthLimit, args.GetOrDefault(M::MemoryMaximumSize));
541   }
542 
543   *runtime_options = std::move(args);
544   return true;
545 }
546 
Exit(int status)547 void ParsedOptions::Exit(int status) {
548   hook_exit_(status);
549 }
550 
Abort()551 void ParsedOptions::Abort() {
552   hook_abort_();
553 }
554 
UsageMessageV(FILE * stream,const char * fmt,va_list ap)555 void ParsedOptions::UsageMessageV(FILE* stream, const char* fmt, va_list ap) {
556   hook_vfprintf_(stream, fmt, ap);
557 }
558 
UsageMessage(FILE * stream,const char * fmt,...)559 void ParsedOptions::UsageMessage(FILE* stream, const char* fmt, ...) {
560   va_list ap;
561   va_start(ap, fmt);
562   UsageMessageV(stream, fmt, ap);
563   va_end(ap);
564 }
565 
Usage(const char * fmt,...)566 void ParsedOptions::Usage(const char* fmt, ...) {
567   bool error = (fmt != nullptr);
568   FILE* stream = error ? stderr : stdout;
569 
570   if (fmt != nullptr) {
571     va_list ap;
572     va_start(ap, fmt);
573     UsageMessageV(stream, fmt, ap);
574     va_end(ap);
575   }
576 
577   const char* program = "dalvikvm";
578   UsageMessage(stream, "%s: [options] class [argument ...]\n", program);
579   UsageMessage(stream, "\n");
580   UsageMessage(stream, "The following standard options are supported:\n");
581   UsageMessage(stream, "  -classpath classpath (-cp classpath)\n");
582   UsageMessage(stream, "  -Dproperty=value\n");
583   UsageMessage(stream, "  -verbose:tag ('gc', 'jit', 'jni', or 'class')\n");
584   UsageMessage(stream, "  -showversion\n");
585   UsageMessage(stream, "  -help\n");
586   UsageMessage(stream, "  -agentlib:jdwp=options\n");
587   UsageMessage(stream, "\n");
588 
589   UsageMessage(stream, "The following extended options are supported:\n");
590   UsageMessage(stream, "  -Xrunjdwp:<options>\n");
591   UsageMessage(stream, "  -Xbootclasspath:bootclasspath\n");
592   UsageMessage(stream, "  -Xcheck:tag  (e.g. 'jni')\n");
593   UsageMessage(stream, "  -XmsN (min heap, must be multiple of 1K, >= 1MB)\n");
594   UsageMessage(stream, "  -XmxN (max heap, must be multiple of 1K, >= 2MB)\n");
595   UsageMessage(stream, "  -XssN (stack size)\n");
596   UsageMessage(stream, "  -Xint\n");
597   UsageMessage(stream, "\n");
598 
599   UsageMessage(stream, "The following Dalvik options are supported:\n");
600   UsageMessage(stream, "  -Xzygote\n");
601   UsageMessage(stream, "  -Xjnitrace:substring (eg NativeClass or nativeMethod)\n");
602   UsageMessage(stream, "  -Xstacktracefile:<filename>\n");
603   UsageMessage(stream, "  -Xgc:[no]preverify\n");
604   UsageMessage(stream, "  -Xgc:[no]postverify\n");
605   UsageMessage(stream, "  -XX:HeapGrowthLimit=N\n");
606   UsageMessage(stream, "  -XX:HeapMinFree=N\n");
607   UsageMessage(stream, "  -XX:HeapMaxFree=N\n");
608   UsageMessage(stream, "  -XX:NonMovingSpaceCapacity=N\n");
609   UsageMessage(stream, "  -XX:HeapTargetUtilization=doublevalue\n");
610   UsageMessage(stream, "  -XX:ForegroundHeapGrowthMultiplier=doublevalue\n");
611   UsageMessage(stream, "  -XX:LowMemoryMode\n");
612   UsageMessage(stream, "  -Xprofile:{threadcpuclock,wallclock,dualclock}\n");
613   UsageMessage(stream, "  -Xjitcodecachesize:N\n");
614   UsageMessage(stream, "  -Xjitthreshold:integervalue\n");
615   UsageMessage(stream, "\n");
616 
617   UsageMessage(stream, "The following unique to ART options are supported:\n");
618   UsageMessage(stream, "  -Xgc:[no]preverify_rosalloc\n");
619   UsageMessage(stream, "  -Xgc:[no]postsweepingverify_rosalloc\n");
620   UsageMessage(stream, "  -Xgc:[no]postverify_rosalloc\n");
621   UsageMessage(stream, "  -Xgc:[no]presweepingverify\n");
622   UsageMessage(stream, "  -Ximage:filename\n");
623   UsageMessage(stream, "  -Xbootclasspath-locations:bootclasspath\n"
624                        "     (override the dex locations of the -Xbootclasspath files)\n");
625   UsageMessage(stream, "  -XX:+DisableExplicitGC\n");
626   UsageMessage(stream, "  -XX:ParallelGCThreads=integervalue\n");
627   UsageMessage(stream, "  -XX:ConcGCThreads=integervalue\n");
628   UsageMessage(stream, "  -XX:MaxSpinsBeforeThinLockInflation=integervalue\n");
629   UsageMessage(stream, "  -XX:LongPauseLogThreshold=integervalue\n");
630   UsageMessage(stream, "  -XX:LongGCLogThreshold=integervalue\n");
631   UsageMessage(stream, "  -XX:DumpGCPerformanceOnShutdown\n");
632   UsageMessage(stream, "  -XX:DumpJITInfoOnShutdown\n");
633   UsageMessage(stream, "  -XX:IgnoreMaxFootprint\n");
634   UsageMessage(stream, "  -XX:UseTLAB\n");
635   UsageMessage(stream, "  -XX:BackgroundGC=none\n");
636   UsageMessage(stream, "  -XX:LargeObjectSpace={disabled,map,freelist}\n");
637   UsageMessage(stream, "  -XX:LargeObjectThreshold=N\n");
638   UsageMessage(stream, "  -Xmethod-trace\n");
639   UsageMessage(stream, "  -Xmethod-trace-file:filename");
640   UsageMessage(stream, "  -Xmethod-trace-file-size:integervalue\n");
641   UsageMessage(stream, "  -Xenable-profiler\n");
642   UsageMessage(stream, "  -Xprofile-filename:filename\n");
643   UsageMessage(stream, "  -Xprofile-period:integervalue\n");
644   UsageMessage(stream, "  -Xprofile-duration:integervalue\n");
645   UsageMessage(stream, "  -Xprofile-interval:integervalue\n");
646   UsageMessage(stream, "  -Xprofile-backoff:doublevalue\n");
647   UsageMessage(stream, "  -Xprofile-start-immediately\n");
648   UsageMessage(stream, "  -Xprofile-top-k-threshold:doublevalue\n");
649   UsageMessage(stream, "  -Xprofile-top-k-change-threshold:doublevalue\n");
650   UsageMessage(stream, "  -Xprofile-type:{method,stack}\n");
651   UsageMessage(stream, "  -Xprofile-max-stack-depth:integervalue\n");
652   UsageMessage(stream, "  -Xcompiler:filename\n");
653   UsageMessage(stream, "  -Xcompiler-option dex2oat-option\n");
654   UsageMessage(stream, "  -Ximage-compiler-option dex2oat-option\n");
655   UsageMessage(stream, "  -Xpatchoat:filename\n");
656   UsageMessage(stream, "  -Xusejit:booleanvalue\n");
657   UsageMessage(stream, "  -X[no]relocate\n");
658   UsageMessage(stream, "  -X[no]dex2oat (Whether to invoke dex2oat on the application)\n");
659   UsageMessage(stream, "  -X[no]image-dex2oat (Whether to create and use a boot image)\n");
660   UsageMessage(stream, "  -Xno-dex-file-fallback "
661                        "(Don't fall back to dex files without oat files)\n");
662   UsageMessage(stream, "\n");
663 
664   UsageMessage(stream, "The following previously supported Dalvik options are ignored:\n");
665   UsageMessage(stream, "  -ea[:<package name>... |:<class name>]\n");
666   UsageMessage(stream, "  -da[:<package name>... |:<class name>]\n");
667   UsageMessage(stream, "   (-enableassertions, -disableassertions)\n");
668   UsageMessage(stream, "  -esa\n");
669   UsageMessage(stream, "  -dsa\n");
670   UsageMessage(stream, "   (-enablesystemassertions, -disablesystemassertions)\n");
671   UsageMessage(stream, "  -Xverify:{none,remote,all}\n");
672   UsageMessage(stream, "  -Xrs\n");
673   UsageMessage(stream, "  -Xint:portable, -Xint:fast, -Xint:jit\n");
674   UsageMessage(stream, "  -Xdexopt:{none,verified,all,full}\n");
675   UsageMessage(stream, "  -Xnoquithandler\n");
676   UsageMessage(stream, "  -Xjniopts:{warnonly,forcecopy}\n");
677   UsageMessage(stream, "  -Xjnigreflimit:integervalue\n");
678   UsageMessage(stream, "  -Xgc:[no]precise\n");
679   UsageMessage(stream, "  -Xgc:[no]verifycardtable\n");
680   UsageMessage(stream, "  -X[no]genregmap\n");
681   UsageMessage(stream, "  -Xverifyopt:[no]checkmon\n");
682   UsageMessage(stream, "  -Xcheckdexsum\n");
683   UsageMessage(stream, "  -Xincludeselectedop\n");
684   UsageMessage(stream, "  -Xjitop:hexopvalue[-endvalue][,hexopvalue[-endvalue]]*\n");
685   UsageMessage(stream, "  -Xincludeselectedmethod\n");
686   UsageMessage(stream, "  -Xjitblocking\n");
687   UsageMessage(stream, "  -Xjitmethod:signature[,signature]* (eg Ljava/lang/String\\;replace)\n");
688   UsageMessage(stream, "  -Xjitclass:classname[,classname]*\n");
689   UsageMessage(stream, "  -Xjitoffset:offset[,offset]\n");
690   UsageMessage(stream, "  -Xjitconfig:filename\n");
691   UsageMessage(stream, "  -Xjitcheckcg\n");
692   UsageMessage(stream, "  -Xjitverbose\n");
693   UsageMessage(stream, "  -Xjitprofile\n");
694   UsageMessage(stream, "  -Xjitdisableopt\n");
695   UsageMessage(stream, "  -Xjitsuspendpoll\n");
696   UsageMessage(stream, "  -XX:mainThreadStackSize=N\n");
697   UsageMessage(stream, "\n");
698 
699   Exit((error) ? 1 : 0);
700 }
701 
702 }  // namespace art
703