diff options
| author | 2016-06-03 12:42:04 +0000 | |
|---|---|---|
| committer | 2016-06-03 12:42:04 +0000 | |
| commit | 6591101bcb3117ca48a707f35c507a92ba6c72c2 (patch) | |
| tree | 8857b7e91ef8e2218e3d016b723f1a54eed56461 /compiler/driver/compiler_driver.cc | |
| parent | 4248fc46289f9940aa13d22e4f89abed5e74b169 (diff) | |
| parent | 492a7fa6df3b197a24099a50f5abf624164f3842 (diff) | |
Merge "Delay dex-to-dex compilation until Optimizing is done."
Diffstat (limited to 'compiler/driver/compiler_driver.cc')
| -rw-r--r-- | compiler/driver/compiler_driver.cc | 135 |
1 files changed, 111 insertions, 24 deletions
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index d20f51001c..7708b97290 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -26,6 +26,7 @@ #include "art_field-inl.h" #include "art_method-inl.h" +#include "base/bit_vector.h" #include "base/stl_util.h" #include "base/systrace.h" #include "base/time_utils.h" @@ -66,6 +67,7 @@ #include "thread_pool.h" #include "trampolines/trampoline_compiler.h" #include "transaction.h" +#include "utils/array_ref.h" #include "utils/dex_cache_arrays_layout-inl.h" #include "utils/swap_space.h" #include "verifier/method_verifier.h" @@ -333,6 +335,24 @@ class CompilerDriver::AOTCompilationStats { DISALLOW_COPY_AND_ASSIGN(AOTCompilationStats); }; +class CompilerDriver::DexFileMethodSet { + public: + explicit DexFileMethodSet(const DexFile& dex_file) + : dex_file_(dex_file), + method_indexes_(dex_file.NumMethodIds(), false, Allocator::GetMallocAllocator()) { + } + DexFileMethodSet(DexFileMethodSet&& other) = default; + + const DexFile& GetDexFile() const { return dex_file_; } + + BitVector& GetMethodIndexes() { return method_indexes_; } + const BitVector& GetMethodIndexes() const { return method_indexes_; } + + private: + const DexFile& dex_file_; + BitVector method_indexes_; +}; + CompilerDriver::CompilerDriver( const CompilerOptions* compiler_options, VerificationResults* verification_results, @@ -379,7 +399,10 @@ CompilerDriver::CompilerDriver( dex_files_for_oat_file_(nullptr), compiled_method_storage_(swap_fd), profile_compilation_info_(profile_compilation_info), - max_arena_alloc_(0) { + max_arena_alloc_(0), + dex_to_dex_references_lock_("dex-to-dex references lock"), + dex_to_dex_references_(), + current_dex_to_dex_methods_(nullptr) { DCHECK(compiler_options_ != nullptr); DCHECK(method_inliner_map_ != nullptr); @@ -552,7 +575,29 @@ static void CompileMethod(Thread* self, uint64_t start_ns = kTimeCompileMethod ? NanoTime() : 0; MethodReference method_ref(&dex_file, method_idx); - if ((access_flags & kAccNative) != 0) { + if (driver->GetCurrentDexToDexMethods() != nullptr) { + // This is the second pass when we dex-to-dex compile previously marked methods. + // TODO: Refactor the compilation to avoid having to distinguish the two passes + // here. That should be done on a higher level. http://b/29089975 + if (driver->GetCurrentDexToDexMethods()->IsBitSet(method_idx)) { + const VerifiedMethod* verified_method = + driver->GetVerificationResults()->GetVerifiedMethod(method_ref); + // Do not optimize if a VerifiedMethod is missing. SafeCast elision, + // for example, relies on it. + compiled_method = optimizer::ArtCompileDEX( + driver, + code_item, + access_flags, + invoke_type, + class_def_idx, + method_idx, + class_loader, + dex_file, + (verified_method != nullptr) + ? dex_to_dex_compilation_level + : optimizer::DexToDexCompilationLevel::kRequired); + } + } else if ((access_flags & kAccNative) != 0) { // Are we extracting only and have support for generic JNI down calls? if (!driver->GetCompilerOptions().IsJniCompilationEnabled() && InstructionSetHasGenericJniStub(driver->GetInstructionSet())) { @@ -588,21 +633,9 @@ static void CompileMethod(Thread* self, } if (compiled_method == nullptr && dex_to_dex_compilation_level != optimizer::DexToDexCompilationLevel::kDontDexToDexCompile) { + DCHECK(!Runtime::Current()->UseJitCompilation()); // TODO: add a command-line option to disable DEX-to-DEX compilation ? - // Do not optimize if a VerifiedMethod is missing. SafeCast elision, for example, relies on - // it. - compiled_method = optimizer::ArtCompileDEX( - driver, - code_item, - access_flags, - invoke_type, - class_def_idx, - method_idx, - class_loader, - dex_file, - (verified_method != nullptr) - ? dex_to_dex_compilation_level - : optimizer::DexToDexCompilationLevel::kRequired); + driver->MarkForDexToDexCompilation(self, method_ref); } } if (kTimeCompileMethod) { @@ -628,12 +661,6 @@ static void CompileMethod(Thread* self, driver->AddCompiledMethod(method_ref, compiled_method, non_relative_linker_patch_count); } - // Done compiling, delete the verified method to reduce native memory usage. Do not delete in - // optimizing compiler, which may need the verified method again for inlining. - if (driver->GetCompilerKind() != Compiler::kOptimizing) { - driver->GetVerificationResults()->RemoveVerifiedMethod(method_ref); - } - if (self->IsExceptionPending()) { ScopedObjectAccess soa(self); LOG(FATAL) << "Unexpected exception compiling: " << PrettyMethod(method_idx, dex_file) << "\n" @@ -680,6 +707,7 @@ void CompilerDriver::CompileOne(Thread* self, ArtMethod* method, TimingLogger* t *dex_file, dex_file->GetClassDef(class_def_idx)); + DCHECK(current_dex_to_dex_methods_ == nullptr); CompileMethod(self, this, code_item, @@ -693,6 +721,34 @@ void CompilerDriver::CompileOne(Thread* self, ArtMethod* method, TimingLogger* t true, dex_cache); + ArrayRef<DexFileMethodSet> dex_to_dex_references; + { + // From this point on, we shall not modify dex_to_dex_references_, so + // just grab a reference to it that we use without holding the mutex. + MutexLock lock(Thread::Current(), dex_to_dex_references_lock_); + dex_to_dex_references = ArrayRef<DexFileMethodSet>(dex_to_dex_references_); + } + if (!dex_to_dex_references.empty()) { + DCHECK_EQ(dex_to_dex_references.size(), 1u); + DCHECK(&dex_to_dex_references[0].GetDexFile() == dex_file); + current_dex_to_dex_methods_ = &dex_to_dex_references.front().GetMethodIndexes(); + DCHECK(current_dex_to_dex_methods_->IsBitSet(method_idx)); + DCHECK_EQ(current_dex_to_dex_methods_->NumSetBits(), 1u); + CompileMethod(self, + this, + code_item, + access_flags, + invoke_type, + class_def_idx, + method_idx, + jclass_loader, + *dex_file, + dex_to_dex_compilation_level, + true, + dex_cache); + current_dex_to_dex_methods_ = nullptr; + } + FreeThreadPools(); self->GetJniEnv()->DeleteGlobalRef(jclass_loader); @@ -1285,6 +1341,17 @@ bool CompilerDriver::CanAssumeClassIsLoaded(mirror::Class* klass) { return IsImageClass(descriptor); } +void CompilerDriver::MarkForDexToDexCompilation(Thread* self, const MethodReference& method_ref) { + MutexLock lock(self, dex_to_dex_references_lock_); + // Since we're compiling one dex file at a time, we need to look for the + // current dex file entry only at the end of dex_to_dex_references_. + if (dex_to_dex_references_.empty() || + &dex_to_dex_references_.back().GetDexFile() != method_ref.dex_file) { + dex_to_dex_references_.emplace_back(*method_ref.dex_file); + } + dex_to_dex_references_.back().GetMethodIndexes().SetBit(method_ref.dex_method_index); +} + bool CompilerDriver::CanAssumeTypeIsPresentInDexCache(Handle<mirror::DexCache> dex_cache, uint32_t type_idx) { bool result = false; @@ -2496,8 +2563,9 @@ void CompilerDriver::Compile(jobject class_loader, ? "null" : profile_compilation_info_->DumpInfo(&dex_files)); } - for (size_t i = 0; i != dex_files.size(); ++i) { - const DexFile* dex_file = dex_files[i]; + + DCHECK(current_dex_to_dex_methods_ == nullptr); + for (const DexFile* dex_file : dex_files) { CHECK(dex_file != nullptr); CompileDexFile(class_loader, *dex_file, @@ -2510,6 +2578,25 @@ void CompilerDriver::Compile(jobject class_loader, max_arena_alloc_ = std::max(arena_alloc, max_arena_alloc_); Runtime::Current()->ReclaimArenaPoolMemory(); } + + ArrayRef<DexFileMethodSet> dex_to_dex_references; + { + // From this point on, we shall not modify dex_to_dex_references_, so + // just grab a reference to it that we use without holding the mutex. + MutexLock lock(Thread::Current(), dex_to_dex_references_lock_); + dex_to_dex_references = ArrayRef<DexFileMethodSet>(dex_to_dex_references_); + } + for (const auto& method_set : dex_to_dex_references) { + current_dex_to_dex_methods_ = &method_set.GetMethodIndexes(); + CompileDexFile(class_loader, + method_set.GetDexFile(), + dex_files, + parallel_thread_pool_.get(), + parallel_thread_count_, + timings); + } + current_dex_to_dex_methods_ = nullptr; + VLOG(compiler) << "Compile: " << GetMemoryUsageString(false); } |