Dex2Oat源码流程(2)——Android6.0


在dex2oat.Compile()的最后,可以看到首先创建了一个对象进行初始化,之后执行了driver_->CompileAll(class_loader, dex_files_, timings_);

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_);

CompileAll()

CompileAll()的实现代码位于art/compiler/driver/compiler_driver.cc

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();
  }
}

从代码中可以看到,Compiler首先为编译线程构造了一个线程池,接下来,依次完成两个函数的调用过程,分别为PreCompile()和Compile()。

CompilerDriver::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::PreCompile()主要做了两个工作:

  1. 对所有的类进行校验——Verify(class_loader, dex_files, thread_pool, timings);
  2. 类的初始化——InitializeClasses(class_loader, dex_files, thread_pool, timings);

CompilerDriver::Compile()

接下来继续分析CompilerDriver::Compile()。

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);
}

从代码中可以看出,Compile()方法循环遍历每个dex文件,调用CompileDexFile()编译。

CompilerDriver::CompileDexFile()

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_);
}

Compile函数是将多个dex拆成每一个dex文件分别进行处理,而CompileDexFile再将其拆成每个类,针对每个类再调用CompileClass来进行编译。

CompilerDriver::CompileClass()

CompileClass类的主要逻辑,就是针对直接方法和虚拟方法,分别遍历然后编译。

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()。

CompilerDriver::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编译,抽象方法编译以及普通方法编译,在处理普通方法时,会调用Compile方法来完成。

compiled_method = compiler_->Compile(code_item, access_flags, invoke_type, class_def_idx,
                                           method_idx, class_loader, dex_file);

在这一步中,compiler_会根据dex2oat传入的执行参数选择QuickCompiler或OptimizationCompiler。当–compiler-backend=Optimizing时,选择OptimizationCompiler的Compile()方法完成编译过程,QuickCompiler同理。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值