dex2oat源码流程分析
来源:互联网 发布:南开大学网络教学平台 编辑:程序博客网 时间:2024/05/21 08:50
dex2oat是ART运行模式下虚拟机必备的一个组件,主要用来把安装的apk和动态加载的dex等文件转换成oat文件,方便下一步的加载解析,获得其中的类并执行相关方法,所以本文以Android 6.0源码为例,对dex的处理流程尝试做一下分析,了解其中的处理情况。
dex2oat源码位于art\dex2oat\Dex2oat.cc,入口函数为main:
int main(int argc, char** argv) { int result = art::dex2oat(argc, argv); if (!art::kIsDebugBuild && (RUNNING_ON_VALGRIND == 0)) { exit(result); } return result;}
这里的整体流程如下图所示(图片来自参考文献),后边也主要分析的这个流程上的代码:
直接调用了同文件art 命名空间下的 dex2oat 函数,做下一步的处理:
static int dex2oat(int argc, char** argv) { b13564922(); TimingLogger timings("compiler", false, false); Dex2Oat dex2oat(&timings); // Parse arguments. Argument mistakes will lead to exit(EXIT_FAILURE) in UsageError. dex2oat.ParseArgs(argc, argv); // Check early that the result of compilation can be written if (!dex2oat.OpenFile()) { return EXIT_FAILURE; } // Print the complete line when any of the following is true: // 1) Debug build // 2) Compiling an image // 3) Compiling with --host // 4) Compiling on the host (not a target build) // Otherwise, print a stripped command line. if (kIsDebugBuild || dex2oat.IsImage() || dex2oat.IsHost() || !kIsTargetBuild) { LOG(INFO) << CommandLine(); } else { LOG(INFO) << StrippedCommandLine(); } if (!dex2oat.Setup()) { dex2oat.EraseOatFile(); return EXIT_FAILURE; } if (dex2oat.IsImage()) { return CompileImage(dex2oat); } else { return CompileApp(dex2oat); }}
dex2oat的整个逻辑是很清晰的:
1. 做一个arm上的workaround,这个与我们分析的主线暂时无关,了解一下就可以了。
2. 构造Dex2oat对象
3. 处理命令行参数
4. 先行判断对于文件是否有写的权限
5. 打印命令行参数
6. 判断dex2oat的setup是否完成
7. 根据是否image分别调用CompileImage或CompileApp的处理
这里放一张来自参考文献的总体流程图:
CompileImage
基本上还是对于dex2oat.Compile的封装,后面都是对写文件和计时的处理:
static int CompileImage(Dex2Oat& dex2oat) { dex2oat.Compile(); // Create the boot.oat. if (!dex2oat.CreateOatFile()) { dex2oat.EraseOatFile(); return EXIT_FAILURE; } // Flush and close the boot.oat. We always expect the output file by name, and it will be // re-opened from the unstripped name. if (!dex2oat.FlushCloseOatFile()) { return EXIT_FAILURE; } // Creates the boot.art and patches the boot.oat. if (!dex2oat.HandleImage()) { return EXIT_FAILURE; } // When given --host, finish early without stripping. if (dex2oat.IsHost()) { dex2oat.DumpTiming(); return EXIT_SUCCESS; } // Copy unstripped to stripped location, if necessary. if (!dex2oat.CopyUnstrippedToStripped()) { return EXIT_FAILURE; } // FlushClose again, as stripping might have re-opened the oat file. if (!dex2oat.FlushCloseOatFile()) { return EXIT_FAILURE; } dex2oat.DumpTiming(); return EXIT_SUCCESS;}
CompileApp
然后我们再看一下基本一模一样的CompileApp.
static int CompileApp(Dex2Oat& dex2oat) { dex2oat.Compile(); // Create the app oat. if (!dex2oat.CreateOatFile()) { dex2oat.EraseOatFile(); return EXIT_FAILURE; } // Do not close the oat file here. We might haven gotten the output file by file descriptor, // which we would lose. if (!dex2oat.FlushOatFile()) { return EXIT_FAILURE; } // When given --host, finish early without stripping. if (dex2oat.IsHost()) { if (!dex2oat.FlushCloseOatFile()) { return EXIT_FAILURE; } dex2oat.DumpTiming(); return EXIT_SUCCESS; } // Copy unstripped to stripped location, if necessary. This will implicitly flush & close the // unstripped version. If this is given, we expect to be able to open writable files by name. if (!dex2oat.CopyUnstrippedToStripped()) { return EXIT_FAILURE; } // Flush and close the file. if (!dex2oat.FlushCloseOatFile()) { return EXIT_FAILURE; } dex2oat.DumpTiming(); return EXIT_SUCCESS;}
Compile
CompileImage和CompileApp都调用了dex2oat.Compile()函数:
// Create and invoke the compiler driver. This will compile all the dex files. void Compile() { TimingLogger::ScopedTiming t("dex2oat Compile", timings_); compiler_phases_timings_.reset(new CumulativeLogger("compilation times")); // Handle and ClassLoader creation needs to come after Runtime::Create jobject class_loader = nullptr; Thread* self = Thread::Current(); if (!boot_image_option_.empty()) { ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); OpenClassPathFiles(runtime_->GetClassPathString(), dex_files_, &class_path_files_); ScopedObjectAccess soa(self); // Classpath: first the class-path given. std::vector<const DexFile*> class_path_files; for (auto& class_path_file : class_path_files_) { class_path_files.push_back(class_path_file.get()); } // Store the classpath we have right now. key_value_store_->Put(OatHeader::kClassPathKey, OatFile::EncodeDexFileDependencies(class_path_files)); // Then the dex files we'll compile. Thus we'll resolve the class-path first. class_path_files.insert(class_path_files.end(), dex_files_.begin(), dex_files_.end()); class_loader = class_linker->CreatePathClassLoader(self, class_path_files); } 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_); }
Java不同于其它很多编译型语言的一点是在于它有ClassLoader。在做编译之前,先要对ClassLoader进行预处理。
然后,就创建一个CompilerDriver对象,并调用driver的ComileAll来完成编译。
CompilerDriver的构造函数
核心逻辑还是compiler_的初始化。看到构造需要这么多参数,我们需要对于dex2oat的命令行参数了解(art\compiler\driver\Compiler_driver.cc):
CompilerDriver::CompilerDriver(const CompilerOptions* compiler_options, VerificationResults* verification_results, DexFileToMethodInlinerMap* method_inliner_map, Compiler::Kind compiler_kind, InstructionSet instruction_set, const InstructionSetFeatures* instruction_set_features, bool image, std::unordered_set<std::string>* image_classes, std::unordered_set<std::string>* compiled_classes, std::unordered_set<std::string>* compiled_methods, size_t thread_count, bool dump_stats, bool dump_passes, const std::string& dump_cfg_file_name, CumulativeLogger* timer, int swap_fd, const std::string& profile_file) : swap_space_(swap_fd == -1 ? nullptr : new SwapSpace(swap_fd, 10 * MB)), swap_space_allocator_(new SwapAllocator<void>(swap_space_.get())), profile_present_(false), compiler_options_(compiler_options), verification_results_(verification_results), method_inliner_map_(method_inliner_map), compiler_(Compiler::Create(this, compiler_kind)), compiler_kind_(compiler_kind), instruction_set_(instruction_set), instruction_set_features_(instruction_set_features), freezing_constructor_lock_("freezing constructor lock"), compiled_classes_lock_("compiled classes lock"), compiled_methods_lock_("compiled method lock"), compiled_methods_(MethodTable::key_compare()), non_relative_linker_patch_count_(0u), image_(image), image_classes_(image_classes), classes_to_compile_(compiled_classes), methods_to_compile_(compiled_methods), had_hard_verifier_failure_(false), thread_count_(thread_count), stats_(new AOTCompilationStats), dedupe_enabled_(true), dump_stats_(dump_stats), dump_passes_(dump_passes), dump_cfg_file_name_(dump_cfg_file_name), timings_logger_(timer), compiler_context_(nullptr), support_boot_image_fixup_(instruction_set != kMips && instruction_set != kMips64), dedupe_code_("dedupe code", *swap_space_allocator_), dedupe_src_mapping_table_("dedupe source mapping table", *swap_space_allocator_), dedupe_mapping_table_("dedupe mapping table", *swap_space_allocator_), dedupe_vmap_table_("dedupe vmap table", *swap_space_allocator_), dedupe_gc_map_("dedupe gc map", *swap_space_allocator_), dedupe_cfi_info_("dedupe cfi info", *swap_space_allocator_) { DCHECK(compiler_options_ != nullptr); DCHECK(verification_results_ != nullptr); DCHECK(method_inliner_map_ != nullptr); dex_to_dex_compiler_ = reinterpret_cast<DexToDexCompilerFn>(ArtCompileDEX); compiler_->Init(); CHECK_EQ(image_, image_classes_.get() != nullptr); // Read the profile file if one is provided. if (!profile_file.empty()) { profile_present_ = profile_file_.LoadFile(profile_file); if (profile_present_) { LOG(INFO) << "Using profile data form file " << profile_file; } else { LOG(INFO) << "Failed to load profile file " << profile_file; } }}
CompilerDriver::CompileAll
CompilerDriver为编译线程构造了一个线程池。
在CompilerDriver进行编译的时候,分成了两个步骤:
- PreCompile
- Compile
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_ - 1)); 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(); }}
CompilerDriver::PreCompile
PreCompile的步骤主要就是两个:
- 做校验
- 做类的初始化
我们将前面判断是否要做校验的部分先略过,这个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::Compile
针对每一个dex,调用CompileDexFile去编译:
void CompilerDriver::Compile(jobject class_loader, const std::vector<const DexFile*>& dex_files, ThreadPool* thread_pool, TimingLogger* timings) { for (size_t i = 0; 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);}
CompilerDriver::CompileDexFile
上面的Compile函数是将多个dex拆成每一个dex文件的粒度,而CompileDexFile再将其拆成每个类的粒度,针对每个类再调用CompileClass来进行编译:
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(0, dex_file.NumClassDefs(), CompilerDriver::CompileClass, thread_count_);}
context.ForAll(0, dex_file.NumClassDefs(), CompilerDriver::CompileClass, thread_count_);这条语句中重要的是CompilerDriver::CompileClass,CompilerDriver::CompileClass代表一个回调函数,这个回调函数将一个dex中的类进行编译。
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<3> 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<1> 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 = -1; 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 = -1; 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函数将一个方法进行编译:
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 <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 = 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(); }}
首先是对JNI调用的处理,我们之前曾经看到过的序列。这里会调用compiler_->JniCompile函数。抽象方法不需要生成代码,下面再开始编普通方法,通过调用compiler_->Compile方法来完成。其中还使用到了类的成员变量dex_to_dex_compiler_,这个成员变量在CompilerDriver类的构造函数中被赋值:
CompilerDriver::CompilerDriver(...){ ...... dex_to_dex_compiler_ = reinterpret_cast<DexToDexCompilerFn>(ArtCompileDEX); ......}
ArtCompileDEX的实现代码如下:
extern "C" void ArtCompileDEX(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, art::DexToDexCompilationLevel dex_to_dex_compilation_level) { UNUSED(invoke_type); if (dex_to_dex_compilation_level != art::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); dex_compiler.Compile(); }}
而compiler_->Compile方法中,compiler_是通过Compiler的构造函数中Compiler::Create(this, compiler_kind)创建的(art\compiler\Compiler.cc):
Compiler* Compiler::Create(CompilerDriver* driver, Compiler::Kind kind) { switch (kind) { case kQuick: return CreateQuickCompiler(driver); case kOptimizing: return CreateOptimizingCompiler(driver); default: LOG(FATAL) << "UNREACHABLE"; UNREACHABLE(); }}
举例说明CreateQuickCompiler函数(art\compiler\dex\quick\Quick_compiler.cc):
Compiler* CreateQuickCompiler(CompilerDriver* driver) { return QuickCompiler::Create(driver);}Compiler* QuickCompiler::Create(CompilerDriver* driver) { return new QuickCompiler(driver);}
所以如果编译类型为QuickCompile的话,compiler_->Compile方法就调用了QuickCompiler的Compile方法:
CompiledMethod* QuickCompiler::Compile(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) const { // TODO: check method fingerprint here to determine appropriate backend type. Until then, use // build default. CompilerDriver* driver = GetCompilerDriver(); VLOG(compiler) << "Compiling " << PrettyMethod(method_idx, dex_file) << "..."; if (Compiler::IsPathologicalCase(*code_item, method_idx, dex_file)) { return nullptr; } if (driver->GetVerifiedMethod(&dex_file, method_idx)->HasRuntimeThrow()) { return nullptr; } DCHECK(driver->GetCompilerOptions().IsCompilationEnabled()); Runtime* const runtime = Runtime::Current(); ClassLinker* const class_linker = runtime->GetClassLinker(); InstructionSet instruction_set = driver->GetInstructionSet(); if (instruction_set == kArm) { instruction_set = kThumb2; } CompilationUnit cu(runtime->GetArenaPool(), instruction_set, driver, class_linker); cu.dex_file = &dex_file; cu.class_def_idx = class_def_idx; cu.method_idx = method_idx; cu.access_flags = access_flags; cu.invoke_type = invoke_type; cu.shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx)); CHECK((cu.instruction_set == kThumb2) || (cu.instruction_set == kArm64) || (cu.instruction_set == kX86) || (cu.instruction_set == kX86_64) || (cu.instruction_set == kMips) || (cu.instruction_set == kMips64)); // TODO: set this from command line constexpr bool compiler_flip_match = false; const std::string compiler_method_match = ""; bool use_match = !compiler_method_match.empty(); bool match = use_match && (compiler_flip_match ^ (PrettyMethod(method_idx, dex_file).find(compiler_method_match) != std::string::npos)); if (!use_match || match) { cu.disable_opt = kCompilerOptimizerDisableFlags; cu.enable_debug = kCompilerDebugFlags; cu.verbose = VLOG_IS_ON(compiler) || (cu.enable_debug & (1 << kDebugVerbose)); } if (driver->GetCompilerOptions().HasVerboseMethods()) { cu.verbose = driver->GetCompilerOptions().IsVerboseMethod(PrettyMethod(method_idx, dex_file)); } if (cu.verbose) { cu.enable_debug |= (1 << kDebugCodegenDump); } /* * TODO: rework handling of optimization and debug flags. Should we split out * MIR and backend flags? Need command-line setting as well. */ InitCompilationUnit(cu); cu.StartTimingSplit("BuildMIRGraph"); cu.mir_graph.reset(new MIRGraph(&cu, &cu.arena)); /* * After creation of the MIR graph, also create the code generator. * The reason we do this is that optimizations on the MIR graph may need to get information * that is only available if a CG exists. */ cu.cg.reset(GetCodeGenerator(&cu, nullptr)); /* Gathering opcode stats? */ if (kCompilerDebugFlags & (1 << kDebugCountOpcodes)) { cu.mir_graph->EnableOpcodeCounting(); } /* Build the raw MIR graph */ cu.mir_graph->InlineMethod(code_item, access_flags, invoke_type, class_def_idx, method_idx, class_loader, dex_file); if (!CanCompileMethod(method_idx, dex_file, &cu)) { VLOG(compiler) << cu.instruction_set << ": Cannot compile method : " << PrettyMethod(method_idx, dex_file); cu.EndTiming(); return nullptr; } cu.NewTimingSplit("MIROpt:CheckFilters"); std::string skip_message; if (cu.mir_graph->SkipCompilation(&skip_message)) { VLOG(compiler) << cu.instruction_set << ": Skipping method : " << PrettyMethod(method_idx, dex_file) << " Reason = " << skip_message; cu.EndTiming(); return nullptr; } /* Create the pass driver and launch it */ PassDriverMEOpts pass_driver(GetPreOptPassManager(), GetPostOptPassManager(), &cu); pass_driver.Launch(); /* For non-leaf methods check if we should skip compilation when the profiler is enabled. */ if (cu.compiler_driver->ProfilePresent() && !cu.mir_graph->MethodIsLeaf() && cu.mir_graph->SkipCompilationByName(PrettyMethod(method_idx, dex_file))) { cu.EndTiming(); return nullptr; } if (cu.enable_debug & (1 << kDebugDumpCheckStats)) { cu.mir_graph->DumpCheckStats(); } if (kCompilerDebugFlags & (1 << kDebugCountOpcodes)) { cu.mir_graph->ShowOpcodeStats(); } /* Reassociate sreg names with original Dalvik vreg names. */ cu.mir_graph->RemapRegLocations(); /* Free Arenas from the cu.arena_stack for reuse by the cu.arena in the codegen. */ if (cu.enable_debug & (1 << kDebugShowMemoryUsage)) { if (cu.arena_stack.PeakBytesAllocated() > 1 * 1024 * 1024) { MemStats stack_stats(cu.arena_stack.GetPeakStats()); LOG(INFO) << PrettyMethod(method_idx, dex_file) << " " << Dumpable<MemStats>(stack_stats); } } cu.arena_stack.Reset(); CompiledMethod* result = nullptr; if (cu.mir_graph->PuntToInterpreter()) { VLOG(compiler) << cu.instruction_set << ": Punted method to interpreter: " << PrettyMethod(method_idx, dex_file); cu.EndTiming(); return nullptr; } cu.cg->Materialize(); cu.NewTimingSplit("Dedupe"); /* deduping takes up the vast majority of time in GetCompiledMethod(). */ result = cu.cg->GetCompiledMethod(); cu.NewTimingSplit("Cleanup"); if (result) { VLOG(compiler) << cu.instruction_set << ": Compiled " << PrettyMethod(method_idx, dex_file); } else { VLOG(compiler) << cu.instruction_set << ": Deferred " << PrettyMethod(method_idx, dex_file); } if (cu.enable_debug & (1 << kDebugShowMemoryUsage)) { if (cu.arena.BytesAllocated() > (1 * 1024 *1024)) { MemStats mem_stats(cu.arena.GetMemStats()); LOG(INFO) << PrettyMethod(method_idx, dex_file) << " " << Dumpable<MemStats>(mem_stats); } } if (cu.enable_debug & (1 << kDebugShowSummaryMemoryUsage)) { LOG(INFO) << "MEMINFO " << cu.arena.BytesAllocated() << " " << cu.mir_graph->GetNumBlocks() << " " << PrettyMethod(method_idx, dex_file); } cu.EndTiming(); driver->GetTimingsLogger()->AddLogger(cu.timings); return result;}
关于cu.cg->GetCompiledMethod()的不再深挖,此处暂时保留。。。
参老文献:
ART世界探险(13) - 初入dex2oat
dex2oat将dex转换为oat的执行路径概览
ART世界探险(16) - 快速编译器下的方法编译
- dex2oat源码流程分析
- Dex2Oat源码流程(1)——Android6.0
- Dex2Oat源码流程(2)——Android6.0
- Dex2Oat源码流程(3)——Android6.0
- dex2oat
- dex2oat: dex2oat
- yii源码分析流程
- CAS流程源码分析。
- Volley源码流程分析
- Picasso 源码流程分析
- StateMachine 源码流程分析
- Retrofit 源码分析流程
- Dalvik的JIT编译流程 & ART的dex2oat流程
- MogileFS启动流程,源码分析
- struts2流程和源码分析
- Android关机流程源码分析
- struts2核心流程源码分析
- solr4 facet 源码流程分析
- vim编辑器(4):环境设置
- python 表示windows路径
- 项目管理的繁杂
- Ubuntu与windows时间不对的问题的解决方案
- 【nginx】相关配置
- dex2oat源码流程分析
- 北京四合院信息
- C++中字符串string的输出,很有意思
- sass 学习
- 删除IntelliJ Idea中Maven Archetype
- java新IO---Selector
- 设计模式(c++)笔记之十六(Observer模式)
- 表单查询 排序 添加
- 【nginx】使用HTTP核心模块配置一个静态WEB服务器