dex2oat將dex轉換為oat的執行路徑概覽
阿新 • • 發佈:2019-02-14
dex2oat是一個可執行檔案,在原始碼中通過編譯檔案art\dex2oat\Dex2oat.cc生成。
dex2oat的執行入口是:
int main(int argc, char** argv) {
return art::dex2oat(argc, argv);
}
在函式dex2oat中呼叫了dex2oat->CreateOatFile函式,在CreateOatFile函式中執行了driver->CompileAll(class_loader, dex_files, timings);語句,這條語句將dex檔案編譯成了oat檔案。
void CompilerDriver::CompileAll(jobject class_loader, const std::vector<const DexFile*>& dex_files, base::TimingLogger& timings) { DCHECK(!Runtime::Current()->IsStarted()); UniquePtr<ThreadPool> thread_pool(new ThreadPool(thread_count_ - 1)); PreCompile(class_loader, dex_files, *thread_pool.get(), timings); Compile(class_loader, dex_files, *thread_pool.get(), timings); if (dump_stats_) { stats_->Dump(); } }
Compile函式
CompileDexFile函式void CompilerDriver::Compile(jobject class_loader, const std::vector<const DexFile*>& dex_files, ThreadPool& thread_pool, base::TimingLogger& timings) { for (size_t i = 0; i != dex_files.size(); ++i) { const DexFile* dex_file = dex_files[i]; CHECK(dex_file != NULL); CompileDexFile(class_loader, *dex_file, thread_pool, timings); } }
void CompilerDriver::CompileDexFile(jobject class_loader, const DexFile& dex_file, ThreadPool& thread_pool, base::TimingLogger& timings) { // TODO: strdup memory leak. timings.NewSplit(strdup(("Compile " + dex_file.GetLocation()).c_str())); ParallelCompilationManager context(Runtime::Current()->GetClassLinker(), class_loader, this, &dex_file, thread_pool); context.ForAll(0, dex_file.NumClassDefs(), CompilerDriver::CompileClass, thread_count_); }
context.ForAll(0, dex_file.NumClassDefs(), CompilerDriver::CompileClass, thread_count_);這條語句中重要的是CompilerDriver::CompileClass,CompilerDriver::CompileClass代表一個回撥函式,這個回撥函式將一個dex中的類進行編譯。
在CompileClass函式中呼叫了CompileMethod函式將一個方法進行編譯,其中使用到了類的成員變數jni_compiler_和compiler_,這兩個成員變數均在CompilerDriver類的建構函式中被賦值:
CompilerDriver::CompilerDriver(CompilerBackend compiler_backend, InstructionSet instruction_set,
bool image, DescriptorSet* image_classes, size_t thread_count,
bool dump_stats) ... {
...
if (compiler_backend_ == kPortable) {
// Initialize compiler_context_
init_compiler_context = reinterpret_cast<void (*)(CompilerDriver&)>(ArtInitCompilerContext);
compiler_ = reinterpret_cast<CompilerFn>(ArtCompileMethod);
} else {
init_compiler_context = reinterpret_cast<void (*)(CompilerDriver&)>(ArtInitQuickCompilerContext);
compiler_ = reinterpret_cast<CompilerFn>(ArtQuickCompileMethod);
}
...
if (compiler_backend_ == kPortable) {
jni_compiler_ = reinterpret_cast<JniCompilerFn>(ArtLLVMJniCompileMethod);
} else {
jni_compiler_ = reinterpret_cast<JniCompilerFn>(ArtQuickJniCompileMethod);
}
...
}
這其中有這麼幾個函式值得關注:ArtCompileMethod、ArtQuickCompileMethod、ArtLLVMJniCompileMethod、ArtQuickJniCompileMethod。
檢視其中ArtCompileMethod函式的程式碼:
extern "C" art::CompiledMethod* ArtCompileMethod(art::CompilerDriver& driver,
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) {
UNUSED(class_def_idx); // TODO: this is used with Compiler::RequiresConstructorBarrier.
art::ClassLinker *class_linker = art::Runtime::Current()->GetClassLinker();
art::DexCompilationUnit dex_compilation_unit(
NULL, class_loader, class_linker, dex_file, code_item,
class_def_idx, method_idx, access_flags);
art::llvm::CompilerLLVM* compiler_llvm = ContextOf(driver);
art::CompiledMethod* result = compiler_llvm->CompileDexMethod(&dex_compilation_unit, invoke_type);
return result;
}
通過上面ArtCompileMethod函式的程式碼發現,使用類art::llvm::CompilerLLVM中的CompileDexMethod函式對dex中的方法進行了編譯。
art::llvm::CompilerLLVM屬於LLVM的範疇。以上就是dex2oat工具將dex轉換為oat的執行路徑概覽,未涉及到具體細節。