diff options
author | Brian Carlstrom <bdc@google.com> | 2014-02-10 23:48:36 -0800 |
---|---|---|
committer | Brian Carlstrom <bdc@google.com> | 2014-02-24 14:24:12 -0800 |
commit | 6449c62e40ef3a9bb75f664f922555affb532ee4 (patch) | |
tree | 2f1b2120bd648c95dea32b68c8e168e42c8e24fd | |
parent | 3fcf18e25241253f23efbeebe77b2a4c4a7c54d3 (diff) | |
download | art-6449c62e40ef3a9bb75f664f922555affb532ee4.zip art-6449c62e40ef3a9bb75f664f922555affb532ee4.tar.gz art-6449c62e40ef3a9bb75f664f922555affb532ee4.tar.bz2 |
Create CompilerOptions
Package up most compiler related options in CompilerOptions. Details include:
- Includes compiler filter, method thresholds, SEA IR mode.
- Excludes those needed during Runtime::Init such as CompilerCallbacks and VerificationResults.
- Pass CompilerOptions to CompilerDriver.
- Remove CompilerOptions from Runtime.
- Add ability to pass options for app and image dex2oat to runtime via
-Xcompiler-option and -Ximage-compiler-option respectively.
Other
- Replace 2x CompilerCallbacks implementations with one.
- Factor out execv code for use by both image and oat generation.
- More OatFile error_msg reporting.
- DCHECK for SuspendAll found trying to run valgrind.
Change-Id: Iecb57da907be0c856d00c3cd634b5042a229e620
-rw-r--r-- | compiler/dex/frontend.cc | 2 | ||||
-rw-r--r-- | compiler/dex/mir_analysis.cc | 39 | ||||
-rw-r--r-- | compiler/dex/mir_graph.h | 2 | ||||
-rw-r--r-- | compiler/dex/verification_results.cc | 20 | ||||
-rw-r--r-- | compiler/dex/verification_results.h | 12 | ||||
-rw-r--r-- | compiler/driver/compiler_callbacks_impl.h | 59 | ||||
-rw-r--r-- | compiler/driver/compiler_driver.cc | 11 | ||||
-rw-r--r-- | compiler/driver/compiler_driver.h | 10 | ||||
-rw-r--r-- | compiler/driver/compiler_options.h | 136 | ||||
-rw-r--r-- | compiler/oat_test.cc | 9 | ||||
-rw-r--r-- | dex2oat/dex2oat.cc | 290 | ||||
-rw-r--r-- | runtime/class_linker.cc | 130 | ||||
-rw-r--r-- | runtime/common_test.h | 53 | ||||
-rw-r--r-- | runtime/gc/space/image_space.cc | 50 | ||||
-rw-r--r-- | runtime/oat_file.cc | 1 | ||||
-rw-r--r-- | runtime/runtime.cc | 61 | ||||
-rw-r--r-- | runtime/runtime.h | 77 | ||||
-rw-r--r-- | runtime/thread_list.cc | 1 | ||||
-rw-r--r-- | runtime/utils.cc | 53 | ||||
-rw-r--r-- | runtime/utils.h | 3 | ||||
-rw-r--r-- | runtime/utils_test.cc | 22 |
21 files changed, 632 insertions, 409 deletions
diff --git a/compiler/dex/frontend.cc b/compiler/dex/frontend.cc index 591d92a..6800f7b 100644 --- a/compiler/dex/frontend.cc +++ b/compiler/dex/frontend.cc @@ -211,7 +211,7 @@ static CompiledMethod* CompileMethod(CompilerDriver& compiler, class_loader, dex_file); cu.NewTimingSplit("MIROpt:CheckFilters"); - if (cu.mir_graph->SkipCompilation(Runtime::Current()->GetCompilerFilter())) { + if (cu.mir_graph->SkipCompilation()) { return NULL; } diff --git a/compiler/dex/mir_analysis.cc b/compiler/dex/mir_analysis.cc index ab55333..7ce8f69 100644 --- a/compiler/dex/mir_analysis.cc +++ b/compiler/dex/mir_analysis.cc @@ -18,6 +18,7 @@ #include "dataflow_iterator-inl.h" #include "dex/quick/dex_file_method_inliner.h" #include "dex/quick/dex_file_to_method_inliner_map.h" +#include "driver/compiler_options.h" namespace art { @@ -958,7 +959,7 @@ bool MIRGraph::ComputeSkipCompilation(MethodStats* stats, bool skip_default) { } // Complex, logic-intensive? - if ((GetNumDalvikInsns() > Runtime::Current()->GetSmallMethodThreshold()) && + if (cu_->compiler_driver->GetCompilerOptions().IsSmallMethod(GetNumDalvikInsns()) && stats->branch_ratio > 0.3) { return false; } @@ -984,7 +985,7 @@ bool MIRGraph::ComputeSkipCompilation(MethodStats* stats, bool skip_default) { } // If significant in size and high proportion of expensive operations, skip. - if ((GetNumDalvikInsns() > Runtime::Current()->GetSmallMethodThreshold()) && + if (cu_->compiler_driver->GetCompilerOptions().IsSmallMethod(GetNumDalvikInsns()) && (stats->heavyweight_ratio > 0.3)) { return true; } @@ -996,12 +997,14 @@ bool MIRGraph::ComputeSkipCompilation(MethodStats* stats, bool skip_default) { * Will eventually want this to be a bit more sophisticated and happen at verification time. * Ultimate goal is to drive with profile data. */ -bool MIRGraph::SkipCompilation(Runtime::CompilerFilter compiler_filter) { - if (compiler_filter == Runtime::kEverything) { +bool MIRGraph::SkipCompilation() { + const CompilerOptions& compiler_options = cu_->compiler_driver->GetCompilerOptions(); + CompilerOptions::CompilerFilter compiler_filter = compiler_options.GetCompilerFilter(); + if (compiler_filter == CompilerOptions::kEverything) { return false; } - if (compiler_filter == Runtime::kInterpretOnly) { + if (compiler_filter == CompilerOptions::kInterpretOnly) { LOG(WARNING) << "InterpretOnly should ideally be filtered out prior to parsing."; return true; } @@ -1010,17 +1013,17 @@ bool MIRGraph::SkipCompilation(Runtime::CompilerFilter compiler_filter) { size_t small_cutoff = 0; size_t default_cutoff = 0; switch (compiler_filter) { - case Runtime::kBalanced: - small_cutoff = Runtime::Current()->GetSmallMethodThreshold(); - default_cutoff = Runtime::Current()->GetLargeMethodThreshold(); + case CompilerOptions::kBalanced: + small_cutoff = compiler_options.GetSmallMethodThreshold(); + default_cutoff = compiler_options.GetLargeMethodThreshold(); break; - case Runtime::kSpace: - small_cutoff = Runtime::Current()->GetTinyMethodThreshold(); - default_cutoff = Runtime::Current()->GetSmallMethodThreshold(); + case CompilerOptions::kSpace: + small_cutoff = compiler_options.GetTinyMethodThreshold(); + default_cutoff = compiler_options.GetSmallMethodThreshold(); break; - case Runtime::kSpeed: - small_cutoff = Runtime::Current()->GetHugeMethodThreshold(); - default_cutoff = Runtime::Current()->GetHugeMethodThreshold(); + case CompilerOptions::kSpeed: + small_cutoff = compiler_options.GetHugeMethodThreshold(); + default_cutoff = compiler_options.GetHugeMethodThreshold(); break; default: LOG(FATAL) << "Unexpected compiler_filter_: " << compiler_filter; @@ -1033,17 +1036,17 @@ bool MIRGraph::SkipCompilation(Runtime::CompilerFilter compiler_filter) { * Filter 1: Huge methods are likely to be machine generated, but some aren't. * If huge, assume we won't compile, but allow futher analysis to turn it back on. */ - if (GetNumDalvikInsns() > Runtime::Current()->GetHugeMethodThreshold()) { + if (compiler_options.IsHugeMethod(GetNumDalvikInsns())) { skip_compilation = true; // If we're got a huge number of basic blocks, don't bother with further analysis. - if (static_cast<size_t>(num_blocks_) > (Runtime::Current()->GetHugeMethodThreshold() / 2)) { + if (static_cast<size_t>(num_blocks_) > (compiler_options.GetHugeMethodThreshold() / 2)) { return true; } - } else if (GetNumDalvikInsns() > Runtime::Current()->GetLargeMethodThreshold() && + } else if (compiler_options.IsLargeMethod(GetNumDalvikInsns()) && /* If it's large and contains no branches, it's likely to be machine generated initialization */ (GetBranchCount() == 0)) { return true; - } else if (compiler_filter == Runtime::kSpeed) { + } else if (compiler_filter == CompilerOptions::kSpeed) { // If not huge, compile. return false; } diff --git a/compiler/dex/mir_graph.h b/compiler/dex/mir_graph.h index d844aac..2174f67 100644 --- a/compiler/dex/mir_graph.h +++ b/compiler/dex/mir_graph.h @@ -372,7 +372,7 @@ class MIRGraph { * Examine the graph to determine whether it's worthwile to spend the time compiling * this method. */ - bool SkipCompilation(Runtime::CompilerFilter compiler_filter); + bool SkipCompilation(); /* * Parse dex method and add MIR at current insert point. Returns id (which is diff --git a/compiler/dex/verification_results.cc b/compiler/dex/verification_results.cc index edccec5..947c22d 100644 --- a/compiler/dex/verification_results.cc +++ b/compiler/dex/verification_results.cc @@ -19,6 +19,8 @@ #include "base/stl_util.h" #include "base/mutex.h" #include "base/mutex-inl.h" +#include "driver/compiler_driver.h" +#include "driver/compiler_options.h" #include "thread.h" #include "thread-inl.h" #include "verified_method.h" @@ -27,8 +29,9 @@ namespace art { -VerificationResults::VerificationResults() - : verified_methods_lock_("compiler verified methods lock"), +VerificationResults::VerificationResults(const CompilerOptions* compiler_options) + : compiler_options_(compiler_options), + verified_methods_lock_("compiler verified methods lock"), verified_methods_(), rejected_classes_lock_("compiler rejected classes lock"), rejected_classes_() { @@ -43,6 +46,7 @@ VerificationResults::~VerificationResults() { } bool VerificationResults::ProcessVerifiedMethod(verifier::MethodVerifier* method_verifier) { + DCHECK(method_verifier != NULL); MethodReference ref = method_verifier->GetMethodReference(); bool compile = IsCandidateForCompilation(ref, method_verifier->GetAccessFlags()); // TODO: Check also for virtual/interface invokes when DEX-to-DEX supports devirtualization. @@ -95,16 +99,18 @@ bool VerificationResults::IsClassRejected(ClassReference ref) { bool VerificationResults::IsCandidateForCompilation(MethodReference& method_ref, const uint32_t access_flags) { #ifdef ART_SEA_IR_MODE - bool use_sea = Runtime::Current()->IsSeaIRMode(); - use_sea = use_sea && (std::string::npos != PrettyMethod( - method_ref.dex_method_index, *(method_ref.dex_file)).find("fibonacci")); - if (use_sea) return true; + bool use_sea = compiler_options_->GetSeaIrMode(); + use_sea = use_sea && (std::string::npos != PrettyMethod( + method_ref.dex_method_index, *(method_ref.dex_file)).find("fibonacci")); + if (use_sea) { + return true; + } #endif // Don't compile class initializers, ever. if (((access_flags & kAccConstructor) != 0) && ((access_flags & kAccStatic) != 0)) { return false; } - return (Runtime::Current()->GetCompilerFilter() != Runtime::kInterpretOnly); + return (compiler_options_->GetCompilerFilter() != CompilerOptions::kInterpretOnly); } } // namespace art diff --git a/compiler/dex/verification_results.h b/compiler/dex/verification_results.h index 2eb0713..278182f 100644 --- a/compiler/dex/verification_results.h +++ b/compiler/dex/verification_results.h @@ -33,11 +33,13 @@ namespace verifier { class MethodVerifier; } // namespace verifier +class CompilerOptions; class VerifiedMethod; +// Used by CompilerCallbacks to track verification information from the Runtime. class VerificationResults { public: - VerificationResults(); + explicit VerificationResults(const CompilerOptions* compiler_options); ~VerificationResults(); bool ProcessVerifiedMethod(verifier::MethodVerifier* method_verifier) @@ -50,15 +52,17 @@ class VerificationResults { void AddRejectedClass(ClassReference ref) LOCKS_EXCLUDED(rejected_classes_lock_); bool IsClassRejected(ClassReference ref) LOCKS_EXCLUDED(rejected_classes_lock_); - static bool IsCandidateForCompilation(MethodReference& method_ref, - const uint32_t access_flags); + bool IsCandidateForCompilation(MethodReference& method_ref, + const uint32_t access_flags); private: + const CompilerOptions* compiler_options_; + // Verified methods. typedef SafeMap<MethodReference, const VerifiedMethod*, MethodReferenceComparator> VerifiedMethodMap; ReaderWriterMutex verified_methods_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER; - VerifiedMethodMap verified_methods_; + VerifiedMethodMap verified_methods_ GUARDED_BY(verified_methods_lock_); // Rejected classes. ReaderWriterMutex rejected_classes_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER; diff --git a/compiler/driver/compiler_callbacks_impl.h b/compiler/driver/compiler_callbacks_impl.h new file mode 100644 index 0000000..ab57832 --- /dev/null +++ b/compiler/driver/compiler_callbacks_impl.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_COMPILER_DRIVER_COMPILER_CALLBACKS_IMPL_H_ +#define ART_COMPILER_DRIVER_COMPILER_CALLBACKS_IMPL_H_ + +#include "compiler_callbacks.h" +#include "dex/quick/dex_file_to_method_inliner_map.h" +#include "verifier/method_verifier-inl.h" + +namespace art { + +class CompilerCallbacksImpl : public CompilerCallbacks { + public: + CompilerCallbacksImpl(VerificationResults* verification_results, + DexFileToMethodInlinerMap* method_inliner_map) + : verification_results_(verification_results), + method_inliner_map_(method_inliner_map) { + CHECK(verification_results != nullptr); + CHECK(method_inliner_map != nullptr); + } + + virtual ~CompilerCallbacksImpl() { } + + virtual bool MethodVerified(verifier::MethodVerifier* verifier) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + bool result = verification_results_->ProcessVerifiedMethod(verifier); + if (result) { + MethodReference ref = verifier->GetMethodReference(); + method_inliner_map_->GetMethodInliner(ref.dex_file) + ->AnalyseMethodCode(verifier); + } + return result; + } + virtual void ClassRejected(ClassReference ref) { + verification_results_->AddRejectedClass(ref); + } + + private: + VerificationResults* verification_results_; + DexFileToMethodInlinerMap* method_inliner_map_; +}; + +} // namespace art + +#endif // ART_COMPILER_DRIVER_COMPILER_CALLBACKS_IMPL_H_ diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 5adb792..530abc8 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -293,14 +293,16 @@ extern "C" art::CompiledMethod* ArtCompileDEX(art::CompilerDriver& compiler, jobject class_loader, const art::DexFile& dex_file); -CompilerDriver::CompilerDriver(VerificationResults* verification_results, +CompilerDriver::CompilerDriver(const CompilerOptions* compiler_options, + VerificationResults* verification_results, DexFileToMethodInlinerMap* method_inliner_map, CompilerBackend::Kind compiler_backend_kind, InstructionSet instruction_set, InstructionSetFeatures instruction_set_features, bool image, DescriptorSet* image_classes, size_t thread_count, bool dump_stats, bool dump_passes, CumulativeLogger* timer) - : verification_results_(verification_results), + : compiler_options_(compiler_options), + verification_results_(verification_results), method_inliner_map_(method_inliner_map), compiler_backend_(CompilerBackend::Create(compiler_backend_kind)), instruction_set_(instruction_set), @@ -325,6 +327,9 @@ CompilerDriver::CompilerDriver(VerificationResults* verification_results, dedupe_mapping_table_("dedupe mapping table"), dedupe_vmap_table_("dedupe vmap table"), dedupe_gc_map_("dedupe gc map") { + DCHECK(compiler_options_ != nullptr); + DCHECK(verification_results_ != nullptr); + DCHECK(method_inliner_map_ != nullptr); CHECK_PTHREAD_CALL(pthread_key_create, (&tls_key_, NULL), "compiler tls key"); @@ -1929,7 +1934,7 @@ void CompilerDriver::CompileMethod(const DexFile::CodeItem* code_item, uint32_t } else if ((access_flags & kAccAbstract) != 0) { } else { MethodReference method_ref(&dex_file, method_idx); - bool compile = VerificationResults::IsCandidateForCompilation(method_ref, access_flags); + bool compile = verification_results_->IsCandidateForCompilation(method_ref, access_flags); if (compile) { // NOTE: if compiler declines to compile this method, it will return NULL. diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index 092fe52..5009779 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -45,6 +45,7 @@ class MethodVerifier; } // namespace verifier class AOTCompilationStats; +class CompilerOptions; class DexCompilationUnit; class DexFileToMethodInlinerMap; class InlineIGetIPutData; @@ -94,7 +95,8 @@ class CompilerDriver { // enabled. "image_classes" lets the compiler know what classes it // can assume will be in the image, with NULL implying all available // classes. - explicit CompilerDriver(VerificationResults* verification_results, + explicit CompilerDriver(const CompilerOptions* compiler_options, + VerificationResults* verification_results, DexFileToMethodInlinerMap* method_inliner_map, CompilerBackend::Kind compiler_backend_kind, InstructionSet instruction_set, @@ -129,6 +131,11 @@ class CompilerDriver { return instruction_set_features_; } + const CompilerOptions& GetCompilerOptions() const { + DCHECK(compiler_options_ != nullptr); + return *compiler_options_; + } + CompilerBackend* GetCompilerBackend() const { return compiler_backend_.get(); } @@ -551,6 +558,7 @@ class CompilerDriver { std::vector<const CallPatchInformation*> methods_to_patch_; std::vector<const TypePatchInformation*> classes_to_patch_; + const CompilerOptions* compiler_options_; VerificationResults* verification_results_; DexFileToMethodInlinerMap* method_inliner_map_; diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h new file mode 100644 index 0000000..9f6745b --- /dev/null +++ b/compiler/driver/compiler_options.h @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_COMPILER_DRIVER_COMPILER_OPTIONS_H_ +#define ART_COMPILER_DRIVER_COMPILER_OPTIONS_H_ + +namespace art { + +class CompilerOptions { + public: + enum CompilerFilter { + kInterpretOnly, // Compile nothing. + kSpace, // Maximize space savings. + kBalanced, // Try to get the best performance return on compilation investment. + kSpeed, // Maximize runtime performance. + kEverything // Force compilation (Note: excludes compilaton of class initializers). + }; + + // Guide heuristics to determine whether to compile method if profile data not available. + static const CompilerFilter kDefaultCompilerFilter = kSpeed; + static const size_t kDefaultHugeMethodThreshold = 10000; + static const size_t kDefaultLargeMethodThreshold = 600; + static const size_t kDefaultSmallMethodThreshold = 60; + static const size_t kDefaultTinyMethodThreshold = 20; + static const size_t kDefaultNumDexMethodsThreshold = 900; + + CompilerOptions() : + compiler_filter_(kDefaultCompilerFilter), + huge_method_threshold_(kDefaultHugeMethodThreshold), + large_method_threshold_(kDefaultLargeMethodThreshold), + small_method_threshold_(kDefaultSmallMethodThreshold), + tiny_method_threshold_(kDefaultTinyMethodThreshold), + num_dex_methods_threshold_(kDefaultNumDexMethodsThreshold) +#ifdef ART_SEA_IR_MODE + , sea_ir_mode_(false) +#endif + {} + + CompilerOptions(CompilerFilter compiler_filter, + size_t huge_method_threshold, + size_t large_method_threshold, + size_t small_method_threshold, + size_t tiny_method_threshold, + size_t num_dex_methods_threshold +#ifdef ART_SEA_IR_MODE + , bool sea_ir_mode +#endif + ) : // NOLINT(whitespace/parens) + compiler_filter_(compiler_filter), + huge_method_threshold_(huge_method_threshold), + large_method_threshold_(large_method_threshold), + small_method_threshold_(small_method_threshold), + tiny_method_threshold_(tiny_method_threshold), + num_dex_methods_threshold_(num_dex_methods_threshold) +#ifdef ART_SEA_IR_MODE + , sea_ir_mode_(sea_ir_mode) +#endif + {} + + CompilerFilter GetCompilerFilter() const { + return compiler_filter_; + } + + void SetCompilerFilter(CompilerFilter compiler_filter) { + compiler_filter_ = compiler_filter; + } + + size_t GetHugeMethodThreshold() const { + return huge_method_threshold_; + } + + size_t GetLargeMethodThreshold() const { + return large_method_threshold_; + } + + size_t GetSmallMethodThreshold() const { + return small_method_threshold_; + } + + size_t GetTinyMethodThreshold() const { + return tiny_method_threshold_; + } + + bool IsHugeMethod(size_t num_dalvik_instructions) const { + return num_dalvik_instructions > huge_method_threshold_; + } + + bool IsLargeMethod(size_t num_dalvik_instructions) const { + return num_dalvik_instructions > large_method_threshold_; + } + + bool IsSmallMethod(size_t num_dalvik_instructions) const { + return num_dalvik_instructions > small_method_threshold_; + } + + bool IsTinyMethod(size_t num_dalvik_instructions) const { + return num_dalvik_instructions > tiny_method_threshold_; + } + + size_t GetNumDexMethodsThreshold() const { + return num_dex_methods_threshold_; + } + +#ifdef ART_SEA_IR_MODE + bool GetSeaIrMode(); +#endif + + private: + CompilerFilter compiler_filter_; + size_t huge_method_threshold_; + size_t large_method_threshold_; + size_t small_method_threshold_; + size_t tiny_method_threshold_; + size_t num_dex_methods_threshold_; + +#ifdef ART_SEA_IR_MODE + bool sea_ir_mode_; +#endif +}; + +} // namespace art + +#endif // ART_COMPILER_DRIVER_COMPILER_OPTIONS_H_ diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc index 10d2c5c..29acc86 100644 --- a/compiler/oat_test.cc +++ b/compiler/oat_test.cc @@ -91,11 +91,14 @@ TEST_F(OatTest, WriteRead) { InstructionSet insn_set = kIsTargetBuild ? kThumb2 : kX86; InstructionSetFeatures insn_features; - verification_results_.reset(new VerificationResults); + compiler_options_.reset(new CompilerOptions); + verification_results_.reset(new VerificationResults(compiler_options_.get())); method_inliner_map_.reset(new DexFileToMethodInlinerMap); - callbacks_.Reset(verification_results_.get(), method_inliner_map_.get()); + callbacks_.reset(new CompilerCallbacksImpl(verification_results_.get(), + method_inliner_map_.get())); timer_.reset(new CumulativeLogger("Compilation times")); - compiler_driver_.reset(new CompilerDriver(verification_results_.get(), + compiler_driver_.reset(new CompilerDriver(compiler_options_.get(), + verification_results_.get(), method_inliner_map_.get(), compiler_backend, insn_set, insn_features, false, NULL, 2, true, true, diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index bfda17d..6c879d0 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -34,7 +34,9 @@ #include "compiler_callbacks.h" #include "dex_file-inl.h" #include "dex/verification_results.h" +#include "driver/compiler_callbacks_impl.h" #include "driver/compiler_driver.h" +#include "driver/compiler_options.h" #include "elf_fixup.h" #include "elf_stripper.h" #include "gc/space/image_space.h" @@ -54,15 +56,22 @@ #include "scoped_thread_state_change.h" #include "sirt_ref.h" #include "vector_output_stream.h" -#include "verifier/method_verifier.h" -#include "verifier/method_verifier-inl.h" #include "well_known_classes.h" #include "zip_archive.h" -#include "dex/quick/dex_file_to_method_inliner_map.h" - namespace art { +static int original_argc; +static char** original_argv; + +static std::string CommandLine() { + std::vector<std::string> command; + for (int i = 0; i < original_argc; ++i) { + command.push_back(original_argv[i]); + } + return Join(command, ' '); +} + static void UsageErrorV(const char* fmt, va_list ap) { std::string error; StringAppendV(&error, fmt, ap); @@ -82,6 +91,8 @@ static void Usage(const char* fmt, ...) { UsageErrorV(fmt, ap); va_end(ap); + UsageError("Command: %s", CommandLine().c_str()); + UsageError("Usage: dex2oat [options]..."); UsageError(""); UsageError(" --dex-file=<dex-file>: specifies a .dex file to compile."); @@ -147,6 +158,46 @@ static void Usage(const char* fmt, ...) { UsageError(" Example: --compiler-backend=Portable"); UsageError(" Default: Quick"); UsageError(""); + UsageError(" --compiler-filter=(interpret-only|space|balanced|speed|everything): select"); + UsageError(" compiler filter."); + UsageError(" Example: --compiler-filter=everything"); +#if ART_SMALL_MODE + UsageError(" Default: interpret-only"); +#else + UsageError(" Default: speed"); +#endif + UsageError(""); + UsageError(" --huge-method-max=<method-instruction-count>: the threshold size for a huge"); + UsageError(" method for compiler filter tuning."); + UsageError(" Example: --huge-method-max=%d", CompilerOptions::kDefaultHugeMethodThreshold); + UsageError(" Default: %d", CompilerOptions::kDefaultHugeMethodThreshold); + UsageError(""); + UsageError(" --huge-method-max=<method-instruction-count>: threshold size for a huge"); + UsageError(" method for compiler filter tuning."); + UsageError(" Example: --huge-method-max=%d", CompilerOptions::kDefaultHugeMethodThreshold); + UsageError(" Default: %d", CompilerOptions::kDefaultHugeMethodThreshold); + UsageError(""); + UsageError(" --large-method-max=<method-instruction-count>: threshold size for a large"); + UsageError(" method for compiler filter tuning."); + UsageError(" Example: --large-method-max=%d", CompilerOptions::kDefaultLargeMethodThreshold); + UsageError(" Default: %d", CompilerOptions::kDefaultLargeMethodThreshold); + UsageError(""); + UsageError(" --small-method-max=<method-instruction-count>: threshold size for a small"); + UsageError(" method for compiler filter tuning."); + UsageError(" Example: --small-method-max=%d", CompilerOptions::kDefaultSmallMethodThreshold); + UsageError(" Default: %d", CompilerOptions::kDefaultSmallMethodThreshold); + UsageError(""); + UsageError(" --tiny-method-max=<method-instruction-count>: threshold size for a tiny"); + UsageError(" method for compiler filter tuning."); + UsageError(" Example: --tiny-method-max=%d", CompilerOptions::kDefaultTinyMethodThreshold); + UsageError(" Default: %d", CompilerOptions::kDefaultTinyMethodThreshold); + UsageError(""); + UsageError(" --num-dex-methods=<method-count>: threshold size for a small dex file for"); + UsageError(" compiler filter tuning. If the input has fewer than this many methods"); + UsageError(" and the filter is not interpret-only, overrides the filter to use speed"); + UsageError(" Example: --num-dex-method=%d", CompilerOptions::kDefaultNumDexMethodsThreshold); + UsageError(" Default: %d", CompilerOptions::kDefaultNumDexMethodsThreshold); + UsageError(""); UsageError(" --host: used with Portable backend to link against host runtime libraries"); UsageError(""); UsageError(" --dump-timing: display a breakdown of where time was spent"); @@ -163,15 +214,25 @@ static void Usage(const char* fmt, ...) { class Dex2Oat { public: static bool Create(Dex2Oat** p_dex2oat, - Runtime::Options& options, + const Runtime::Options& runtime_options, + const CompilerOptions& compiler_options, CompilerBackend::Kind compiler_backend, InstructionSet instruction_set, InstructionSetFeatures instruction_set_features, + VerificationResults* verification_results, + DexFileToMethodInlinerMap* method_inliner_map, size_t thread_count) SHARED_TRYLOCK_FUNCTION(true, Locks::mutator_lock_) { - UniquePtr<Dex2Oat> dex2oat(new Dex2Oat(compiler_backend, instruction_set, - instruction_set_features, thread_count)); - if (!dex2oat->CreateRuntime(options, instruction_set)) { + CHECK(verification_results != nullptr); + CHECK(method_inliner_map != nullptr); + UniquePtr<Dex2Oat> dex2oat(new Dex2Oat(&compiler_options, + compiler_backend, + instruction_set, + instruction_set_features, + verification_results, + method_inliner_map, + thread_count)); + if (!dex2oat->CreateRuntime(runtime_options, instruction_set)) { *p_dex2oat = NULL; return false; } @@ -275,8 +336,9 @@ class Dex2Oat { Runtime::Current()->SetCompileTimeClassPath(class_loader, class_path_files); } - UniquePtr<CompilerDriver> driver(new CompilerDriver(verification_results_.get(), - method_inliner_map_.get(), + UniquePtr<CompilerDriver> driver(new CompilerDriver(compiler_options_, + verification_results_, + method_inliner_map_, compiler_backend_, instruction_set_, instruction_set_features_, @@ -353,53 +415,30 @@ class Dex2Oat { } private: - class Dex2OatCompilerCallbacks : public CompilerCallbacks { - public: - Dex2OatCompilerCallbacks(VerificationResults* verification_results, - DexFileToMethodInlinerMap* method_inliner_map) - : verification_results_(verification_results), - method_inliner_map_(method_inliner_map) { } - virtual ~Dex2OatCompilerCallbacks() { } - - virtual bool MethodVerified(verifier::MethodVerifier* verifier) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - bool result = verification_results_->ProcessVerifiedMethod(verifier); - if (result) { - MethodReference ref = verifier->GetMethodReference(); - method_inliner_map_->GetMethodInliner(ref.dex_file) - ->AnalyseMethodCode(verifier); - } - return result; - } - virtual void ClassRejected(ClassReference ref) { - verification_results_->AddRejectedClass(ref); - } - - private: - VerificationResults* verification_results_; - DexFileToMethodInlinerMap* method_inliner_map_; - }; - - explicit Dex2Oat(CompilerBackend::Kind compiler_backend, + explicit Dex2Oat(const CompilerOptions* compiler_options, + CompilerBackend::Kind compiler_backend, InstructionSet instruction_set, InstructionSetFeatures instruction_set_features, + VerificationResults* verification_results, + DexFileToMethodInlinerMap* method_inliner_map, size_t thread_count) - : compiler_backend_(compiler_backend), + : compiler_options_(compiler_options), + compiler_backend_(compiler_backend), instruction_set_(instruction_set), instruction_set_features_(instruction_set_features), - verification_results_(new VerificationResults), - method_inliner_map_(new DexFileToMethodInlinerMap), - callbacks_(verification_results_.get(), method_inliner_map_.get()), + verification_results_(verification_results), + method_inliner_map_(method_inliner_map), runtime_(nullptr), thread_count_(thread_count), start_ns_(NanoTime()) { + CHECK(compiler_options != nullptr); + CHECK(verification_results != nullptr); + CHECK(method_inliner_map != nullptr); } - bool CreateRuntime(Runtime::Options& options, InstructionSet instruction_set) + bool CreateRuntime(const Runtime::Options& runtime_options, InstructionSet instruction_set) SHARED_TRYLOCK_FUNCTION(true, Locks::mutator_lock_) { - options.push_back( - std::make_pair("compilercallbacks", static_cast<CompilerCallbacks*>(&callbacks_))); - if (!Runtime::Create(options, false)) { + if (!Runtime::Create(runtime_options, false)) { LOG(ERROR) << "Failed to create runtime"; return false; } @@ -448,14 +487,14 @@ class Dex2Oat { return false; } + const CompilerOptions* compiler_options_; const CompilerBackend::Kind compiler_backend_; const InstructionSet instruction_set_; const InstructionSetFeatures instruction_set_features_; - UniquePtr<VerificationResults> verification_results_; - UniquePtr<DexFileToMethodInlinerMap> method_inliner_map_; - Dex2OatCompilerCallbacks callbacks_; + VerificationResults* verification_results_; + DexFileToMethodInlinerMap* method_inliner_map_; Runtime* runtime_; size_t thread_count_; uint64_t start_ns_; @@ -656,6 +695,9 @@ static InstructionSetFeatures ParseFeatureList(std::string str) { } static int dex2oat(int argc, char** argv) { + original_argc = argc; + original_argv = argv; + TimingLogger timings("compiler", false, false); CumulativeLogger compiler_phases_timings("compilation times"); @@ -690,6 +732,12 @@ static int dex2oat(int argc, char** argv) { CompilerBackend::Kind compiler_backend = kUsePortableCompiler ? CompilerBackend::kPortable : CompilerBackend::kQuick; + const char* compiler_filter_string = NULL; + int huge_method_threshold = CompilerOptions::kDefaultHugeMethodThreshold; + int large_method_threshold = CompilerOptions::kDefaultLargeMethodThreshold; + int small_method_threshold = CompilerOptions::kDefaultSmallMethodThreshold; + int tiny_method_threshold = CompilerOptions::kDefaultTinyMethodThreshold; + int num_dex_methods_threshold = CompilerOptions::kDefaultNumDexMethodsThreshold; // Take the default set of instruction features from the build. InstructionSetFeatures instruction_set_features = @@ -713,7 +761,6 @@ static int dex2oat(int argc, char** argv) { bool dump_slow_timing = kIsDebugBuild; bool watch_dog_enabled = !kIsTargetBuild; - for (int i = 0; i < argc; i++) { const StringPiece option(argv[i]); bool log_options = false; @@ -729,6 +776,9 @@ static int dex2oat(int argc, char** argv) { if (!ParseInt(zip_fd_str, &zip_fd)) { Usage("Failed to parse --zip-fd argument '%s' as an integer", zip_fd_str); } + if (zip_fd < 0) { + Usage("--zip-fd passed a negative value %d", zip_fd); + } } else if (option.starts_with("--zip-location=")) { zip_location = option.substr(strlen("--zip-location=")).data(); } else if (option.starts_with("--oat-file=")) { @@ -740,6 +790,9 @@ static int dex2oat(int argc, char** argv) { if (!ParseInt(oat_fd_str, &oat_fd)) { Usage("Failed to parse --oat-fd argument '%s' as an integer", oat_fd_str); } + if (oat_fd < 0) { + Usage("--oat-fd passed a negative value %d", oat_fd); + } } else if (option == "--watch-dog") { watch_dog_enabled = true; } else if (option == "--no-watch-dog") { @@ -793,6 +846,48 @@ static int dex2oat(int argc, char** argv) { } else if (backend_str == "Portable") { compiler_backend = CompilerBackend::kPortable; } + } else if (option.starts_with("--compiler-filter=")) { + compiler_filter_string = option.substr(strlen("--compiler-filter=")).data(); + } else if (option.starts_with("--huge-method-max=")) { + const char* threshold = option.substr(strlen("--huge-method-max=")).data(); + if (!ParseInt(threshold, &huge_method_threshold)) { + Usage("Failed to parse --huge-method-max '%s' as an integer", threshold); + } + if (huge_method_threshold < 0) { + Usage("--huge-method-max passed a negative value %s", huge_method_threshold); + } + } else if (option.starts_with("--large-method-max=")) { + const char* threshold = option.substr(strlen("--large-method-max=")).data(); + if (!ParseInt(threshold, &large_method_threshold)) { + Usage("Failed to parse --large-method-max '%s' as an integer", threshold); + } + if (large_method_threshold < 0) { + Usage("--large-method-max passed a negative value %s", large_method_threshold); + } + } else if (option.starts_with("--small-method-max=")) { + const char* threshold = option.substr(strlen("--small-method-max=")).data(); + if (!ParseInt(threshold, &small_method_threshold)) { + Usage("Failed to parse --small-method-max '%s' as an integer", threshold); + } + if (small_method_threshold < 0) { + Usage("--small-method-max passed a negative value %s", small_method_threshold); + } + } else if (option.starts_with("--tiny-method-max=")) { + const char* threshold = option.substr(strlen("--tiny-method-max=")).data(); + if (!ParseInt(threshold, &tiny_method_threshold)) { + Usage("Failed to parse --tiny-method-max '%s' as an integer", threshold); + } + if (tiny_method_threshold < 0) { + Usage("--tiny-method-max passed a negative value %s", tiny_method_threshold); + } + } else if (option.starts_with("--num-dex-methods=")) { + const char* threshold = option.substr(strlen("--num-dex-methods=")).data(); + if (!ParseInt(threshold, &num_dex_methods_threshold)) { + Usage("Failed to parse --num-dex-methods '%s' as an integer", threshold); + } + if (num_dex_methods_threshold < 0) { + Usage("--num-dex-methods passed a negative value %s", num_dex_methods_threshold); + } } else if (option == "--host") { is_host = true; } else if (option == "--runtime-arg") { @@ -915,6 +1010,44 @@ static int dex2oat(int argc, char** argv) { oat_unstripped += oat_filename; } + if (compiler_filter_string == NULL) { + if (image) { + compiler_filter_string = "everything"; + } else { +#if ART_SMALL_MODE + compiler_filter_string = "interpret-only"; +#else + compiler_filter_string = "speed"; +#endif + } + } + CHECK(compiler_filter_string != nullptr); + CompilerOptions::CompilerFilter compiler_filter = CompilerOptions::kDefaultCompilerFilter; + if (strcmp(compiler_filter_string, "interpret-only") == 0) { + compiler_filter = CompilerOptions::kInterpretOnly; + } else if (strcmp(compiler_filter_string, "space") == 0) { + compiler_filter = CompilerOptions::kSpace; + } else if (strcmp(compiler_filter_string, "balanced") == 0) { + compiler_filter = CompilerOptions::kBalanced; + } else if (strcmp(compiler_filter_string, "speed") == 0) { + compiler_filter = CompilerOptions::kSpeed; + } else if (strcmp(compiler_filter_string, "everything") == 0) { + compiler_filter = CompilerOptions::kEverything; + } else { + Usage("Unknown --compiler-filter value %s", compiler_filter_string); + } + + CompilerOptions compiler_options(compiler_filter, + huge_method_threshold, + large_method_threshold, + small_method_threshold, + tiny_method_threshold, + num_dex_methods_threshold +#ifdef ART_SEA_IR_MODE + , compiler_options.sea_ir_ = true; +#endif + ); // NOLINT(whitespace/parens) + // Done with usage checks, enable watchdog if requested WatchDog watch_dog(watch_dog_enabled); @@ -940,22 +1073,9 @@ static int dex2oat(int argc, char** argv) { } timings.StartSplit("dex2oat Setup"); - LOG(INFO) << "dex2oat: " << oat_location; + LOG(INFO) << "dex2oat: " << CommandLine(); - if (image) { - bool has_compiler_filter = false; - for (const char* r : runtime_args) { - if (strncmp(r, "-compiler-filter:", 17) == 0) { - has_compiler_filter = true; - break; - } - } - if (!has_compiler_filter) { - runtime_args.push_back("-compiler-filter:everything"); - } - } - - Runtime::Options options; + Runtime::Options runtime_options; std::vector<const DexFile*> boot_class_path; if (boot_image_option.empty()) { size_t failure_count = OpenDexFiles(dex_filenames, dex_locations, boot_class_path); @@ -963,24 +1083,33 @@ static int dex2oat(int argc, char** argv) { LOG(ERROR) << "Failed to open some dex files: " << failure_count; return EXIT_FAILURE; } - options.push_back(std::make_pair("bootclasspath", &boot_class_path)); + runtime_options.push_back(std::make_pair("bootclasspath", &boot_class_path)); } else { - options.push_back(std::make_pair(boot_image_option.c_str(), reinterpret_cast<void*>(NULL))); + runtime_options.push_back(std::make_pair(boot_image_option.c_str(), + reinterpret_cast<void*>(NULL))); } if (host_prefix.get() != NULL) { - options.push_back(std::make_pair("host-prefix", host_prefix->c_str())); + runtime_options.push_back(std::make_pair("host-prefix", host_prefix->c_str())); } for (size_t i = 0; i < runtime_args.size(); i++) { - options.push_back(std::make_pair(runtime_args[i], reinterpret_cast<void*>(NULL))); + runtime_options.push_back(std::make_pair(runtime_args[i], reinterpret_cast<void*>(NULL))); } -#ifdef ART_SEA_IR_MODE - options.push_back(std::make_pair("-sea_ir", reinterpret_cast<void*>(NULL))); -#endif + VerificationResults verification_results(&compiler_options); + DexFileToMethodInlinerMap method_inliner_map; + CompilerCallbacksImpl callbacks(&verification_results, &method_inliner_map); + runtime_options.push_back(std::make_pair("compilercallbacks", &callbacks)); Dex2Oat* p_dex2oat; - if (!Dex2Oat::Create(&p_dex2oat, options, compiler_backend, instruction_set, - instruction_set_features, thread_count)) { + if (!Dex2Oat::Create(&p_dex2oat, + runtime_options, + compiler_options, + compiler_backend, + instruction_set, + instruction_set_features, + &verification_results, + &method_inliner_map, + thread_count)) { LOG(ERROR) << "Failed to create dex2oat"; return EXIT_FAILURE; } @@ -1050,7 +1179,8 @@ static int dex2oat(int argc, char** argv) { std::string tmp_file_name(StringPrintf("/data/local/tmp/dex2oat.%d.%zd.dex", getpid(), i)); UniquePtr<File> tmp_file(OS::CreateEmptyFile(tmp_file_name.c_str())); if (tmp_file.get() == nullptr) { - PLOG(ERROR) << "Failed to open file " << tmp_file_name << ". Try: adb shell chmod 777 /data/local/tmp"; + PLOG(ERROR) << "Failed to open file " << tmp_file_name + << ". Try: adb shell chmod 777 /data/local/tmp"; continue; } tmp_file->WriteFully(dex_file->Begin(), dex_file->Size()); @@ -1070,15 +1200,15 @@ static int dex2oat(int argc, char** argv) { * If we're not in interpret-only mode, go ahead and compile small applications. Don't * bother to check if we're doing the image. */ - if (!image && (Runtime::Current()->GetCompilerFilter() != Runtime::kInterpretOnly)) { + if (!image && (compiler_options.GetCompilerFilter() != CompilerOptions::kInterpretOnly)) { size_t num_methods = 0; for (size_t i = 0; i != dex_files.size(); ++i) { const DexFile* dex_file = dex_files[i]; CHECK(dex_file != NULL); num_methods += dex_file->NumMethodIds(); } - if (num_methods <= Runtime::Current()->GetNumDexMethodsThreshold()) { - Runtime::Current()->SetCompilerFilter(Runtime::kSpeed); + if (num_methods <= compiler_options.GetNumDexMethodsThreshold()) { + compiler_options.SetCompilerFilter(CompilerOptions::kSpeed); VLOG(compiler) << "Below method threshold, compiling anyways"; } } @@ -1222,13 +1352,13 @@ static int dex2oat(int argc, char** argv) { // Everything was successfully written, do an explicit exit here to avoid running Runtime // destructors that take time (bug 10645725) unless we're a debug build or running on valgrind. - if (!kIsDebugBuild || (RUNNING_ON_VALGRIND == 0)) { + if (!kIsDebugBuild && (RUNNING_ON_VALGRIND == 0)) { dex2oat->LogCompletionTime(); exit(EXIT_SUCCESS); } return EXIT_SUCCESS; -} +} // NOLINT(readability/fn_size) } // namespace art int main(int argc, char** argv) { diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 48ec5ab..52dd541 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -550,101 +550,41 @@ bool ClassLinker::GenerateOatFile(const char* dex_filename, const char* class_path = Runtime::Current()->GetClassPathString().c_str(); gc::Heap* heap = Runtime::Current()->GetHeap(); - std::string boot_image_option_string("--boot-image="); - boot_image_option_string += heap->GetImageSpace()->GetImageFilename(); - const char* boot_image_option = boot_image_option_string.c_str(); - - std::string dex_file_option_string("--dex-file="); - dex_file_option_string += dex_filename; - const char* dex_file_option = dex_file_option_string.c_str(); - - std::string oat_fd_option_string("--oat-fd="); - StringAppendF(&oat_fd_option_string, "%d", oat_fd); - const char* oat_fd_option = oat_fd_option_string.c_str(); - - std::string oat_location_option_string("--oat-location="); - oat_location_option_string += oat_cache_filename; - const char* oat_location_option = oat_location_option_string.c_str(); - - std::string oat_compiler_filter_string("-compiler-filter:"); - Runtime::CompilerFilter filter = Runtime::Current()->GetCompilerFilter(); - switch (filter) { - case Runtime::kInterpretOnly: - oat_compiler_filter_string += "interpret-only"; - break; - case Runtime::kSpace: - oat_compiler_filter_string += "space"; - break; - case Runtime::kBalanced: - oat_compiler_filter_string += "balanced"; - break; - case Runtime::kSpeed: - oat_compiler_filter_string += "speed"; - break; - case Runtime::kEverything: - oat_compiler_filter_string += "everything"; - break; - default: - LOG(FATAL) << "Unexpected case: " << filter; - } - const char* oat_compiler_filter_option = oat_compiler_filter_string.c_str(); - - // fork and exec dex2oat - pid_t pid = fork(); - if (pid == 0) { - // no allocation allowed between fork and exec - - // change process groups, so we don't get reaped by ProcessManager - setpgid(0, 0); - - // gLogVerbosity.class_linker = true; - VLOG(class_linker) << dex2oat - << " --runtime-arg -Xms64m" - << " --runtime-arg -Xmx64m" - << " --runtime-arg -classpath" - << " --runtime-arg " << class_path - << " --runtime-arg " << oat_compiler_filter_option -#if !defined(ART_TARGET) - << " --host" -#endif - << " " << boot_image_option - << " " << dex_file_option - << " " << oat_fd_option - << " " << oat_location_option; - - execl(dex2oat, dex2oat, - "--runtime-arg", "-Xms64m", - "--runtime-arg", "-Xmx64m", - "--runtime-arg", "-classpath", - "--runtime-arg", class_path, - "--runtime-arg", oat_compiler_filter_option, -#if !defined(ART_TARGET) - "--host", -#endif - boot_image_option, - dex_file_option, - oat_fd_option, - oat_location_option, - NULL); - - PLOG(FATAL) << "execl(" << dex2oat << ") failed"; - return false; - } else { - // wait for dex2oat to finish - int status; - pid_t got_pid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0)); - if (got_pid != pid) { - *error_msg = StringPrintf("Failed to create oat file. Waitpid failed: wanted %d, got %d", - pid, got_pid); - return false; - } - if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { - *error_msg = StringPrintf("Failed to create oat file. %s failed with dex-file '%s'", - dex2oat, dex_filename); - return false; - } - } - return true; + std::string boot_image_option("--boot-image="); + boot_image_option += heap->GetImageSpace()->GetImageFilename(); + + std::string dex_file_option("--dex-file="); + dex_file_option += dex_filename; + + std::string oat_fd_option("--oat-fd="); + StringAppendF(&oat_fd_option, "%d", oat_fd); + + std::string oat_location_option("--oat-location="); + oat_location_option += oat_cache_filename; + + std::vector<std::string> argv; + argv.push_back(dex2oat); + argv.push_back("--runtime-arg"); + argv.push_back("-Xms64m"); + argv.push_back("--runtime-arg"); + argv.push_back("-Xmx64m"); + argv.push_back("--runtime-arg"); + argv.push_back("-classpath"); + argv.push_back("--runtime-arg"); + argv.push_back(class_path); + if (!kIsTargetBuild) { + argv.push_back("--host"); + } + argv.push_back(boot_image_option); + argv.push_back(dex_file_option); + argv.push_back(oat_fd_option); + argv.push_back(oat_location_option); + const std::vector<std::string>& compiler_options = Runtime::Current()->GetCompilerOptions(); + for (size_t i = 0; compiler_options.size(); ++i) { + argv.push_back(compiler_options[i].c_str()); + } + + return Exec(argv, error_msg); } const OatFile* ClassLinker::RegisterOatFile(const OatFile* oat_file) { diff --git a/runtime/common_test.h b/runtime/common_test.h index 7f9b6b1..e3843be 100644 --- a/runtime/common_test.h +++ b/runtime/common_test.h @@ -28,7 +28,9 @@ #include "../compiler/compiler_backend.h" #include "../compiler/dex/quick/dex_file_to_method_inliner_map.h" #include "../compiler/dex/verification_results.h" +#include "../compiler/driver/compiler_callbacks_impl.h" #include "../compiler/driver/compiler_driver.h" +#include "../compiler/driver/compiler_options.h" #include "base/macros.h" #include "base/stl_util.h" #include "base/stringprintf.h" @@ -458,11 +460,13 @@ class CommonTest : public testing::Test { ? CompilerBackend::kPortable : CompilerBackend::kQuick; - verification_results_.reset(new VerificationResults); + compiler_options_.reset(new CompilerOptions); + verification_results_.reset(new VerificationResults(compiler_options_.get())); method_inliner_map_.reset(new DexFileToMethodInlinerMap); - callbacks_.Reset(verification_results_.get(), method_inliner_map_.get()); + callbacks_.reset(new CompilerCallbacksImpl(verification_results_.get(), + method_inliner_map_.get())); Runtime::Options options; - options.push_back(std::make_pair("compilercallbacks", static_cast<CompilerCallbacks*>(&callbacks_))); + options.push_back(std::make_pair("compilercallbacks", callbacks_.get())); options.push_back(std::make_pair("bootclasspath", &boot_class_path_)); options.push_back(std::make_pair("-Xcheck:jni", reinterpret_cast<void*>(NULL))); options.push_back(std::make_pair(min_heap_string.c_str(), reinterpret_cast<void*>(NULL))); @@ -472,8 +476,8 @@ class CommonTest : public testing::Test { return; } runtime_.reset(Runtime::Current()); - // Runtime::Create acquired the mutator_lock_ that is normally given away when we Runtime::Start, - // give it away now and then switch to a more managable ScopedObjectAccess. + // Runtime::Create acquired the mutator_lock_ that is normally given away when we + // Runtime::Start, give it away now and then switch to a more managable ScopedObjectAccess. Thread::Current()->TransitionFromRunnableToSuspended(kNative); { ScopedObjectAccess soa(Thread::Current()); @@ -512,7 +516,8 @@ class CommonTest : public testing::Test { } class_linker_->FixupDexCaches(runtime_->GetResolutionMethod()); timer_.reset(new CumulativeLogger("Compilation times")); - compiler_driver_.reset(new CompilerDriver(verification_results_.get(), + compiler_driver_.reset(new CompilerDriver(compiler_options_.get(), + verification_results_.get(), method_inliner_map_.get(), compiler_backend, instruction_set, instruction_set_features, @@ -563,9 +568,10 @@ class CommonTest : public testing::Test { compiler_driver_.reset(); timer_.reset(); - callbacks_.Reset(nullptr, nullptr); + callbacks_.reset(); method_inliner_map_.reset(); verification_results_.reset(); + compiler_options_.reset(); STLDeleteElements(&opened_dex_files_); Runtime::Current()->GetHeap()->VerifyHeap(); // Check for heap corruption after the test @@ -693,36 +699,6 @@ class CommonTest : public testing::Test { image_reservation_.reset(); } - class TestCompilerCallbacks : public CompilerCallbacks { - public: - TestCompilerCallbacks() : verification_results_(nullptr), method_inliner_map_(nullptr) {} - - void Reset(VerificationResults* verification_results, - DexFileToMethodInlinerMap* method_inliner_map) { - verification_results_ = verification_results; - method_inliner_map_ = method_inliner_map; - } - - virtual bool MethodVerified(verifier::MethodVerifier* verifier) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - CHECK(verification_results_); - bool result = verification_results_->ProcessVerifiedMethod(verifier); - if (result && method_inliner_map_ != nullptr) { - MethodReference ref = verifier->GetMethodReference(); - method_inliner_map_->GetMethodInliner(ref.dex_file) - ->AnalyseMethodCode(verifier); - } - return result; - } - virtual void ClassRejected(ClassReference ref) { - verification_results_->AddRejectedClass(ref); - } - - private: - VerificationResults* verification_results_; - DexFileToMethodInlinerMap* method_inliner_map_; - }; - std::string android_data_; std::string dalvik_cache_; const DexFile* java_lang_dex_file_; // owned by runtime_ @@ -730,9 +706,10 @@ class CommonTest : public testing::Test { UniquePtr<Runtime> runtime_; // Owned by the runtime ClassLinker* class_linker_; + UniquePtr<CompilerOptions> compiler_options_; UniquePtr<VerificationResults> verification_results_; UniquePtr<DexFileToMethodInlinerMap> method_inliner_map_; - TestCompilerCallbacks callbacks_; + UniquePtr<CompilerCallbacksImpl> callbacks_; UniquePtr<CompilerDriver> compiler_driver_; UniquePtr<CumulativeLogger> timer_; diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc index ebad8dd..86dee1d 100644 --- a/runtime/gc/space/image_space.cc +++ b/runtime/gc/space/image_space.cc @@ -89,52 +89,14 @@ static bool GenerateImage(const std::string& image_file_name, std::string* error arg_vector.push_back("--host"); } - std::string command_line(Join(arg_vector, ' ')); - LOG(INFO) << "GenerateImage: " << command_line; - - // Convert the args to char pointers. - std::vector<char*> char_args; - for (std::vector<std::string>::iterator it = arg_vector.begin(); it != arg_vector.end(); - ++it) { - char_args.push_back(const_cast<char*>(it->c_str())); + const std::vector<std::string>& compiler_options = Runtime::Current()->GetImageCompilerOptions(); + for (size_t i = 0; compiler_options.size(); ++i) { + arg_vector.push_back(compiler_options[i].c_str()); } - char_args.push_back(NULL); - - // fork and exec dex2oat - pid_t pid = fork(); - if (pid == 0) { - // no allocation allowed between fork and exec - - // change process groups, so we don't get reaped by ProcessManager - setpgid(0, 0); - execv(dex2oat.c_str(), &char_args[0]); - - PLOG(FATAL) << "execv(" << dex2oat << ") failed"; - return false; - } else { - if (pid == -1) { - *error_msg = StringPrintf("Failed to generate image '%s' because fork failed: %s", - image_file_name.c_str(), strerror(errno)); - return false; - } - - // wait for dex2oat to finish - int status; - pid_t got_pid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0)); - if (got_pid != pid) { - *error_msg = StringPrintf("Failed to generate image '%s' because waitpid failed: " - "wanted %d, got %d: %s", - image_file_name.c_str(), pid, got_pid, strerror(errno)); - return false; - } - if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { - *error_msg = StringPrintf("Failed to generate image '%s' because dex2oat failed: %s", - image_file_name.c_str(), command_line.c_str()); - return false; - } - } - return true; + std::string command_line(Join(arg_vector, ' ')); + LOG(INFO) << "GenerateImage: " << command_line; + return Exec(arg_vector, error_msg); } ImageSpace* ImageSpace::Create(const char* original_image_file_name) { diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc index 00a8506..61f023c 100644 --- a/runtime/oat_file.cc +++ b/runtime/oat_file.cc @@ -84,6 +84,7 @@ OatFile* OatFile::Open(const std::string& filename, // This won't work for portable runtime execution because it doesn't process relocations. UniquePtr<File> file(OS::OpenFileForReading(filename.c_str())); if (file.get() == NULL) { + *error_msg = StringPrintf("Failed to open oat filename for reading: %s", strerror(errno)); return NULL; } return OpenElfFile(file.get(), location, requested_base, false, executable, error_msg); diff --git a/runtime/runtime.cc b/runtime/runtime.cc index 3ccea36..1ef15f7 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -77,13 +77,6 @@ Runtime::Runtime() is_zygote_(false), is_concurrent_gc_enabled_(true), is_explicit_gc_disabled_(false), - compiler_filter_(kSpeed), - huge_method_threshold_(0), - large_method_threshold_(0), - small_method_threshold_(0), - tiny_method_threshold_(0), - num_dex_methods_threshold_(0), - sea_ir_mode_(false), default_stack_size_(0), heap_(nullptr), max_spins_before_thin_lock_inflation_(Monitor::kDefaultMaxSpinsBeforeThinLockInflation), @@ -452,14 +445,6 @@ Runtime::ParsedOptions* Runtime::ParsedOptions::Create(const Options& options, b parsed->hook_exit_ = exit; parsed->hook_abort_ = NULL; // We don't call abort(3) by default; see Runtime::Abort. - parsed->compiler_filter_ = Runtime::kDefaultCompilerFilter; - parsed->huge_method_threshold_ = Runtime::kDefaultHugeMethodThreshold; - parsed->large_method_threshold_ = Runtime::kDefaultLargeMethodThreshold; - parsed->small_method_threshold_ = Runtime::kDefaultSmallMethodThreshold; - parsed->tiny_method_threshold_ = Runtime::kDefaultTinyMethodThreshold; - parsed->num_dex_methods_threshold_ = Runtime::kDefaultNumDexMethodsThreshold; - - parsed->sea_ir_mode_ = false; // gLogVerbosity.class_linker = true; // TODO: don't check this in! // gLogVerbosity.compiler = true; // TODO: don't check this in! // gLogVerbosity.verifier = true; // TODO: don't check this in! @@ -721,28 +706,22 @@ Runtime::ParsedOptions* Runtime::ParsedOptions::Create(const Options& options, b } else if (StartsWith(option, "-Xprofile-backoff:")) { parsed->profile_backoff_coefficient_ = ParseDoubleOrDie( option, ':', 1.0, 10.0, ignore_unrecognized, parsed->profile_backoff_coefficient_); - } else if (option == "-compiler-filter:interpret-only") { - parsed->compiler_filter_ = kInterpretOnly; - } else if (option == "-compiler-filter:space") { - parsed->compiler_filter_ = kSpace; - } else if (option == "-compiler-filter:balanced") { - parsed->compiler_filter_ = kBalanced; - } else if (option == "-compiler-filter:speed") { - parsed->compiler_filter_ = kSpeed; - } else if (option == "-compiler-filter:everything") { - parsed->compiler_filter_ = kEverything; - } else if (option == "-sea_ir") { - parsed->sea_ir_mode_ = true; - } else if (StartsWith(option, "-huge-method-max:")) { - parsed->huge_method_threshold_ = ParseIntegerOrDie(option, ':'); - } else if (StartsWith(option, "-large-method-max:")) { - parsed->large_method_threshold_ = ParseIntegerOrDie(option, ':'); - } else if (StartsWith(option, "-small-method-max:")) { - parsed->small_method_threshold_ = ParseIntegerOrDie(option, ':'); - } else if (StartsWith(option, "-tiny-method-max:")) { - parsed->tiny_method_threshold_ = ParseIntegerOrDie(option, ':'); - } else if (StartsWith(option, "-num-dex-methods-max:")) { - parsed->num_dex_methods_threshold_ = ParseIntegerOrDie(option, ':'); + } else if (option == "-Xcompiler-option") { + i++; + if (i == options.size()) { + // TODO: usage + LOG(FATAL) << "Missing required compiler option for " << option; + return NULL; + } + parsed->compiler_options_.push_back(options[i].first); + } else if (option == "-Ximage-compiler-option") { + i++; + if (i == options.size()) { + // TODO: usage + LOG(FATAL) << "Missing required compiler option for " << option; + return NULL; + } + parsed->image_compiler_options_.push_back(options[i].first); } else { if (!ignore_unrecognized) { // TODO: print usage via vfprintf @@ -988,14 +967,6 @@ bool Runtime::Init(const Options& raw_options, bool ignore_unrecognized) { is_zygote_ = options->is_zygote_; is_explicit_gc_disabled_ = options->is_explicit_gc_disabled_; - compiler_filter_ = options->compiler_filter_; - huge_method_threshold_ = options->huge_method_threshold_; - large_method_threshold_ = options->large_method_threshold_; - small_method_threshold_ = options->small_method_threshold_; - tiny_method_threshold_ = options->tiny_method_threshold_; - num_dex_methods_threshold_ = options->num_dex_methods_threshold_; - - sea_ir_mode_ = options->sea_ir_mode_; vfprintf_ = options->hook_vfprintf_; exit_ = options->hook_exit_; abort_ = options->hook_abort_; diff --git a/runtime/runtime.h b/runtime/runtime.h index 223b8d5..8924921 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -72,26 +72,6 @@ class Runtime { public: typedef std::vector<std::pair<std::string, const void*> > Options; - enum CompilerFilter { - kInterpretOnly, // Compile nothing. - kSpace, // Maximize space savings. - kBalanced, // Try to get the best performance return on compilation investment. - kSpeed, // Maximize runtime performance. - kEverything // Force compilation (Note: excludes compilaton of class initializers). - }; - - // Guide heuristics to determine whether to compile method if profile data not available. -#if ART_SMALL_MODE - static const CompilerFilter kDefaultCompilerFilter = kInterpretOnly; -#else - static const CompilerFilter kDefaultCompilerFilter = kSpeed; -#endif - static const size_t kDefaultHugeMethodThreshold = 10000; - static const size_t kDefaultLargeMethodThreshold = 600; - static const size_t kDefaultSmallMethodThreshold = 60; - static const size_t kDefaultTinyMethodThreshold = 20; - static const size_t kDefaultNumDexMethodsThreshold = 900; - class ParsedOptions { public: // returns null if problem parsing and ignore_unrecognized is false @@ -140,13 +120,8 @@ class Runtime { void (*hook_exit_)(jint status); void (*hook_abort_)(); std::vector<std::string> properties_; - CompilerFilter compiler_filter_; - size_t huge_method_threshold_; - size_t large_method_threshold_; - size_t small_method_threshold_; - size_t tiny_method_threshold_; - size_t num_dex_methods_threshold_; - bool sea_ir_mode_; + std::vector<std::string> compiler_options_; + std::vector<std::string> image_compiler_options_; bool profile_; std::string profile_output_filename_; int profile_period_s_; @@ -178,42 +153,12 @@ class Runtime { return is_explicit_gc_disabled_; } -#ifdef ART_SEA_IR_MODE - bool IsSeaIRMode() const { - return sea_ir_mode_; - } -#endif - - void SetSeaIRMode(bool sea_ir_mode) { - sea_ir_mode_ = sea_ir_mode; - } - - CompilerFilter GetCompilerFilter() const { - return compiler_filter_; - } - - void SetCompilerFilter(CompilerFilter compiler_filter) { - compiler_filter_ = compiler_filter; + const std::vector<std::string>& GetCompilerOptions() const { + return compiler_options_; } - size_t GetHugeMethodThreshold() const { - return huge_method_threshold_; - } - - size_t GetLargeMethodThreshold() const { - return large_method_threshold_; - } - - size_t GetSmallMethodThreshold() const { - return small_method_threshold_; - } - - size_t GetTinyMethodThreshold() const { - return tiny_method_threshold_; - } - - size_t GetNumDexMethodsThreshold() const { - return num_dex_methods_threshold_; + const std::vector<std::string>& GetImageCompilerOptions() const { + return image_compiler_options_; } const std::string& GetHostPrefix() const { @@ -525,14 +470,8 @@ class Runtime { bool is_concurrent_gc_enabled_; bool is_explicit_gc_disabled_; - CompilerFilter compiler_filter_; - size_t huge_method_threshold_; - size_t large_method_threshold_; - size_t small_method_threshold_; - size_t tiny_method_threshold_; - size_t num_dex_methods_threshold_; - - bool sea_ir_mode_; + std::vector<std::string> compiler_options_; + std::vector<std::string> image_compiler_options_; // The host prefix is used during cross compilation. It is removed // from the start of host paths such as: diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc index 74e6f1c..d311945 100644 --- a/runtime/thread_list.cc +++ b/runtime/thread_list.cc @@ -269,6 +269,7 @@ size_t ThreadList::RunCheckpoint(Closure* checkpoint_function) { void ThreadList::SuspendAll() { Thread* self = Thread::Current(); + DCHECK(self != nullptr); VLOG(threads) << *self << " SuspendAll starting..."; diff --git a/runtime/utils.cc b/runtime/utils.cc index aad21bc..8e6ddaf 100644 --- a/runtime/utils.cc +++ b/runtime/utils.cc @@ -24,6 +24,7 @@ #include <unistd.h> #include "UniquePtr.h" +#include "base/stl_util.h" #include "base/unix_file/fd_file.h" #include "dex_file-inl.h" #include "mirror/art_field-inl.h" @@ -1203,4 +1204,56 @@ bool IsOatMagic(uint32_t magic) { sizeof(OatHeader::kOatMagic)) == 0); } +bool Exec(std::vector<std::string>& arg_vector, std::string* error_msg) { + const std::string command_line(Join(arg_vector, ' ')); + + CHECK_GE(arg_vector.size(), 1U) << command_line; + + // Convert the args to char pointers. + const char* program = arg_vector[0].c_str(); + std::vector<char*> args; + for (std::vector<std::string>::const_iterator it = arg_vector.begin(); it != arg_vector.end(); + ++it) { + CHECK(*it != nullptr); + args.push_back(const_cast<char*>(it->c_str())); + } + args.push_back(NULL); + + // fork and exec + pid_t pid = fork(); + if (pid == 0) { + // no allocation allowed between fork and exec + + // change process groups, so we don't get reaped by ProcessManager + setpgid(0, 0); + + execv(program, &args[0]); + + *error_msg = StringPrintf("Failed to execv(%s): %s", command_line.c_str(), strerror(errno)); + return false; + } else { + if (pid == -1) { + *error_msg = StringPrintf("Failed to execv(%s) because fork failed: %s", + command_line.c_str(), strerror(errno)); + return false; + } + + // wait for subprocess to finish + int status; + pid_t got_pid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0)); + if (got_pid != pid) { + *error_msg = StringPrintf("Failed after fork for execv(%s) because waitpid failed: " + "wanted %d, got %d: %s", + command_line.c_str(), pid, got_pid, strerror(errno)); + return false; + } + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { + *error_msg = StringPrintf("Failed execv(%s) because non-0 exit status", + command_line.c_str()); + return false; + } + } + return true; +} + } // namespace art diff --git a/runtime/utils.h b/runtime/utils.h index e2d8966..0bb06de 100644 --- a/runtime/utils.h +++ b/runtime/utils.h @@ -396,6 +396,9 @@ bool IsZipMagic(uint32_t magic); bool IsDexMagic(uint32_t magic); bool IsOatMagic(uint32_t magic); +// Wrapper on fork/execv to run a command in a subprocess. +bool Exec(std::vector<std::string>& arg_vector, std::string* error_msg); + class VoidFunctor { public: template <typename A> diff --git a/runtime/utils_test.cc b/runtime/utils_test.cc index b43177b..ff65e47 100644 --- a/runtime/utils_test.cc +++ b/runtime/utils_test.cc @@ -349,4 +349,26 @@ TEST_F(UtilsTest, GetDalvikCacheFilenameOrDie) { CheckGetDalvikCacheFilenameOrDie("/system/framework/boot.art", "system@framework@boot.art"); } +TEST_F(UtilsTest, ExecSuccess) { + std::vector<std::string> command; + if (kIsTargetBuild) { + command.push_back("/system/bin/id"); + } else { + command.push_back("/usr/bin/id"); + } + std::string error_msg; + EXPECT_TRUE(Exec(command, &error_msg)); + EXPECT_EQ(0U, error_msg.size()) << error_msg; +} + +// TODO: Disabled due to hang tearing down CommonTest. +// Renable after splitting into RuntimeTest and CompilerTest. +TEST_F(UtilsTest, DISABLED_ExecError) { + std::vector<std::string> command; + command.push_back("bogus"); + std::string error_msg; + EXPECT_FALSE(Exec(command, &error_msg)); + EXPECT_NE(0U, error_msg.size()); +} + } // namespace art |