From: Andreas Gampe Date: Thu, 23 Jul 2015 08:19:26 +0000 (-0700) Subject: ART: Wire up DexToDexCompiler without extern X-Git-Tag: android-x86-7.1-r1~889^2~613^2 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=5eb0d38dabda4d17a315c557f07f457308d28fa7;p=android-x86%2Fart.git ART: Wire up DexToDexCompiler without extern The extern declaration actually had the wrong signature, a parameter was missing, and we never noticed. Remove the function field and extern. Add a header for the compiler. Use the header file. Change-Id: Ia4d4dd86211da6045709a45c7bf8430471d1b62b --- diff --git a/compiler/Android.mk b/compiler/Android.mk index 39470785a..49449157f 100644 --- a/compiler/Android.mk +++ b/compiler/Android.mk @@ -171,6 +171,7 @@ LIBART_COMPILER_ENUM_OPERATOR_OUT_HEADER_FILES := \ dex/quick/mips/mips_lir.h \ dex/quick/resource_mask.h \ dex/compiler_enums.h \ + dex/dex_to_dex_compiler.h \ dex/global_value_numbering.h \ dex/pass_me.h \ driver/compiler_driver.h \ diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc index 4b56b69a1..603130ab9 100644 --- a/compiler/dex/dex_to_dex_compiler.cc +++ b/compiler/dex/dex_to_dex_compiler.cc @@ -14,6 +14,8 @@ * limitations under the License. */ +#include "dex_to_dex_compiler.h" + #include "art_field-inl.h" #include "art_method-inl.h" #include "base/logging.h" @@ -65,7 +67,7 @@ class DexCompiler { } bool PerformOptimizations() const { - return dex_to_dex_compilation_level_ >= kOptimize; + return dex_to_dex_compilation_level_ >= DexToDexCompilationLevel::kOptimize; } // Compiles a RETURN-VOID into a RETURN-VOID-BARRIER within a constructor where @@ -108,7 +110,7 @@ class DexCompiler { }; void DexCompiler::Compile() { - DCHECK_GE(dex_to_dex_compilation_level_, kRequired); + DCHECK_GE(dex_to_dex_compilation_level_, DexToDexCompilationLevel::kRequired); const DexFile::CodeItem* code_item = unit_.GetCodeItem(); const uint16_t* insns = code_item->insns_; const uint32_t insns_size = code_item->insns_size_in_code_units_; @@ -310,21 +312,22 @@ void DexCompiler::CompileInvokeVirtual(Instruction* inst, uint32_t dex_pc, } } -extern "C" CompiledMethod* ArtCompileDEX( - art::CompilerDriver& driver, - const art::DexFile::CodeItem* code_item, +CompiledMethod* ArtCompileDEX( + CompilerDriver* driver, + const DexFile::CodeItem* code_item, uint32_t access_flags, - art::InvokeType invoke_type ATTRIBUTE_UNUSED, + InvokeType invoke_type ATTRIBUTE_UNUSED, uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, - const art::DexFile& dex_file, - art::DexToDexCompilationLevel dex_to_dex_compilation_level) { - if (dex_to_dex_compilation_level != art::kDontDexToDexCompile) { + const DexFile& dex_file, + DexToDexCompilationLevel dex_to_dex_compilation_level) { + DCHECK(driver != nullptr); + if (dex_to_dex_compilation_level != DexToDexCompilationLevel::kDontDexToDexCompile) { art::DexCompilationUnit unit(nullptr, class_loader, art::Runtime::Current()->GetClassLinker(), dex_file, code_item, class_def_idx, method_idx, access_flags, - driver.GetVerifiedMethod(&dex_file, method_idx)); - art::optimizer::DexCompiler dex_compiler(driver, unit, dex_to_dex_compilation_level); + driver->GetVerifiedMethod(&dex_file, method_idx)); + art::optimizer::DexCompiler dex_compiler(*driver, unit, dex_to_dex_compilation_level); dex_compiler.Compile(); if (dex_compiler.GetQuickenedInfo().empty()) { // No need to create a CompiledMethod if there are no quickened opcodes. @@ -337,13 +340,13 @@ extern "C" CompiledMethod* ArtCompileDEX( builder.PushBackUnsigned(info.dex_pc); builder.PushBackUnsigned(info.dex_member_index); } - InstructionSet instruction_set = driver.GetInstructionSet(); + InstructionSet instruction_set = driver->GetInstructionSet(); if (instruction_set == kThumb2) { // Don't use the thumb2 instruction set to avoid the one off code delta. instruction_set = kArm; } return CompiledMethod::SwapAllocCompiledMethod( - &driver, + driver, instruction_set, ArrayRef(), // no code 0, diff --git a/compiler/dex/dex_to_dex_compiler.h b/compiler/dex/dex_to_dex_compiler.h new file mode 100644 index 000000000..3fad6d4c9 --- /dev/null +++ b/compiler/dex/dex_to_dex_compiler.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2015 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_DEX_DEX_TO_DEX_COMPILER_H_ +#define ART_COMPILER_DEX_DEX_TO_DEX_COMPILER_H_ + +#include "jni.h" + +#include "dex_file.h" +#include "invoke_type.h" + +namespace art { + +class CompiledMethod; +class CompilerDriver; + +namespace optimizer { + +enum class DexToDexCompilationLevel { + kDontDexToDexCompile, // Only meaning wrt image time interpretation. + kRequired, // Dex-to-dex compilation required for correctness. + kOptimize // Perform required transformation and peep-hole optimizations. +}; +std::ostream& operator<<(std::ostream& os, const DexToDexCompilationLevel& rhs); + +CompiledMethod* ArtCompileDEX(CompilerDriver* driver, + const DexFile::CodeItem* code_item, + uint32_t access_flags, + InvokeType invoke_type, + uint16_t class_def_idx, + uint32_t method_idx, + jobject class_loader, + const DexFile& dex_file, + DexToDexCompilationLevel dex_to_dex_compilation_level); + +} // namespace optimizer + +} // namespace art + +#endif // ART_COMPILER_DEX_DEX_TO_DEX_COMPILER_H_ diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index affa52a37..299b99585 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -39,6 +39,7 @@ #include "compiler_driver-inl.h" #include "dex_compilation_unit.h" #include "dex_file-inl.h" +#include "dex/dex_to_dex_compiler.h" #include "dex/verification_results.h" #include "dex/verified_method.h" #include "dex/quick/dex_file_method_inliner.h" @@ -334,16 +335,6 @@ class CompilerDriver::AOTCompilationStats { DISALLOW_COPY_AND_ASSIGN(AOTCompilationStats); }; - -extern "C" art::CompiledMethod* ArtCompileDEX(art::CompilerDriver& compiler, - const art::DexFile::CodeItem* code_item, - uint32_t access_flags, - art::InvokeType invoke_type, - uint16_t class_def_idx, - uint32_t method_idx, - jobject class_loader, - const art::DexFile& dex_file); - CompilerDriver::CompilerDriver(const CompilerOptions* compiler_options, VerificationResults* verification_results, DexFileToMethodInlinerMap* method_inliner_map, @@ -394,8 +385,6 @@ CompilerDriver::CompilerDriver(const CompilerOptions* compiler_options, DCHECK(verification_results_ != nullptr); DCHECK(method_inliner_map_ != nullptr); - dex_to_dex_compiler_ = reinterpret_cast(ArtCompileDEX); - compiler_->Init(); CHECK_EQ(image_, image_classes_.get() != nullptr); @@ -508,13 +497,14 @@ void CompilerDriver::CompileAll(jobject class_loader, } } -DexToDexCompilationLevel CompilerDriver::GetDexToDexCompilationlevel( - Thread* self, Handle class_loader, const DexFile& dex_file, - const DexFile::ClassDef& class_def) { +static optimizer::DexToDexCompilationLevel GetDexToDexCompilationLevel( + Thread* self, const CompilerDriver& driver, Handle class_loader, + const DexFile& dex_file, const DexFile::ClassDef& class_def) + SHARED_REQUIRES(Locks::mutator_lock_) { auto* const runtime = Runtime::Current(); - if (runtime->UseJit() || GetCompilerOptions().VerifyAtRuntime()) { + if (runtime->UseJit() || driver.GetCompilerOptions().VerifyAtRuntime()) { // Verify at runtime shouldn't dex to dex since we didn't resolve of verify. - return kDontDexToDexCompile; + return optimizer::DexToDexCompilationLevel::kDontDexToDexCompile; } const char* descriptor = dex_file.GetClassDescriptor(class_def); ClassLinker* class_linker = runtime->GetClassLinker(); @@ -522,7 +512,7 @@ DexToDexCompilationLevel CompilerDriver::GetDexToDexCompilationlevel( if (klass == nullptr) { CHECK(self->IsExceptionPending()); self->ClearException(); - return kDontDexToDexCompile; + return optimizer::DexToDexCompilationLevel::kDontDexToDexCompile; } // DexToDex at the kOptimize level may introduce quickened opcodes, which replace symbolic // references with actual offsets. We cannot re-verify such instructions. @@ -532,14 +522,142 @@ DexToDexCompilationLevel CompilerDriver::GetDexToDexCompilationlevel( // optimize when a class has been fully verified before. if (klass->IsVerified()) { // Class is verified so we can enable DEX-to-DEX compilation for performance. - return kOptimize; + return optimizer::DexToDexCompilationLevel::kOptimize; } else if (klass->IsCompileTimeVerified()) { // Class verification has soft-failed. Anyway, ensure at least correctness. DCHECK_EQ(klass->GetStatus(), mirror::Class::kStatusRetryVerificationAtRuntime); - return kRequired; + return optimizer::DexToDexCompilationLevel::kRequired; } else { // Class verification has failed: do not run DEX-to-DEX compilation. - return kDontDexToDexCompile; + return optimizer::DexToDexCompilationLevel::kDontDexToDexCompile; + } +} + +static optimizer::DexToDexCompilationLevel GetDexToDexCompilationLevel( + Thread* self, + const CompilerDriver& driver, + jobject jclass_loader, + const DexFile& dex_file, + const DexFile::ClassDef& class_def) { + ScopedObjectAccess soa(self); + StackHandleScope<1> hs(soa.Self()); + Handle class_loader( + hs.NewHandle(soa.Decode(jclass_loader))); + return GetDexToDexCompilationLevel(self, driver, class_loader, dex_file, class_def); +} + +// Does the runtime for the InstructionSet provide an implementation returned by +// GetQuickGenericJniStub allowing down calls that aren't compiled using a JNI compiler? +static bool InstructionSetHasGenericJniStub(InstructionSet isa) { + switch (isa) { + case kArm: + case kArm64: + case kThumb2: + case kMips: + case kMips64: + case kX86: + case kX86_64: return true; + default: return false; + } +} + +static void CompileMethod(Thread* self, + CompilerDriver* driver, + const DexFile::CodeItem* code_item, + uint32_t access_flags, + InvokeType invoke_type, + uint16_t class_def_idx, + uint32_t method_idx, + jobject class_loader, + const DexFile& dex_file, + optimizer::DexToDexCompilationLevel dex_to_dex_compilation_level, + bool compilation_enabled) + REQUIRES(!driver->compiled_methods_lock_) { + DCHECK(driver != nullptr); + CompiledMethod* compiled_method = nullptr; + uint64_t start_ns = kTimeCompileMethod ? NanoTime() : 0; + MethodReference method_ref(&dex_file, method_idx); + + if ((access_flags & kAccNative) != 0) { + // Are we interpreting only and have support for generic JNI down calls? + if (!driver->GetCompilerOptions().IsCompilationEnabled() && + InstructionSetHasGenericJniStub(driver->GetInstructionSet())) { + // Leaving this empty will trigger the generic JNI version + } else { + compiled_method = driver->GetCompiler()->JniCompile(access_flags, method_idx, dex_file); + CHECK(compiled_method != nullptr); + } + } else if ((access_flags & kAccAbstract) != 0) { + // Abstract methods don't have code. + } else { + bool has_verified_method = driver->GetVerificationResults() + ->GetVerifiedMethod(method_ref) != nullptr; + bool compile = compilation_enabled && + // Basic checks, e.g., not . + driver->GetVerificationResults() + ->IsCandidateForCompilation(method_ref, access_flags) && + // Did not fail to create VerifiedMethod metadata. + has_verified_method && + // Is eligable for compilation by methods-to-compile filter. + driver->IsMethodToCompile(method_ref); + if (compile) { + // NOTE: if compiler declines to compile this method, it will return null. + compiled_method = driver->GetCompiler()->Compile(code_item, access_flags, invoke_type, + class_def_idx, method_idx, class_loader, + dex_file); + } + if (compiled_method == nullptr && + dex_to_dex_compilation_level != optimizer::DexToDexCompilationLevel::kDontDexToDexCompile) { + // 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, + has_verified_method + ? dex_to_dex_compilation_level + : optimizer::DexToDexCompilationLevel::kRequired); + } + } + if (kTimeCompileMethod) { + uint64_t duration_ns = NanoTime() - start_ns; + if (duration_ns > MsToNs(driver->GetCompiler()->GetMaximumCompilationTimeBeforeWarning())) { + LOG(WARNING) << "Compilation of " << PrettyMethod(method_idx, dex_file) + << " took " << PrettyDuration(duration_ns); + } + } + + if (compiled_method != nullptr) { + // Count non-relative linker patches. + size_t non_relative_linker_patch_count = 0u; + for (const LinkerPatch& patch : compiled_method->GetPatches()) { + if (!patch.IsPcRelative()) { + ++non_relative_linker_patch_count; + } + } + bool compile_pic = driver->GetCompilerOptions().GetCompilePic(); // Off by default + // When compiling with PIC, there should be zero non-relative linker patches + CHECK(!compile_pic || non_relative_linker_patch_count == 0u); + + 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" + << self->GetException()->Dump(); } } @@ -570,24 +688,30 @@ void CompilerDriver::CompileOne(Thread* self, ArtMethod* method, TimingLogger* t PreCompile(jclass_loader, dex_files, thread_pool.get(), timings); // Can we run DEX-to-DEX compiler on this class ? - DexToDexCompilationLevel dex_to_dex_compilation_level = kDontDexToDexCompile; - { - ScopedObjectAccess soa(self); - const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_idx); - StackHandleScope<1> hs(soa.Self()); - Handle class_loader( - hs.NewHandle(soa.Decode(jclass_loader))); - dex_to_dex_compilation_level = GetDexToDexCompilationlevel(self, class_loader, *dex_file, - class_def); - } - CompileMethod(self, code_item, access_flags, invoke_type, class_def_idx, method_idx, - jclass_loader, *dex_file, dex_to_dex_compilation_level, true); + optimizer::DexToDexCompilationLevel dex_to_dex_compilation_level = + GetDexToDexCompilationLevel(self, + *this, + jclass_loader, + *dex_file, + dex_file->GetClassDef(class_def_idx)); + + CompileMethod(self, + this, + code_item, + access_flags, + invoke_type, + class_def_idx, + method_idx, + jclass_loader, + *dex_file, + dex_to_dex_compilation_level, + true); self->GetJniEnv()->DeleteGlobalRef(jclass_loader); self->TransitionFromSuspendedToRunnable(); } -CompiledMethod* CompilerDriver::CompileMethod(Thread* self, ArtMethod* method) { +CompiledMethod* CompilerDriver::CompileArtMethod(Thread* self, ArtMethod* method) { const uint32_t method_idx = method->GetDexMethodIndex(); const uint32_t access_flags = method->GetAccessFlags(); const InvokeType invoke_type = method->GetInvokeType(); @@ -598,12 +722,21 @@ CompiledMethod* CompilerDriver::CompileMethod(Thread* self, ArtMethod* method) { const DexFile* dex_file = method->GetDexFile(); const uint16_t class_def_idx = method->GetClassDefIndex(); const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_idx); - DexToDexCompilationLevel dex_to_dex_compilation_level = - GetDexToDexCompilationlevel(self, class_loader, *dex_file, class_def); + optimizer::DexToDexCompilationLevel dex_to_dex_compilation_level = + GetDexToDexCompilationLevel(self, *this, class_loader, *dex_file, class_def); const DexFile::CodeItem* code_item = dex_file->GetCodeItem(method->GetCodeItemOffset()); self->TransitionFromRunnableToSuspended(kNative); - CompileMethod(self, code_item, access_flags, invoke_type, class_def_idx, method_idx, - jclass_loader, *dex_file, dex_to_dex_compilation_level, true); + CompileMethod(self, + this, + code_item, + access_flags, + invoke_type, + class_def_idx, + method_idx, + jclass_loader, + *dex_file, + dex_to_dex_compilation_level, + true); auto* compiled_method = GetCompiledMethod(MethodReference(dex_file, method_idx)); self->TransitionFromSuspendedToRunnable(); return compiled_method; @@ -2237,15 +2370,9 @@ class CompileClassVisitor : public CompilationVisitor { CompilerDriver* const driver = manager_->GetCompiler(); // Can we run DEX-to-DEX compiler on this class ? - DexToDexCompilationLevel dex_to_dex_compilation_level = kDontDexToDexCompile; - { - ScopedObjectAccess soa(self); - StackHandleScope<1> hs(soa.Self()); - Handle class_loader( - hs.NewHandle(soa.Decode(jclass_loader))); - dex_to_dex_compilation_level = driver->GetDexToDexCompilationlevel( - soa.Self(), class_loader, dex_file, class_def); - } + optimizer::DexToDexCompilationLevel dex_to_dex_compilation_level = + GetDexToDexCompilationLevel(self, *driver, jclass_loader, dex_file, class_def); + ClassDataItemIterator it(dex_file, class_data); // Skip fields while (it.HasNextStaticField()) { @@ -2269,10 +2396,10 @@ class CompileClassVisitor : public CompilationVisitor { continue; } previous_direct_method_idx = method_idx; - driver->CompileMethod(self, it.GetMethodCodeItem(), it.GetMethodAccessFlags(), - it.GetMethodInvokeType(class_def), class_def_index, - method_idx, jclass_loader, dex_file, dex_to_dex_compilation_level, - compilation_enabled); + CompileMethod(self, driver, it.GetMethodCodeItem(), it.GetMethodAccessFlags(), + it.GetMethodInvokeType(class_def), class_def_index, + method_idx, jclass_loader, dex_file, dex_to_dex_compilation_level, + compilation_enabled); it.Next(); } // Compile virtual methods @@ -2286,10 +2413,10 @@ class CompileClassVisitor : public CompilationVisitor { continue; } previous_virtual_method_idx = method_idx; - driver->CompileMethod(self, it.GetMethodCodeItem(), it.GetMethodAccessFlags(), - it.GetMethodInvokeType(class_def), class_def_index, - method_idx, jclass_loader, dex_file, dex_to_dex_compilation_level, - compilation_enabled); + CompileMethod(self, driver, it.GetMethodCodeItem(), it.GetMethodAccessFlags(), + it.GetMethodInvokeType(class_def), class_def_index, + method_idx, jclass_loader, dex_file, dex_to_dex_compilation_level, + compilation_enabled); it.Next(); } DCHECK(!it.HasNext()); @@ -2309,112 +2436,18 @@ void CompilerDriver::CompileDexFile(jobject class_loader, const DexFile& dex_fil context.ForAll(0, dex_file.NumClassDefs(), &visitor, thread_count_); } -// Does the runtime for the InstructionSet provide an implementation returned by -// GetQuickGenericJniStub allowing down calls that aren't compiled using a JNI compiler? -static bool InstructionSetHasGenericJniStub(InstructionSet isa) { - switch (isa) { - case kArm: - case kArm64: - case kThumb2: - case kMips: - case kMips64: - case kX86: - case kX86_64: return true; - default: return false; - } -} - -void CompilerDriver::CompileMethod(Thread* self, const DexFile::CodeItem* code_item, - uint32_t access_flags, InvokeType invoke_type, - uint16_t class_def_idx, uint32_t method_idx, - jobject class_loader, const DexFile& dex_file, - DexToDexCompilationLevel dex_to_dex_compilation_level, - bool compilation_enabled) { - CompiledMethod* compiled_method = nullptr; - uint64_t start_ns = kTimeCompileMethod ? NanoTime() : 0; - MethodReference method_ref(&dex_file, method_idx); - - if ((access_flags & kAccNative) != 0) { - // Are we interpreting only and have support for generic JNI down calls? - if (!compiler_options_->IsCompilationEnabled() && - InstructionSetHasGenericJniStub(instruction_set_)) { - // Leaving this empty will trigger the generic JNI version - } else { - compiled_method = compiler_->JniCompile(access_flags, method_idx, dex_file); - CHECK(compiled_method != nullptr); - } - } else if ((access_flags & kAccAbstract) != 0) { - // Abstract methods don't have code. - } else { - bool has_verified_method = verification_results_->GetVerifiedMethod(method_ref) != nullptr; - bool compile = compilation_enabled && - // Basic checks, e.g., not . - verification_results_->IsCandidateForCompilation(method_ref, access_flags) && - // Did not fail to create VerifiedMethod metadata. - has_verified_method && - // Is eligable for compilation by methods-to-compile filter. - IsMethodToCompile(method_ref); - if (compile) { - // NOTE: if compiler declines to compile this method, it will return null. - compiled_method = compiler_->Compile(code_item, access_flags, invoke_type, class_def_idx, - method_idx, class_loader, dex_file); - } - if (compiled_method == nullptr && dex_to_dex_compilation_level != kDontDexToDexCompile) { - // 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 = (*dex_to_dex_compiler_)( - *this, - code_item, - access_flags, - invoke_type, - class_def_idx, - method_idx, - class_loader, - dex_file, - has_verified_method ? dex_to_dex_compilation_level : kRequired); - } - } - if (kTimeCompileMethod) { - uint64_t duration_ns = NanoTime() - start_ns; - if (duration_ns > MsToNs(compiler_->GetMaximumCompilationTimeBeforeWarning())) { - LOG(WARNING) << "Compilation of " << PrettyMethod(method_idx, dex_file) - << " took " << PrettyDuration(duration_ns); - } - } - - if (compiled_method != nullptr) { - // Count non-relative linker patches. - size_t non_relative_linker_patch_count = 0u; - for (const LinkerPatch& patch : compiled_method->GetPatches()) { - if (!patch.IsPcRelative()) { - ++non_relative_linker_patch_count; - } - } - bool compile_pic = GetCompilerOptions().GetCompilePic(); // Off by default - // When compiling with PIC, there should be zero non-relative linker patches - CHECK(!compile_pic || non_relative_linker_patch_count == 0u); - - DCHECK(GetCompiledMethod(method_ref) == nullptr) << PrettyMethod(method_idx, dex_file); - { - MutexLock mu(self, compiled_methods_lock_); - compiled_methods_.Put(method_ref, compiled_method); - non_relative_linker_patch_count_ += non_relative_linker_patch_count; - } - DCHECK(GetCompiledMethod(method_ref) != nullptr) << PrettyMethod(method_idx, dex_file); - } - - // 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 (compiler_kind_ != Compiler::kOptimizing) { - verification_results_->RemoveVerifiedMethod(method_ref); - } - - if (self->IsExceptionPending()) { - ScopedObjectAccess soa(self); - LOG(FATAL) << "Unexpected exception compiling: " << PrettyMethod(method_idx, dex_file) << "\n" - << self->GetException()->Dump(); +void CompilerDriver::AddCompiledMethod(const MethodReference& method_ref, + CompiledMethod* const compiled_method, + size_t non_relative_linker_patch_count) { + DCHECK(GetCompiledMethod(method_ref) == nullptr) + << PrettyMethod(method_ref.dex_method_index, *method_ref.dex_file); + { + MutexLock mu(Thread::Current(), compiled_methods_lock_); + compiled_methods_.Put(method_ref, compiled_method); + non_relative_linker_patch_count_ += non_relative_linker_patch_count; } + DCHECK(GetCompiledMethod(method_ref) != nullptr) + << PrettyMethod(method_ref.dex_method_index, *method_ref.dex_file); } void CompilerDriver::RemoveCompiledMethod(const MethodReference& method_ref) { diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index 88e03a231..4de9c734b 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -80,13 +80,6 @@ enum EntryPointCallingConvention { kQuickAbi }; -enum DexToDexCompilationLevel { - kDontDexToDexCompile, // Only meaning wrt image time interpretation. - kRequired, // Dex-to-dex compilation required for correctness. - kOptimize // Perform required transformation and peep-hole optimizations. -}; -std::ostream& operator<<(std::ostream& os, const DexToDexCompilationLevel& rhs); - static constexpr bool kUseMurmur3Hash = true; class CompilerDriver { @@ -116,7 +109,7 @@ class CompilerDriver { TimingLogger* timings) REQUIRES(!Locks::mutator_lock_, !compiled_classes_lock_); - CompiledMethod* CompileMethod(Thread* self, ArtMethod*) + CompiledMethod* CompileArtMethod(Thread* self, ArtMethod*) SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!compiled_methods_lock_) WARN_UNUSED; // Compile a single Method. @@ -185,6 +178,11 @@ class CompilerDriver { size_t GetNonRelativeLinkerPatchCount() const REQUIRES(!compiled_methods_lock_); + // Add a compiled method. + void AddCompiledMethod(const MethodReference& method_ref, + CompiledMethod* const compiled_method, + size_t non_relative_linker_patch_count) + REQUIRES(!compiled_methods_lock_); // Remove and delete a compiled method. void RemoveCompiledMethod(const MethodReference& method_ref) REQUIRES(!compiled_methods_lock_); @@ -476,6 +474,10 @@ class CompilerDriver { had_hard_verifier_failure_ = true; } + Compiler::Kind GetCompilerKind() { + return compiler_kind_; + } + private: // Return whether the declaring class of `resolved_member` is // available to `referrer_class` for read or write access using two @@ -546,10 +548,6 @@ class CompilerDriver { SHARED_REQUIRES(Locks::mutator_lock_); private: - DexToDexCompilationLevel GetDexToDexCompilationlevel( - Thread* self, Handle class_loader, const DexFile& dex_file, - const DexFile::ClassDef& class_def) SHARED_REQUIRES(Locks::mutator_lock_); - void PreCompile(jobject class_loader, const std::vector& dex_files, ThreadPool* thread_pool, TimingLogger* timings) REQUIRES(!Locks::mutator_lock_, !compiled_classes_lock_); @@ -599,12 +597,6 @@ class CompilerDriver { const std::vector& dex_files, ThreadPool* thread_pool, TimingLogger* timings) REQUIRES(!Locks::mutator_lock_); - void CompileMethod(Thread* self, const DexFile::CodeItem* code_item, uint32_t access_flags, - InvokeType invoke_type, uint16_t class_def_idx, uint32_t method_idx, - jobject class_loader, const DexFile& dex_file, - DexToDexCompilationLevel dex_to_dex_compilation_level, - bool compilation_enabled) - REQUIRES(!compiled_methods_lock_); // Swap pool and allocator used for native allocations. May be file-backed. Needs to be first // as other fields rely on this. @@ -634,8 +626,13 @@ class CompilerDriver { ClassTable compiled_classes_ GUARDED_BY(compiled_classes_lock_); typedef SafeMap MethodTable; - // All method references that this compiler has compiled. + + public: + // Lock is public so that non-members can have lock annotations. mutable Mutex compiled_methods_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER; + + private: + // All method references that this compiler has compiled. MethodTable compiled_methods_ GUARDED_BY(compiled_methods_lock_); // Number of non-relative patches in all compiled methods. These patches need space // in the .oat_patches ELF section if requested in the compiler options. @@ -675,15 +672,6 @@ class CompilerDriver { typedef void (*CompilerCallbackFn)(CompilerDriver& driver); typedef MutexLock* (*CompilerMutexLockFn)(CompilerDriver& driver); - typedef CompiledMethod* (*DexToDexCompilerFn)( - CompilerDriver& driver, - const DexFile::CodeItem* code_item, - uint32_t access_flags, InvokeType invoke_type, - uint32_t class_dex_idx, uint32_t method_idx, - jobject class_loader, const DexFile& dex_file, - DexToDexCompilationLevel dex_to_dex_compilation_level); - DexToDexCompilerFn dex_to_dex_compiler_; - void* compiler_context_; bool support_boot_image_fixup_; diff --git a/compiler/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc index c95bac24f..4215f3cdd 100644 --- a/compiler/jit/jit_compiler.cc +++ b/compiler/jit/jit_compiler.cc @@ -153,7 +153,7 @@ bool JitCompiler::CompileMethod(Thread* self, ArtMethod* method) { CompiledMethod* compiled_method = nullptr; { TimingLogger::ScopedTiming t2("Compiling", &logger); - compiled_method = compiler_driver_->CompileMethod(self, method); + compiled_method = compiler_driver_->CompileArtMethod(self, method); } { TimingLogger::ScopedTiming t2("TrimMaps", &logger);