art 是怎么把 dalvik 指令编译成 native code 第一篇(雾里看花)
来源:互联网 发布:skitch是什么软件 编辑:程序博客网 时间:2024/04/29 05:50
compiler_kind :这个选项很重要,表示了用什么后端模式去编译 dalvik 指令
static int dex2oat(int argc, char** argv){ b13564922(); original_argc = argc; original_argv = argv; TimingLogger timings("compiler", false, false); CumulativeLogger compiler_phases_timings("compilation times"); InitLogging(argv); // Skip over argv[0]. argv++; argc--; if (argc == 0) { Usage("No arguments specified"); } std::vector<const char*> dex_filenames; std::vector<const char*> dex_locations; int zip_fd = -1; std::string zip_location; std::string oat_filename; std::string oat_symbols; std::string oat_location; int oat_fd = -1; std::string bitcode_filename; const char* image_classes_zip_filename = nullptr; const char* image_classes_filename = nullptr; const char* compiled_classes_zip_filename = nullptr; const char* compiled_classes_filename = nullptr; std::string image_filename; std::string boot_image_filename; uintptr_t image_base = 0; std::string android_root; std::vector<const char*> runtime_args; int thread_count = sysconf(_SC_NPROCESSORS_CONF); /******************************************************** (runtime) Globals.h 中,ART_USE_PORTABLE_COMPILER 在编 译中默认是未开启的。 所以是false ,默认是 Compiler::kQuick #if defined(ART_USE_PORTABLE_COMPILER) static constexpr bool kUsePortableCompiler = true; #else static constexpr bool kUsePortableCompiler = false; #endif ********************************************************/ Compiler::Kind ***compiler_kind*** = kUsePortableCompiler ? Compiler::kPortable : Compiler::kQuick;....... //我了个去,省去了好大堆参数解析,记住自己要分析的选项,这里就不说了。 // Set the compilation target's implicit checks options. switch (instruction_set) { case kArm: case kThumb2: case kArm64: case kX86: case kX86_64: implicit_null_checks = true; implicit_so_checks = true; break; default: // Defaults are correct. break; } //把编译选项都堆在里面去,不管身材怎么样,穿上一身华丽的衣服。 std::unique_ptr<CompilerOptions> compiler_options(new CompilerOptions(compiler_filter, huge_method_threshold, large_method_threshold, small_method_threshold, tiny_method_threshold, num_dex_methods_threshold, generate_gdb_information, include_patch_information, top_k_profile_threshold, include_debug_symbols, implicit_null_checks, implicit_so_checks, implicit_suspend_checks, compile_pic#ifdef ART_SEA_IR_MODE , compiler_options.sea_ir_ = true;#endif )); // NOLINT(whitespace/parens)......... Dex2Oat* p_dex2oat; //这里开始进入主题了。 if (!Dex2Oat::Create(&p_dex2oat, runtime_options, *compiler_options, compiler_kind, instruction_set, instruction_set_features, verification_results.get(), &method_inliner_map, thread_count)) { LOG(ERROR) << "Failed to create dex2oat"; timings.EndTiming(); oat_file->Erase(); return EXIT_FAILURE; } std::unique_ptr<Dex2Oat> dex2oat(p_dex2oat); // Runtime::Create acquired the mutator_lock_ that is normally given away when we Runtime::Start, // give it away now so that we don't starve GC. Thread* self = Thread::Current(); self->TransitionFromRunnableToSuspended(kNative); // If we're doing the image, override the compiler filter to force full compilation. Must be // done ahead of WellKnownClasses::Init that causes verification. Note: doesn't force // compilation of class initializers. // Whilst we're in native take the opportunity to initialize well known classes. WellKnownClasses::Init(self->GetJniEnv()); // If --image-classes was specified, calculate the full list of classes to include in the image std::unique_ptr<std::set<std::string>> image_classes(nullptr); if (image_classes_filename != nullptr) { std::string error_msg; if (image_classes_zip_filename != nullptr) { image_classes.reset(dex2oat->ReadImageClassesFromZip(image_classes_zip_filename, image_classes_filename, &error_msg)); } else { image_classes.reset(dex2oat->ReadImageClassesFromFile(image_classes_filename)); } if (image_classes.get() == nullptr) { LOG(ERROR) << "Failed to create list of image classes from '" << image_classes_filename << "': " << error_msg; timings.EndTiming(); oat_file->Erase(); return EXIT_FAILURE; } } else if (image) { image_classes.reset(new std::set<std::string>); } // If --compiled-classes was specified, calculate the full list of classes to compile in the // image. std::unique_ptr<std::set<std::string>> compiled_classes(nullptr); if (compiled_classes_filename != nullptr) { std::string error_msg; if (compiled_classes_zip_filename != nullptr) { compiled_classes.reset(dex2oat->ReadImageClassesFromZip(compiled_classes_zip_filename, compiled_classes_filename, &error_msg)); } else { compiled_classes.reset(dex2oat->ReadImageClassesFromFile(compiled_classes_filename)); } if (compiled_classes.get() == nullptr) { LOG(ERROR) << "Failed to create list of compiled classes from '" << compiled_classes_filename << "': " << error_msg; timings.EndTiming(); oat_file->Erase(); return EXIT_FAILURE; } } else if (image) { compiled_classes.reset(nullptr); // By default compile everything. } std::vector<const DexFile*> dex_files; if (boot_image_option.empty()) { dex_files = Runtime::Current()->GetClassLinker()->GetBootClassPath(); } else { if (dex_filenames.empty()) { ATRACE_BEGIN("Opening zip archive from file descriptor"); std::string error_msg; std::unique_ptr<ZipArchive> zip_archive(ZipArchive::OpenFromFd(zip_fd, zip_location.c_str(), &error_msg)); if (zip_archive.get() == nullptr) { LOG(ERROR) << "Failed to open zip from file descriptor for '" << zip_location << "': " << error_msg; timings.EndTiming(); oat_file->Erase(); return EXIT_FAILURE; } if (!DexFile::OpenFromZip(*zip_archive.get(), zip_location, &error_msg, &dex_files)) { LOG(ERROR) << "Failed to open dex from file descriptor for zip file '" << zip_location << "': " << error_msg; timings.EndTiming(); oat_file->Erase(); return EXIT_FAILURE; } ATRACE_END(); } else { size_t failure_count = OpenDexFiles(dex_filenames, dex_locations, dex_files); if (failure_count > 0) { LOG(ERROR) << "Failed to open some dex files: " << failure_count; timings.EndTiming(); oat_file->Erase(); return EXIT_FAILURE; } } const bool kSaveDexInput = false; if (kSaveDexInput) { for (size_t i = 0; i < dex_files.size(); ++i) { const DexFile* dex_file = dex_files[i]; std::string tmp_file_name(StringPrintf("/data/local/tmp/dex2oat.%d.%zd.dex", getpid(), i)); std::unique_ptr<File> tmp_file(OS::CreateEmptyFile(tmp_file_name.c_str())); if (tmp_file.get() == nullptr) { PLOG(ERROR) << "Failed to open file " << tmp_file_name << ". Try: adb shell chmod 777 /data/local/tmp"; continue; } // This is just dumping files for debugging. Ignore errors, and leave remnants. UNUSED(tmp_file->WriteFully(dex_file->Begin(), dex_file->Size())); UNUSED(tmp_file->Flush()); UNUSED(tmp_file->Close()); LOG(INFO) << "Wrote input to " << tmp_file_name; } } } // Ensure opened dex files are writable for dex-to-dex transformations. for (const auto& dex_file : dex_files) { if (!dex_file->EnableWrite()) { PLOG(ERROR) << "Failed to make .dex file writeable '" << dex_file->GetLocation() << "'\n"; } } // If we use a swap file, ensure we are above the threshold to make it necessary. if (swap_fd != -1) { if (!UseSwap(image, dex_files)) { close(swap_fd); swap_fd = -1; LOG(INFO) << "Decided to run without swap."; } else { LOG(INFO) << "Accepted running with swap."; } } /* * If we're not in interpret-only or verify-none mode, go ahead and compile small applications. * Don't bother to check if we're doing the image. */ if (!image && compiler_options->IsCompilationEnabled()) { size_t num_methods = 0; for (size_t i = 0; i != dex_files.size(); ++i) { const DexFile* dex_file = dex_files[i]; CHECK(dex_file != nullptr); num_methods += dex_file->NumMethodIds(); } if (num_methods <= compiler_options->GetNumDexMethodsThreshold()) { compiler_options->SetCompilerFilter(CompilerOptions::kSpeed); VLOG(compiler) << "Below method threshold, compiling anyways"; } } // Fill some values into the key-value store for the oat header. std::unique_ptr<SafeMap<std::string, std::string> > key_value_store( new SafeMap<std::string, std::string>()); // Insert some compiler things. { std::ostringstream oss; for (int i = 0; i < argc; ++i) { if (i > 0) { oss << ' '; } oss << argv[i]; } key_value_store->Put(OatHeader::kDex2OatCmdLineKey, oss.str()); oss.str(""); // Reset. oss << kRuntimeISA; key_value_store->Put(OatHeader::kDex2OatHostKey, oss.str()); key_value_store->Put(OatHeader::kPicKey, compile_pic ? "true" : "false"); } //在这里对dex 文件进行编译,创建 oat file。 std::unique_ptr<const CompilerDriver> compiler(dex2oat->CreateOatFile(boot_image_option, android_root, is_host, dex_files, oat_file.get(), oat_location, bitcode_filename, image, image_classes, compiled_classes, dump_stats, dump_passes, timings, compiler_phases_timings, swap_fd, profile_file, key_value_store.get())); if (compiler.get() == nullptr) { LOG(ERROR) << "Failed to create oat file: " << oat_location; timings.EndTiming(); return EXIT_FAILURE; } if (!kUsePortableCompiler) { if (oat_file->FlushCloseOrErase() != 0) { PLOG(ERROR) << "Failed to flush and close oat file: " << oat_location; timings.EndTiming(); return EXIT_FAILURE; } oat_file.reset(); } ......... return EXIT_SUCCESS;}
const CompilerDriver* CreateOatFile(const std::string& boot_image_option, const std::string& android_root, bool is_host, const std::vector<const DexFile*>& dex_files, File* oat_file, const std::string& oat_location, const std::string& bitcode_filename, bool image, std::unique_ptr<std::set<std::string>>& image_classes, std::unique_ptr<std::set<std::string>>& compiled_classes, bool dump_stats, bool dump_passes, TimingLogger& timings, CumulativeLogger& compiler_phases_timings, int swap_fd, std::string profile_file, SafeMap<std::string, std::string>* key_value_store) { CHECK(key_value_store != nullptr); // 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(); std::vector<const DexFile*> class_path_files(dex_files); OpenClassPathFiles(runtime_->GetClassPathString(), class_path_files); ScopedObjectAccess soa(self); for (size_t i = 0; i < class_path_files.size(); i++) { class_linker->RegisterDexFile(*class_path_files[i]); } soa.Env()->AllocObject(WellKnownClasses::dalvik_system_PathClassLoader); ScopedLocalRef<jobject> class_loader_local(soa.Env(), soa.Env()->AllocObject(WellKnownClasses::dalvik_system_PathClassLoader)); class_loader = soa.Env()->NewGlobalRef(class_loader_local.get()); Runtime::Current()->SetCompileTimeClassPath(class_loader, class_path_files); } std::unique_ptr<CompilerDriver> driver(new CompilerDriver(compiler_options_, verification_results_, method_inliner_map_, compiler_kind_, instruction_set_, instruction_set_features_, image, image_classes.release(), compiled_classes.release(), thread_count_, dump_stats, dump_passes, &compiler_phases_timings, swap_fd, profile_file)); driver->GetCompiler()->SetBitcodeFileName(*driver.get(), bitcode_filename); driver->CompileAll(class_loader, dex_files, &timings); TimingLogger::ScopedTiming t2("dex2oat OatWriter", &timings); std::string image_file_location; uint32_t image_file_location_oat_checksum = 0; uintptr_t image_file_location_oat_data_begin = 0; int32_t image_patch_delta = 0; if (!driver->IsImage()) { TimingLogger::ScopedTiming t3("Loading image checksum", &timings); gc::space::ImageSpace* image_space = Runtime::Current()->GetHeap()->GetImageSpace(); image_file_location_oat_checksum = image_space->GetImageHeader().GetOatChecksum(); image_file_location_oat_data_begin = reinterpret_cast<uintptr_t>(image_space->GetImageHeader().GetOatDataBegin()); image_file_location = image_space->GetImageFilename(); image_patch_delta = image_space->GetImageHeader().GetPatchDelta(); } if (!image_file_location.empty()) { key_value_store->Put(OatHeader::kImageLocationKey, image_file_location); } OatWriter oat_writer(dex_files, image_file_location_oat_checksum, image_file_location_oat_data_begin, image_patch_delta, driver.get(), &timings, key_value_store); t2.NewTiming("Writing ELF"); if (!driver->WriteElf(android_root, is_host, dex_files, &oat_writer, oat_file)) { LOG(ERROR) << "Failed to write ELF file " << oat_file->GetPath(); oat_file->Erase(); return nullptr; } // Flush result to disk. Patching code will re-open the file (mmap), so ensure that our view // of the file already made it there and won't be re-ordered with writes from PatchOat or // image patching. if (oat_file->Flush() != 0) { PLOG(ERROR) << "Failed flushing oat file " << oat_file->GetPath(); oat_file->Erase(); return nullptr; } if (!driver->IsImage() && driver->GetCompilerOptions().GetIncludePatchInformation()) { t2.NewTiming("Patching ELF"); std::string error_msg; if (!PatchOatCode(driver.get(), oat_file, oat_location, &error_msg)) { LOG(ERROR) << "Failed to fixup ELF file " << oat_file->GetPath() << ": " << error_msg; oat_file->Erase(); return nullptr; } } return driver.release(); }
Compiler* Compiler::Create(CompilerDriver* driver, Compiler::Kind kind) { switch (kind) { case kQuick: return new QuickCompiler(driver); break; case kOptimizing: return new OptimizingCompiler(driver); break; case kPortable:#ifdef ART_USE_PORTABLE_COMPILER return new LLVMCompiler(driver);#else LOG(FATAL) << "Portable compiler not compiled";#endif break; default: LOG(FATAL) << "UNREACHABLE"; } return nullptr;}
CreateOatFile 中创建了一个 CompilerDriver 类的对象,它是整个编译过程中的一个驱动者,它处理前面设置好的参数把编译事项吩咐下去。
在构造CompilerDriver 过程中,有我们关心的一点就是根据 CompilerDriver 传进去的 Compiler::Kind compiler_kind 去设置具体的 compiler_(Compiler::Create(this, compiler_kind)) 具体可以看代码片段 Compiler* Compiler::Create(CompilerDriver* driver, Compiler::Kind kind) 函数。
默认是 return new QuickCompiler(driver); Quick 后端。这里说个体外话(很多人以为 art 是通过 llvm 对dex 做的编译,其实不是,源码目录 compiler 目录下的 portable 就是用的llvm,可自从android 4.4 加入art以来,这个就没有用过。那么Quick 从哪里来的呢?我在网上看到有人说是从Dalvik 本身的 JIT
编译器改造而来,我也没去证实过)
去给我干活。编译dex。
driver->CompileAll(class_loader, dex_files, &timings);
后面还有会陆续分析,也是业余爱好,没什么水平,谢谢批评。
0 0
- art 是怎么把 dalvik 指令编译成 native code 第一篇(雾里看花)
- art 是怎么把 dalvik 指令编译成 native code 第二篇(走马观花)
- java开发编译器:把C语言的循环指令编译成java字节码
- visual studio中怎么把C#程序编译成exe文件
- idea下,jdk 1.8 下怎么把类编译成1.6
- [Objective-C] @property是不能被“预处理”的,而是直接编译成汇编指令
- 把aspx文件编译成DLL文件
- 把aspx文件编译成DLL文件
- 把cs文件编译成dll
- 把aspx文件编译成DLL文件
- 把aspx文件编译成DLL文件
- 把aspx文件编译成DLL文件
- 把aspx文件编译成DLL文件
- 把CS文件编译成dll文件
- 把aspx文件编译成DLL文件
- 把aspx文件编译成DLL文件
- 把aspx编译成dll文件
- 把aspx文件编译成DLL文件
- iOS-FMDB和SQLite3使用
- 深入HTTP head的使用详解
- GUI系统(Graphical User Interface)图形用户界面
- mybatis:getting started
- 二手房过户时七大注意事项
- art 是怎么把 dalvik 指令编译成 native code 第一篇(雾里看花)
- C#中HttpWebRequest的用法详解
- 网页返回的状态码查询表
- ffmpeg 搭配ffserver输出http协议视频流
- Java的堆和栈
- Linux unlink()
- leetcode 22. Generate Parentheses
- Android Studio检测内存泄露和性能
- 秦并天下