在dex2oat.Compile()的最後,可以看到首先建立了一個對象進行初始化,之後執行了driver_->CompileAll(class_loader, dex_files_, timings_);
driver_.reset(new CompilerDriver(compiler_options_.get(),
verification_results_.get(),
&method_inliner_map_,
compiler_kind_,
instruction_set_,
instruction_set_features_.get(),
image_,
image_classes_.release(),
compiled_classes_.release(),
nullptr,
thread_count_,
dump_stats_,
dump_passes_,
dump_cfg_file_name_,
compiler_phases_timings_.get(),
swap_fd_,
profile_file_));
driver_->CompileAll(class_loader, dex_files_, timings_);
CompileAll()
CompileAll()的實作代碼位于art/compiler/driver/compiler_driver.cc。
void CompilerDriver::CompileAll(jobject class_loader, const std::vector<const DexFile*>& dex_files, TimingLogger* timings) {
DCHECK(!Runtime::Current()->IsStarted());
std::unique_ptr<ThreadPool> thread_pool(
new ThreadPool("Compiler driver thread pool", thread_count_ - ));
VLOG(compiler) << "Before precompile " << GetMemoryUsageString(false);
PreCompile(class_loader, dex_files, thread_pool.get(), timings);
Compile(class_loader, dex_files, thread_pool.get(), timings);
if (dump_stats_) {
stats_->Dump();
}
}
從代碼中可以看到,Compiler首先為編譯線程構造了一個線程池,接下來,依次完成兩個函數的調用過程,分别為PreCompile()和Compile()。
CompilerDriver::PreCompile()
void CompilerDriver::PreCompile(jobject class_loader, const std::vector<const DexFile*>& dex_files, ThreadPool* thread_pool, TimingLogger* timings) {
LoadImageClasses(timings);
VLOG(compiler) << "LoadImageClasses: " << GetMemoryUsageString(false);
const bool verification_enabled = compiler_options_->IsVerificationEnabled();
const bool never_verify = compiler_options_->NeverVerify();
// We need to resolve for never_verify since it needs to run dex to dex to add the
// RETURN_VOID_NO_BARRIER.
if (never_verify || verification_enabled) {
Resolve(class_loader, dex_files, thread_pool, timings);
VLOG(compiler) << "Resolve: " << GetMemoryUsageString(false);
}
if (never_verify) {
VLOG(compiler) << "Verify none mode specified, skipping verification.";
SetVerified(class_loader, dex_files, thread_pool, timings);
}
if (!verification_enabled) {
return;
}
Verify(class_loader, dex_files, thread_pool, timings);
VLOG(compiler) << "Verify: " << GetMemoryUsageString(false);
if (had_hard_verifier_failure_ && GetCompilerOptions().AbortOnHardVerifierFailure()) {
LOG(FATAL) << "Had a hard failure verifying all classes, and was asked to abort in such "
<< "situations. Please check the log.";
}
InitializeClasses(class_loader, dex_files, thread_pool, timings);
VLOG(compiler) << "InitializeClasses: " << GetMemoryUsageString(false);
UpdateImageClasses(timings);
VLOG(compiler) << "UpdateImageClasses: " << GetMemoryUsageString(false);
}
從代碼中可以看出,其實CompilerDriver::PreCompile()主要做了兩個工作:
- 對所有的類進行校驗——Verify(class_loader, dex_files, thread_pool, timings);
- 類的初始化——InitializeClasses(class_loader, dex_files, thread_pool, timings);
CompilerDriver::Compile()
接下來繼續分析CompilerDriver::Compile()。
void CompilerDriver::Compile(jobject class_loader, const std::vector<const DexFile*>& dex_files, ThreadPool* thread_pool, TimingLogger* timings) {
for (size_t i = ; i != dex_files.size(); ++i) {
const DexFile* dex_file = dex_files[i];
CHECK(dex_file != nullptr);
CompileDexFile(class_loader, *dex_file, dex_files, thread_pool, timings);
}
VLOG(compiler) << "Compile: " << GetMemoryUsageString(false);
}
從代碼中可以看出,Compile()方法循環周遊每個dex檔案,調用CompileDexFile()編譯。
CompilerDriver::CompileDexFile()
void CompilerDriver::CompileDexFile(jobject class_loader, const DexFile& dex_file, const std::vector<const DexFile*>& dex_files, ThreadPool* thread_pool, TimingLogger* timings) {
TimingLogger::ScopedTiming t("Compile Dex File", timings);
ParallelCompilationManager context(Runtime::Current()->GetClassLinker(), class_loader, this, &dex_file, dex_files, thread_pool);
context.ForAll(, dex_file.NumClassDefs(), CompilerDriver::CompileClass, thread_count_);
}
Compile函數是将多個dex拆成每一個dex檔案分别進行處理,而CompileDexFile再将其拆成每個類,針對每個類再調用CompileClass來進行編譯。
CompilerDriver::CompileClass()
CompileClass類的主要邏輯,就是針對直接方法和虛拟方法,分别周遊然後編譯。
void CompilerDriver::CompileClass(const ParallelCompilationManager* manager,
size_t class_def_index) {
ATRACE_CALL();
const DexFile& dex_file = *manager->GetDexFile();
const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
ClassLinker* class_linker = manager->GetClassLinker();
jobject jclass_loader = manager->GetClassLoader();
Thread* self = Thread::Current();
{
// Use a scoped object access to perform to the quick SkipClass check.
const char* descriptor = dex_file.GetClassDescriptor(class_def);
ScopedObjectAccess soa(self);
StackHandleScope<> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader(
hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
Handle<mirror::Class> klass(
hs.NewHandle(class_linker->FindClass(soa.Self(), descriptor, class_loader)));
if (klass.Get() == nullptr) {
CHECK(soa.Self()->IsExceptionPending());
soa.Self()->ClearException();
} else if (SkipClass(jclass_loader, dex_file, klass.Get())) {
return;
}
}
ClassReference ref(&dex_file, class_def_index);
// Skip compiling classes with generic verifier failures since they will still fail at runtime
if (manager->GetCompiler()->verification_results_->IsClassRejected(ref)) {
return;
}
const uint8_t* class_data = dex_file.GetClassData(class_def);
if (class_data == nullptr) {
// empty class, probably a marker interface
return;
}
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<> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader(
hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
dex_to_dex_compilation_level = driver->GetDexToDexCompilationlevel(
soa.Self(), class_loader, dex_file, class_def);
}
ClassDataItemIterator it(dex_file, class_data);
// Skip fields
while (it.HasNextStaticField()) {
it.Next();
}
while (it.HasNextInstanceField()) {
it.Next();
}
bool compilation_enabled = driver->IsClassToCompile(
dex_file.StringByTypeIdx(class_def.class_idx_));
// Compile direct methods
int64_t previous_direct_method_idx = -;
while (it.HasNextDirectMethod()) {
uint32_t method_idx = it.GetMemberIndex();
if (method_idx == previous_direct_method_idx) {
// smali can create dex files with two encoded_methods sharing the same method_idx
// http://code.google.com/p/smali/issues/detail?id=119
it.Next();
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);
it.Next();
}
// Compile virtual methods
int64_t previous_virtual_method_idx = -;
while (it.HasNextVirtualMethod()) {
uint32_t method_idx = it.GetMemberIndex();
if (method_idx == previous_virtual_method_idx) {
// smali can create dex files with two encoded_methods sharing the same method_idx
// http://code.google.com/p/smali/issues/detail?id=119
it.Next();
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);
it.Next();
}
DCHECK(!it.HasNext());
}
代碼中可以看到,在編譯直接方法和虛拟方法時,都調用了driver->CompileMethod()。
CompilerDriver::CompileMethod()
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() : ;
MethodReference method_ref(&dex_file, method_idx);
if ((access_flags & kAccNative) != ) {
// 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) != ) {
// 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 <clinit>.
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.
(*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 = u;
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 == u);
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();
}
}
在這個方法中可以看到,在首先完成一些初始化工作之後,會根據條件判斷是否需要進行jni編譯,抽象方法編譯以及普通方法編譯,在處理普通方法時,會調用Compile方法來完成。
compiled_method = compiler_->Compile(code_item, access_flags, invoke_type, class_def_idx,
method_idx, class_loader, dex_file);
在這一步中,compiler_會根據dex2oat傳入的執行參數選擇QuickCompiler或OptimizationCompiler。當–compiler-backend=Optimizing時,選擇OptimizationCompiler的Compile()方法完成編譯過程,QuickCompiler同理。