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