art 是怎么把 dalvik 指令编译成 native code 第一篇(雾里看花)

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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值